internal/cabi: transform pkg to cabi
This commit is contained in:
356
internal/cabi/arch.go
Normal file
356
internal/cabi/arch.go
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
package cabi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llvm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func elementTypesCount(typ llvm.Type) int {
|
||||||
|
switch typ.TypeKind() {
|
||||||
|
case llvm.VoidTypeKind:
|
||||||
|
return 0
|
||||||
|
case llvm.StructTypeKind:
|
||||||
|
var count int
|
||||||
|
for _, t := range typ.StructElementTypes() {
|
||||||
|
count += elementTypesCount(t)
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
case llvm.ArrayTypeKind:
|
||||||
|
return typ.ArrayLength() * elementTypesCount(typ.ElementType())
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func elementTypes(td llvm.TargetData, typ llvm.Type) (types []llvm.Type) {
|
||||||
|
switch typ.TypeKind() {
|
||||||
|
case llvm.VoidTypeKind:
|
||||||
|
case llvm.StructTypeKind:
|
||||||
|
for _, t := range typ.StructElementTypes() {
|
||||||
|
types = append(types, elementTypes(td, t)...)
|
||||||
|
}
|
||||||
|
case llvm.ArrayTypeKind:
|
||||||
|
sub := elementTypes(td, typ.ElementType())
|
||||||
|
n := typ.ArrayLength()
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
types = append(types, sub...)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
types = append(types, typ)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkTypes(typs []llvm.Type, typ llvm.Type) bool {
|
||||||
|
for _, t := range typs {
|
||||||
|
if t != typ {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasTypes(typs []llvm.Type, typ llvm.Type) bool {
|
||||||
|
for _, t := range typs {
|
||||||
|
if t == typ {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfoAmd64 struct {
|
||||||
|
*Transformer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoAmd64) SupportByVal() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoAmd64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
|
||||||
|
return elementTypesCount(typ) >= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoAmd64) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
|
||||||
|
info := &TypeInfo{}
|
||||||
|
info.Type = typ
|
||||||
|
info.Type1 = typ
|
||||||
|
if typ.TypeKind() == llvm.VoidTypeKind {
|
||||||
|
info.Kind = AttrVoid
|
||||||
|
return info
|
||||||
|
} else if typ.TypeKind() == llvm.PointerTypeKind {
|
||||||
|
}
|
||||||
|
info.Size = p.Sizeof(typ)
|
||||||
|
info.Align = p.Alignof(typ)
|
||||||
|
if n := elementTypesCount(typ); n >= 2 {
|
||||||
|
if info.Size > 16 {
|
||||||
|
info.Kind = AttrPointer
|
||||||
|
info.Type1 = llvm.PointerType(typ, 0)
|
||||||
|
} else if info.Size <= 8 {
|
||||||
|
info.Kind = AttrWidthType
|
||||||
|
info.Type1 = ctx.IntType(info.Size * 8)
|
||||||
|
types := elementTypes(p.td, typ)
|
||||||
|
if types[0] == ctx.FloatType() && types[1] == ctx.FloatType() {
|
||||||
|
info.Type1 = llvm.VectorType(ctx.FloatType(), 2)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
types := elementTypes(p.td, typ)
|
||||||
|
if n == 2 {
|
||||||
|
// skip (float32,float32)
|
||||||
|
if types[0] == ctx.FloatType() && types[1] == ctx.FloatType() {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
// skip (i64|double,*) (*,i64/double)
|
||||||
|
if p.Sizeof(types[0]) == 8 || p.Sizeof(types[1]) == 8 {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.Kind = AttrWidthType2
|
||||||
|
var count int
|
||||||
|
for i, et := range types {
|
||||||
|
count += p.Sizeof(et)
|
||||||
|
if count >= 8 {
|
||||||
|
if i == 0 {
|
||||||
|
info.Type1 = et
|
||||||
|
} else if i == 1 && types[0] == ctx.FloatType() && types[1] == ctx.FloatType() {
|
||||||
|
info.Type1 = llvm.VectorType(ctx.FloatType(), 2)
|
||||||
|
} else {
|
||||||
|
info.Type1 = ctx.Int64Type()
|
||||||
|
}
|
||||||
|
right := len(types) - i
|
||||||
|
if count == 8 {
|
||||||
|
right--
|
||||||
|
}
|
||||||
|
if right == 1 {
|
||||||
|
info.Type2 = types[len(types)-1]
|
||||||
|
} else if right == 2 && types[len(types)-1] == ctx.FloatType() && types[len(types)-2] == ctx.FloatType() {
|
||||||
|
info.Type2 = llvm.VectorType(ctx.FloatType(), 2)
|
||||||
|
} else {
|
||||||
|
info.Type2 = ctx.IntType((info.Size - 8) * 8)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfoArm64 struct {
|
||||||
|
*Transformer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoArm64) SupportByVal() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoArm64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
|
||||||
|
switch typ.TypeKind() {
|
||||||
|
case llvm.StructTypeKind, llvm.ArrayTypeKind:
|
||||||
|
if bret && elementTypesCount(typ) == 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoArm64) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
|
||||||
|
info := &TypeInfo{}
|
||||||
|
info.Type = typ
|
||||||
|
info.Type1 = typ
|
||||||
|
kind := typ.TypeKind()
|
||||||
|
if kind == llvm.VoidTypeKind {
|
||||||
|
info.Kind = AttrVoid
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
info.Size = p.Sizeof(typ)
|
||||||
|
info.Align = p.Alignof(typ)
|
||||||
|
switch kind {
|
||||||
|
case llvm.StructTypeKind, llvm.ArrayTypeKind:
|
||||||
|
types := elementTypes(p.td, typ)
|
||||||
|
n := len(types)
|
||||||
|
if bret && n == 1 {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
if n == 2 {
|
||||||
|
// skip (i64/ptr,i64/ptr)
|
||||||
|
if (types[0].TypeKind() == llvm.PointerTypeKind || types[0] == ctx.Int64Type()) &&
|
||||||
|
(types[1].TypeKind() == llvm.PointerTypeKind || types[1] == ctx.Int64Type()) {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n <= 4 {
|
||||||
|
if checkTypes(types, ctx.FloatType()) || checkTypes(types, ctx.DoubleType()) {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if info.Size > 16 {
|
||||||
|
info.Kind = AttrPointer
|
||||||
|
info.Type1 = llvm.PointerType(typ, 0)
|
||||||
|
} else if info.Size <= 8 {
|
||||||
|
info.Kind = AttrWidthType
|
||||||
|
if bret {
|
||||||
|
info.Type1 = ctx.IntType(info.Size * 8)
|
||||||
|
} else {
|
||||||
|
info.Type1 = ctx.Int64Type()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info.Kind = AttrWidthType
|
||||||
|
info.Type1 = llvm.ArrayType(ctx.Int64Type(), 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfoArm struct {
|
||||||
|
*Transformer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoArm) SupportByVal() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoArm) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
|
||||||
|
switch typ.TypeKind() {
|
||||||
|
case llvm.StructTypeKind, llvm.ArrayTypeKind:
|
||||||
|
if bret && elementTypesCount(typ) == 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoArm) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
|
||||||
|
info := &TypeInfo{}
|
||||||
|
info.Type = typ
|
||||||
|
info.Type1 = typ
|
||||||
|
kind := typ.TypeKind()
|
||||||
|
if kind == llvm.VoidTypeKind {
|
||||||
|
info.Kind = AttrVoid
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
info.Size = p.Sizeof(typ)
|
||||||
|
info.Align = p.Alignof(typ)
|
||||||
|
switch kind {
|
||||||
|
case llvm.StructTypeKind, llvm.ArrayTypeKind:
|
||||||
|
types := elementTypes(p.td, typ)
|
||||||
|
n := len(types)
|
||||||
|
if bret && n == 1 {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
if n <= 4 {
|
||||||
|
if checkTypes(types, ctx.FloatType()) || checkTypes(types, ctx.DoubleType()) {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bret {
|
||||||
|
if info.Size > 4 {
|
||||||
|
info.Kind = AttrPointer
|
||||||
|
info.Type1 = llvm.PointerType(typ, 0)
|
||||||
|
} else {
|
||||||
|
info.Kind = AttrWidthType
|
||||||
|
info.Type1 = ctx.Int32Type()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if info.Size > 64 {
|
||||||
|
info.Kind = AttrPointer
|
||||||
|
info.Type1 = llvm.PointerType(typ, 0)
|
||||||
|
} else {
|
||||||
|
info.Kind = AttrWidthType
|
||||||
|
if hasTypes(types, ctx.Int64Type()) || hasTypes(types, ctx.DoubleType()) {
|
||||||
|
info.Type1 = llvm.ArrayType(ctx.Int64Type(), info.Size/8)
|
||||||
|
} else {
|
||||||
|
info.Type1 = llvm.ArrayType(ctx.Int32Type(), info.Size/4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfo32 struct {
|
||||||
|
*Transformer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfo32) SupportByVal() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfo32) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
|
||||||
|
return elementTypesCount(typ) >= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfo32) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
|
||||||
|
info := &TypeInfo{}
|
||||||
|
info.Type = typ
|
||||||
|
info.Type1 = typ
|
||||||
|
if typ.TypeKind() == llvm.VoidTypeKind {
|
||||||
|
info.Kind = AttrVoid
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
info.Size = p.Sizeof(typ)
|
||||||
|
info.Align = p.Alignof(typ)
|
||||||
|
if n := elementTypesCount(typ); n >= 2 {
|
||||||
|
info.Kind = AttrPointer
|
||||||
|
info.Type1 = llvm.PointerType(typ, 0)
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfoRiscv64 struct {
|
||||||
|
*Transformer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoRiscv64) SupportByVal() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoRiscv64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
|
||||||
|
switch typ.TypeKind() {
|
||||||
|
case llvm.StructTypeKind, llvm.ArrayTypeKind:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TypeInfoRiscv64) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
|
||||||
|
info := &TypeInfo{}
|
||||||
|
info.Type = typ
|
||||||
|
info.Type1 = typ
|
||||||
|
if typ.TypeKind() == llvm.VoidTypeKind {
|
||||||
|
info.Kind = AttrVoid
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
info.Size = p.Sizeof(typ)
|
||||||
|
info.Align = p.Alignof(typ)
|
||||||
|
switch typ.TypeKind() {
|
||||||
|
case llvm.StructTypeKind, llvm.ArrayTypeKind:
|
||||||
|
types := elementTypes(p.td, typ)
|
||||||
|
switch len(types) {
|
||||||
|
case 1:
|
||||||
|
if types[0].TypeKind() == llvm.PointerTypeKind || types[0] == ctx.Int64Type() {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if (types[0].TypeKind() == llvm.PointerTypeKind || types[0] == ctx.Int64Type()) &&
|
||||||
|
(types[1].TypeKind() == llvm.PointerTypeKind || types[1] == ctx.Int64Type()) {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if info.Size > 16 {
|
||||||
|
info.Kind = AttrPointer
|
||||||
|
info.Type1 = llvm.PointerType(typ, 0)
|
||||||
|
} else if info.Size <= 8 {
|
||||||
|
info.Kind = AttrWidthType
|
||||||
|
info.Type1 = ctx.Int64Type()
|
||||||
|
} else {
|
||||||
|
info.Kind = AttrWidthType
|
||||||
|
info.Type1 = llvm.ArrayType(ctx.Int64Type(), 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
545
internal/cabi/cabi.go
Normal file
545
internal/cabi/cabi.go
Normal file
@@ -0,0 +1,545 @@
|
|||||||
|
package cabi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/ssa"
|
||||||
|
"github.com/goplus/llvm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModeNone Mode = iota
|
||||||
|
ModeCFunc
|
||||||
|
ModeAllFunc
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTransformer(prog ssa.Program, mode Mode) *Transformer {
|
||||||
|
target := prog.Target()
|
||||||
|
tr := &Transformer{
|
||||||
|
prog: prog,
|
||||||
|
td: prog.TargetData(),
|
||||||
|
GOOS: target.GOOS,
|
||||||
|
GOARCH: target.GOARCH,
|
||||||
|
mode: mode,
|
||||||
|
}
|
||||||
|
switch target.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
tr.sys = &TypeInfoAmd64{tr}
|
||||||
|
case "arm64":
|
||||||
|
tr.sys = &TypeInfoArm64{tr}
|
||||||
|
case "arm":
|
||||||
|
tr.sys = &TypeInfoArm{tr}
|
||||||
|
case "wasm", "i386":
|
||||||
|
tr.sys = &TypeInfo32{tr}
|
||||||
|
case "riscv64":
|
||||||
|
tr.sys = &TypeInfoRiscv64{tr}
|
||||||
|
}
|
||||||
|
return tr
|
||||||
|
}
|
||||||
|
|
||||||
|
type Transformer struct {
|
||||||
|
prog ssa.Program
|
||||||
|
td llvm.TargetData
|
||||||
|
GOOS string
|
||||||
|
GOARCH string
|
||||||
|
sys TypeInfoSys
|
||||||
|
mode Mode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) isCFunc(name string) bool {
|
||||||
|
return !strings.Contains(name, ".")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) TransformModule(pkg ssa.Package) {
|
||||||
|
m := pkg.Module()
|
||||||
|
ctx := m.Context()
|
||||||
|
var fns []llvm.Value
|
||||||
|
var callInstrs []llvm.Value
|
||||||
|
switch p.mode {
|
||||||
|
case ModeNone:
|
||||||
|
return
|
||||||
|
case ModeCFunc:
|
||||||
|
fn := m.FirstFunction()
|
||||||
|
for !fn.IsNil() {
|
||||||
|
if p.isCFunc(fn.Name()) {
|
||||||
|
p.transformFuncCall(m, fn)
|
||||||
|
if p.isWrapFunctionType(m.Context(), fn.GlobalValueType()) {
|
||||||
|
fns = append(fns, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn = llvm.NextFunction(fn)
|
||||||
|
}
|
||||||
|
case ModeAllFunc:
|
||||||
|
fn := m.FirstFunction()
|
||||||
|
for !fn.IsNil() {
|
||||||
|
if p.isWrapFunctionType(ctx, fn.GlobalValueType()) {
|
||||||
|
fns = append(fns, fn)
|
||||||
|
}
|
||||||
|
bb := fn.FirstBasicBlock()
|
||||||
|
for !bb.IsNil() {
|
||||||
|
instr := bb.FirstInstruction()
|
||||||
|
for !instr.IsNil() {
|
||||||
|
if call := instr.IsACallInst(); !call.IsNil() {
|
||||||
|
if p.isWrapFunctionType(ctx, call.CalledFunctionType()) {
|
||||||
|
callInstrs = append(callInstrs, call)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instr = llvm.NextInstruction(instr)
|
||||||
|
}
|
||||||
|
bb = llvm.NextBasicBlock(bb)
|
||||||
|
}
|
||||||
|
fn = llvm.NextFunction(fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, call := range callInstrs {
|
||||||
|
p.transformCallInstr(ctx, call)
|
||||||
|
}
|
||||||
|
for _, fn := range fns {
|
||||||
|
p.transformFunc(m, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) isWrapFunctionType(ctx llvm.Context, ft llvm.Type) bool {
|
||||||
|
if p.IsWrapType(ctx, ft.ReturnType(), true) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, typ := range ft.ParamTypes() {
|
||||||
|
if p.IsWrapType(ctx, typ, false) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfoSys interface {
|
||||||
|
SupportByVal() bool
|
||||||
|
IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool
|
||||||
|
GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type AttrKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AttrNone AttrKind = iota
|
||||||
|
AttrVoid // param type void
|
||||||
|
AttrPointer // param type => type*
|
||||||
|
AttrWidthType // type => width int i16/i24/i32/i40/i48/i56/i64 float/double
|
||||||
|
AttrWidthType2 // type => width two int {i64,i16} float/double
|
||||||
|
)
|
||||||
|
|
||||||
|
type FuncInfo struct {
|
||||||
|
Type llvm.Type // func type
|
||||||
|
Return *TypeInfo // return info
|
||||||
|
Params []*TypeInfo // params info
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *FuncInfo) HasWrap() bool {
|
||||||
|
if p.Return.Kind > AttrVoid {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, t := range p.Params {
|
||||||
|
if t.Kind > AttrVoid {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfo struct {
|
||||||
|
Type llvm.Type
|
||||||
|
Kind AttrKind
|
||||||
|
Type1 llvm.Type // AttrWidthType
|
||||||
|
Type2 llvm.Type // AttrWidthType2
|
||||||
|
Size int
|
||||||
|
Align int
|
||||||
|
}
|
||||||
|
|
||||||
|
func byvalAttribute(ctx llvm.Context, typ llvm.Type) llvm.Attribute {
|
||||||
|
id := llvm.AttributeKindID("byval")
|
||||||
|
return ctx.CreateTypeAttribute(id, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sretAttribute(ctx llvm.Context, typ llvm.Type) llvm.Attribute {
|
||||||
|
id := llvm.AttributeKindID("sret")
|
||||||
|
return ctx.CreateTypeAttribute(id, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func funcInlineHint(ctx llvm.Context) llvm.Attribute {
|
||||||
|
return ctx.CreateEnumAttribute(llvm.AttributeKindID("inlinehint"), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
|
||||||
|
if p.sys != nil {
|
||||||
|
return p.sys.IsWrapType(ctx, typ, bret)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
|
||||||
|
if p.sys != nil {
|
||||||
|
return p.sys.GetTypeInfo(ctx, typ, bret)
|
||||||
|
}
|
||||||
|
panic("not implment: " + p.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) Sizeof(typ llvm.Type) int {
|
||||||
|
return int(p.td.TypeAllocSize(typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) Alignof(typ llvm.Type) int {
|
||||||
|
return int(p.td.ABITypeAlignment(typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) GetFuncInfo(ctx llvm.Context, typ llvm.Type) (info FuncInfo) {
|
||||||
|
info.Type = typ
|
||||||
|
info.Return = p.GetTypeInfo(ctx, typ.ReturnType(), true)
|
||||||
|
params := typ.ParamTypes()
|
||||||
|
info.Params = make([]*TypeInfo, len(params))
|
||||||
|
for i, t := range params {
|
||||||
|
info.Params[i] = p.GetTypeInfo(ctx, t, false)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) transformFuncType(ctx llvm.Context, info *FuncInfo) (llvm.Type, map[int]llvm.Attribute) {
|
||||||
|
var paramTypes []llvm.Type
|
||||||
|
var returnType llvm.Type
|
||||||
|
attrs := make(map[int]llvm.Attribute)
|
||||||
|
switch info.Return.Kind {
|
||||||
|
case AttrPointer:
|
||||||
|
returnType = ctx.VoidType()
|
||||||
|
paramTypes = append(paramTypes, info.Return.Type1)
|
||||||
|
attrs[1] = sretAttribute(ctx, info.Return.Type)
|
||||||
|
case AttrWidthType:
|
||||||
|
returnType = info.Return.Type1
|
||||||
|
case AttrWidthType2:
|
||||||
|
returnType = llvm.StructType([]llvm.Type{info.Return.Type1, info.Return.Type2}, false)
|
||||||
|
default:
|
||||||
|
returnType = info.Return.Type1
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ti := range info.Params {
|
||||||
|
switch ti.Kind {
|
||||||
|
case AttrNone, AttrWidthType:
|
||||||
|
paramTypes = append(paramTypes, ti.Type1)
|
||||||
|
case AttrPointer:
|
||||||
|
paramTypes = append(paramTypes, ti.Type1)
|
||||||
|
if p.sys.SupportByVal() {
|
||||||
|
attrs[len(paramTypes)] = byvalAttribute(ctx, ti.Type)
|
||||||
|
}
|
||||||
|
case AttrWidthType2:
|
||||||
|
paramTypes = append(paramTypes, ti.Type1, ti.Type2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return llvm.FunctionType(returnType, paramTypes, info.Type.IsFunctionVarArg()), attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) transformFunc(m llvm.Module, fn llvm.Value) bool {
|
||||||
|
ctx := m.Context()
|
||||||
|
info := p.GetFuncInfo(ctx, fn.GlobalValueType())
|
||||||
|
if !info.HasWrap() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
nft, attrs := p.transformFuncType(ctx, &info)
|
||||||
|
fname := fn.Name()
|
||||||
|
fn.SetName("")
|
||||||
|
nfn := llvm.AddFunction(m, fname, nft)
|
||||||
|
for i, attr := range attrs {
|
||||||
|
nfn.AddAttributeAtIndex(i, attr)
|
||||||
|
}
|
||||||
|
nfn.SetLinkage(fn.Linkage())
|
||||||
|
nfn.SetFunctionCallConv(fn.FunctionCallConv())
|
||||||
|
for _, attr := range fn.GetFunctionAttributes() {
|
||||||
|
nfn.AddAttributeAtIndex(-1, attr)
|
||||||
|
}
|
||||||
|
if sp := fn.Subprogram(); !sp.IsNil() {
|
||||||
|
nfn.SetSubprogram(sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fn.IsDeclaration() {
|
||||||
|
p.transformFuncBody(ctx, &info, fn, nfn, nft)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn.ReplaceAllUsesWith(nfn)
|
||||||
|
fn.EraseFromParentAsFunction()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) transformFuncBody(ctx llvm.Context, info *FuncInfo, fn llvm.Value, nfn llvm.Value, nft llvm.Type) {
|
||||||
|
var blocks []llvm.BasicBlock
|
||||||
|
bb := fn.FirstBasicBlock()
|
||||||
|
for !bb.IsNil() {
|
||||||
|
blocks = append(blocks, bb)
|
||||||
|
bb = llvm.NextBasicBlock(bb)
|
||||||
|
}
|
||||||
|
for _, bb := range blocks {
|
||||||
|
bb.RemoveFromParent()
|
||||||
|
llvm.AppendExistingBasicBlock(nfn, bb)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := ctx.NewBuilder()
|
||||||
|
b.SetInsertPointBefore(nfn.EntryBasicBlock().FirstInstruction())
|
||||||
|
|
||||||
|
params := nfn.Params()
|
||||||
|
index := 0
|
||||||
|
if info.Return.Kind == AttrPointer {
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
for i, ti := range info.Params {
|
||||||
|
nv := params[index]
|
||||||
|
switch ti.Kind {
|
||||||
|
default:
|
||||||
|
case AttrPointer:
|
||||||
|
nv = b.CreateLoad(ti.Type, params[index], "")
|
||||||
|
case AttrWidthType:
|
||||||
|
iptr := llvm.CreateAlloca(b, ti.Type1)
|
||||||
|
b.CreateStore(params[index], iptr)
|
||||||
|
ptr := b.CreateBitCast(iptr, llvm.PointerType(ti.Type, 0), "")
|
||||||
|
nv = b.CreateLoad(ti.Type, ptr, "")
|
||||||
|
case AttrWidthType2:
|
||||||
|
typ := llvm.StructType([]llvm.Type{ti.Type1, ti.Type2}, false)
|
||||||
|
iptr := llvm.CreateAlloca(b, typ)
|
||||||
|
b.CreateStore(params[index], b.CreateStructGEP(typ, iptr, 0, ""))
|
||||||
|
index++
|
||||||
|
b.CreateStore(params[index], b.CreateStructGEP(typ, iptr, 1, ""))
|
||||||
|
ptr := b.CreateBitCast(iptr, llvm.PointerType(ti.Type, 0), "")
|
||||||
|
nv = b.CreateLoad(ti.Type, ptr, "")
|
||||||
|
}
|
||||||
|
fn.Param(i).ReplaceAllUsesWith(nv)
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
if info.Return.Kind >= AttrPointer {
|
||||||
|
var retInstrs []llvm.Value
|
||||||
|
bb := nfn.FirstBasicBlock()
|
||||||
|
for !bb.IsNil() {
|
||||||
|
instr := bb.FirstInstruction()
|
||||||
|
for !instr.IsNil() {
|
||||||
|
if !instr.IsAReturnInst().IsNil() {
|
||||||
|
retInstrs = append(retInstrs, instr)
|
||||||
|
}
|
||||||
|
instr = llvm.NextInstruction(instr)
|
||||||
|
}
|
||||||
|
bb = llvm.NextBasicBlock(bb)
|
||||||
|
}
|
||||||
|
for _, instr := range retInstrs {
|
||||||
|
ret := instr.Operand(0)
|
||||||
|
b.SetInsertPointBefore(instr)
|
||||||
|
var rv llvm.Value
|
||||||
|
switch info.Return.Kind {
|
||||||
|
case AttrPointer:
|
||||||
|
b.CreateStore(ret, params[0])
|
||||||
|
rv = b.CreateRetVoid()
|
||||||
|
case AttrWidthType, AttrWidthType2:
|
||||||
|
ptr := llvm.CreateAlloca(b, info.Return.Type)
|
||||||
|
b.CreateStore(ret, ptr)
|
||||||
|
iptr := b.CreateBitCast(ptr, llvm.PointerType(nft.ReturnType(), 0), "")
|
||||||
|
rv = b.CreateRet(b.CreateLoad(nft.ReturnType(), iptr, ""))
|
||||||
|
}
|
||||||
|
instr.ReplaceAllUsesWith(rv)
|
||||||
|
instr.EraseFromParentAsInstruction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) transformCallInstr(ctx llvm.Context, call llvm.Value) bool {
|
||||||
|
nfn := call.CalledValue()
|
||||||
|
info := p.GetFuncInfo(ctx, call.CalledFunctionType())
|
||||||
|
if !info.HasWrap() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
nft, attrs := p.transformFuncType(ctx, &info)
|
||||||
|
b := ctx.NewBuilder()
|
||||||
|
b.SetInsertPointBefore(call)
|
||||||
|
operandCount := len(info.Params)
|
||||||
|
var nparams []llvm.Value
|
||||||
|
for i := 0; i < operandCount; i++ {
|
||||||
|
param := call.Operand(i)
|
||||||
|
ti := info.Params[i]
|
||||||
|
switch ti.Kind {
|
||||||
|
default:
|
||||||
|
nparams = append(nparams, param)
|
||||||
|
case AttrPointer:
|
||||||
|
ptr := llvm.CreateAlloca(b, ti.Type)
|
||||||
|
b.CreateStore(param, ptr)
|
||||||
|
nparams = append(nparams, ptr)
|
||||||
|
case AttrWidthType:
|
||||||
|
ptr := llvm.CreateAlloca(b, ti.Type)
|
||||||
|
b.CreateStore(param, ptr)
|
||||||
|
iptr := b.CreateBitCast(ptr, llvm.PointerType(ti.Type1, 0), "")
|
||||||
|
nparams = append(nparams, b.CreateLoad(ti.Type1, iptr, ""))
|
||||||
|
case AttrWidthType2:
|
||||||
|
ptr := llvm.CreateAlloca(b, ti.Type)
|
||||||
|
b.CreateStore(param, ptr)
|
||||||
|
typ := llvm.StructType([]llvm.Type{ti.Type1, ti.Type2}, false) // {i8,i64}
|
||||||
|
iptr := b.CreateBitCast(ptr, llvm.PointerType(typ, 0), "")
|
||||||
|
nparams = append(nparams, b.CreateLoad(ti.Type1, b.CreateStructGEP(typ, iptr, 0, ""), ""))
|
||||||
|
nparams = append(nparams, b.CreateLoad(ti.Type2, b.CreateStructGEP(typ, iptr, 1, ""), ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCallAttr := func(call llvm.Value) {
|
||||||
|
for i, attr := range attrs {
|
||||||
|
call.AddCallSiteAttribute(i, attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var instr llvm.Value
|
||||||
|
switch info.Return.Kind {
|
||||||
|
case AttrVoid:
|
||||||
|
instr = llvm.CreateCall(b, nft, nfn, nparams)
|
||||||
|
updateCallAttr(instr)
|
||||||
|
case AttrPointer:
|
||||||
|
ret := llvm.CreateAlloca(b, info.Return.Type)
|
||||||
|
call := llvm.CreateCall(b, nft, nfn, append([]llvm.Value{ret}, nparams...))
|
||||||
|
updateCallAttr(call)
|
||||||
|
instr = b.CreateLoad(info.Return.Type, ret, "")
|
||||||
|
case AttrWidthType, AttrWidthType2:
|
||||||
|
ret := llvm.CreateCall(b, nft, nfn, nparams)
|
||||||
|
updateCallAttr(ret)
|
||||||
|
ptr := llvm.CreateAlloca(b, nft.ReturnType())
|
||||||
|
b.CreateStore(ret, ptr)
|
||||||
|
pret := b.CreateBitCast(ptr, llvm.PointerType(info.Return.Type, 0), "")
|
||||||
|
instr = b.CreateLoad(info.Return.Type, pret, "")
|
||||||
|
default:
|
||||||
|
instr = llvm.CreateCall(b, nft, nfn, nparams)
|
||||||
|
updateCallAttr(instr)
|
||||||
|
}
|
||||||
|
call.ReplaceAllUsesWith(instr)
|
||||||
|
call.RemoveFromParentAsInstruction()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) transformFuncCall(m llvm.Module, fn llvm.Value) {
|
||||||
|
u := fn.FirstUse()
|
||||||
|
ctx := m.Context()
|
||||||
|
for !u.IsNil() {
|
||||||
|
if call := u.User().IsACallInst(); !call.IsNil() {
|
||||||
|
n := call.OperandsCount()
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
op := call.Operand(i)
|
||||||
|
if op == fn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if gv := op.IsAGlobalValue(); !gv.IsNil() {
|
||||||
|
if ft := gv.GlobalValueType(); ft.TypeKind() == llvm.FunctionTypeKind {
|
||||||
|
if p.isCFunc(gv.Name()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p.isWrapFunctionType(ctx, ft) {
|
||||||
|
if wrap, ok := p.transformCallbackFunc(m, gv); ok {
|
||||||
|
call.SetOperand(i, wrap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u = u.NextUse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap llvm.Value, ok bool) {
|
||||||
|
var paramTypes []llvm.Type
|
||||||
|
var returnType llvm.Type
|
||||||
|
attrs := make(map[int]llvm.Attribute)
|
||||||
|
ctx := m.Context()
|
||||||
|
info := p.GetFuncInfo(ctx, fn.GlobalValueType())
|
||||||
|
if !info.HasWrap() {
|
||||||
|
return fn, false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch info.Return.Kind {
|
||||||
|
case AttrPointer:
|
||||||
|
returnType = ctx.VoidType()
|
||||||
|
paramTypes = append(paramTypes, info.Return.Type1)
|
||||||
|
attrs[1] = sretAttribute(ctx, info.Return.Type)
|
||||||
|
case AttrWidthType:
|
||||||
|
returnType = info.Return.Type1
|
||||||
|
case AttrWidthType2:
|
||||||
|
returnType = llvm.StructType([]llvm.Type{info.Return.Type1, info.Return.Type2}, false)
|
||||||
|
default:
|
||||||
|
returnType = info.Return.Type1
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ti := range info.Params {
|
||||||
|
switch ti.Kind {
|
||||||
|
case AttrNone, AttrWidthType:
|
||||||
|
paramTypes = append(paramTypes, ti.Type1)
|
||||||
|
case AttrPointer:
|
||||||
|
paramTypes = append(paramTypes, ti.Type1)
|
||||||
|
if p.sys.SupportByVal() {
|
||||||
|
attrs[len(paramTypes)] = byvalAttribute(ctx, ti.Type)
|
||||||
|
}
|
||||||
|
case AttrWidthType2:
|
||||||
|
paramTypes = append(paramTypes, ti.Type1, ti.Type2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fname := fn.Name()
|
||||||
|
nft := llvm.FunctionType(returnType, paramTypes, info.Type.IsFunctionVarArg())
|
||||||
|
wrapName := "__llgo_cdecl$" + fname
|
||||||
|
if wrapFunc := m.NamedFunction(wrapName); !wrapFunc.IsNil() {
|
||||||
|
return wrapFunc, true
|
||||||
|
}
|
||||||
|
wrapFunc := llvm.AddFunction(m, wrapName, nft)
|
||||||
|
wrapFunc.SetLinkage(llvm.LinkOnceAnyLinkage)
|
||||||
|
wrapFunc.AddFunctionAttr(funcInlineHint(ctx))
|
||||||
|
|
||||||
|
for i, attr := range attrs {
|
||||||
|
wrapFunc.AddAttributeAtIndex(i, attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := ctx.NewBuilder()
|
||||||
|
block := llvm.AddBasicBlock(wrapFunc, "entry")
|
||||||
|
b.SetInsertPointAtEnd(block)
|
||||||
|
|
||||||
|
var nparams []llvm.Value
|
||||||
|
params := wrapFunc.Params()
|
||||||
|
index := 0
|
||||||
|
if info.Return.Kind == AttrPointer {
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
for _, ti := range info.Params {
|
||||||
|
switch ti.Kind {
|
||||||
|
default:
|
||||||
|
case AttrPointer:
|
||||||
|
nparams = append(nparams, b.CreateLoad(ti.Type, params[index], ""))
|
||||||
|
case AttrWidthType:
|
||||||
|
iptr := llvm.CreateAlloca(b, ti.Type1)
|
||||||
|
b.CreateStore(params[index], iptr)
|
||||||
|
ptr := b.CreateBitCast(iptr, llvm.PointerType(ti.Type, 0), "")
|
||||||
|
nparams = append(nparams, b.CreateLoad(ti.Type, ptr, ""))
|
||||||
|
case AttrWidthType2:
|
||||||
|
typ := llvm.StructType([]llvm.Type{ti.Type1, ti.Type2}, false)
|
||||||
|
iptr := llvm.CreateAlloca(b, typ)
|
||||||
|
b.CreateStore(params[index], b.CreateStructGEP(typ, iptr, 0, ""))
|
||||||
|
index++
|
||||||
|
b.CreateStore(params[index], b.CreateStructGEP(typ, iptr, 1, ""))
|
||||||
|
ptr := b.CreateBitCast(iptr, llvm.PointerType(ti.Type, 0), "")
|
||||||
|
nparams = append(nparams, b.CreateLoad(ti.Type, ptr, ""))
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
|
||||||
|
switch info.Return.Kind {
|
||||||
|
case AttrVoid:
|
||||||
|
llvm.CreateCall(b, info.Type, fn, nparams)
|
||||||
|
b.CreateRetVoid()
|
||||||
|
case AttrPointer:
|
||||||
|
ret := llvm.CreateCall(b, info.Type, fn, nparams)
|
||||||
|
b.CreateStore(ret, params[0])
|
||||||
|
b.CreateRetVoid()
|
||||||
|
case AttrWidthType, AttrWidthType2:
|
||||||
|
ret := llvm.CreateCall(b, info.Type, fn, nparams)
|
||||||
|
ptr := llvm.CreateAlloca(b, info.Return.Type)
|
||||||
|
b.CreateStore(ret, ptr)
|
||||||
|
iptr := b.CreateBitCast(ptr, llvm.PointerType(returnType, 0), "")
|
||||||
|
b.CreateRet(b.CreateLoad(returnType, iptr, ""))
|
||||||
|
default:
|
||||||
|
ret := llvm.CreateCall(b, info.Type, fn, nparams)
|
||||||
|
b.CreateRet(ret)
|
||||||
|
}
|
||||||
|
return wrapFunc, true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user