Merge pull request #1220 from visualfc/cabi

internal/cabi: support arch 386
This commit is contained in:
xushiwei
2025-08-21 10:55:43 +08:00
committed by GitHub
11 changed files with 294 additions and 77 deletions

View File

@@ -6,7 +6,7 @@ target triple = "amd64-unknown-linux-gnu"
%struct.empty = type {}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @demo1() #0 {
define dso_local void @demo0() #0 {
%1 = alloca %struct.empty, align 1
%2 = alloca %struct.empty, align 1
%3 = bitcast %struct.empty* %1 to i8*
@@ -18,6 +18,18 @@ define dso_local void @demo1() #0 {
; Function Attrs: argmemonly nofree nounwind willreturn
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @demo1(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1
%3 = alloca %struct.empty, align 1
%4 = alloca i32, align 4
store i32 %0, i32* %4, align 4
%5 = bitcast %struct.empty* %2 to i8*
%6 = bitcast %struct.empty* %3 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %5, i8* align 1 %6, i64 0, i1 false)
ret void
}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @demo2(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1

View File

@@ -6,7 +6,7 @@ target triple = "aarch64-unknown-linux-gnu"
%struct.empty = type {}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @demo1() #0 {
define dso_local void @demo0() #0 {
%1 = alloca %struct.empty, align 1
%2 = alloca %struct.empty, align 1
%3 = bitcast %struct.empty* %1 to i8*
@@ -18,6 +18,18 @@ define dso_local void @demo1() #0 {
; Function Attrs: argmemonly nofree nounwind willreturn
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @demo1(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1
%3 = alloca %struct.empty, align 1
%4 = alloca i32, align 4
store i32 %0, i32* %4, align 4
%5 = bitcast %struct.empty* %2 to i8*
%6 = bitcast %struct.empty* %3 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %5, i8* align 1 %6, i64 0, i1 false)
ret void
}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @demo2(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1

View File

@@ -6,7 +6,7 @@ target triple = "armv6kz-unknown-linux-gnueabihf"
%struct.empty = type {}
; Function Attrs: noinline nounwind optnone
define dso_local void @demo1() #0 {
define dso_local void @demo0() #0 {
%1 = alloca %struct.empty, align 1
%2 = alloca %struct.empty, align 1
%3 = bitcast %struct.empty* %1 to i8*
@@ -18,6 +18,18 @@ define dso_local void @demo1() #0 {
; Function Attrs: argmemonly nofree nounwind willreturn
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #1
; Function Attrs: noinline nounwind optnone
define dso_local void @demo1(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1
%3 = alloca %struct.empty, align 1
%4 = alloca i32, align 4
store i32 %0, i32* %4, align 4
%5 = bitcast %struct.empty* %2 to i8*
%6 = bitcast %struct.empty* %3 to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %5, i8* align 1 %6, i32 0, i1 false)
ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local i32 @demo2(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1

View File

@@ -6,7 +6,7 @@ target triple = "i386-unknown-linux-gnu"
%struct.empty = type {}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @demo1(%struct.empty* noalias sret(%struct.empty) align 1 %0) #0 {
define dso_local void @demo0(%struct.empty* noalias sret(%struct.empty) align 1 %0) #0 {
%2 = alloca i8*, align 4
%3 = alloca %struct.empty, align 1
%4 = bitcast %struct.empty* %0 to i8*
@@ -20,6 +20,20 @@ define dso_local void @demo1(%struct.empty* noalias sret(%struct.empty) align 1
; Function Attrs: argmemonly nofree nounwind willreturn
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @demo1(%struct.empty* noalias sret(%struct.empty) align 1 %0, i32 noundef %1) #0 {
%3 = alloca i8*, align 4
%4 = alloca %struct.empty, align 1
%5 = alloca i32, align 4
%6 = bitcast %struct.empty* %0 to i8*
store i8* %6, i8** %3, align 4
store i32 %1, i32* %5, align 4
%7 = bitcast %struct.empty* %0 to i8*
%8 = bitcast %struct.empty* %4 to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %7, i8* align 1 %8, i32 0, i1 false)
ret void
}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @demo2(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1

View File

@@ -6,7 +6,7 @@ target triple = "riscv64-unknown-unknown-elf"
%struct.empty = type {}
; Function Attrs: noinline nounwind optnone
define dso_local void @demo1() #0 {
define dso_local void @demo0() #0 {
%1 = alloca %struct.empty, align 1
%2 = alloca %struct.empty, align 1
%3 = bitcast %struct.empty* %1 to i8*
@@ -18,6 +18,18 @@ define dso_local void @demo1() #0 {
; Function Attrs: argmemonly nofree nounwind willreturn
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1
; Function Attrs: noinline nounwind optnone
define dso_local void @demo1(i32 noundef signext %0) #0 {
%2 = alloca %struct.empty, align 1
%3 = alloca %struct.empty, align 1
%4 = alloca i32, align 4
store i32 %0, i32* %4, align 4
%5 = bitcast %struct.empty* %2 to i8*
%6 = bitcast %struct.empty* %3 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %5, i8* align 1 %6, i64 0, i1 false)
ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local signext i32 @demo2(i32 noundef signext %0) #0 {
%2 = alloca %struct.empty, align 1

View File

@@ -6,7 +6,7 @@ target triple = "wasm32-unknown-emscripten"
%struct.empty = type {}
; Function Attrs: noinline nounwind optnone
define hidden void @demo1() #0 {
define hidden void @demo0() #0 {
%1 = alloca %struct.empty, align 1
%2 = alloca %struct.empty, align 1
%3 = bitcast %struct.empty* %1 to i8*
@@ -18,6 +18,18 @@ define hidden void @demo1() #0 {
; Function Attrs: argmemonly nofree nounwind willreturn
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #1
; Function Attrs: noinline nounwind optnone
define hidden void @demo1(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1
%3 = alloca %struct.empty, align 1
%4 = alloca i32, align 4
store i32 %0, i32* %4, align 4
%5 = bitcast %struct.empty* %2 to i8*
%6 = bitcast %struct.empty* %3 to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %5, i8* align 1 %6, i32 0, i1 false)
ret void
}
; Function Attrs: noinline nounwind optnone
define hidden i32 @demo2(i32 noundef %0) #0 {
%2 = alloca %struct.empty, align 1

