From da362b8a24fe271bd03a98d44305c47bcfefe05b Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 25 Nov 2022 02:27:27 +0100 Subject: [PATCH] wasm: support ThinLTO Using ThinLTO manages to optimize binaries quite significantly. The exact amount varies a lot by program but it's about 10-15% usually. Don't remove non-ThinLTO support yet. It would not surprise me if this triggered some unintended side effect. Eventually, non-ThinLTO support should be removed though. --- compileopts/config.go | 14 ++++---------- compiler/compiler.go | 5 +++++ compiler/testdata/pragma.ll | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compileopts/config.go b/compileopts/config.go index b22db15d..499dcd27 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -190,17 +190,11 @@ func (c *Config) StackSize() uint64 { return c.Target.DefaultStackSize } -// UseThinLTO returns whether ThinLTO should be used for the given target. Some -// targets (such as wasm) are not yet supported. -// We should try and remove as many exceptions as possible in the future, so -// that this optimization can be applied in more places. +// UseThinLTO returns whether ThinLTO should be used for the given target. func (c *Config) UseThinLTO() bool { - parts := strings.Split(c.Triple(), "-") - if parts[0] == "wasm32" { - // wasm-ld doesn't seem to support ThinLTO yet. - return false - } - // Other architectures support ThinLTO. + // All architectures support ThinLTO now. However, this code is kept for the + // time being in case there are regressions. The non-ThinLTO code support + // should be removed when it is proven to work reliably. return true } diff --git a/compiler/compiler.go b/compiler/compiler.go index 53086478..92e95a05 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1099,6 +1099,11 @@ func (b *builder) createFunctionStart(intrinsic bool) { // otherwise the function is not exported. functionAttr := b.ctx.CreateStringAttribute("wasm-export-name", b.info.linkName) b.llvmFn.AddFunctionAttr(functionAttr) + // Unlike most targets, exported functions are actually visible in + // WebAssembly (even if it's not called from within the WebAssembly + // module). But LTO generally optimizes such functions away. Therefore, + // exported functions must be explicitly marked as used. + llvmutil.AppendToGlobal(b.mod, "llvm.used", b.llvmFn) } // Some functions have a pragma controlling the inlining level. diff --git a/compiler/testdata/pragma.ll b/compiler/testdata/pragma.ll index 00c619d5..68288804 100644 --- a/compiler/testdata/pragma.ll +++ b/compiler/testdata/pragma.ll @@ -6,6 +6,7 @@ target triple = "wasm32-unknown-wasi" @extern_global = external global [0 x i8], align 1 @main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32 @main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16 +@llvm.used = appending global [2 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection] @main.globalInSection = hidden global i32 0, section ".special_global_section", align 4 @undefinedGlobalNotInSection = external global i32, align 4 @main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024