1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage cc 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "fmt" 19*333d2b36SAndroid Build Coastguard Worker 20*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 21*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 22*333d2b36SAndroid Build Coastguard Worker 23*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 24*333d2b36SAndroid Build Coastguard Worker) 25*333d2b36SAndroid Build Coastguard Worker 26*333d2b36SAndroid Build Coastguard Worker// LTO (link-time optimization) allows the compiler to optimize and generate 27*333d2b36SAndroid Build Coastguard Worker// code for the entire module at link time, rather than per-compilation 28*333d2b36SAndroid Build Coastguard Worker// unit. LTO is required for Clang CFI and other whole-program optimization 29*333d2b36SAndroid Build Coastguard Worker// techniques. LTO also allows cross-compilation unit optimizations that should 30*333d2b36SAndroid Build Coastguard Worker// result in faster and smaller code, at the expense of additional compilation 31*333d2b36SAndroid Build Coastguard Worker// time. 32*333d2b36SAndroid Build Coastguard Worker// 33*333d2b36SAndroid Build Coastguard Worker// To properly build a module with LTO, the module and all recursive static 34*333d2b36SAndroid Build Coastguard Worker// dependencies should be compiled with -flto which directs the compiler to emit 35*333d2b36SAndroid Build Coastguard Worker// bitcode rather than native object files. These bitcode files are then passed 36*333d2b36SAndroid Build Coastguard Worker// by the linker to the LLVM plugin for compilation at link time. Static 37*333d2b36SAndroid Build Coastguard Worker// dependencies not built as bitcode will still function correctly but cannot be 38*333d2b36SAndroid Build Coastguard Worker// optimized at link time and may not be compatible with features that require 39*333d2b36SAndroid Build Coastguard Worker// LTO, such as CFI. 40*333d2b36SAndroid Build Coastguard Worker// 41*333d2b36SAndroid Build Coastguard Worker// This file adds support to soong to automatically propagate LTO options to a 42*333d2b36SAndroid Build Coastguard Worker// new variant of all static dependencies for each module with LTO enabled. 43*333d2b36SAndroid Build Coastguard Worker 44*333d2b36SAndroid Build Coastguard Workertype LTOProperties struct { 45*333d2b36SAndroid Build Coastguard Worker // Lto must violate capitalization style for acronyms so that it can be 46*333d2b36SAndroid Build Coastguard Worker // referred to in blueprint files as "lto" 47*333d2b36SAndroid Build Coastguard Worker Lto struct { 48*333d2b36SAndroid Build Coastguard Worker Never *bool `android:"arch_variant"` 49*333d2b36SAndroid Build Coastguard Worker Thin *bool `android:"arch_variant"` 50*333d2b36SAndroid Build Coastguard Worker } `android:"arch_variant"` 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Worker LtoEnabled bool `blueprint:"mutated"` 53*333d2b36SAndroid Build Coastguard Worker LtoDefault bool `blueprint:"mutated"` 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Worker // Use -fwhole-program-vtables cflag. 56*333d2b36SAndroid Build Coastguard Worker Whole_program_vtables *bool 57*333d2b36SAndroid Build Coastguard Worker 58*333d2b36SAndroid Build Coastguard Worker // Use --lto-O0 flag. 59*333d2b36SAndroid Build Coastguard Worker Lto_O0 *bool 60*333d2b36SAndroid Build Coastguard Worker} 61*333d2b36SAndroid Build Coastguard Worker 62*333d2b36SAndroid Build Coastguard Workertype lto struct { 63*333d2b36SAndroid Build Coastguard Worker Properties LTOProperties 64*333d2b36SAndroid Build Coastguard Worker} 65*333d2b36SAndroid Build Coastguard Worker 66*333d2b36SAndroid Build Coastguard Workerfunc (lto *lto) props() []interface{} { 67*333d2b36SAndroid Build Coastguard Worker return []interface{}{<o.Properties} 68*333d2b36SAndroid Build Coastguard Worker} 69*333d2b36SAndroid Build Coastguard Worker 70*333d2b36SAndroid Build Coastguard Workerfunc (lto *lto) begin(ctx BaseModuleContext) { 71*333d2b36SAndroid Build Coastguard Worker // First, determine the module independent default LTO mode. 72*333d2b36SAndroid Build Coastguard Worker ltoDefault := true 73*333d2b36SAndroid Build Coastguard Worker if ctx.Config().IsEnvTrue("DISABLE_LTO") { 74*333d2b36SAndroid Build Coastguard Worker ltoDefault = false 75*333d2b36SAndroid Build Coastguard Worker } else if lto.Never() { 76*333d2b36SAndroid Build Coastguard Worker ltoDefault = false 77*333d2b36SAndroid Build Coastguard Worker } else if ctx.Host() { 78*333d2b36SAndroid Build Coastguard Worker // Performance and binary size are less important for host binaries. 79*333d2b36SAndroid Build Coastguard Worker ltoDefault = false 80*333d2b36SAndroid Build Coastguard Worker } else if ctx.Arch().ArchType.Multilib == "lib32" { 81*333d2b36SAndroid Build Coastguard Worker // LP32 has many subtle issues and less test coverage. 82*333d2b36SAndroid Build Coastguard Worker ltoDefault = false 83*333d2b36SAndroid Build Coastguard Worker } 84*333d2b36SAndroid Build Coastguard Worker 85*333d2b36SAndroid Build Coastguard Worker // Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs 86*333d2b36SAndroid Build Coastguard Worker // to be created. 87*333d2b36SAndroid Build Coastguard Worker ltoEnabled := ltoDefault 88*333d2b36SAndroid Build Coastguard Worker if lto.Never() { 89*333d2b36SAndroid Build Coastguard Worker ltoEnabled = false 90*333d2b36SAndroid Build Coastguard Worker } else if lto.ThinLTO() { 91*333d2b36SAndroid Build Coastguard Worker // Module explicitly requests for LTO. 92*333d2b36SAndroid Build Coastguard Worker ltoEnabled = true 93*333d2b36SAndroid Build Coastguard Worker } else if ctx.testBinary() || ctx.testLibrary() { 94*333d2b36SAndroid Build Coastguard Worker // Do not enable LTO for tests for better debugging. 95*333d2b36SAndroid Build Coastguard Worker ltoEnabled = false 96*333d2b36SAndroid Build Coastguard Worker } 97*333d2b36SAndroid Build Coastguard Worker 98*333d2b36SAndroid Build Coastguard Worker lto.Properties.LtoDefault = ltoDefault 99*333d2b36SAndroid Build Coastguard Worker lto.Properties.LtoEnabled = ltoEnabled 100*333d2b36SAndroid Build Coastguard Worker} 101*333d2b36SAndroid Build Coastguard Worker 102*333d2b36SAndroid Build Coastguard Workerfunc (lto *lto) flags(ctx ModuleContext, flags Flags) Flags { 103*333d2b36SAndroid Build Coastguard Worker // TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves. 104*333d2b36SAndroid Build Coastguard Worker // This has be checked late because these properties can be mutated. 105*333d2b36SAndroid Build Coastguard Worker if ctx.isCfi() || ctx.isFuzzer() { 106*333d2b36SAndroid Build Coastguard Worker return flags 107*333d2b36SAndroid Build Coastguard Worker } 108*333d2b36SAndroid Build Coastguard Worker if lto.Properties.LtoEnabled { 109*333d2b36SAndroid Build Coastguard Worker ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"} 110*333d2b36SAndroid Build Coastguard Worker var ltoLdFlags []string 111*333d2b36SAndroid Build Coastguard Worker 112*333d2b36SAndroid Build Coastguard Worker // Do not perform costly LTO optimizations for Eng builds. 113*333d2b36SAndroid Build Coastguard Worker if Bool(lto.Properties.Lto_O0) || ctx.Config().Eng() { 114*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0") 115*333d2b36SAndroid Build Coastguard Worker } 116*333d2b36SAndroid Build Coastguard Worker 117*333d2b36SAndroid Build Coastguard Worker if Bool(lto.Properties.Whole_program_vtables) { 118*333d2b36SAndroid Build Coastguard Worker ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables") 119*333d2b36SAndroid Build Coastguard Worker } 120*333d2b36SAndroid Build Coastguard Worker 121*333d2b36SAndroid Build Coastguard Worker if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") { 122*333d2b36SAndroid Build Coastguard Worker // Set appropriate ThinLTO cache policy 123*333d2b36SAndroid Build Coastguard Worker cacheDirFormat := "-Wl,--thinlto-cache-dir=" 124*333d2b36SAndroid Build Coastguard Worker cacheDir := android.PathForOutput(ctx, "thinlto-cache").String() 125*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir) 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Worker // Limit the size of the ThinLTO cache to the lesser of 10% of available 128*333d2b36SAndroid Build Coastguard Worker // disk space and 10GB. 129*333d2b36SAndroid Build Coastguard Worker cachePolicyFormat := "-Wl,--thinlto-cache-policy=" 130*333d2b36SAndroid Build Coastguard Worker policy := "cache_size=10%:cache_size_bytes=10g" 131*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy) 132*333d2b36SAndroid Build Coastguard Worker } 133*333d2b36SAndroid Build Coastguard Worker 134*333d2b36SAndroid Build Coastguard Worker // Reduce the inlining threshold for a better balance of binary size and 135*333d2b36SAndroid Build Coastguard Worker // performance. 136*333d2b36SAndroid Build Coastguard Worker if !ctx.Darwin() { 137*333d2b36SAndroid Build Coastguard Worker if ctx.isAfdoCompile(ctx) { 138*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40") 139*333d2b36SAndroid Build Coastguard Worker } else { 140*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5") 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker } 143*333d2b36SAndroid Build Coastguard Worker 144*333d2b36SAndroid Build Coastguard Worker if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") { 145*333d2b36SAndroid Build Coastguard Worker // Register allocation MLGO flags for ARM64. 146*333d2b36SAndroid Build Coastguard Worker if ctx.Arch().ArchType == android.Arm64 && !ctx.optimizeForSize() { 147*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release") 148*333d2b36SAndroid Build Coastguard Worker } 149*333d2b36SAndroid Build Coastguard Worker // Flags for training MLGO model. 150*333d2b36SAndroid Build Coastguard Worker if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") { 151*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import") 152*333d2b36SAndroid Build Coastguard Worker ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files") 153*333d2b36SAndroid Build Coastguard Worker } 154*333d2b36SAndroid Build Coastguard Worker } 155*333d2b36SAndroid Build Coastguard Worker 156*333d2b36SAndroid Build Coastguard Worker flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...) 157*333d2b36SAndroid Build Coastguard Worker flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...) 158*333d2b36SAndroid Build Coastguard Worker flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...) 159*333d2b36SAndroid Build Coastguard Worker flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...) 160*333d2b36SAndroid Build Coastguard Worker } 161*333d2b36SAndroid Build Coastguard Worker return flags 162*333d2b36SAndroid Build Coastguard Worker} 163*333d2b36SAndroid Build Coastguard Worker 164*333d2b36SAndroid Build Coastguard Workerfunc (lto *lto) ThinLTO() bool { 165*333d2b36SAndroid Build Coastguard Worker return lto != nil && proptools.Bool(lto.Properties.Lto.Thin) 166*333d2b36SAndroid Build Coastguard Worker} 167*333d2b36SAndroid Build Coastguard Worker 168*333d2b36SAndroid Build Coastguard Workerfunc (lto *lto) Never() bool { 169*333d2b36SAndroid Build Coastguard Worker return lto != nil && proptools.Bool(lto.Properties.Lto.Never) 170*333d2b36SAndroid Build Coastguard Worker} 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Workerfunc ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool { 173*333d2b36SAndroid Build Coastguard Worker libTag, isLibTag := tag.(libraryDependencyTag) 174*333d2b36SAndroid Build Coastguard Worker // Do not recurse down non-static dependencies 175*333d2b36SAndroid Build Coastguard Worker if isLibTag { 176*333d2b36SAndroid Build Coastguard Worker return libTag.static() 177*333d2b36SAndroid Build Coastguard Worker } else { 178*333d2b36SAndroid Build Coastguard Worker return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag 179*333d2b36SAndroid Build Coastguard Worker } 180*333d2b36SAndroid Build Coastguard Worker} 181*333d2b36SAndroid Build Coastguard Worker 182*333d2b36SAndroid Build Coastguard Worker// ltoTransitionMutator creates LTO variants of cc modules. Variant "" is the default variant, which may 183*333d2b36SAndroid Build Coastguard Worker// or may not have LTO enabled depending on the config and the module's type and properties. "lto-thin" or 184*333d2b36SAndroid Build Coastguard Worker// "lto-none" variants are created when a module needs to compile in the non-default state for that module. 185*333d2b36SAndroid Build Coastguard Workertype ltoTransitionMutator struct{} 186*333d2b36SAndroid Build Coastguard Worker 187*333d2b36SAndroid Build Coastguard Workerconst LTO_NONE_VARIATION = "lto-none" 188*333d2b36SAndroid Build Coastguard Workerconst LTO_THIN_VARIATION = "lto-thin" 189*333d2b36SAndroid Build Coastguard Worker 190*333d2b36SAndroid Build Coastguard Workerfunc (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string { 191*333d2b36SAndroid Build Coastguard Worker return []string{""} 192*333d2b36SAndroid Build Coastguard Worker} 193*333d2b36SAndroid Build Coastguard Worker 194*333d2b36SAndroid Build Coastguard Workerfunc (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { 195*333d2b36SAndroid Build Coastguard Worker if m, ok := ctx.Module().(*Module); ok && m.lto != nil { 196*333d2b36SAndroid Build Coastguard Worker if !ltoPropagateViaDepTag(ctx.DepTag()) { 197*333d2b36SAndroid Build Coastguard Worker return "" 198*333d2b36SAndroid Build Coastguard Worker } 199*333d2b36SAndroid Build Coastguard Worker 200*333d2b36SAndroid Build Coastguard Worker if sourceVariation != "" { 201*333d2b36SAndroid Build Coastguard Worker return sourceVariation 202*333d2b36SAndroid Build Coastguard Worker } 203*333d2b36SAndroid Build Coastguard Worker 204*333d2b36SAndroid Build Coastguard Worker // Always request an explicit variation, IncomingTransition will rewrite it back to the default variation 205*333d2b36SAndroid Build Coastguard Worker // if necessary. 206*333d2b36SAndroid Build Coastguard Worker if m.lto.Properties.LtoEnabled { 207*333d2b36SAndroid Build Coastguard Worker return LTO_THIN_VARIATION 208*333d2b36SAndroid Build Coastguard Worker } else { 209*333d2b36SAndroid Build Coastguard Worker return LTO_NONE_VARIATION 210*333d2b36SAndroid Build Coastguard Worker } 211*333d2b36SAndroid Build Coastguard Worker } 212*333d2b36SAndroid Build Coastguard Worker return "" 213*333d2b36SAndroid Build Coastguard Worker} 214*333d2b36SAndroid Build Coastguard Worker 215*333d2b36SAndroid Build Coastguard Workerfunc (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { 216*333d2b36SAndroid Build Coastguard Worker if m, ok := ctx.Module().(*Module); ok && m.lto != nil { 217*333d2b36SAndroid Build Coastguard Worker if m.lto.Never() { 218*333d2b36SAndroid Build Coastguard Worker return "" 219*333d2b36SAndroid Build Coastguard Worker } 220*333d2b36SAndroid Build Coastguard Worker // Rewrite explicit variations back to the default variation if the default variation matches. 221*333d2b36SAndroid Build Coastguard Worker if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault { 222*333d2b36SAndroid Build Coastguard Worker return "" 223*333d2b36SAndroid Build Coastguard Worker } else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault { 224*333d2b36SAndroid Build Coastguard Worker return "" 225*333d2b36SAndroid Build Coastguard Worker } 226*333d2b36SAndroid Build Coastguard Worker return incomingVariation 227*333d2b36SAndroid Build Coastguard Worker } 228*333d2b36SAndroid Build Coastguard Worker return "" 229*333d2b36SAndroid Build Coastguard Worker} 230*333d2b36SAndroid Build Coastguard Worker 231*333d2b36SAndroid Build Coastguard Workerfunc (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { 232*333d2b36SAndroid Build Coastguard Worker // Default module which will be installed. Variation set above according to explicit LTO properties. 233*333d2b36SAndroid Build Coastguard Worker if variation == "" { 234*333d2b36SAndroid Build Coastguard Worker return 235*333d2b36SAndroid Build Coastguard Worker } 236*333d2b36SAndroid Build Coastguard Worker 237*333d2b36SAndroid Build Coastguard Worker if m, ok := ctx.Module().(*Module); ok && m.lto != nil { 238*333d2b36SAndroid Build Coastguard Worker // Non-default variation, set the LTO properties to match the variation. 239*333d2b36SAndroid Build Coastguard Worker switch variation { 240*333d2b36SAndroid Build Coastguard Worker case LTO_THIN_VARIATION: 241*333d2b36SAndroid Build Coastguard Worker m.lto.Properties.LtoEnabled = true 242*333d2b36SAndroid Build Coastguard Worker case LTO_NONE_VARIATION: 243*333d2b36SAndroid Build Coastguard Worker m.lto.Properties.LtoEnabled = false 244*333d2b36SAndroid Build Coastguard Worker default: 245*333d2b36SAndroid Build Coastguard Worker panic(fmt.Errorf("unknown variation %s", variation)) 246*333d2b36SAndroid Build Coastguard Worker } 247*333d2b36SAndroid Build Coastguard Worker // Non-default variations are never installed. 248*333d2b36SAndroid Build Coastguard Worker m.Properties.PreventInstall = true 249*333d2b36SAndroid Build Coastguard Worker m.Properties.HideFromMake = true 250*333d2b36SAndroid Build Coastguard Worker } 251*333d2b36SAndroid Build Coastguard Worker} 252