transform: remove switched func lowering

The switched func lowering was mainly necessary for coroutines.
With coroutines removed, this is no longer necessary.
This commit is contained in:
Nia Waldvogel
2021-12-31 13:51:47 -05:00
committed by Nia
parent ea2a6b70b2
commit 0c2fefa09b
14 changed files with 57 additions and 617 deletions
-1
View File
@@ -47,7 +47,6 @@ type Config struct {
// Various compiler options that determine how code is generated.
Scheduler string
FuncImplementation string
AutomaticStackSize bool
DefaultStackSize uint64
NeedsStackObjects bool
+1 -2
View File
@@ -55,7 +55,7 @@ func TestCompiler(t *testing.T) {
{"string.go", "", ""},
{"float.go", "", ""},
{"interface.go", "", ""},
{"func.go", "", "none"},
{"func.go", "", ""},
{"pragma.go", "", ""},
{"goroutine.go", "wasm", "asyncify"},
{"goroutine.go", "cortex-m-qemu", "tasks"},
@@ -105,7 +105,6 @@ func TestCompiler(t *testing.T) {
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(),
FuncImplementation: config.FuncImplementation(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize,
NeedsStackObjects: config.NeedsStackObjects(),
+9 -54
View File
@@ -19,29 +19,8 @@ func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signat
// createFuncValue creates a function value from a raw function pointer with no
// context.
func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
var funcValueScalar llvm.Value
switch c.FuncImplementation {
case "doubleword":
// Closure is: {context, function pointer}
funcValueScalar = llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
case "switch":
funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature"
funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName)
if funcValueWithSignatureGlobal.IsNil() {
funcValueWithSignatureType := c.getLLVMRuntimeType("funcValueWithSignature")
funcValueWithSignature := llvm.ConstNamedStruct(funcValueWithSignatureType, []llvm.Value{
llvm.ConstPtrToInt(funcPtr, c.uintptrType),
c.getFuncSignatureID(sig),
})
funcValueWithSignatureGlobal = llvm.AddGlobal(c.mod, funcValueWithSignatureType, funcValueWithSignatureGlobalName)
funcValueWithSignatureGlobal.SetInitializer(funcValueWithSignature)
funcValueWithSignatureGlobal.SetGlobalConstant(true)
funcValueWithSignatureGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
}
funcValueScalar = llvm.ConstPtrToInt(funcValueWithSignatureGlobal, c.uintptrType)
default:
panic("unimplemented func value variant")
}
// Closure is: {context, function pointer}
funcValueScalar := llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
funcValueType := c.getFuncType(sig)
funcValue := llvm.Undef(funcValueType)
funcValue = builder.CreateInsertValue(funcValue, context, 0, "")
@@ -78,43 +57,19 @@ 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, "")
switch b.FuncImplementation {
case "doubleword":
bitcast := b.CreateExtractValue(funcValue, 1, "")
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
funcPtr = bitcast.Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
case "switch":
if !funcValue.IsAConstant().IsNil() {
// If this is a constant func value, the underlying function is
// known and can be returned directly.
funcValueWithSignatureGlobal := llvm.ConstExtractValue(funcValue, []uint32{1}).Operand(0)
funcPtr = llvm.ConstExtractValue(funcValueWithSignatureGlobal.Initializer(), []uint32{0}).Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
sigGlobal := b.getFuncSignatureID(sig)
funcPtr = b.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
funcPtr = b.CreateIntToPtr(funcPtr, llvmSig, "")
default:
panic("unimplemented func value variant")
bitcast := b.CreateExtractValue(funcValue, 1, "")
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
funcPtr = bitcast.Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
return
}
// getFuncType returns the type of a func value given a signature.
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
switch c.FuncImplementation {
case "doubleword":
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
case "switch":
return c.getLLVMRuntimeType("funcValue")
default:
panic("unimplemented func value variant")
}
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
}
// getRawFuncType returns a LLVM function pointer type for a given signature.
-55
View File
@@ -1,55 +0,0 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%runtime.funcValueWithSignature = type { i32, i8* }
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
@"main.someFunc$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @main.someFunc to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(i8* %callback.context, i32 %callback.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i32 @runtime.getFuncPtr(i8* %callback.context, i32 %callback.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null) #0
%1 = icmp eq i32 %0, 0
br i1 %1, label %fpcall.throw, label %fpcall.next
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef, i8* null) #0
unreachable
fpcall.next: ; preds = %entry
%2 = inttoptr i32 %0 to void (i32, i8*, i8*)*
call void %2(i32 3, i8* %callback.context, i8* undef) #0
ret void
}
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
declare void @runtime.nilPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.bar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @main.foo(i8* undef, i32 ptrtoint (%runtime.funcValueWithSignature* @"main.someFunc$withSignature" to i32), i8* undef, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
attributes #0 = { nounwind }
+47
View File
@@ -0,0 +1,47 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(i8* %callback.context, void ()* %callback.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp eq void ()* %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef, i8* null) #0
unreachable
fpcall.next: ; preds = %entry
%1 = bitcast void ()* %callback.funcptr to void (i32, i8*, i8*)*
call void %1(i32 3, i8* %callback.context, i8* undef) #0
ret void
}
declare void @runtime.nilPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.bar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @main.foo(i8* undef, void ()* bitcast (void (i32, i8*, i8*)* @main.someFunc to void ()*), i8* undef, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
attributes #0 = { nounwind }
-5
View File
@@ -61,11 +61,6 @@ func newStruct() {
}
func newFuncValue() *func() {
// On some platforms that use runtime.funcValue ("switch" style) function
// values, a func value is allocated as having two pointer words while the
// struct looks like {unsafe.Pointer; uintptr}. This is so that the interp
// package won't get confused, see getPointerBitmap in compiler/llvm.go for
// details.
return new(func())
}