Skip to content

Commit b2dd536

Browse files
[Feat] Enable LTO
Signed-off-by: ZhouGuangyuan <zhouguangyuan.xian@gmail.com>
1 parent 6f3b222 commit b2dd536

File tree

6 files changed

+65
-2
lines changed

6 files changed

+65
-2
lines changed

_demo/embed/targetsbuild/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ case "$test_dir" in
111111
"riscv32"
112112
"riscv64"
113113
"rp2040"
114+
"nintendoswitch" # undefined symbol under lto, should not work when no-lto
114115
)
115116
;;
116117
defer)

internal/build/plan9asm.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ func filterPlan9AsmFuncs(pkgPath, goos, goarch string, funcs []plan9asm.Func, re
254254
if pkgPath == "syscall" && goos == "linux" && (goarch == "arm64" || goarch == "amd64") && strings.HasSuffix(resolved, "rawVforkSyscall") {
255255
continue
256256
}
257+
if pkgPath == "syscall" && goos == "darwin" && (goarch == "arm64" || goarch == "amd64") &&
258+
(strings.HasSuffix(resolved, "RawSyscall") || strings.HasSuffix(resolved, "RawSyscall6")) {
259+
continue
260+
}
257261
keep = append(keep, fn)
258262
}
259263
return keep

internal/crosscompile/crosscompile.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,9 @@ func use(goos, goarch string, wasiThreads, forceEspClang bool) (export Export, e
225225
"-Wl,--error-limit=0",
226226
"-fuse-ld=lld",
227227
// Enable ICF (Identical Code Folding) to reduce binary size
228-
"-Xlinker",
229-
"--icf=safe",
228+
"-Wl,--icf=safe",
229+
// Enable ThinLTO, Using default lto kind(thinlto).
230+
"-Wl,--lto-O0",
230231
}
231232
if clangRoot != "" {
232233
clangLib := filepath.Join(clangRoot, "lib")
@@ -249,6 +250,7 @@ func use(goos, goarch string, wasiThreads, forceEspClang bool) (export Export, e
249250
export.CCFLAGS = []string{
250251
"-Qunused-arguments",
251252
"-Wno-unused-command-line-argument",
253+
"-flto=thin",
252254
}
253255

254256
// Add sysroot for macOS only
@@ -499,6 +501,13 @@ func UseTarget(targetName string) (export Export, err error) {
499501
expandedCFlags := env.ExpandEnvSlice(config.CFlags, envs)
500502
cflags = append(cflags, expandedCFlags...)
501503

504+
if config.Linker == "ld.lld" {
505+
// Enable ThinLTO, Using default lto kind(thinlto).
506+
ldflags = append(ldflags, "--lto-O0")
507+
cflags = append(cflags, "-flto=thin")
508+
ccflags = append(ccflags, "-flto=thin")
509+
}
510+
502511
// The following parameters are inspired by tinygo/builder/library.go
503512
// Handle CPU configuration
504513
if cpu != "" {
@@ -545,6 +554,8 @@ func UseTarget(targetName string) (export Export, err error) {
545554
ccflags = append(ccflags, "-fforce-enable-int128")
546555
case "riscv64":
547556
ccflags = append(ccflags, "-march=rv64gc")
557+
// codegen option should be added to ldflags for lto
558+
ldflags = append(ldflags, "-mllvm", "-march=rv64gc")
548559
case "mips":
549560
ccflags = append(ccflags, "-fno-pic")
550561
}
@@ -574,9 +585,13 @@ func UseTarget(targetName string) (export Export, err error) {
574585
// Handle code generation configuration
575586
if config.CodeModel != "" {
576587
ccflags = append(ccflags, "-mcmodel="+config.CodeModel)
588+
// codegen option should be added to ldflags for lto
589+
ldflags = append(ldflags, "-mllvm", "-code-model="+config.CodeModel)
577590
}
578591
if config.TargetABI != "" {
579592
ccflags = append(ccflags, "-mabi="+config.TargetABI)
593+
// codegen option should be added to ldflags for lto
594+
ldflags = append(ldflags, "-mllvm", "-target-abi="+config.TargetABI)
580595
}
581596
if config.RelocationModel != "" {
582597
switch config.RelocationModel {

ssa/datastruct.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
342342
if lowIsNil {
343343
low = prog.IntVal(0, prog.Int())
344344
}
345+
low = b.fitIntSize(low)
346+
if !high.IsNil() {
347+
high = b.fitIntSize(high)
348+
}
345349
switch t := x.raw.Type.Underlying().(type) {
346350
case *types.Basic:
347351
if t.Kind() != types.String {
@@ -382,6 +386,7 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
382386
if max.IsNil() {
383387
max = nCap
384388
}
389+
max = b.fitIntSize(max)
385390
ret.impl = b.InlineCall(b.Pkg.rtFunc("NewSlice3"), base, nEltSize, nCap, low, high, max).impl
386391
return
387392
}

ssa/decl.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, has
211211
if instantiated {
212212
fn.SetLinkage(llvm.LinkOnceAnyLinkage)
213213
}
214+
if p.Prog.requiresFramePointer() {
215+
attr := p.mod.Context().CreateStringAttribute("frame-pointer", "all")
216+
fn.AddFunctionAttr(attr)
217+
}
214218
if p.isPreservedName(name) {
215219
p.markLLVMUsed(fn)
216220
}
@@ -345,6 +349,10 @@ func (p Function) Block(idx int) BasicBlock {
345349
return p.blks[idx]
346350
}
347351

352+
func (p Program) requiresFramePointer() bool {
353+
return p.target != nil && p.target.GOOS == "darwin" && p.target.GOARCH == "arm64"
354+
}
355+
348356
// SetRecover sets the recover block for the function.
349357
func (p Function) SetRecover(blk BasicBlock) {
350358
p.recov = blk

ssa/ssa_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,36 @@ func TestNewFuncExLLVMUsed(t *testing.T) {
134134
}
135135
}
136136

137+
func TestNewFuncExFramePointerAttrOnDarwinArm64(t *testing.T) {
138+
prog := NewProgram(&Target{GOOS: "darwin", GOARCH: "arm64"})
139+
pkg := prog.NewPackage("main", "main")
140+
sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
141+
142+
fn := pkg.NewFunc("Foo", sig, InGo)
143+
attr := fn.impl.GetStringAttributeAtIndex(-1, "frame-pointer")
144+
if attr.IsNil() {
145+
t.Fatal("missing frame-pointer function attribute")
146+
}
147+
if got := pkg.String(); !strings.Contains(got, `"frame-pointer"="non-leaf"`) {
148+
t.Fatalf("module missing frame-pointer attribute:\n%s", got)
149+
}
150+
}
151+
152+
func TestNewFuncExFramePointerAttrNotForcedOnOtherTargets(t *testing.T) {
153+
prog := NewProgram(&Target{GOOS: "linux", GOARCH: "amd64"})
154+
pkg := prog.NewPackage("main", "main")
155+
sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
156+
157+
fn := pkg.NewFunc("Foo", sig, InGo)
158+
attr := fn.impl.GetStringAttributeAtIndex(-1, "frame-pointer")
159+
if !attr.IsNil() {
160+
t.Fatal("unexpected frame-pointer function attribute")
161+
}
162+
if got := pkg.String(); strings.Contains(got, `"frame-pointer"="non-leaf"`) {
163+
t.Fatalf("unexpected frame-pointer attribute in module:\n%s", got)
164+
}
165+
}
166+
137167
func TestSetBlock(t *testing.T) {
138168
defer func() {
139169
if r := recover(); r == nil {

0 commit comments

Comments
 (0)