mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-16 02:33:28 +00:00
all: add support for ThinLTO
ThinLTO optimizes across LLVM modules at link time. This means that optimizations (such as inlining and const-propagation) are possible between C and Go. This makes this change especially useful for CGo, but not just for CGo. By doing some optimizations at link time, the linker can discard some unused functions and this leads to a size reduction on average. It does increase code size in some cases, but that's true for most optimizations. I've excluded a number of targets for now (wasm, avr, xtensa, windows, macos). They can probably be supported with some more work, but that should be done in separate PRs. Overall, this change results in an average 3.24% size reduction over all the tinygo.org/x/drivers smoke tests. TODO: this commit runs part of the pass pipeline twice. We should set the PrepareForThinLTO flag in the PassManagerBuilder for even further reduced code size (0.7%) and improved compilation speed.
This commit is contained in:
committed by
Ron Evans
parent
d4b1467e4c
commit
603fff78d4
@@ -151,6 +151,7 @@ func Optimize(mod llvm.Module, config *compileopts.Config, optLevel, sizeLevel i
|
||||
funcPasses.FinalizeFunc()
|
||||
|
||||
// Run module passes.
|
||||
// TODO: somehow set the PrepareForThinLTO flag in the pass manager builder.
|
||||
modPasses := llvm.NewPassManager()
|
||||
defer modPasses.Dispose()
|
||||
builder.Populate(modPasses)
|
||||
|
||||
+25
-1
@@ -11,8 +11,9 @@ import (
|
||||
// modified after linking.
|
||||
func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string {
|
||||
functionMap := map[llvm.Value][]llvm.Value{}
|
||||
var functions []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.
|
||||
@@ -23,6 +24,7 @@ func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string
|
||||
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)
|
||||
}
|
||||
@@ -44,6 +46,9 @@ func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string
|
||||
}
|
||||
stackSizesGlobal.SetInitializer(llvm.ConstArray(functions[0].Type(), defaultStackSizes))
|
||||
|
||||
// Add all relevant values to llvm.used (for LTO).
|
||||
appendToUsedGlobals(mod, append([]llvm.Value{stackSizesGlobal}, functionValues...)...)
|
||||
|
||||
// Replace the calls with loads from the new global with stack sizes.
|
||||
irbuilder := mod.Context().NewBuilder()
|
||||
defer irbuilder.Dispose()
|
||||
@@ -62,3 +67,22 @@ func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string
|
||||
|
||||
return functionNames
|
||||
}
|
||||
|
||||
// Append the given values to the llvm.used array. The values can be any pointer
|
||||
// type, they will be bitcast to i8*.
|
||||
func appendToUsedGlobals(mod llvm.Module, values ...llvm.Value) {
|
||||
if !mod.NamedGlobal("llvm.used").IsNil() {
|
||||
// Sanity check. TODO: we don't emit such a global at the moment, but
|
||||
// when we do we should append to it instead.
|
||||
panic("todo: append to existing llvm.used")
|
||||
}
|
||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||
var castValues []llvm.Value
|
||||
for _, value := range values {
|
||||
castValues = append(castValues, llvm.ConstBitCast(value, i8ptrType))
|
||||
}
|
||||
usedInitializer := llvm.ConstArray(i8ptrType, castValues)
|
||||
used := llvm.AddGlobal(mod, usedInitializer.Type(), "llvm.used")
|
||||
used.SetInitializer(usedInitializer)
|
||||
used.SetLinkage(llvm.AppendingLinkage)
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -2,6 +2,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "armv7m-none-eabi"
|
||||
|
||||
@"internal/task.stackSizes" = global [1 x i32] [i32 1024], section ".tinygo_stacksizes"
|
||||
@llvm.used = appending global [2 x i8*] [i8* bitcast ([1 x i32]* @"internal/task.stackSizes" to i8*), i8* bitcast (void (i8*)* @"runtime.run$1$gowrapper" to i8*)]
|
||||
|
||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*, i8*)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user