Skip to content

Commit

Permalink
Merge pull request #881 from cpunion/cgo-extra
Browse files Browse the repository at this point in the history
cgo: support macros and callbacks (fpvars)
  • Loading branch information
xushiwei authored Nov 28, 2024
2 parents 38a7f4f + c3407ea commit 5e5df6b
Show file tree
Hide file tree
Showing 38 changed files with 965 additions and 155 deletions.
1 change: 1 addition & 0 deletions _demo/cgobasic
1 change: 1 addition & 0 deletions _demo/cgocfiles
1 change: 1 addition & 0 deletions _demo/cgodefer
1 change: 1 addition & 0 deletions _demo/cgofull
1 change: 1 addition & 0 deletions _demo/cgomacro
1 change: 1 addition & 0 deletions _demo/cgopython
File renamed without changes.
404 changes: 404 additions & 0 deletions cl/_testgo/cgobasic/out.ll

Large diffs are not rendered by default.

File renamed without changes.
File renamed without changes.
File renamed without changes.
180 changes: 180 additions & 0 deletions cl/_testgo/cgocfiles/out.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
; ModuleID = 'main'
source_filename = "main"

%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr }
%main._Ctype_struct___3 = type { i32 }
%main._Ctype_struct___4 = type { i32, i32 }
%main._Ctype_struct___0 = type { i32, i32, i32 }
%main._Ctype_struct___1 = type { i32, i32, i32, i32 }
%main._Ctype_struct___2 = type { i32, i32, i32, i32, i32 }
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }

@"github.com/goplus/llgo/internal/runtime.cgoAlwaysFalse" = external global i1, align 1
@_cgo_35faaf752e93_Cfunc_test_structs = external global i8, align 1
@main._cgo_35faaf752e93_Cfunc_test_structs = global ptr null, align 8
@"main.init$guard" = global i1 false, align 1
@__llgo_argc = global i32 0, align 4
@__llgo_argv = global ptr null, align 8
@_llgo_main._Ctype_int = linkonce global ptr null, align 8
@0 = private unnamed_addr constant [15 x i8] c"main._Ctype_int", align 1
@_llgo_int32 = linkonce global ptr null, align 8
@1 = private unnamed_addr constant [4 x i8] c"main", align 1
@2 = private unnamed_addr constant [10 x i8] c"_Ctype_int", align 1
@3 = private unnamed_addr constant [19 x i8] c"test_structs failed", align 1
@_llgo_string = linkonce global ptr null, align 8

