diff --git a/compiler/compiler.go b/compiler/compiler.go index a60341af..26f145b5 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -57,6 +57,7 @@ type Compiler struct { targetData llvm.TargetData intType llvm.Type i8ptrType llvm.Type // for convenience + funcPtrAddrSpace int uintptrType llvm.Type initFuncs []llvm.Value interfaceInvokeWrappers []interfaceInvokeWrapper @@ -125,6 +126,11 @@ func NewCompiler(pkgName string, config Config) (*Compiler, error) { } c.i8ptrType = llvm.PointerType(c.ctx.Int8Type(), 0) + dummyFuncType := llvm.FunctionType(c.ctx.VoidType(), nil, false) + dummyFunc := llvm.AddFunction(c.mod, "tinygo.dummy", dummyFuncType) + c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace() + dummyFunc.EraseFromParentAsFunction() + return c, nil } @@ -462,7 +468,7 @@ func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) { // {context, funcptr} paramTypes = append(paramTypes, c.i8ptrType) // context paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine - ptr := llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), 0) + ptr := llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace) ptr = c.ctx.StructType([]llvm.Type{c.i8ptrType, ptr}, false) return ptr, nil case *types.Slice: diff --git a/compiler/interface-lowering.go b/compiler/interface-lowering.go index 52093233..73623709 100644 --- a/compiler/interface-lowering.go +++ b/compiler/interface-lowering.go @@ -304,7 +304,7 @@ func (p *lowerInterfacesPass) run() { // interface value should already have returned false. // Replace the function pointer with undef (which will then be // called), indicating to the optimizer this code is unreachable. - use.ReplaceAllUsesWith(llvm.Undef(p.i8ptrType)) + use.ReplaceAllUsesWith(llvm.Undef(p.uintptrType)) use.EraseFromParentAsInstruction() } else if len(itf.types) == 1 { // There is only one implementation of the given type. @@ -314,12 +314,12 @@ func (p *lowerInterfacesPass) run() { // There are multiple types implementing this interface, thus there // are multiple possible functions to call. Delegate calling the // right function to a special wrapper function. - bitcasts := getUses(use) - if len(bitcasts) != 1 || bitcasts[0].IsABitCastInst().IsNil() { - panic("expected exactly one bitcast use of runtime.interfaceMethod") + inttoptrs := getUses(use) + if len(inttoptrs) != 1 || inttoptrs[0].IsAIntToPtrInst().IsNil() { + panic("expected exactly one inttoptr use of runtime.interfaceMethod") } - bitcast := bitcasts[0] - calls := getUses(bitcast) + inttoptr := inttoptrs[0] + calls := getUses(inttoptr) if len(calls) != 1 || calls[0].IsACallInst().IsNil() { panic("expected exactly one call use of runtime.interfaceMethod") } @@ -340,14 +340,14 @@ func (p *lowerInterfacesPass) run() { // call, after selecting the right concrete type. redirector := p.getInterfaceMethodFunc(itf, signature, call.Type(), paramTypes) - // Replace the old lookup/bitcast/call with the new call. + // Replace the old lookup/inttoptr/call with the new call. p.builder.SetInsertPointBefore(call) retval := p.builder.CreateCall(redirector, params, "") if retval.Type().TypeKind() != llvm.VoidTypeKind { call.ReplaceAllUsesWith(retval) } call.EraseFromParentAsInstruction() - bitcast.EraseFromParentAsInstruction() + inttoptr.EraseFromParentAsInstruction() use.EraseFromParentAsInstruction() } } @@ -542,22 +542,22 @@ func (p *lowerInterfacesPass) getSignature(name string) *signatureInfo { return p.signatures[name] } -// replaceInvokeWithCall replaces a runtime.interfaceMethod + bitcast with a +// replaceInvokeWithCall replaces a runtime.interfaceMethod + inttoptr with a // concrete method. This can be done when only one type implements the // interface. func (p *lowerInterfacesPass) replaceInvokeWithCall(use llvm.Value, typ *typeInfo, signature *signatureInfo) { - bitcasts := getUses(use) - if len(bitcasts) != 1 || bitcasts[0].IsABitCastInst().IsNil() { - panic("expected exactly one bitcast use of runtime.interfaceMethod") + inttoptrs := getUses(use) + if len(inttoptrs) != 1 || inttoptrs[0].IsAIntToPtrInst().IsNil() { + panic("expected exactly one inttoptr use of runtime.interfaceMethod") } - bitcast := bitcasts[0] + inttoptr := inttoptrs[0] function := typ.getMethod(signature).function - if bitcast.Type() != function.Type() { + if inttoptr.Type() != function.Type() { p.builder.SetInsertPointBefore(use) - function = p.builder.CreateBitCast(function, bitcast.Type(), "") + function = p.builder.CreateBitCast(function, inttoptr.Type(), "") } - bitcast.ReplaceAllUsesWith(function) - bitcast.EraseFromParentAsInstruction() + inttoptr.ReplaceAllUsesWith(function) + inttoptr.EraseFromParentAsInstruction() use.EraseFromParentAsInstruction() } diff --git a/compiler/interface.go b/compiler/interface.go index 3a2f64bf..f39bc105 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -203,7 +203,7 @@ func (c *Compiler) getTypeMethodSet(typ types.Type) (llvm.Value, error) { } methodInfo := llvm.ConstNamedStruct(interfaceMethodInfoType, []llvm.Value{ signatureGlobal, - llvm.ConstBitCast(fn, c.i8ptrType), + llvm.ConstPtrToInt(fn, c.uintptrType), }) methods[i] = methodInfo } @@ -400,7 +400,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu c.getMethodSignature(instr.Method), } fn := c.createRuntimeCall("interfaceMethod", values, "invoke.func") - fnCast := c.builder.CreateBitCast(fn, llvmFnType, "invoke.func.cast") + fnCast := c.builder.CreateIntToPtr(fn, llvmFnType, "invoke.func.cast") receiverValue := c.builder.CreateExtractValue(itf, 1, "invoke.func.receiver") args := []llvm.Value{receiverValue} diff --git a/src/runtime/interface.go b/src/runtime/interface.go index 3daf56d2..61d3114d 100644 --- a/src/runtime/interface.go +++ b/src/runtime/interface.go @@ -39,8 +39,8 @@ func interfaceTypeAssert(ok bool) { // See compiler/interface-lowering.go for details. type interfaceMethodInfo struct { - signature *uint8 // external *i8 with a name identifying the Go function signature - funcptr *uint8 // bitcast from the actual function pointer + signature *uint8 // external *i8 with a name identifying the Go function signature + funcptr uintptr // bitcast from the actual function pointer } // Pseudo function call used while putting a concrete value in an interface, @@ -59,4 +59,4 @@ func interfaceImplements(typecode uintptr, interfaceMethodSet **uint8) bool // Pseudo function that returns a function pointer to the method to call. // See the interface lowering pass for how this is lowered to a real call. -func interfaceMethod(typecode uintptr, interfaceMethodSet **uint8, signature *uint8) *uint8 +func interfaceMethod(typecode uintptr, interfaceMethodSet **uint8, signature *uint8) uintptr