
This is a pure refactor, it doesn't change the behavior of anything. It's separate from the next commit so that the actual changes are easier to read.
75 строки
2,8 КиБ
Go
75 строки
2,8 КиБ
Go
package transform
|
|
|
|
import (
|
|
"github.com/tinygo-org/tinygo/compileopts"
|
|
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
|
"tinygo.org/x/go-llvm"
|
|
)
|
|
|
|
// CreateStackSizeLoads replaces internal/task.getGoroutineStackSize calls with
|
|
// loads from internal/task.stackSizes that will be updated after linking. This
|
|
// way the stack sizes are loaded from a separate section and can easily be
|
|
// modified after linking.
|
|
func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string {
|
|
functionMap := map[llvm.Value][]llvm.Value{}
|
|
var functions []llvm.Value // ptrtoint values of functions
|
|
var functionNames []string
|
|
var functionValues []llvm.Value // direct references to functions
|
|
for _, use := range getUses(mod.NamedFunction("internal/task.getGoroutineStackSize")) {
|
|
if use.FirstUse().IsNil() {
|
|
// Apparently this stack size isn't used.
|
|
use.EraseFromParentAsInstruction()
|
|
continue
|
|
}
|
|
ptrtoint := use.Operand(0)
|
|
if _, ok := functionMap[ptrtoint]; !ok {
|
|
functions = append(functions, ptrtoint)
|
|
functionNames = append(functionNames, ptrtoint.Operand(0).Name())
|
|
functionValues = append(functionValues, ptrtoint.Operand(0))
|
|
}
|
|
functionMap[ptrtoint] = append(functionMap[ptrtoint], use)
|
|
}
|
|
|
|
if len(functions) == 0 {
|
|
// Nothing to do.
|
|
return nil
|
|
}
|
|
|
|
ctx := mod.Context()
|
|
targetData := llvm.NewTargetData(mod.DataLayout())
|
|
defer targetData.Dispose()
|
|
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
|
|
|
|
// Create the new global with stack sizes, that will be put in a new section
|
|
// just for itself.
|
|
stackSizesGlobalType := llvm.ArrayType(functions[0].Type(), len(functions))
|
|
stackSizesGlobal := llvm.AddGlobal(mod, stackSizesGlobalType, "internal/task.stackSizes")
|
|
stackSizesGlobal.SetSection(".tinygo_stacksizes")
|
|
defaultStackSizes := make([]llvm.Value, len(functions))
|
|
defaultStackSize := llvm.ConstInt(functions[0].Type(), config.StackSize(), false)
|
|
for i := range defaultStackSizes {
|
|
defaultStackSizes[i] = defaultStackSize
|
|
}
|
|
stackSizesGlobal.SetInitializer(llvm.ConstArray(functions[0].Type(), defaultStackSizes))
|
|
|
|
// Add all relevant values to llvm.used (for LTO).
|
|
llvmutil.AppendToUsedGlobals(mod, append([]llvm.Value{stackSizesGlobal}, functionValues...)...)
|
|
|
|
// Replace the calls with loads from the new global with stack sizes.
|
|
irbuilder := ctx.NewBuilder()
|
|
defer irbuilder.Dispose()
|
|
for i, function := range functions {
|
|
for _, use := range functionMap[function] {
|
|
ptr := llvm.ConstGEP(stackSizesGlobalType, stackSizesGlobal, []llvm.Value{
|
|
llvm.ConstInt(ctx.Int32Type(), 0, false),
|
|
llvm.ConstInt(ctx.Int32Type(), uint64(i), false),
|
|
})
|
|
irbuilder.SetInsertPointBefore(use)
|
|
stacksize := irbuilder.CreateLoad(uintptrType, ptr, "stacksize")
|
|
use.ReplaceAllUsesWith(stacksize)
|
|
use.EraseFromParentAsInstruction()
|
|
}
|
|
}
|
|
|
|
return functionNames
|
|
}
|