
ThinLTO results in a small code size reduction, which is nice (especially on these very small chips). It also brings us one step closer to using ThinLTO everywhere.
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.AppendToGlobal(mod, "llvm.used", 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
|
|
}
|