244bf079f9
ThinLTO achieves comparable performance to full LTO while taking much less time for compilation. Test: Build hwui with "thin" and "full" LTO Change-Id: If3400b82af0d5e0226410c8b740999cdad746a59
135 lines
4.4 KiB
Go
135 lines
4.4 KiB
Go
// Copyright 2017 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package cc
|
|
|
|
import (
|
|
"github.com/google/blueprint"
|
|
|
|
"android/soong/android"
|
|
)
|
|
|
|
// LTO (link-time optimization) allows the compiler to optimize and generate
|
|
// code for the entire module at link time, rather than per-compilation
|
|
// unit. LTO is required for Clang CFI and other whole-program optimization
|
|
// techniques. LTO also allows cross-compilation unit optimizations that should
|
|
// result in faster and smaller code, at the expense of additional compilation
|
|
// time.
|
|
//
|
|
// To properly build a module with LTO, the module and all recursive static
|
|
// dependencies should be compiled with -flto which directs the compiler to emit
|
|
// bitcode rather than native object files. These bitcode files are then passed
|
|
// by the linker to the LLVM plugin for compilation at link time. Static
|
|
// dependencies not built as bitcode will still function correctly but cannot be
|
|
// optimized at link time and may not be compatible with features that require
|
|
// LTO, such as CFI.
|
|
//
|
|
// This file adds support to soong to automatically propogate LTO options to a
|
|
// new variant of all static dependencies for each module with LTO enabled.
|
|
|
|
type LTOProperties struct {
|
|
// Lto must violate capitialization style for acronyms so that it can be
|
|
// referred to in blueprint files as "lto"
|
|
Lto struct {
|
|
Full *bool `android:"arch_variant"`
|
|
Thin *bool `android:"arch_variant"`
|
|
} `android:"arch_variant"`
|
|
LTODep bool `blueprint:"mutated"`
|
|
}
|
|
|
|
type lto struct {
|
|
Properties LTOProperties
|
|
}
|
|
|
|
func (lto *lto) props() []interface{} {
|
|
return []interface{}{<o.Properties}
|
|
}
|
|
|
|
func (lto *lto) begin(ctx BaseModuleContext) {
|
|
}
|
|
|
|
func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps {
|
|
return deps
|
|
}
|
|
|
|
func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
|
|
if lto.LTO() {
|
|
var ltoFlag string
|
|
if Bool(lto.Properties.Lto.Thin) {
|
|
ltoFlag = "-flto=thin"
|
|
} else {
|
|
ltoFlag = "-flto"
|
|
}
|
|
|
|
flags.CFlags = append(flags.CFlags, ltoFlag)
|
|
flags.LdFlags = append(flags.LdFlags, ltoFlag)
|
|
if ctx.Device() {
|
|
// Work around bug in Clang that doesn't pass correct emulated
|
|
// TLS option to target
|
|
flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls")
|
|
}
|
|
flags.ArFlags = append(flags.ArFlags, " --plugin ${config.LLVMGoldPlugin}")
|
|
}
|
|
return flags
|
|
}
|
|
|
|
// Can be called with a null receiver
|
|
func (lto *lto) LTO() bool {
|
|
if lto == nil {
|
|
return false
|
|
}
|
|
|
|
full := Bool(lto.Properties.Lto.Full)
|
|
thin := Bool(lto.Properties.Lto.Thin)
|
|
return full || thin
|
|
}
|
|
|
|
// Propagate lto requirements down from binaries
|
|
func ltoDepsMutator(mctx android.TopDownMutatorContext) {
|
|
if c, ok := mctx.Module().(*Module); ok && c.lto.LTO() {
|
|
full := Bool(c.lto.Properties.Lto.Full)
|
|
thin := Bool(c.lto.Properties.Lto.Thin)
|
|
if full && thin {
|
|
mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
|
|
}
|
|
|
|
mctx.VisitDepsDepthFirst(func(m blueprint.Module) {
|
|
tag := mctx.OtherModuleDependencyTag(m)
|
|
switch tag {
|
|
case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
|
|
if cc, ok := m.(*Module); ok && cc.lto != nil {
|
|
cc.lto.Properties.LTODep = true
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Create lto variants for modules that need them
|
|
func ltoMutator(mctx android.BottomUpMutatorContext) {
|
|
if c, ok := mctx.Module().(*Module); ok && c.lto != nil {
|
|
if c.lto.LTO() {
|
|
mctx.SetDependencyVariation("lto")
|
|
} else if c.lto.Properties.LTODep {
|
|
modules := mctx.CreateVariations("", "lto")
|
|
modules[0].(*Module).lto.Properties.Lto.Full = boolPtr(false)
|
|
modules[0].(*Module).lto.Properties.Lto.Thin = boolPtr(false)
|
|
modules[0].(*Module).lto.Properties.LTODep = false
|
|
modules[1].(*Module).lto.Properties.LTODep = false
|
|
modules[1].(*Module).Properties.PreventInstall = true
|
|
modules[1].(*Module).Properties.HideFromMake = true
|
|
}
|
|
c.lto.Properties.LTODep = false
|
|
}
|
|
}
|