2017-05-10 06:44:35 +08:00
|
|
|
// 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 (
|
|
|
|
"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"
|
2017-08-29 11:10:09 +08:00
|
|
|
Lto struct {
|
2017-09-28 08:01:15 +08:00
|
|
|
Never *bool `android:"arch_variant"`
|
|
|
|
Full *bool `android:"arch_variant"`
|
|
|
|
Thin *bool `android:"arch_variant"`
|
2017-08-29 11:10:09 +08:00
|
|
|
} `android:"arch_variant"`
|
2017-09-28 08:01:15 +08:00
|
|
|
|
|
|
|
// Dep properties indicate that this module needs to be built with LTO
|
|
|
|
// since it is an object dependency of an LTO module.
|
|
|
|
FullDep bool `blueprint:"mutated"`
|
|
|
|
ThinDep bool `blueprint:"mutated"`
|
2018-04-04 02:33:34 +08:00
|
|
|
|
|
|
|
// Use clang lld instead of gnu ld.
|
|
|
|
Use_clang_lld *bool
|
2020-09-21 01:18:32 +08:00
|
|
|
|
|
|
|
// Use -fwhole-program-vtables cflag.
|
|
|
|
Whole_program_vtables *bool
|
2017-05-10 06:44:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type lto struct {
|
|
|
|
Properties LTOProperties
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lto *lto) props() []interface{} {
|
|
|
|
return []interface{}{<o.Properties}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lto *lto) begin(ctx BaseModuleContext) {
|
2018-02-01 07:15:08 +08:00
|
|
|
if ctx.Config().IsEnvTrue("DISABLE_LTO") {
|
|
|
|
lto.Properties.Lto.Never = boolPtr(true)
|
2020-09-21 21:41:03 +08:00
|
|
|
} else if ctx.Config().IsEnvTrue("GLOBAL_THINLTO") {
|
2020-09-29 08:44:45 +08:00
|
|
|
staticLib := ctx.static() && !ctx.staticBinary()
|
|
|
|
hostBin := ctx.Host()
|
|
|
|
if !staticLib && !hostBin {
|
|
|
|
if !lto.Never() && !lto.FullLTO() {
|
|
|
|
lto.Properties.Lto.Thin = boolPtr(true)
|
|
|
|
}
|
|
|
|
}
|
2018-02-01 07:15:08 +08:00
|
|
|
}
|
2017-05-10 06:44:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps {
|
|
|
|
return deps
|
|
|
|
}
|
|
|
|
|
2018-04-04 02:33:34 +08:00
|
|
|
func (lto *lto) useClangLld(ctx BaseModuleContext) bool {
|
|
|
|
if lto.Properties.Use_clang_lld != nil {
|
|
|
|
return Bool(lto.Properties.Use_clang_lld)
|
|
|
|
}
|
2018-10-22 10:47:01 +08:00
|
|
|
return true
|
2018-04-04 02:33:34 +08:00
|
|
|
}
|
|
|
|
|
2017-05-10 06:44:35 +08:00
|
|
|
func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
|
2019-08-03 07:57:55 +08:00
|
|
|
// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
|
|
|
|
// LTO breaks fuzzer builds.
|
2019-11-05 01:37:55 +08:00
|
|
|
if inList("-fsanitize=fuzzer-no-link", flags.Local.CFlags) {
|
2019-08-03 07:57:55 +08:00
|
|
|
return flags
|
|
|
|
}
|
|
|
|
|
2017-08-29 11:10:09 +08:00
|
|
|
if lto.LTO() {
|
|
|
|
var ltoFlag string
|
2020-09-21 21:41:03 +08:00
|
|
|
if lto.ThinLTO() {
|
2019-03-06 06:11:41 +08:00
|
|
|
ltoFlag = "-flto=thin -fsplit-lto-unit"
|
2017-08-29 11:10:09 +08:00
|
|
|
} else {
|
|
|
|
ltoFlag = "-flto"
|
|
|
|
}
|
|
|
|
|
2019-11-05 01:37:55 +08:00
|
|
|
flags.Local.CFlags = append(flags.Local.CFlags, ltoFlag)
|
|
|
|
flags.Local.LdFlags = append(flags.Local.LdFlags, ltoFlag)
|
2018-02-16 20:36:16 +08:00
|
|
|
|
2020-09-21 01:18:32 +08:00
|
|
|
if Bool(lto.Properties.Whole_program_vtables) {
|
|
|
|
flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
|
|
|
|
}
|
|
|
|
|
2020-09-21 21:41:03 +08:00
|
|
|
if lto.ThinLTO() && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && lto.useClangLld(ctx) {
|
2018-02-16 20:36:16 +08:00
|
|
|
// Set appropriate ThinLTO cache policy
|
2019-03-23 12:28:39 +08:00
|
|
|
cacheDirFormat := "-Wl,--thinlto-cache-dir="
|
2018-02-16 20:36:16 +08:00
|
|
|
cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
|
2019-11-05 01:37:55 +08:00
|
|
|
flags.Local.LdFlags = append(flags.Local.LdFlags, cacheDirFormat+cacheDir)
|
2018-02-16 20:36:16 +08:00
|
|
|
|
|
|
|
// Limit the size of the ThinLTO cache to the lesser of 10% of available
|
|
|
|
// disk space and 10GB.
|
2019-03-23 12:28:39 +08:00
|
|
|
cachePolicyFormat := "-Wl,--thinlto-cache-policy="
|
2018-02-16 20:36:16 +08:00
|
|
|
policy := "cache_size=10%:cache_size_bytes=10g"
|
2019-11-05 01:37:55 +08:00
|
|
|
flags.Local.LdFlags = append(flags.Local.LdFlags, cachePolicyFormat+policy)
|
2018-02-16 20:36:16 +08:00
|
|
|
}
|
|
|
|
|
2020-09-23 00:54:50 +08:00
|
|
|
// If the module does not have a profile, be conservative and limit cross TU inline
|
|
|
|
// limit to 5 LLVM IR instructions, to balance binary size increase and performance.
|
2019-03-23 12:28:39 +08:00
|
|
|
if !ctx.isPgoCompile() {
|
2019-11-05 01:37:55 +08:00
|
|
|
flags.Local.LdFlags = append(flags.Local.LdFlags,
|
2020-09-23 00:54:50 +08:00
|
|
|
"-Wl,-plugin-opt,-import-instr-limit=5")
|
2018-02-14 18:16:12 +08:00
|
|
|
}
|
2017-05-10 06:44:35 +08:00
|
|
|
}
|
|
|
|
return flags
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can be called with a null receiver
|
|
|
|
func (lto *lto) LTO() bool {
|
2020-09-28 14:41:50 +08:00
|
|
|
if lto == nil || lto.Never() {
|
2017-05-10 06:44:35 +08:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-09-21 21:41:03 +08:00
|
|
|
return lto.FullLTO() || lto.ThinLTO()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lto *lto) FullLTO() bool {
|
|
|
|
return Bool(lto.Properties.Lto.Full)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lto *lto) ThinLTO() bool {
|
|
|
|
return Bool(lto.Properties.Lto.Thin)
|
2017-05-10 06:44:35 +08:00
|
|
|
}
|
|
|
|
|
2017-09-28 08:01:15 +08:00
|
|
|
// Is lto.never explicitly set to true?
|
2020-09-28 14:41:50 +08:00
|
|
|
func (lto *lto) Never() bool {
|
|
|
|
return Bool(lto.Properties.Lto.Never)
|
2017-09-28 08:01:15 +08:00
|
|
|
}
|
|
|
|
|
2017-05-10 06:44:35 +08:00
|
|
|
// Propagate lto requirements down from binaries
|
|
|
|
func ltoDepsMutator(mctx android.TopDownMutatorContext) {
|
2017-09-28 08:01:15 +08:00
|
|
|
if m, ok := mctx.Module().(*Module); ok && m.lto.LTO() {
|
2020-09-21 21:41:03 +08:00
|
|
|
full := m.lto.FullLTO()
|
|
|
|
thin := m.lto.ThinLTO()
|
2017-08-29 11:10:09 +08:00
|
|
|
if full && thin {
|
|
|
|
mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
|
|
|
|
}
|
|
|
|
|
2017-09-28 08:01:15 +08:00
|
|
|
mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
|
|
|
|
tag := mctx.OtherModuleDependencyTag(dep)
|
2020-07-28 12:26:48 +08:00
|
|
|
libTag, isLibTag := tag.(libraryDependencyTag)
|
|
|
|
|
|
|
|
// Do not recurse down non-static dependencies
|
|
|
|
if isLibTag {
|
2020-07-30 03:55:55 +08:00
|
|
|
if !libTag.static() {
|
2020-07-28 12:26:48 +08:00
|
|
|
return false
|
2017-05-10 06:44:35 +08:00
|
|
|
}
|
2020-07-28 12:26:48 +08:00
|
|
|
} else {
|
|
|
|
if tag != objDepTag && tag != reuseObjTag {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2017-09-28 08:01:15 +08:00
|
|
|
|
2020-07-28 12:26:48 +08:00
|
|
|
if dep, ok := dep.(*Module); ok && dep.lto != nil &&
|
2020-09-28 14:41:50 +08:00
|
|
|
!dep.lto.Never() {
|
2020-09-21 21:41:03 +08:00
|
|
|
if full && !dep.lto.FullLTO() {
|
2020-07-28 12:26:48 +08:00
|
|
|
dep.lto.Properties.FullDep = true
|
|
|
|
}
|
2020-09-21 21:41:03 +08:00
|
|
|
if thin && !dep.lto.ThinLTO() {
|
2020-07-28 12:26:48 +08:00
|
|
|
dep.lto.Properties.ThinDep = true
|
|
|
|
}
|
2017-05-10 06:44:35 +08:00
|
|
|
}
|
2017-09-28 08:01:15 +08:00
|
|
|
|
2020-07-28 12:26:48 +08:00
|
|
|
// Recursively walk static dependencies
|
|
|
|
return true
|
2017-05-10 06:44:35 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create lto variants for modules that need them
|
|
|
|
func ltoMutator(mctx android.BottomUpMutatorContext) {
|
2017-09-28 08:01:15 +08:00
|
|
|
if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
|
|
|
|
// Create variations for LTO types required as static
|
|
|
|
// dependencies
|
|
|
|
variationNames := []string{""}
|
2020-09-21 21:41:03 +08:00
|
|
|
if m.lto.Properties.FullDep && !m.lto.FullLTO() {
|
2017-09-28 08:01:15 +08:00
|
|
|
variationNames = append(variationNames, "lto-full")
|
|
|
|
}
|
2020-09-21 21:41:03 +08:00
|
|
|
if m.lto.Properties.ThinDep && !m.lto.ThinLTO() {
|
2017-09-28 08:01:15 +08:00
|
|
|
variationNames = append(variationNames, "lto-thin")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use correct dependencies if LTO property is explicitly set
|
|
|
|
// (mutually exclusive)
|
2020-09-21 21:41:03 +08:00
|
|
|
if m.lto.FullLTO() {
|
2017-09-28 08:01:15 +08:00
|
|
|
mctx.SetDependencyVariation("lto-full")
|
|
|
|
}
|
2020-09-21 21:41:03 +08:00
|
|
|
if m.lto.ThinLTO() {
|
2017-09-28 08:01:15 +08:00
|
|
|
mctx.SetDependencyVariation("lto-thin")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(variationNames) > 1 {
|
|
|
|
modules := mctx.CreateVariations(variationNames...)
|
|
|
|
for i, name := range variationNames {
|
|
|
|
variation := modules[i].(*Module)
|
|
|
|
// Default module which will be
|
|
|
|
// installed. Variation set above according to
|
|
|
|
// explicit LTO properties
|
|
|
|
if name == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// LTO properties for dependencies
|
|
|
|
if name == "lto-full" {
|
|
|
|
variation.lto.Properties.Lto.Full = boolPtr(true)
|
|
|
|
variation.lto.Properties.Lto.Thin = boolPtr(false)
|
|
|
|
}
|
|
|
|
if name == "lto-thin" {
|
|
|
|
variation.lto.Properties.Lto.Full = boolPtr(false)
|
|
|
|
variation.lto.Properties.Lto.Thin = boolPtr(true)
|
|
|
|
}
|
|
|
|
variation.Properties.PreventInstall = true
|
|
|
|
variation.Properties.HideFromMake = true
|
|
|
|
variation.lto.Properties.FullDep = false
|
|
|
|
variation.lto.Properties.ThinDep = false
|
|
|
|
}
|
2017-05-10 06:44:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|