builder: add optsize attribute while building the package

This simplifies future changes. While the move itself is very simple, it
required some other changes to a few transforms that create new
functions to add the optsize attribute manually. It also required
abstracting away the optimization level flags (based on the -opt flag)
so that it can easily be retrieved from the config object.

This commit does not impact binary size on baremetal and WebAssembly.
I've seen a few tests on linux/amd64 grow slightly in size, but I'm not
too worried about those.
This commit is contained in:
Ayke van Laethem
2021-04-04 17:50:47 +02:00
committed by Ron Evans
parent fa6c1b69ce
commit 49ec3eb58e
9 changed files with 66 additions and 33 deletions
+15 -15
View File
@@ -60,6 +60,7 @@ type packageAction struct {
CFlags []string
FileHashes map[string]string // hash of every file that's part of the package
Imports map[string]string // map from imported package to action ID hash
SizeLevel int // LLVM optimization for size level (0-2)
}
// Build performs a single package to executable Go build. It takes in a package
@@ -127,6 +128,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
var packageJobs []*compileJob
packageBitcodePaths := make(map[string]string)
packageActionIDs := make(map[string]string)
_, sizeLevel, _ := config.OptLevels()
for _, pkg := range lprogram.Sorted() {
pkg := pkg // necessary to avoid a race condition
@@ -141,6 +143,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
CFlags: pkg.CFlags,
FileHashes: make(map[string]string, len(pkg.FileHashes)),
Imports: make(map[string]string, len(pkg.Pkg.Imports())),
SizeLevel: sizeLevel,
}
for filePath, hash := range pkg.FileHashes {
actionID.FileHashes[filePath] = hex.EncodeToString(hash)
@@ -206,6 +209,16 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
return errors.New("verification error after interpreting " + pkgInit.Name())
}
if sizeLevel >= 2 {
// Set the "optsize" attribute to make slightly smaller
// binaries at the cost of some performance.
kind := llvm.AttributeKindID("optsize")
attr := mod.Context().CreateEnumAttribute(kind, 0)
for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
fn.AddFunctionAttr(attr)
}
}
// Serialize the LLVM module as a bitcode file.
// Write to a temporary path that is renamed to the destination
// file to avoid race conditions with other TinyGo invocatiosn
@@ -617,21 +630,8 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
// Optimization levels here are roughly the same as Clang, but probably not
// exactly.
var errs []error
switch config.Options.Opt {
case "none", "0":
errs = transform.Optimize(mod, config, 0, 0, 0) // -O0
case "1":
errs = transform.Optimize(mod, config, 1, 0, 0) // -O1
case "2":
errs = transform.Optimize(mod, config, 2, 0, 225) // -O2
case "s":
errs = transform.Optimize(mod, config, 2, 1, 225) // -Os
case "z":
errs = transform.Optimize(mod, config, 2, 2, 5) // -Oz, default
default:
return errors.New("unknown optimization level: -opt=" + config.Options.Opt)
}
optLevel, sizeLevel, inlinerThreshold := config.OptLevels()
errs := transform.Optimize(mod, config, optLevel, sizeLevel, inlinerThreshold)
if len(errs) > 0 {
return newMultiError(errs)
}