define i32 @main._Cfunc_test_structs(ptr %0, ptr %1, ptr %2, ptr %3, ptr %4) {
_llgo_0:
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
%6 = load ptr, ptr @main._cgo_35faaf752e93_Cfunc_test_structs, align 8
%7 = load ptr, ptr %6, align 8
%8 = call i32 %7(ptr %0, ptr %1, ptr %2, ptr %3, ptr %4)
ret i32 %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
br i1 %0, label %_llgo_2, label %_llgo_1

_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
call void @syscall.init()
call void @fmt.init()
call void @"main.init$after"()
store ptr @_cgo_35faaf752e93_Cfunc_test_structs, ptr @main._cgo_35faaf752e93_Cfunc_test_structs, align 8
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()
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 4)
%3 = getelementptr inbounds %main._Ctype_struct___3, ptr %2, i32 0, i32 0
store i32 1, ptr %3, align 4
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
%5 = getelementptr inbounds %main._Ctype_struct___4, ptr %4, i32 0, i32 0
%6 = getelementptr inbounds %main._Ctype_struct___4, ptr %4, i32 0, i32 1
store i32 1, ptr %5, align 4
store i32 2, ptr %6, align 4
%7 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 12)
%8 = getelementptr inbounds %main._Ctype_struct___0, ptr %7, i32 0, i32 0
%9 = getelementptr inbounds %main._Ctype_struct___0, ptr %7, i32 0, i32 1
%10 = getelementptr inbounds %main._Ctype_struct___0, ptr %7, i32 0, i32 2
store i32 1, ptr %8, align 4
store i32 2, ptr %9, align 4
store i32 3, ptr %10, align 4
%11 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16)
%12 = getelementptr inbounds %main._Ctype_struct___1, ptr %11, i32 0, i32 0
%13 = getelementptr inbounds %main._Ctype_struct___1, ptr %11, i32 0, i32 1
%14 = getelementptr inbounds %main._Ctype_struct___1, ptr %11, i32 0, i32 2
%15 = getelementptr inbounds %main._Ctype_struct___1, ptr %11, i32 0, i32 3
store i32 1, ptr %12, align 4
store i32 2, ptr %13, align 4
store i32 3, ptr %14, align 4
store i32 4, ptr %15, align 4
%16 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 20)
%17 = getelementptr inbounds %main._Ctype_struct___2, ptr %16, i32 0, i32 0
%18 = getelementptr inbounds %main._Ctype_struct___2, ptr %16, i32 0, i32 1
%19 = getelementptr inbounds %main._Ctype_struct___2, ptr %16, i32 0, i32 2
%20 = getelementptr inbounds %main._Ctype_struct___2, ptr %16, i32 0, i32 3
%21 = getelementptr inbounds %main._Ctype_struct___2, ptr %16, i32 0, i32 4
store i32 1, ptr %17, align 4
store i32 2, ptr %18, align 4
store i32 3, ptr %19, align 4
store i32 4, ptr %20, align 4
store i32 5, ptr %21, align 4
%22 = call i32 @main._Cfunc_test_structs(ptr %2, ptr %4, ptr %7, ptr %11, ptr %16)
%23 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16)
%24 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %23, i64 0
%25 = load ptr, ptr @_llgo_main._Ctype_int, align 8
%26 = sext i32 %22 to i64
%27 = inttoptr i64 %26 to ptr
%28 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %25, 0
%29 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %28, ptr %27, 1
store %"github.com/goplus/llgo/internal/runtime.eface" %29, ptr %24, align 8
%30 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" undef, ptr %23, 0
%31 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %30, i64 1, 1
%32 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %31, i64 1, 2
%33 = call { i64, %"github.com/goplus/llgo/internal/runtime.iface" } @fmt.Println(%"github.com/goplus/llgo/internal/runtime.Slice" %32)
%34 = icmp ne i32 %22, 35
br i1 %34, label %_llgo_1, label %_llgo_2

_llgo_1: ; preds = %_llgo_0
%35 = load ptr, ptr @_llgo_string, align 8
%36 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @3, i64 19 }, ptr %36, align 8
%37 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %35, 0
%38 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %37, ptr %36, 1
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %38)
unreachable

_llgo_2: ; preds = %_llgo_0
ret i32 0
}

declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)

declare void @syscall.init()

declare void @fmt.init()

declare void @"github.com/goplus/llgo/internal/runtime.init"()

define void @"main.init$after"() {
_llgo_0:
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.NewNamed"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @0, i64 15 }, i64 5, i64 4, i64 0, i64 0)
store ptr %0, ptr @_llgo_main._Ctype_int, align 8
%1 = load ptr, ptr @_llgo_int32, align 8
%2 = icmp eq ptr %1, null
br i1 %2, label %_llgo_1, label %_llgo_2

_llgo_1: ; preds = %_llgo_0
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 37)
store ptr %3, ptr @_llgo_int32, align 8
br label %_llgo_2

_llgo_2: ; preds = %_llgo_1, %_llgo_0
%4 = load ptr, ptr @_llgo_int32, align 8
call void @"github.com/goplus/llgo/internal/runtime.InitNamed"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" { ptr @1, i64 4 }, %"github.com/goplus/llgo/internal/runtime.String" { ptr @2, i64 10 }, ptr %4, { ptr, i64, i64 } zeroinitializer, { ptr, i64, i64 } zeroinitializer)
%5 = load ptr, ptr @_llgo_string, align 8
%6 = icmp eq ptr %5, null
br i1 %6, label %_llgo_3, label %_llgo_4

_llgo_3: ; preds = %_llgo_2
%7 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24)
store ptr %7, ptr @_llgo_string, align 8
br label %_llgo_4

_llgo_4: ; preds = %_llgo_3, %_llgo_2
ret void
}

declare ptr @"github.com/goplus/llgo/internal/runtime.NewNamed"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64, i64, i64)

declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64)

declare void @"github.com/goplus/llgo/internal/runtime.InitNamed"(ptr, %"github.com/goplus/llgo/internal/runtime.String", %"github.com/goplus/llgo/internal/runtime.String", ptr, %"github.com/goplus/llgo/internal/runtime.Slice", %"github.com/goplus/llgo/internal/runtime.Slice")

