cgo: support macros

This commit is contained in:
Li Jie
2024-11-24 22:45:25 +08:00
parent 38a7f4f7d5
commit d6c527f662
5 changed files with 153 additions and 64 deletions

View File

@@ -189,8 +189,17 @@ var (
argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8]))
)
func isCgoCfunc(f *ssa.Function) bool {
return strings.HasPrefix(f.Name(), "_Cfunc_")
func isCgoCfuncOrCmacro(f *ssa.Function) bool {
name := f.Name()
return isCgoCfunc(name) || isCgoCmacro(name)
}
func isCgoCfunc(name string) bool {
return strings.HasPrefix(name, "_Cfunc_")
}
func isCgoCmacro(name string) bool {
return strings.HasPrefix(name, "_Cmacro_")
}
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Function, llssa.PyObjRef, int) {
@@ -246,10 +255,11 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
fn.Inline(llssa.NoInline)
}
}
isCgo := isCgoCfuncOrCmacro(f)
if nblk := len(f.Blocks); nblk > 0 {
p.cgoCalled = false
p.cgoArgs = nil
if isCgoCfunc(f) {
if isCgo {
fn.MakeBlocks(1)
} else {
fn.MakeBlocks(nblk) // to set fn.HasBody() = true
@@ -278,7 +288,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
}
p.bvals = make(map[ssa.Value]llssa.Expr)
off := make([]int, len(f.Blocks))
if isCgoCfunc(f) {
if isCgo {
p.cgoArgs = make([]llssa.Expr, len(f.Params))
for i, param := range f.Params {
p.cgoArgs[i] = p.compileValue(b, param)
@@ -295,7 +305,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
doMainInit := (i == 0 && name == "main")
doModInit := (i == 1 && isInit)
p.compileBlock(b, block, off[i], doMainInit, doModInit)
if isCgoCfunc(f) {
if isCgo {
// just process first block for performance
break
}
@@ -409,36 +419,46 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
if funcs, ok := p.cgoFuncs[fname]; ok {
cgoFuncs = funcs
}
fnName := block.Parent().Name()
cgoReturned := false
isCgoCfunc := isCgoCfunc(fnName)
isCgoCmacro := isCgoCmacro(fnName)
for i, instr := range instrs {
if i == 1 && doModInit && p.state == pkgInPatch { // in patch package but no pkgFNoOldInit
initFnNameOld := initFnNameOfHasPatch(p.fn.Name())
fnOld := pkg.NewFunc(initFnNameOld, llssa.NoArgsNoRet, llssa.InC)
b.Call(fnOld.Expr)
}
if isCgoCfunc(block.Parent()) {
if isCgoCfunc || isCgoCmacro {
switch instr := instr.(type) {
case *ssa.Alloc:
// return value allocation
p.compileInstr(b, instr)
case *ssa.UnOp:
// load cgo function pointer
if instr.Op == token.MUL && strings.HasPrefix(instr.X.Name(), "_cgo_") {
cgoFuncs = append(cgoFuncs, instr.X.Name())
varName := instr.X.Name()
if instr.Op == token.MUL && strings.HasPrefix(varName, "_cgo_") {
cgoFuncs = append(cgoFuncs, varName)
p.cgoFuncs[fname] = cgoFuncs
p.compileInstr(b, instr)
}
case *ssa.Call:
// call c function
p.compileInstr(b, instr)
p.cgoCalled = true
if isCgoCmacro {
p.cgoRet = p.compileValue(b, instr.Call.Args[0])
p.cgoCalled = true
} else {
// call c function
p.compileInstr(b, instr)
p.cgoCalled = true
}
case *ssa.Return:
// return cgo function result
if len(instr.Results) > 0 {
b.Return(p.cgoRet)
} else {
b.Return(llssa.Nil)
if isCgoCmacro {
ty := p.type_(instr.Results[0].Type(), llssa.InGo)
p.cgoRet.Type = p.prog.Pointer(ty)
p.cgoRet = b.Load(p.cgoRet)
}
b.Return(p.cgoRet)
cgoReturned = true
}
} else {
@@ -446,18 +466,14 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
}
}
// is cgo cfunc but not return yet, some funcs has multiple blocks
if isCgoCfunc(block.Parent()) && !cgoReturned {
if (isCgoCfunc || isCgoCmacro) && !cgoReturned {
if !p.cgoCalled {
panic("cgo cfunc not called")
}
for _, block := range block.Parent().Blocks {
for _, instr := range block.Instrs {
if instr, ok := instr.(*ssa.Return); ok {
if len(instr.Results) > 0 {
b.Return(p.cgoRet)
} else {
b.Return(llssa.Nil)
}
if _, ok := instr.(*ssa.Return); ok {
b.Return(p.cgoRet)
goto end
}
}