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
|
//go:linkname Str llgo.cstr
|
||||||
func Str(string) *Char
|
func Str(string) *Char
|
||||||
|
|
||||||
|
//go:linkname Func llgo.funcAddr
|
||||||
|
func Func(any) Pointer
|
||||||
|
|
||||||
// llgo:link Advance llgo.advance
|
// llgo:link Advance llgo.advance
|
||||||
func Advance[PtrT any, I integer](ptr PtrT, offset I) PtrT { return ptr }
|
func Advance[PtrT any, I integer](ptr PtrT, offset I) PtrT { return ptr }
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/c/math/cmplx"
|
"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("abs(3+4i):", cmplx.Absf(c))
|
||||||
println("real(3+4i):", real(z))
|
println("real(3+4i):", real(z))
|
||||||
println("imag(3+4i):", imag(z))
|
println("imag(3+4i):", imag(z))
|
||||||
@@ -14,6 +16,6 @@ func main() {
|
|||||||
re := float32(3.0)
|
re := float32(3.0)
|
||||||
im := float32(4.0)
|
im := float32(4.0)
|
||||||
z := complex64(3 + 4i)
|
z := complex64(3 + 4i)
|
||||||
c := complex(re, im)
|
x := complex(re, im)
|
||||||
f(c, z)
|
f(x, z, c.Func(f))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,49 +4,60 @@ source_filename = "main"
|
|||||||
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
||||||
|
|
||||||
@"main.init$guard" = global i1 false, align 1
|
@"main.init$guard" = global i1 false, align 1
|
||||||
@0 = private unnamed_addr constant [10 x i8] c"abs(3+4i):", align 1
|
@0 = private unnamed_addr constant [5 x i8] c"addr:", align 1
|
||||||
@1 = private unnamed_addr constant [11 x i8] c"real(3+4i):", 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"imag(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_argc = global i32 0, align 4
|
||||||
@__llgo_argv = global ptr null, align 8
|
@__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:
|
_llgo_0:
|
||||||
%2 = call float @cabsf({ float, float } %0)
|
|
||||||
%3 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
%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
|
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 0
|
||||||
store ptr @0, ptr %4, align 8
|
store ptr @0, ptr %4, align 8
|
||||||
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 1
|
%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
|
%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.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %6)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
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.PrintPointer"(ptr %2)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %7)
|
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
%8 = extractvalue { float, float } %1, 0
|
%7 = call float @cabsf({ float, float } %0)
|
||||||
%9 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
%8 = 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
|
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %8, i32 0, i32 0
|
||||||
store ptr @1, ptr %10, align 8
|
store ptr @1, ptr %9, align 8
|
||||||
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %9, i32 0, i32 1
|
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %8, i32 0, i32 1
|
||||||
store i64 11, ptr %11, align 4
|
store i64 10, ptr %10, align 4
|
||||||
%12 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %9, align 8
|
%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" %12)
|
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)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
%13 = fpext float %8 to double
|
%12 = fpext float %7 to double
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %13)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %12)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
%14 = extractvalue { float, float } %1, 1
|
%13 = extractvalue { float, float } %1, 0
|
||||||
%15 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
%14 = 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
|
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i32 0, i32 0
|
||||||
store ptr @2, ptr %16, align 8
|
store ptr @2, ptr %15, align 8
|
||||||
%17 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %15, i32 0, i32 1
|
%16 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i32 0, i32 1
|
||||||
store i64 11, ptr %17, align 4
|
store i64 11, ptr %16, align 4
|
||||||
%18 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %15, align 8
|
%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" %18)
|
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)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
%19 = fpext float %14 to double
|
%18 = fpext float %13 to double
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %19)
|
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)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
@@ -76,16 +87,18 @@ _llgo_0:
|
|||||||
%4 = getelementptr inbounds { float, float }, ptr %2, i32 0, i32 1
|
%4 = getelementptr inbounds { float, float }, ptr %2, i32 0, i32 1
|
||||||
store float 4.000000e+00, ptr %4, align 4
|
store float 4.000000e+00, ptr %4, align 4
|
||||||
%5 = load { float, float }, ptr %2, 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
|
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.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.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.PrintFloat"(double)
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
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("allocaCStr", func(ctx *context) { ctx.allocaCStr(nil, nil) })
|
||||||
test("string", func(ctx *context) { ctx.string(nil, nil) })
|
test("string", func(ctx *context) { ctx.string(nil, nil) })
|
||||||
test("stringData", func(ctx *context) { ctx.stringData(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("sigsetjmp", func(ctx *context) { ctx.sigsetjmp(nil, nil) })
|
||||||
test("siglongjmp", func(ctx *context) { ctx.siglongjmp(nil, nil) })
|
test("siglongjmp", func(ctx *context) { ctx.siglongjmp(nil, nil) })
|
||||||
test("cstr(NoArgs)", func(ctx *context) { cstr(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)
|
ret = b.Slice(x, low, high, max)
|
||||||
case *ssa.MakeInterface:
|
case *ssa.MakeInterface:
|
||||||
if refs := *v.Referrers(); len(refs) == 1 {
|
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 va, ok := ref.Addr.(*ssa.IndexAddr); ok {
|
||||||
if _, ok = p.isVArgs(va.X); ok { // varargs: this is a varargs store
|
if _, ok = p.isVArgs(va.X); ok { // varargs: this is a varargs store
|
||||||
return
|
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)
|
t := p.prog.Type(v.Type(), llssa.InGo)
|
||||||
|
|||||||
@@ -384,6 +384,7 @@ const (
|
|||||||
llgoDeferData = llgoInstrBase + 6
|
llgoDeferData = llgoInstrBase + 6
|
||||||
llgoStringData = llgoInstrBase + 7
|
llgoStringData = llgoInstrBase + 7
|
||||||
llgoString = llgoInstrBase + 8
|
llgoString = llgoInstrBase + 8
|
||||||
|
llgoFuncAddr = llgoInstrBase + 9
|
||||||
|
|
||||||
llgoSigjmpbuf = llgoInstrBase + 0xa
|
llgoSigjmpbuf = llgoInstrBase + 0xa
|
||||||
llgoSigsetjmp = llgoInstrBase + 0xb
|
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")
|
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) {
|
func (p *context) sigsetjmp(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
if len(args) == 2 {
|
if len(args) == 2 {
|
||||||
jb := p.compileValue(b, args[0])
|
jb := p.compileValue(b, args[0])
|
||||||
@@ -160,6 +174,7 @@ var llgoInstrs = map[string]int{
|
|||||||
"allocaCStr": llgoAllocaCStr,
|
"allocaCStr": llgoAllocaCStr,
|
||||||
"string": llgoString,
|
"string": llgoString,
|
||||||
"stringData": llgoStringData,
|
"stringData": llgoStringData,
|
||||||
|
"funcAddr": llgoFuncAddr,
|
||||||
"pyList": llgoPyList,
|
"pyList": llgoPyList,
|
||||||
"sigjmpbuf": llgoSigjmpbuf,
|
"sigjmpbuf": llgoSigjmpbuf,
|
||||||
"sigsetjmp": llgoSigsetjmp,
|
"sigsetjmp": llgoSigsetjmp,
|
||||||
@@ -327,6 +342,8 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon
|
|||||||
ret = b.AllocaSigjmpBuf()
|
ret = b.AllocaSigjmpBuf()
|
||||||
case llgoDeferData: // func deferData() *Defer
|
case llgoDeferData: // func deferData() *Defer
|
||||||
ret = b.DeferData()
|
ret = b.DeferData()
|
||||||
|
case llgoFuncAddr:
|
||||||
|
ret = p.funcAddr(b, args)
|
||||||
case llgoUnreachable: // func unreachable()
|
case llgoUnreachable: // func unreachable()
|
||||||
b.Unreachable()
|
b.Unreachable()
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user