mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
compiler: resolve callees before lowering arguments
createFunctionCall and createGo currently lower arguments before they determine whether the call is direct, an interface invoke, or through a function value. Resolve the callee, function type, and context first, then append the arguments in the same order as before. This does not change the generated LLVM IR.
This commit is contained in:
committed by
Damian Gryski
parent
5ec2632461
commit
deaf532d61
+14
-10
@@ -2090,14 +2090,10 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
}
|
||||
}
|
||||
|
||||
var params []llvm.Value
|
||||
for _, param := range instr.Args {
|
||||
params = append(params, b.getValue(param, getPos(instr)))
|
||||
}
|
||||
|
||||
// Try to call the function directly for trivially static calls.
|
||||
var callee, context llvm.Value
|
||||
var calleeType llvm.Type
|
||||
var invokeTypecode, invokeReceiver llvm.Value
|
||||
exported := false
|
||||
if fn := instr.StaticCallee(); fn != nil {
|
||||
calleeType, callee = b.getFunction(fn)
|
||||
@@ -2127,19 +2123,18 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
exported = info.exported
|
||||
} else if call, ok := instr.Value.(*ssa.Builtin); ok {
|
||||
// Builtin function (append, close, delete, etc.).)
|
||||
var params []llvm.Value
|
||||
var argTypes []types.Type
|
||||
for _, arg := range instr.Args {
|
||||
argTypes = append(argTypes, arg.Type())
|
||||
params = append(params, b.getValue(arg, getPos(instr)))
|
||||
}
|
||||
return b.createBuiltin(argTypes, params, call.Name(), instr.Pos())
|
||||
} else if instr.IsInvoke() {
|
||||
// Interface method call (aka invoke call).
|
||||
itf := b.getValue(instr.Value, getPos(instr)) // interface value (runtime._interface)
|
||||
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
|
||||
value := b.CreateExtractValue(itf, 1, "invoke.func.value") // receiver
|
||||
// Prefix the params with receiver value and suffix with typecode.
|
||||
params = append([]llvm.Value{value}, params...)
|
||||
params = append(params, typecode)
|
||||
invokeTypecode = b.CreateExtractValue(itf, 0, "invoke.func.typecode")
|
||||
invokeReceiver = b.CreateExtractValue(itf, 1, "invoke.func.value")
|
||||
callee = b.getInvokeFunction(instr)
|
||||
calleeType = callee.GlobalValueType()
|
||||
context = llvm.Undef(b.dataPtrType)
|
||||
@@ -2153,6 +2148,15 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
b.createNilCheck(instr.Value, callee, "fpcall")
|
||||
}
|
||||
|
||||
var params []llvm.Value
|
||||
for _, param := range instr.Args {
|
||||
params = append(params, b.getValue(param, getPos(instr)))
|
||||
}
|
||||
if instr.IsInvoke() {
|
||||
params = append([]llvm.Value{invokeReceiver}, params...)
|
||||
params = append(params, invokeTypecode)
|
||||
}
|
||||
|
||||
if !exported {
|
||||
// This function takes a context parameter.
|
||||
// Add it to the end of the parameter list.
|
||||
|
||||
+13
-11
@@ -47,20 +47,15 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get all function parameters to pass to the goroutine.
|
||||
var params []llvm.Value
|
||||
for _, param := range instr.Call.Args {
|
||||
params = append(params, b.getGoroutineCallArgument(param)...)
|
||||
}
|
||||
|
||||
var prefix string
|
||||
var funcPtr llvm.Value
|
||||
var funcType llvm.Type
|
||||
var context llvm.Value
|
||||
hasContext := false
|
||||
if callee := instr.Call.StaticCallee(); callee != nil {
|
||||
// Static callee is known. This makes it easier to start a new
|
||||
// goroutine.
|
||||
var context llvm.Value
|
||||
switch value := instr.Call.Value.(type) {
|
||||
case *ssa.Function:
|
||||
// Goroutine call is regular function call. No context is necessary.
|
||||
@@ -73,7 +68,6 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
panic("StaticCallee returned an unexpected value")
|
||||
}
|
||||
if !context.IsNil() {
|
||||
params = append(params, context) // context parameter
|
||||
hasContext = true
|
||||
}
|
||||
funcType, funcPtr = b.getFunction(callee)
|
||||
@@ -84,22 +78,30 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
itfValue := b.CreateExtractValue(itf, 1, "")
|
||||
funcPtr = b.getInvokeFunction(&instr.Call)
|
||||
funcType = funcPtr.GlobalValueType()
|
||||
params = append([]llvm.Value{itfValue}, params...) // start with receiver
|
||||
params = append(params, itfTypeCode) // end with typecode
|
||||
params = append(params, itfValue)
|
||||
context = itfTypeCode
|
||||
} else {
|
||||
// This is a function pointer.
|
||||
// At the moment, two extra params are passed to the newly started
|
||||
// goroutine:
|
||||
// * The function context, for closures.
|
||||
// * The function pointer (for tasks).
|
||||
var context llvm.Value
|
||||
funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value, getPos(instr)))
|
||||
funcType = b.getLLVMFunctionType(instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||
params = append(params, context, funcPtr)
|
||||
hasContext = true
|
||||
prefix = b.getFunctionInfo(b.fn).linkName
|
||||
}
|
||||
|
||||
for _, param := range instr.Call.Args {
|
||||
params = append(params, b.getGoroutineCallArgument(param)...)
|
||||
}
|
||||
if !context.IsNil() {
|
||||
params = append(params, context)
|
||||
}
|
||||
if hasContext && instr.Call.StaticCallee() == nil {
|
||||
params = append(params, funcPtr)
|
||||
}
|
||||
|
||||
paramBundle := b.emitPointerPack(params, instr.Pos())
|
||||
var stackSize llvm.Value
|
||||
callee := b.createGoroutineStartWrapper(funcType, funcPtr, prefix, hasContext, false, instr.Pos())
|
||||
|
||||
Reference in New Issue
Block a user