cgo: supports c/go callback funcs
This commit is contained in:
@@ -77,9 +77,26 @@ static void test_macros() {
|
||||
#define MY_VERSION "1.0.0"
|
||||
#define MY_CODE 0x12345678
|
||||
|
||||
void test_void() {
|
||||
static void test_void() {
|
||||
printf("test_void\n");
|
||||
}
|
||||
|
||||
typedef int (*Cb)(int);
|
||||
|
||||
extern int go_callback(int);
|
||||
|
||||
extern int c_callback(int i);
|
||||
|
||||
static void test_callback(Cb cb) {
|
||||
printf("test_callback, cb: %p, go_callback: %p, c_callback: %p\n", cb, go_callback, c_callback);
|
||||
printf("test_callback, *cb: %p, *go_callback: %p, *c_callback: %p\n", *(void**)cb, *(void**)(go_callback), *(void**)(c_callback));
|
||||
printf("cb result: %d\n", cb(123));
|
||||
printf("done\n");
|
||||
}
|
||||
|
||||
static void run_callback() {
|
||||
test_callback(c_callback);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
@@ -90,6 +107,11 @@ import (
|
||||
"github.com/goplus/llgo/_demo/cgofull/pymod2"
|
||||
)
|
||||
|
||||
//export go_callback
|
||||
func go_callback(i C.int) C.int {
|
||||
return i + 1
|
||||
}
|
||||
|
||||
func main() {
|
||||
runPy()
|
||||
f := &C.Foo{a: 1}
|
||||
@@ -104,6 +126,16 @@ func main() {
|
||||
fmt.Println(C.MY_VERSION)
|
||||
fmt.Println(int(C.MY_CODE))
|
||||
C.test_void()
|
||||
|
||||
println("call run_callback")
|
||||
C.run_callback()
|
||||
|
||||
// test _Cgo_ptr and _cgoCheckResult
|
||||
println("call with go_callback")
|
||||
C.test_callback((C.Cb)(C.go_callback))
|
||||
|
||||
println("call with c_callback")
|
||||
C.test_callback((C.Cb)(C.c_callback))
|
||||
}
|
||||
|
||||
func runPy() {
|
||||
@@ -112,4 +144,6 @@ func runPy() {
|
||||
Run("print('Hello, Python!')")
|
||||
C.PyObject_Print((*C.PyObject)(unsafe.Pointer(pymod1.Float(1.23))), C.stderr, 0)
|
||||
C.PyObject_Print((*C.PyObject)(unsafe.Pointer(pymod2.Long(123))), C.stdout, 0)
|
||||
// test _Cgo_use
|
||||
C.PyObject_Print((*C.PyObject)(unsafe.Pointer(C.PyComplex_FromDoubles(C.double(1.23), C.double(4.56)))), C.stdout, 0)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include "foo.h"
|
||||
|
||||
void print_foo(Foo* f) {
|
||||
void print_foo(Foo *f)
|
||||
{
|
||||
printf("print_foo: %d\n", f->a);
|
||||
}
|
||||
|
||||
int c_callback(int i)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
||||
|
||||
@"main.init$guard" = global i1 false, align 1
|
||||
@0 = private unnamed_addr constant [5 x i8] c"hello", align 1
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
|
||||
define i64 @main.Foo(%"github.com/goplus/llgo/internal/runtime.String" %0) {
|
||||
_llgo_0:
|
||||
%1 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %0, 1
|
||||
ret i64 %1
|
||||
}
|
||||
|
||||
define void @main.Test() {
|
||||
_llgo_0:
|
||||
br label %_llgo_3
|
||||
|
||||
_llgo_1: ; preds = %_llgo_3
|
||||
%0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0
|
||||
store ptr @0, ptr %1, align 8
|
||||
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1
|
||||
store i64 5, ptr %2, align 4
|
||||
%3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8
|
||||
%4 = call i64 @main.Foo(%"github.com/goplus/llgo/internal/runtime.String" %3)
|
||||
%5 = add i64 %6, 1
|
||||
br label %_llgo_3
|
||||
|
||||
_llgo_2: ; preds = %_llgo_3
|
||||
ret void
|
||||
|
||||
_llgo_3: ; preds = %_llgo_1, %_llgo_0
|
||||
%6 = phi i64 [ 0, %_llgo_0 ], [ %5, %_llgo_1 ]
|
||||
%7 = icmp slt i64 %6, 1000000
|
||||
br i1 %7, label %_llgo_1, label %_llgo_2
|
||||
}
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"main.init$guard", align 1
|
||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
store i1 true, ptr @"main.init$guard", align 1
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %0, ptr %1) {
|
||||
_llgo_0:
|
||||
store i32 %0, ptr @__llgo_argc, align 4
|
||||
store ptr %1, ptr @__llgo_argv, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
call void @main.init()
|
||||
call void @main.Test()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
@@ -1,12 +1,23 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr }
|
||||
|
||||
@"github.com/goplus/llgo/internal/runtime.cgoAlwaysFalse" = external global i1, align 1
|
||||
@main.format = global [10 x i8] zeroinitializer, align 1
|
||||
@"main.init$guard" = global i1 false, align 1
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
|
||||
define ptr @main._Cgo_ptr(ptr %0) {
|
||||
_llgo_0:
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
declare void @runtime.cgoUse(%"github.com/goplus/llgo/internal/runtime.eface")
|
||||
|
||||
declare void @runtime.cgoCheckResult(%"github.com/goplus/llgo/internal/runtime.eface")
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"main.init$guard", align 1
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
source_filename = "main"
|
||||
|
||||
%main.Foo = type { i32, i1 }
|
||||
%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr }
|
||||
|
||||
@"github.com/goplus/llgo/internal/runtime.cgoAlwaysFalse" = external global i1, align 1
|
||||
@main.format = global [10 x i8] zeroinitializer, align 1
|
||||
@@ -35,6 +36,15 @@ _llgo_0:
|
||||
ret void
|
||||
}
|
||||
|
||||
define ptr @main._Cgo_ptr(ptr %0) {
|
||||
_llgo_0:
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
declare void @runtime.cgoUse(%"github.com/goplus/llgo/internal/runtime.eface")
|
||||
|
||||
declare void @runtime.cgoCheckResult(%"github.com/goplus/llgo/internal/runtime.eface")
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"main.init$guard", align 1
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr }
|
||||
|
||||
@"github.com/goplus/llgo/internal/runtime.cgoAlwaysFalse" = external global i1, align 1
|
||||
@main.format = global [10 x i8] zeroinitializer, align 1
|
||||
@"main.init$guard" = global i1 false, align 1
|
||||
@@ -23,6 +25,15 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
define ptr @main._Cgo_ptr(ptr %0) {
|
||||
_llgo_0:
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
declare void @runtime.cgoUse(%"github.com/goplus/llgo/internal/runtime.eface")
|
||||
|
||||
declare void @runtime.cgoCheckResult(%"github.com/goplus/llgo/internal/runtime.eface")
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"main.init$guard", align 1
|
||||
|
||||
@@ -189,7 +189,7 @@ var (
|
||||
argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8]))
|
||||
)
|
||||
|
||||
func isCgoCfuncOrCmacro(f *ssa.Function) bool {
|
||||
func isCgoExternSymbol(f *ssa.Function) bool {
|
||||
name := f.Name()
|
||||
return isCgoCfunc(name) || isCgoCmacro(name)
|
||||
}
|
||||
@@ -202,6 +202,10 @@ func isCgoCmacro(name string) bool {
|
||||
return strings.HasPrefix(name, "_Cmacro_")
|
||||
}
|
||||
|
||||
func isCgoVar(name string) bool {
|
||||
return strings.HasPrefix(name, "__cgo_")
|
||||
}
|
||||
|
||||
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Function, llssa.PyObjRef, int) {
|
||||
pkgTypes, name, ftype := p.funcName(f, true)
|
||||
if ftype != goFunc {
|
||||
@@ -255,7 +259,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
||||
fn.Inline(llssa.NoInline)
|
||||
}
|
||||
}
|
||||
isCgo := isCgoCfuncOrCmacro(f)
|
||||
isCgo := isCgoExternSymbol(f)
|
||||
if nblk := len(f.Blocks); nblk > 0 {
|
||||
p.cgoCalled = false
|
||||
p.cgoArgs = nil
|
||||
@@ -918,7 +922,17 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
||||
}
|
||||
return pyFn.Expr
|
||||
case *ssa.Global:
|
||||
varName := v.Name()
|
||||
val := p.varOf(b, v)
|
||||
if isCgoVar(varName) {
|
||||
fname := p.fset.Position(v.Pos()).Filename
|
||||
funcs, ok := p.cgoFuncs[fname]
|
||||
if !ok {
|
||||
funcs = make([]string, 0, 1)
|
||||
}
|
||||
funcs = append(funcs, val.Name())
|
||||
p.cgoFuncs[fname] = funcs
|
||||
}
|
||||
if debugSymbols {
|
||||
pos := p.fset.Position(v.Pos())
|
||||
b.DIGlobal(val, v.Name(), pos)
|
||||
@@ -1053,6 +1067,26 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [
|
||||
fn()
|
||||
}
|
||||
externs = ctx.cgoFuncs
|
||||
// TODO(lijie): read export name
|
||||
for _, funcs := range externs {
|
||||
for _, funcName := range funcs {
|
||||
if strings.Contains(funcName, ".__cgo_") {
|
||||
goFnName := strings.Replace(funcName, ".__cgo_", ".", 1)
|
||||
idx := strings.LastIndex(funcName, ".__cgo_")
|
||||
cfuncName := funcName[idx+len(".__cgo_"):]
|
||||
v := ret.VarOf(funcName)
|
||||
if fn := ret.FuncOf(goFnName); fn != nil {
|
||||
// TODO(lijie): naive go:export, need better way from comment
|
||||
fn.SetName(cfuncName)
|
||||
// Replace symbol instead of static linking
|
||||
v.ReplaceAllUsesWith(fn.Expr)
|
||||
} else if fn := ret.FuncOf(cfuncName); fn != nil {
|
||||
// Replace symbol instead of static linking
|
||||
v.ReplaceAllUsesWith(fn.Expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -448,7 +448,7 @@ func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, strin
|
||||
if checkCgo(fname) && !cgoIgnored(fname) {
|
||||
return nil, fname, llgoInstr
|
||||
}
|
||||
if isCgoCfuncOrCmacro(fn) {
|
||||
if isCgoExternSymbol(fn) {
|
||||
if _, ok := llgoInstrs[fname]; ok {
|
||||
return nil, fname, llgoInstr
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user