Merge pull request #387 from xushiwei/q
cl: c.Func (llgo.funcAddr); demo: cppintf (how to use c++ interface)
This commit is contained in:
37
_demo/cppintf/cppintf.go
Normal file
37
_demo/cppintf/cppintf.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/_demo/cppintf/foo"
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
type Bar struct {
|
||||
foo.Callback
|
||||
a int
|
||||
b float64
|
||||
}
|
||||
|
||||
func NewBar(a int, b float64) *Bar {
|
||||
return &Bar{
|
||||
Callback: foo.Callback{
|
||||
Vptr: &foo.CallbackVtbl{
|
||||
ValA: c.Func((*Bar).getA),
|
||||
ValB: c.Func((*Bar).getB),
|
||||
},
|
||||
},
|
||||
a: a, b: b,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Bar) getA() int {
|
||||
return p.a
|
||||
}
|
||||
|
||||
func (p *Bar) getB() float64 {
|
||||
return p.b
|
||||
}
|
||||
|
||||
func main() {
|
||||
bar := NewBar(1, 2.0)
|
||||
foo.F(&bar.Callback)
|
||||
}
|
||||
11
_demo/cppintf/foo/bar/bar.cpp
Normal file
11
_demo/cppintf/foo/bar/bar.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#define interface struct
|
||||
|
||||
interface ICallback {
|
||||
virtual int valA() = 0;
|
||||
virtual double valB() = 0;
|
||||
};
|
||||
|
||||
extern "C" void f(ICallback* cb) {
|
||||
printf("Hello %d, %lf!\n", cb->valA(), cb->valB());
|
||||
}
|
||||
22
_demo/cppintf/foo/foo.go
Normal file
22
_demo/cppintf/foo/foo.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package foo
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "bar/bar.cpp"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
type Callback struct {
|
||||
Vptr *CallbackVtbl
|
||||
}
|
||||
|
||||
type CallbackVtbl struct {
|
||||
ValA unsafe.Pointer
|
||||
ValB unsafe.Pointer
|
||||
}
|
||||
|
||||
//go:linkname F C.f
|
||||
func F(cb *Callback)
|
||||
BIN
_demo/cppintf/foo/llgo_autogen.lla
Normal file
BIN
_demo/cppintf/foo/llgo_autogen.lla
Normal file
Binary file not shown.
3
c/c.go
3
c/c.go
@@ -48,6 +48,9 @@ type integer interface {
|
||||
//go:linkname Str llgo.cstr
|
||||
func Str(string) *Char
|
||||
|
||||
//go:linkname Func llgo.funcAddr
|
||||
func Func(any) Pointer
|
||||
|
||||
// llgo:link Advance llgo.advance
|
||||
func Advance[PtrT any, I integer](ptr PtrT, offset I) PtrT { return ptr }
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/math/cmplx"
|
||||
)
|
||||
|
||||
func f(c, z complex64) {
|
||||
func f(c, z complex64, addr c.Pointer) {
|
||||
println("addr:", addr)
|
||||
println("abs(3+4i):", cmplx.Absf(c))
|
||||
println("real(3+4i):", real(z))
|
||||
println("imag(3+4i):", imag(z))
|
||||
@@ -14,6 +16,6 @@ func main() {
|
||||
re := float32(3.0)
|
||||
im := float32(4.0)
|
||||
z := complex64(3 + 4i)
|
||||
c := complex(re, im)
|
||||
f(c, z)
|
||||
x := complex(re, im)
|
||||
f(x, z, c.Func(f))
|
||||
}
|
||||
|
||||
@@ -4,49 +4,60 @@ 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 [10 x i8] c"abs(3+4i):", align 1
|
||||
@1 = private unnamed_addr constant [11 x i8] c"real(3+4i):", align 1
|
||||
@2 = private unnamed_addr constant [11 x i8] c"imag(3+4i):", align 1
|
||||
@0 = private unnamed_addr constant [5 x i8] c"addr:", align 1
|
||||
@1 = private unnamed_addr constant [10 x i8] c"abs(3+4i):", align 1
|
||||
@2 = private unnamed_addr constant [11 x i8] c"real(3+4i):", align 1
|
||||
@3 = private unnamed_addr constant [11 x i8] c"imag(3+4i):", align 1
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
|
||||
define void @main.f({ float, float } %0, { float, float } %1) {
|
||||
define void @main.f({ float, float } %0, { float, float } %1, ptr %2) {
|
||||
_llgo_0:
|
||||
%2 = call float @cabsf({ float, float } %0)
|
||||
%3 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 0
|
||||
store ptr @0, ptr %4, align 8
|
||||
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 1
|
||||
store i64 10, ptr %5, align 4
|
||||
store i64 5, ptr %5, align 4
|
||||
%6 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %3, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %6)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
%7 = fpext float %2 to double
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %7)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintPointer"(ptr %2)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
%8 = extractvalue { float, float } %1, 0
|
||||
%9 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %9, i32 0, i32 0
|
||||
store ptr @1, ptr %10, align 8
|
||||
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %9, i32 0, i32 1
|
||||
store i64 11, ptr %11, align 4
|
||||
%12 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %9, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %12)
|
||||
%7 = call float @cabsf({ float, float } %0)
|
||||
%8 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %8, i32 0, i32 0
|
||||
store ptr @1, ptr %9, align 8
|
||||
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %8, i32 0, i32 1
|
||||
store i64 10, ptr %10, align 4
|
||||
%11 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %8, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %11)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
%13 = fpext float %8 to double
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %13)
|
||||
%12 = fpext float %7 to double
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %12)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
%14 = extractvalue { float, float } %1, 1
|
||||
%15 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%16 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %15, i32 0, i32 0
|
||||
store ptr @2, ptr %16, align 8
|
||||
%17 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %15, i32 0, i32 1
|
||||
store i64 11, ptr %17, align 4
|
||||
%18 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %15, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %18)
|
||||
%13 = extractvalue { float, float } %1, 0
|
||||
%14 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i32 0, i32 0
|
||||
store ptr @2, ptr %15, align 8
|
||||
%16 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i32 0, i32 1
|
||||
store i64 11, ptr %16, align 4
|
||||
%17 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %14, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %17)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
%19 = fpext float %14 to double
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %19)
|
||||
%18 = fpext float %13 to double
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %18)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
%19 = extractvalue { float, float } %1, 1
|
||||
%20 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%21 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %20, i32 0, i32 0
|
||||
store ptr @3, ptr %21, align 8
|
||||
%22 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %20, i32 0, i32 1
|
||||
store i64 11, ptr %22, align 4
|
||||
%23 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %20, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %23)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
%24 = fpext float %19 to double
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %24)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
ret void
|
||||
}
|
||||
@@ -76,16 +87,18 @@ _llgo_0:
|
||||
%4 = getelementptr inbounds { float, float }, ptr %2, i32 0, i32 1
|
||||
store float 4.000000e+00, ptr %4, align 4
|
||||
%5 = load { float, float }, ptr %2, align 4
|
||||
call void @main.f({ float, float } %5, { float, float } { float 3.000000e+00, float 4.000000e+00 })
|
||||
call void @main.f({ float, float } %5, { float, float } { float 3.000000e+00, float 4.000000e+00 }, ptr @main.f)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare float @cabsf({ float, float })
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintPointer"(ptr)
|
||||
|
||||
declare float @cabsf({ float, float })
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double)
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
|
||||
@@ -139,6 +139,7 @@ func TestErrBuiltin(t *testing.T) {
|
||||
test("allocaCStr", func(ctx *context) { ctx.allocaCStr(nil, nil) })
|
||||
test("string", func(ctx *context) { ctx.string(nil, nil) })
|
||||
test("stringData", func(ctx *context) { ctx.stringData(nil, nil) })
|
||||
test("funcAddr", func(ctx *context) { ctx.funcAddr(nil, nil) })
|
||||
test("sigsetjmp", func(ctx *context) { ctx.sigsetjmp(nil, nil) })
|
||||
test("siglongjmp", func(ctx *context) { ctx.siglongjmp(nil, nil) })
|
||||
test("cstr(NoArgs)", func(ctx *context) { cstr(nil, nil) })
|
||||
|
||||
@@ -524,12 +524,19 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
||||
ret = b.Slice(x, low, high, max)
|
||||
case *ssa.MakeInterface:
|
||||
if refs := *v.Referrers(); len(refs) == 1 {
|
||||
if ref, ok := refs[0].(*ssa.Store); ok {
|
||||
switch ref := refs[0].(type) {
|
||||
case *ssa.Store:
|
||||
if va, ok := ref.Addr.(*ssa.IndexAddr); ok {
|
||||
if _, ok = p.isVArgs(va.X); ok { // varargs: this is a varargs store
|
||||
return
|
||||
}
|
||||
}
|
||||
case *ssa.Call:
|
||||
if fn, ok := ref.Call.Value.(*ssa.Function); ok {
|
||||
if _, _, ftype := p.funcOf(fn); ftype == llgoFuncAddr { // llgo.funcAddr
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t := p.prog.Type(v.Type(), llssa.InGo)
|
||||
|
||||
@@ -384,6 +384,7 @@ const (
|
||||
llgoDeferData = llgoInstrBase + 6
|
||||
llgoStringData = llgoInstrBase + 7
|
||||
llgoString = llgoInstrBase + 8
|
||||
llgoFuncAddr = llgoInstrBase + 9
|
||||
|
||||
llgoSigjmpbuf = llgoInstrBase + 0xa
|
||||
llgoSigsetjmp = llgoInstrBase + 0xb
|
||||
|
||||
17
cl/instr.go
17
cl/instr.go
@@ -94,6 +94,20 @@ func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr)
|
||||
panic("stringData(s string): invalid arguments")
|
||||
}
|
||||
|
||||
// func funcAddr(fn any) unsafe.Pointer
|
||||
func (p *context) funcAddr(b llssa.Builder, args []ssa.Value) llssa.Expr {
|
||||
if len(args) == 1 {
|
||||
if fn, ok := args[0].(*ssa.MakeInterface); ok {
|
||||
if fnDecl, ok := fn.X.(*ssa.Function); ok {
|
||||
if aFn, _, _ := p.compileFunction(fnDecl); aFn != nil {
|
||||
return aFn.Expr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
panic("funcAddr(<func>): invalid arguments")
|
||||
}
|
||||
|
||||
func (p *context) sigsetjmp(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if len(args) == 2 {
|
||||
jb := p.compileValue(b, args[0])
|
||||
@@ -160,6 +174,7 @@ var llgoInstrs = map[string]int{
|
||||
"allocaCStr": llgoAllocaCStr,
|
||||
"string": llgoString,
|
||||
"stringData": llgoStringData,
|
||||
"funcAddr": llgoFuncAddr,
|
||||
"pyList": llgoPyList,
|
||||
"sigjmpbuf": llgoSigjmpbuf,
|
||||
"sigsetjmp": llgoSigsetjmp,
|
||||
@@ -327,6 +342,8 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon
|
||||
ret = b.AllocaSigjmpBuf()
|
||||
case llgoDeferData: // func deferData() *Defer
|
||||
ret = b.DeferData()
|
||||
case llgoFuncAddr:
|
||||
ret = p.funcAddr(b, args)
|
||||
case llgoUnreachable: // func unreachable()
|
||||
b.Unreachable()
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user