diff --git a/compiler/compiler.go b/compiler/compiler.go index b079235c8e..a4c6f026a5 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -23,7 +23,7 @@ import ( // Version of the compiler pacakge. Must be incremented each time the compiler // package changes in a way that affects the generated LLVM module. // This version is independent of the TinyGo version number. -const Version = 22 // last change: check for divide by zero +const Version = 23 // last change: fix recursive function types func init() { llvm.InitializeAllTargets() @@ -76,6 +76,7 @@ type compilerContext struct { targetData llvm.TargetData intType llvm.Type i8ptrType llvm.Type // for convenience + rawVoidFuncType llvm.Type // for convenience funcPtrAddrSpace int uintptrType llvm.Type program *ssa.Program @@ -121,6 +122,7 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C dummyFuncType := llvm.FunctionType(c.ctx.VoidType(), nil, false) dummyFunc := llvm.AddFunction(c.mod, "tinygo.dummy", dummyFuncType) c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace() + c.rawVoidFuncType = dummyFunc.Type() dummyFunc.EraseFromParentAsFunction() return c diff --git a/compiler/func.go b/compiler/func.go index 7472f4070e..a82d1f1b80 100644 --- a/compiler/func.go +++ b/compiler/func.go @@ -23,7 +23,7 @@ func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context switch c.FuncImplementation { case "doubleword": // Closure is: {context, function pointer} - funcValueScalar = funcPtr + funcValueScalar = llvm.ConstBitCast(funcPtr, c.rawVoidFuncType) case "switch": funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature" funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName) @@ -78,11 +78,11 @@ func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value { // value. This may be an expensive operation. func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (funcPtr, context llvm.Value) { context = b.CreateExtractValue(funcValue, 0, "") + llvmSig := b.getRawFuncType(sig) switch b.FuncImplementation { case "doubleword": - funcPtr = b.CreateExtractValue(funcValue, 1, "") + funcPtr = b.CreateBitCast(b.CreateExtractValue(funcValue, 1, ""), llvmSig, "") case "switch": - llvmSig := b.getRawFuncType(sig) sigGlobal := b.getFuncSignatureID(sig) funcPtr = b.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "") funcPtr = b.CreateIntToPtr(funcPtr, llvmSig, "") @@ -96,8 +96,7 @@ func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (f func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type { switch c.FuncImplementation { case "doubleword": - rawPtr := c.getRawFuncType(typ) - return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false) + return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false) case "switch": return c.getLLVMRuntimeType("funcValue") default: diff --git a/compiler/testdata/goroutine-cortex-m-qemu.ll b/compiler/testdata/goroutine-cortex-m-qemu.ll index 15e3f4eed7..8c99dce9a9 100644 --- a/compiler/testdata/goroutine-cortex-m-qemu.ll +++ b/compiler/testdata/goroutine-cortex-m-qemu.ll @@ -103,7 +103,7 @@ entry: declare void @runtime.printint32(i32, i8*, i8*) ; Function Attrs: nounwind -define hidden void @main.funcGoroutine(i8* %fn.context, void (i32, i8*, i8*)* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 { +define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 { entry: %0 = call i8* @runtime.alloc(i32 12, i8* undef, i8* null) #0 %1 = bitcast i8* %0 to i32* @@ -112,8 +112,8 @@ entry: %3 = bitcast i8* %2 to i8** store i8* %fn.context, i8** %3, align 4 %4 = getelementptr inbounds i8, i8* %0, i32 8 - %5 = bitcast i8* %4 to void (i32, i8*, i8*)** - store void (i32, i8*, i8*)* %fn.funcptr, void (i32, i8*, i8*)** %5, align 4 + %5 = bitcast i8* %4 to void ()** + store void ()* %fn.funcptr, void ()** %5, align 4 %stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef, i8* undef) #0 call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef, i8* null) #0 ret void diff --git a/testdata/calls.go b/testdata/calls.go index 94e6c0df75..b8b10c2c97 100644 --- a/testdata/calls.go +++ b/testdata/calls.go @@ -228,3 +228,7 @@ type issue1304 struct { func (x issue1304) call() { // nothing to do } + +type recursiveFuncType func(recursiveFuncType) + +var recursiveFunction recursiveFuncType diff --git a/transform/interrupt.go b/transform/interrupt.go index 74c0bf5f48..8cfaf0cb61 100644 --- a/transform/interrupt.go +++ b/transform/interrupt.go @@ -66,7 +66,8 @@ func LowerInterrupts(mod llvm.Module, sizeLevel int) []error { softwareVector := make(map[int64]llvm.Value) ctx := mod.Context() - nullptr := llvm.ConstNull(llvm.PointerType(ctx.Int8Type(), 0)) + i8ptrType := llvm.PointerType(ctx.Int8Type(), 0) + nullptr := llvm.ConstNull(i8ptrType) builder := ctx.NewBuilder() defer builder.Dispose() @@ -236,6 +237,8 @@ func LowerInterrupts(mod llvm.Module, sizeLevel int) []error { // Fill the function declaration with the forwarding call. // In practice, the called function will often be inlined which avoids // the extra indirection. + handlerFuncPtrType := llvm.PointerType(llvm.FunctionType(ctx.VoidType(), []llvm.Type{num.Type(), i8ptrType, i8ptrType}, false), handlerFuncPtr.Type().PointerAddressSpace()) + handlerFuncPtr = llvm.ConstBitCast(handlerFuncPtr, handlerFuncPtrType) builder.CreateCall(handlerFuncPtr, []llvm.Value{num, handlerContext, nullptr}, "") // Replace all ptrtoint uses of the global with the interrupt constant.