declare { i64, %"github.com/goplus/llgo/internal/runtime.iface" } @fmt.Println(%"github.com/goplus/llgo/internal/runtime.Slice")

declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64)

declare void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface")
File renamed without changes.
1 change: 1 addition & 0 deletions cl/_testgo/cgodefer/out.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
;
File renamed without changes.
64 changes: 63 additions & 1 deletion _demo/cgofull/cgofull.go → cl/_testgo/cgofull/cgofull.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ package main
#cgo windows,amd64 CFLAGS: -D_WIN64
#cgo linux,amd64 CFLAGS: -D_LINUX64
#cgo !windows,amd64 CFLAGS: -D_UNIX64
#cgo pkg-config: python3-embed
#include <stdio.h>
#include <Python.h>
#include "foo.h"
typedef struct {
int a;
Expand Down Expand Up @@ -71,9 +73,52 @@ static void test_macros() {
printf("UNIX64 is defined\n");
#endif
}
#define MY_VERSION "1.0.0"
#define MY_CODE 0x12345678
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");
}
extern int go_callback_not_use_in_go(int);
static void run_callback() {
test_callback(c_callback);
test_callback(go_callback_not_use_in_go);
}
*/
import "C"
import "fmt"
import (
"fmt"
"unsafe"

"github.com/goplus/llgo/cl/_testgo/cgofull/pymod1"
"github.com/goplus/llgo/cl/_testgo/cgofull/pymod2"
)

//export go_callback_not_use_in_go
func go_callback_not_use_in_go(i C.int) C.int {
return i + 1
}

//export go_callback
func go_callback(i C.int) C.int {
return i + 1
}

func main() {
runPy()
Expand All @@ -86,10 +131,27 @@ func main() {
if r != 35 {
panic("test_structs failed")
}
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() {
Initialize()
defer Finalize()
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)
}
8 changes: 7 additions & 1 deletion _demo/cgofull/foo.c → cl/_testgo/cgofull/foo.c
Original file line number Diff line number Diff line change
@@ -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;
}
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions cl/_testgo/cgofull/out.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
;
File renamed without changes.
11 changes: 11 additions & 0 deletions cl/_testgo/cgofull/pymod1/pymod1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package pymod1

/*
#cgo pkg-config: python3-embed
#include <Python.h>
*/
import "C"

func Float(f float64) *C.PyObject {
return C.PyFloat_FromDouble(C.double(f))
}
11 changes: 11 additions & 0 deletions cl/_testgo/cgofull/pymod2/pymod2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package pymod2

/*
#cgo pkg-config: python3-embed
#include <Python.h>
*/
import "C"

func Long(l int64) *C.PyObject {
return C.PyLong_FromLongLong(C.longlong(l))
}
31 changes: 31 additions & 0 deletions cl/_testgo/cgomacro/cgomacro.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

/*
#cgo pkg-config: python3-embed
#include <stdio.h>
#include <Python.h>
void test_stdout() {
printf("stdout ptr: %p\n", stdout);
fputs("outputs to stdout\n", stdout);
}
*/
import "C"
import (
"unsafe"

"github.com/goplus/llgo/c"
)

func main() {
C.test_stdout()
C.fputs((*C.char)(unsafe.Pointer(c.Str("hello\n"))), C.stdout)
C.Py_Initialize()
defer C.Py_Finalize()
C.PyObject_Print(C.Py_True, C.stdout, 0)
C.fputs((*C.char)(unsafe.Pointer(c.Str("\n"))), C.stdout)
C.PyObject_Print(C.Py_False, C.stdout, 0)
C.fputs((*C.char)(unsafe.Pointer(c.Str("\n"))), C.stdout)
C.PyObject_Print(C.Py_None, C.stdout, 0)
C.fputs((*C.char)(unsafe.Pointer(c.Str("\n"))), C.stdout)
}
1 change: 1 addition & 0 deletions cl/_testgo/cgomacro/out.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
;
File renamed without changes.
1 change: 1 addition & 0 deletions cl/_testgo/cgopython/out.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
;
Loading

0 comments on commit 5e5df6b

Please sign in to comment.