vkFuncDecl, vkFuncPtr, vkClosure; callback example
This commit is contained in:
15
cl/_testrt/callback/in.go
Normal file
15
cl/_testrt/callback/in.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/internal/runtime/c"
|
||||
)
|
||||
|
||||
func callback(f func()) {
|
||||
f()
|
||||
}
|
||||
|
||||
func main() {
|
||||
callback(func() {
|
||||
c.Printf(c.Str("Hello, callback\n"))
|
||||
})
|
||||
}
|
||||
49
cl/_testrt/callback/out.ll
Normal file
49
cl/_testrt/callback/out.ll
Normal file
@@ -0,0 +1,49 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
@"main.init$guard" = global ptr null
|
||||
@0 = private unnamed_addr constant [17 x i8] c"Hello, callback\0A\00", align 1
|
||||
|
||||
define void @main.callback({ ptr, ptr } %0) {
|
||||
_llgo_0:
|
||||
%1 = extractvalue { ptr, ptr } %0, 0
|
||||
call void %1()
|
||||
ret void
|
||||
}
|
||||
|
||||
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 void @main() {
|
||||
_llgo_0:
|
||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
call void @main.init()
|
||||
%0 = alloca { ptr, ptr }, align 8
|
||||
%1 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 0
|
||||
store ptr @"main.main$1", ptr %1, align 8
|
||||
%2 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr null, ptr %2, align 8
|
||||
%3 = load { ptr, ptr }, ptr %0, align 8
|
||||
call void @main.callback({ ptr, ptr } %3)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
|
||||
define void @"main.main$1"() {
|
||||
_llgo_0:
|
||||
%0 = call i32 (ptr, ...) @printf(ptr @0)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @printf(ptr, ...)
|
||||
@@ -22,10 +22,10 @@ _llgo_1: ; preds = %_llgo_2, %_llgo_0
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1
|
||||
%9 = extractvalue { ptr, ptr } %1, 0
|
||||
%10 = call addrspace(37) { ptr, ptr } %1()
|
||||
%10 = call i32 %9()
|
||||
%11 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %4)
|
||||
%12 = getelementptr inbounds i32, ptr %11, i64 %7
|
||||
store ptr %10, ptr %12, align 8
|
||||
store i32 %10, ptr %12, align 4
|
||||
br label %_llgo_1
|
||||
|
||||
_llgo_3: ; preds = %_llgo_1
|
||||
|
||||
@@ -29,7 +29,7 @@ func testCompile(t *testing.T, src, expected string) {
|
||||
}
|
||||
|
||||
func TestFromTestrt(t *testing.T) {
|
||||
cltest.FromDir(t, "", "./_testrt", true)
|
||||
cltest.FromDir(t, "callback", "./_testrt", true)
|
||||
}
|
||||
|
||||
func TestFromTestdata(t *testing.T) {
|
||||
|
||||
@@ -35,6 +35,33 @@ func TestRuntime(t *testing.T) {
|
||||
cltest.Pkg(t, "github.com/goplus/llgo/internal/abi", "../internal/abi/llgo_autogen.ll")
|
||||
}
|
||||
|
||||
/*
|
||||
func TestCallback(t *testing.T) {
|
||||
ctx := llvm.NewContext()
|
||||
mod := ctx.NewModule("foo/bar")
|
||||
|
||||
tc := llvm.FunctionType(ctx.VoidType(), nil, false)
|
||||
callback := llvm.PointerType(tc, 0)
|
||||
params := []llvm.Type{callback}
|
||||
|
||||
tfn := llvm.FunctionType(ctx.VoidType(), params, false)
|
||||
f := llvm.AddFunction(mod, "fn", tfn)
|
||||
b := ctx.NewBuilder()
|
||||
blk := llvm.AddBasicBlock(f, "")
|
||||
b.SetInsertPointAtEnd(blk)
|
||||
|
||||
arg := f.Param(0)
|
||||
// arg = b.CreateLoad(tc, arg, "")
|
||||
b.CreateCall(tc, arg, nil, "")
|
||||
b.CreateRetVoid()
|
||||
|
||||
expected := `; ModuleID = 'foo/bar'
|
||||
`
|
||||
if v := mod.String(); v != expected {
|
||||
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestMap(t *testing.T) {
|
||||
var m typeutil.Map
|
||||
|
||||
@@ -124,8 +124,9 @@ func (g Global) Init(v Expr) {
|
||||
// respectively, and is nil in the generic method.
|
||||
type aFunction struct {
|
||||
Expr
|
||||
pkg Package
|
||||
prog Program
|
||||
Pkg Package
|
||||
Prog Program
|
||||
|
||||
blks []BasicBlock
|
||||
|
||||
params []Type
|
||||
@@ -162,7 +163,7 @@ func (p Function) Param(i int) Expr {
|
||||
|
||||
// NewBuilder creates a new Builder for the function.
|
||||
func (p Function) NewBuilder() Builder {
|
||||
prog := p.prog
|
||||
prog := p.Prog
|
||||
b := prog.ctx.NewBuilder()
|
||||
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||
// b.Finalize()
|
||||
|
||||
41
ssa/expr.go
41
ssa/expr.go
@@ -183,7 +183,7 @@ func (b Builder) CStr(v string) Expr {
|
||||
func (b Builder) Str(v string) (ret Expr) {
|
||||
prog := b.Prog
|
||||
cstr := b.CStr(v)
|
||||
ret = b.InlineCall(b.fn.pkg.rtFunc("NewString"), cstr, prog.Val(len(v)))
|
||||
ret = b.InlineCall(b.Func.Pkg.rtFunc("NewString"), cstr, prog.Val(len(v)))
|
||||
ret.Type = prog.String()
|
||||
return
|
||||
}
|
||||
@@ -296,7 +296,7 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
|
||||
switch kind {
|
||||
case vkString:
|
||||
if op == token.ADD {
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
return b.InlineCall(pkg.rtFunc("StringCat"), x, y)
|
||||
}
|
||||
case vkComplex:
|
||||
@@ -566,7 +566,7 @@ func (b Builder) IndexAddr(x, idx Expr) Expr {
|
||||
pt := prog.Pointer(telem)
|
||||
switch x.raw.Type.Underlying().(type) {
|
||||
case *types.Slice:
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
ptr := b.InlineCall(pkg.rtFunc("SliceData"), x)
|
||||
indices := []llvm.Value{idx.impl}
|
||||
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt}
|
||||
@@ -596,7 +596,7 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) Expr) Expr {
|
||||
panic(fmt.Errorf("invalid operation: cannot index %v", t))
|
||||
}
|
||||
telem = prog.rawType(types.Typ[types.Byte])
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
ptr = b.InlineCall(pkg.rtFunc("StringData"), x)
|
||||
case *types.Array:
|
||||
telem = prog.Index(x.Type)
|
||||
@@ -631,7 +631,7 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
|
||||
log.Printf("Slice %v, %v, %v\n", x.impl, low.impl, high.impl)
|
||||
}
|
||||
prog := b.Prog
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
var nCap Expr
|
||||
var nEltSize Expr
|
||||
var base Expr
|
||||
@@ -693,7 +693,7 @@ func (b Builder) MakeMap(t Type, nReserve Expr) (ret Expr) {
|
||||
if debugInstr {
|
||||
log.Printf("MakeMap %v, %v\n", t.RawType(), nReserve.impl)
|
||||
}
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
ret.Type = t
|
||||
ret.impl = b.InlineCall(pkg.rtFunc("MakeSmallMap")).impl
|
||||
// TODO(xsw): nReserve
|
||||
@@ -718,7 +718,7 @@ func (b Builder) MakeSlice(t Type, len, cap Expr) (ret Expr) {
|
||||
if debugInstr {
|
||||
log.Printf("MakeSlice %v, %v, %v\n", t.RawType(), len.impl, cap.impl)
|
||||
}
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
if cap.IsNil() {
|
||||
cap = len
|
||||
}
|
||||
@@ -756,7 +756,7 @@ func (b Builder) Alloc(elem Type, heap bool) (ret Expr) {
|
||||
log.Printf("Alloc %v, %v\n", elem.RawType(), heap)
|
||||
}
|
||||
prog := b.Prog
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
size := b.SizeOf(elem)
|
||||
if heap {
|
||||
ret = b.InlineCall(pkg.rtFunc("AllocZ"), size)
|
||||
@@ -797,7 +797,7 @@ func (b Builder) AllocaCStr(gostr Expr) (ret Expr) {
|
||||
if debugInstr {
|
||||
log.Printf("AllocaCStr %v\n", gostr.impl)
|
||||
}
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
n := b.InlineCall(pkg.rtFunc("StringLen"), gostr)
|
||||
n1 := b.BinOp(token.ADD, n, b.Prog.Val(1))
|
||||
cstr := b.Alloca(n1)
|
||||
@@ -931,7 +931,7 @@ func (b Builder) MakeInterface(tinter Type, x Expr, mayDelay bool) (ret Expr) {
|
||||
isAny := tiund.Empty()
|
||||
fnDo := func() Expr {
|
||||
prog := b.Prog
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
switch tx := x.raw.Type.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
kind := tx.Kind()
|
||||
@@ -998,7 +998,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
|
||||
}
|
||||
switch assertedTyp.kind {
|
||||
case vkSigned, vkUnsigned, vkFloat:
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
fnName := "I2Int"
|
||||
if commaOk {
|
||||
fnName = "CheckI2Int"
|
||||
@@ -1051,20 +1051,25 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
||||
}
|
||||
log.Println(b.String())
|
||||
}
|
||||
var ll llvm.Type
|
||||
var sig *types.Signature
|
||||
var raw = fn.raw.Type
|
||||
switch fn.kind {
|
||||
case vkClosure:
|
||||
fn := b.Field(fn, 0)
|
||||
fn = b.Field(fn, 0)
|
||||
raw = fn.raw.Type
|
||||
fallthrough
|
||||
case vkFunc:
|
||||
case vkFuncPtr:
|
||||
sig = raw.(*types.Signature)
|
||||
ret.Type = prog.retType(sig)
|
||||
ll = prog.FuncDecl(sig, InC).ll
|
||||
case vkFuncDecl:
|
||||
sig = raw.(*types.Signature)
|
||||
ll = fn.ll
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
ret.impl = llvm.CreateCall(b.impl, fn.ll, fn.impl, llvmValues(args, sig.Params(), b))
|
||||
ret.Type = prog.retType(sig)
|
||||
ret.impl = llvm.CreateCall(b.impl, ll, fn.impl, llvmValues(args, sig.Params(), b))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1081,10 +1086,10 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
||||
arg := args[0]
|
||||
switch t := arg.raw.Type.Underlying().(type) {
|
||||
case *types.Slice:
|
||||
return b.InlineCall(b.fn.pkg.rtFunc("SliceLen"), arg)
|
||||
return b.InlineCall(b.Func.Pkg.rtFunc("SliceLen"), arg)
|
||||
case *types.Basic:
|
||||
if t.Kind() == types.String {
|
||||
return b.InlineCall(b.fn.pkg.rtFunc("StringLen"), arg)
|
||||
return b.InlineCall(b.Func.Pkg.rtFunc("StringLen"), arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1093,7 +1098,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
||||
arg := args[0]
|
||||
switch arg.raw.Type.Underlying().(type) {
|
||||
case *types.Slice:
|
||||
return b.InlineCall(b.fn.pkg.rtFunc("SliceCap"), arg)
|
||||
return b.InlineCall(b.Func.Pkg.rtFunc("SliceCap"), arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ type aPackage struct {
|
||||
mod llvm.Module
|
||||
fns map[string]Function
|
||||
vars map[string]Global
|
||||
prog Program
|
||||
Prog Program
|
||||
}
|
||||
|
||||
type Package = *aPackage
|
||||
@@ -326,7 +326,7 @@ func (p Package) NewConst(name string, val constant.Value) NamedConst {
|
||||
|
||||
// NewVar creates a new global variable.
|
||||
func (p Package) NewVar(name string, typ types.Type, bg Background) Global {
|
||||
t := p.prog.Type(typ, bg)
|
||||
t := p.Prog.Type(typ, bg)
|
||||
gbl := llvm.AddGlobal(p.mod, t.ll, name)
|
||||
ret := &aGlobal{Expr{gbl, t}}
|
||||
p.vars[name] = ret
|
||||
@@ -343,18 +343,18 @@ func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Funct
|
||||
if v, ok := p.fns[name]; ok {
|
||||
return v
|
||||
}
|
||||
t := p.prog.FuncDecl(sig, bg)
|
||||
t := p.Prog.FuncDecl(sig, bg)
|
||||
if debugInstr {
|
||||
log.Println("NewFunc", name, t.raw.Type)
|
||||
}
|
||||
fn := llvm.AddFunction(p.mod, name, t.ll)
|
||||
ret := newFunction(fn, t, p, p.prog)
|
||||
ret := newFunction(fn, t, p, p.Prog)
|
||||
p.fns[name] = ret
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p Package) rtFunc(fnName string) Expr {
|
||||
fn := p.prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
||||
fn := p.Prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
||||
name := FullName(fn.Pkg(), fnName)
|
||||
sig := fn.Type().(*types.Signature)
|
||||
return p.NewFunc(name, sig, InGo).Expr
|
||||
|
||||
@@ -50,7 +50,7 @@ func (p BasicBlock) Index() int {
|
||||
|
||||
type aBuilder struct {
|
||||
impl llvm.Builder
|
||||
fn Function
|
||||
Func Function
|
||||
Prog Program
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ type Builder = *aBuilder
|
||||
|
||||
// SetBlock sets the current block to the specified basic block.
|
||||
func (b Builder) SetBlock(blk BasicBlock) Builder {
|
||||
if b.fn != blk.fn {
|
||||
if b.Func != blk.fn {
|
||||
panic("mismatched function")
|
||||
}
|
||||
if debugInstr {
|
||||
@@ -74,7 +74,7 @@ func (b Builder) Panic(v Expr) {
|
||||
if debugInstr {
|
||||
log.Printf("Panic %v\n", v.impl)
|
||||
}
|
||||
pkg := b.fn.pkg
|
||||
pkg := b.Func.Pkg
|
||||
b.Call(pkg.rtFunc("TracePanic"), v)
|
||||
b.impl.CreateUnreachable()
|
||||
}
|
||||
@@ -103,14 +103,14 @@ func (b Builder) Return(results ...Expr) {
|
||||
case 1:
|
||||
b.impl.CreateRet(results[0].impl)
|
||||
default:
|
||||
tret := b.fn.raw.Type.(*types.Signature).Results()
|
||||
tret := b.Func.raw.Type.(*types.Signature).Results()
|
||||
b.impl.CreateAggregateRet(llvmValues(results, tret, b))
|
||||
}
|
||||
}
|
||||
|
||||
// Jump emits a jump instruction.
|
||||
func (b Builder) Jump(jmpb BasicBlock) {
|
||||
if b.fn != jmpb.fn {
|
||||
if b.Func != jmpb.fn {
|
||||
panic("mismatched function")
|
||||
}
|
||||
if debugInstr {
|
||||
@@ -121,7 +121,7 @@ func (b Builder) Jump(jmpb BasicBlock) {
|
||||
|
||||
// If emits an if instruction.
|
||||
func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
|
||||
if b.fn != thenb.fn || b.fn != elseb.fn {
|
||||
if b.Func != thenb.fn || b.Func != elseb.fn {
|
||||
panic("mismatched function")
|
||||
}
|
||||
if debugInstr {
|
||||
|
||||
@@ -40,7 +40,8 @@ const (
|
||||
vkString
|
||||
vkBool
|
||||
vkPtr
|
||||
vkFunc
|
||||
vkFuncDecl
|
||||
vkFuncPtr
|
||||
vkClosure
|
||||
vkTuple
|
||||
vkDelayExpr = -1
|
||||
@@ -241,7 +242,7 @@ func (p Program) toType(raw types.Type) Type {
|
||||
case *types.Named:
|
||||
return p.toNamed(t)
|
||||
case *types.Signature: // represents a C function pointer in raw type
|
||||
return &aType{p.toLLVMFuncPtr(t), typ, vkFunc}
|
||||
return &aType{p.toLLVMFuncPtr(t), typ, vkFuncPtr}
|
||||
case *types.Array:
|
||||
elem := p.rawType(t.Elem())
|
||||
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid}
|
||||
|
||||
@@ -56,7 +56,7 @@ func (p Program) FuncDecl(sig *types.Signature, bg Background) Type {
|
||||
if bg == InGo {
|
||||
sig = p.gocvt.cvtFunc(sig, true)
|
||||
}
|
||||
return &aType{p.toLLVMFunc(sig), rawType{sig}, vkFunc}
|
||||
return &aType{p.toLLVMFunc(sig), rawType{sig}, vkFuncDecl}
|
||||
}
|
||||
|
||||
func (p goTypes) cvtType(typ types.Type) (raw types.Type, cvt bool) {
|
||||
|
||||
Reference in New Issue
Block a user