View File

@@ -20,16 +20,28 @@ func main() {}
type empty struct {
}
//go:linkname cdemo1 C.demo1
func cdemo1(empty) empty
//go:linkname cdemo0 C.demo0
func cdemo0(empty) empty
func demo1(a empty) empty {
func demo0(a empty) empty {
return a
}
func init() {
assert("cdemo1", cdemo1(empty{}) == empty{})
assert("demo1", demo1(empty{}) == empty{})
assert("cdemo0", cdemo0(empty{}) == empty{})
assert("demo0", demo0(empty{}) == empty{})
}
//go:linkname cdemo1 C.demo1
func cdemo1(empty, int32) empty
func demo1(a empty, b int32) empty {
return a
}
func init() {
assert("cdemo1", cdemo1(empty{}, 1) == empty{})
assert("demo1", demo1(empty{}, 2) == empty{})
}
//go:linkname cdemo2 C.demo2

View File

@@ -1,7 +1,11 @@
struct empty {
};
struct empty demo1(struct empty a) {
struct empty demo0(struct empty a) {
return a;
}
struct empty demo1(struct empty a, int v) {
return a;
}

View File

@@ -4,8 +4,6 @@ import (
"github.com/goplus/llvm"
)
const skip_same_size = false
func elementTypesCount(typ llvm.Type) int {
switch typ.TypeKind() {
case llvm.VoidTypeKind:
@@ -67,11 +65,15 @@ func (p *TypeInfoAmd64) SupportByVal() bool {
return true
}
func (p *TypeInfoAmd64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
func (p *TypeInfoAmd64) SkipEmptyParams() bool {
return true
}
func (p *TypeInfoAmd64) IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool {
return elementTypesCount(typ) >= 2
}
func (p *TypeInfoAmd64) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
func (p *TypeInfoAmd64) GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo {
info := &TypeInfo{}
info.Type = typ
info.Type1 = typ
@@ -150,7 +152,12 @@ func (p *TypeInfoArm64) SupportByVal() bool {
return false
}
func (p *TypeInfoArm64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
func (p *TypeInfoArm64) SkipEmptyParams() bool {
return true
}
func (p *TypeInfoArm64) IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool {
bret := index == 0
switch typ.TypeKind() {
case llvm.StructTypeKind, llvm.ArrayTypeKind:
if bret && elementTypesCount(typ) == 1 {
@@ -162,7 +169,8 @@ func (p *TypeInfoArm64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) b
}
}
func (p *TypeInfoArm64) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
func (p *TypeInfoArm64) GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo {
bret := index == 0
info := &TypeInfo{}
info.Type = typ
info.Type1 = typ
@@ -219,7 +227,11 @@ func (p *TypeInfoArm) SupportByVal() bool {
return false
}
func (p *TypeInfoArm) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
func (p *TypeInfoArm) SkipEmptyParams() bool {
return true
}
func (p *TypeInfoArm) IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool {
switch typ.TypeKind() {
case llvm.StructTypeKind, llvm.ArrayTypeKind:
return true
@@ -228,7 +240,8 @@ func (p *TypeInfoArm) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) boo
}
}
func (p *TypeInfoArm) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
func (p *TypeInfoArm) GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo {
bret := index == 0
info := &TypeInfo{}
info.Type = typ
info.Type1 = typ
@@ -284,11 +297,15 @@ func (p *TypeInfoWasm) SupportByVal() bool {
return true
}
func (p *TypeInfoWasm) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
func (p *TypeInfoWasm) SkipEmptyParams() bool {
return true
}
func (p *TypeInfoWasm) IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool {
return elementTypesCount(typ) >= 2
}
func (p *TypeInfoWasm) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
func (p *TypeInfoWasm) GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo {
info := &TypeInfo{}
info.Type = typ
info.Type1 = typ
@@ -313,7 +330,11 @@ func (p *TypeInfoRiscv64) SupportByVal() bool {
return true
}
func (p *TypeInfoRiscv64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
func (p *TypeInfoRiscv64) SkipEmptyParams() bool {
return true
}
func (p *TypeInfoRiscv64) IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool {
switch typ.TypeKind() {
case llvm.StructTypeKind, llvm.ArrayTypeKind:
return true
@@ -321,7 +342,7 @@ func (p *TypeInfoRiscv64) IsWrapType(ctx llvm.Context, typ llvm.Type, bret bool)
return false
}
func (p *TypeInfoRiscv64) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
func (p *TypeInfoRiscv64) GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo {
info := &TypeInfo{}
info.Type = typ
info.Type1 = typ
@@ -358,3 +379,88 @@ func (p *TypeInfoRiscv64) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool
}
return info
}
type TypeInfo386 struct {
*Transformer
}
func (p *TypeInfo386) SupportByVal() bool {
return true
}
func (p *TypeInfo386) SkipEmptyParams() bool {
return false
}
func (p *TypeInfo386) IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool {
switch typ.TypeKind() {
case llvm.ArrayTypeKind, llvm.StructTypeKind:
return true
}
return false
}
func (p *TypeInfo386) GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo {
bret := index == 0
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 info.Size == 0 {
if bret {
return info
}
if index == 1 {
info.Kind = AttrPointer
info.Type1 = llvm.PointerType(typ, 0)
return info
}
info.Kind = AttrVoid
info.Type1 = ctx.VoidType()
return info
}
switch typ.TypeKind() {
case llvm.StructTypeKind:
if !bret && info.Size <= 16 {
var extract bool
subs := typ.StructElementTypes()
loop:
for _, sub := range subs {
switch sub.TypeKind() {
case llvm.FloatTypeKind, llvm.DoubleTypeKind, llvm.PointerTypeKind:
extract = true
case llvm.IntegerTypeKind:
if width := sub.IntTypeWidth(); width == 32 || width == 64 {
extract = true
} else {
extract = false
break loop
}
default:
extract = false
break loop
}
}
if extract {
if len(subs) == 1 {
info.Kind = AttrWidthType
info.Type1 = subs[0]
} else {
info.Kind = AttrExtract
}
return info
}
}
info.Kind = AttrPointer
info.Type1 = llvm.PointerType(typ, 0)
case llvm.ArrayTypeKind:
info.Kind = AttrPointer
info.Type1 = llvm.PointerType(typ, 0)
}
return info
}

View File

@@ -35,6 +35,8 @@ func NewTransformer(prog ssa.Program, mode Mode) *Transformer {
tr.sys = &TypeInfoWasm{tr}
case "riscv64":
tr.sys = &TypeInfoRiscv64{tr}
case "386":
tr.sys = &TypeInfo386{tr}
}
return tr
}
@@ -108,11 +110,11 @@ func (p *Transformer) TransformModule(path string, m llvm.Module) {
}
func (p *Transformer) isWrapFunctionType(ctx llvm.Context, ft llvm.Type) bool {
if p.IsWrapType(ctx, ft.ReturnType(), true) {
if p.IsWrapType(ctx, ft, ft.ReturnType(), 0) {
return true
}
for _, typ := range ft.ParamTypes() {
if p.IsWrapType(ctx, typ, false) {
for i, typ := range ft.ParamTypes() {
if p.IsWrapType(ctx, ft, typ, i+1) {
return true
}
}
@@ -121,8 +123,9 @@ func (p *Transformer) isWrapFunctionType(ctx llvm.Context, ft llvm.Type) bool {
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
SkipEmptyParams() bool
IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool
GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo
}
type AttrKind int
@@ -133,6 +136,7 @@ const (
AttrPointer // type => type*
AttrWidthType // type => width int i16/i24/i32/i40/i48/i56/i64 float/double
AttrWidthType2 // type => width two int {i64,i16} float/double
AttrExtract // extract struct type
)
type FuncInfo struct {
@@ -176,27 +180,45 @@ 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 {
func (p *Transformer) IsWrapType(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) bool {
if p.sys != nil {
if !bret && (typ.TypeKind() == llvm.VoidTypeKind || p.Sizeof(typ) == 0) {
bret := index == 0
if p.sys.SkipEmptyParams() && p.isWrapEmptyType(ctx, typ, bret) {
return true
}
return p.sys.IsWrapType(ctx, typ, bret)
return p.sys.IsWrapType(ctx, ftyp, typ, index)
}
return false
}
func (p *Transformer) GetTypeInfo(ctx llvm.Context, typ llvm.Type, bret bool) *TypeInfo {
if p.sys != nil {
func (p *Transformer) isWrapEmptyType(ctx llvm.Context, typ llvm.Type, bret bool) bool {
if !bret && (typ.TypeKind() == llvm.VoidTypeKind || p.Sizeof(typ) == 0) {
return true
}
return false
}
func (p *Transformer) getEmptyType(ctx llvm.Context, typ llvm.Type, bret bool) (*TypeInfo, bool) {
if typ.TypeKind() == llvm.VoidTypeKind {
return &TypeInfo{Type: typ, Kind: AttrVoid, Type1: ctx.VoidType()}
return &TypeInfo{Type: typ, Kind: AttrVoid, Type1: ctx.VoidType()}, true
} else if p.Sizeof(typ) == 0 {
if bret {
return &TypeInfo{Type: typ, Kind: AttrNone, Type1: typ}
return &TypeInfo{Type: typ, Kind: AttrNone, Type1: typ}, true
}
return &TypeInfo{Type: typ, Kind: AttrVoid, Type1: ctx.VoidType()}
return &TypeInfo{Type: typ, Kind: AttrVoid, Type1: ctx.VoidType()}, true
}
return p.sys.GetTypeInfo(ctx, typ, bret)
return nil, false
}
func (p *Transformer) GetTypeInfo(ctx llvm.Context, ftyp llvm.Type, typ llvm.Type, index int) *TypeInfo {
if p.sys != nil {
bret := index == 0
if p.sys.SkipEmptyParams() {
if info, ok := p.getEmptyType(ctx, typ, bret); ok {
return info
}
}
return p.sys.GetTypeInfo(ctx, ftyp, typ, index)
}
panic("not implment: " + p.GOARCH)
}
@@ -211,11 +233,11 @@ func (p *Transformer) Alignof(typ llvm.Type) int {
func (p *Transformer) GetFuncInfo(ctx llvm.Context, typ llvm.Type) (info FuncInfo) {
info.Type = typ
info.Return = p.GetTypeInfo(ctx, typ.ReturnType(), true)
info.Return = p.GetTypeInfo(ctx, typ, typ.ReturnType(), 0)
params := typ.ParamTypes()
info.Params = make([]*TypeInfo, len(params))
for i, t := range params {
info.Params[i] = p.GetTypeInfo(ctx, t, false)
info.Params[i] = p.GetTypeInfo(ctx, typ, t, i+1)
}
return
}
@@ -250,6 +272,9 @@ func (p *Transformer) transformFuncType(ctx llvm.Context, info *FuncInfo) (llvm.
}
case AttrWidthType2:
paramTypes = append(paramTypes, ti.Type1, ti.Type2)
case AttrExtract:
subs := ti.Type.StructElementTypes()
paramTypes = append(paramTypes, subs...)
}
}
return llvm.FunctionType(returnType, paramTypes, info.Type.IsFunctionVarArg()), attrs
@@ -331,6 +356,15 @@ func (p *Transformer) transformFuncBody(ctx llvm.Context, info *FuncInfo, fn llv
b.CreateStore(params[index], b.CreateStructGEP(typ, iptr, 1, ""))
ptr := b.CreateBitCast(iptr, llvm.PointerType(ti.Type, 0), "")
nv = b.CreateLoad(ti.Type, ptr, "")
case AttrExtract:
nsubs := ti.Type.StructElementTypesCount()
nv = llvm.Undef(ti.Type)
for i := 0; i < nsubs; i++ {
nv = b.CreateInsertValue(nv, params[index], i, "")
index++
}
fn.Param(i).ReplaceAllUsesWith(nv)
continue
}
fn.Param(i).ReplaceAllUsesWith(nv)
index++
@@ -403,6 +437,11 @@ func (p *Transformer) transformCallInstr(ctx llvm.Context, call llvm.Value) bool
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, ""), ""))
case AttrExtract:
nsubs := ti.Type.StructElementTypesCount()
for i := 0; i < nsubs; i++ {
nparams = append(nparams, b.CreateExtractValue(param, i, ""))
}
}
}
@@ -468,44 +507,15 @@ func (p *Transformer) transformFuncCall(m llvm.Module, fn llvm.Value) {
}
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)
}
}
nft, attrs := p.transformFuncType(ctx, &info)
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
@@ -548,6 +558,15 @@ func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap
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, ""))
case AttrExtract:
nsubs := ti.Type.StructElementTypesCount()
nv := llvm.Undef(ti.Type)
for i := 0; i < nsubs; i++ {
nv = b.CreateInsertValue(nv, params[index], i, "")
index++
}
nparams = append(nparams, nv)
continue
}
index++
}
@@ -564,6 +583,7 @@ func (p *Transformer) transformCallbackFunc(m llvm.Module, fn llvm.Value) (wrap
ret := llvm.CreateCall(b, info.Type, fn, nparams)
ptr := llvm.CreateAlloca(b, info.Return.Type)
b.CreateStore(ret, ptr)
returnType := nft.ReturnType()
iptr := b.CreateBitCast(ptr, llvm.PointerType(returnType, 0), "")
b.CreateRet(b.CreateLoad(returnType, iptr, ""))
default:

View File

@@ -18,8 +18,8 @@ import (
var (
modes = []cabi.Mode{cabi.ModeNone, cabi.ModeCFunc, cabi.ModeAllFunc}
archs = []string{"amd64", "arm64", "riscv64", "arm"}
archDir = []string{"amd64", "arm64", "riscv64", "armv6"}
archs = []string{"amd64", "arm64", "riscv64", "arm", "386"}
archDir = []string{"amd64", "arm64", "riscv64", "armv6", "i386"}
)
func init() {
@@ -125,7 +125,8 @@ func testFunc(t *testing.T, ctx context, td llvm.TargetData, fn llvm.Value, cfn
pts := ft.ParamTypes()
cpts := cft.ParamTypes()
if len(pts) != len(cpts) {
t.Fatalf("%v %v: bad param type %v != %v", ctx, fn.Name(), ft, cft)
t.Logf("%v %v: bad param type %v != %v", ctx, fn.Name(), ft, cft)
return
}
for i, pt := range pts {
if !checkType(td, pt, cpts[i], false) {