github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cc/lto.go (about) 1 // Copyright 2017 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cc 16 17 import ( 18 "android/soong/android" 19 ) 20 21 // LTO (link-time optimization) allows the compiler to optimize and generate 22 // code for the entire module at link time, rather than per-compilation 23 // unit. LTO is required for Clang CFI and other whole-program optimization 24 // techniques. LTO also allows cross-compilation unit optimizations that should 25 // result in faster and smaller code, at the expense of additional compilation 26 // time. 27 // 28 // To properly build a module with LTO, the module and all recursive static 29 // dependencies should be compiled with -flto which directs the compiler to emit 30 // bitcode rather than native object files. These bitcode files are then passed 31 // by the linker to the LLVM plugin for compilation at link time. Static 32 // dependencies not built as bitcode will still function correctly but cannot be 33 // optimized at link time and may not be compatible with features that require 34 // LTO, such as CFI. 35 // 36 // This file adds support to soong to automatically propogate LTO options to a 37 // new variant of all static dependencies for each module with LTO enabled. 38 39 type LTOProperties struct { 40 // Lto must violate capitialization style for acronyms so that it can be 41 // referred to in blueprint files as "lto" 42 Lto struct { 43 Never *bool `android:"arch_variant"` 44 Full *bool `android:"arch_variant"` 45 Thin *bool `android:"arch_variant"` 46 } `android:"arch_variant"` 47 48 // Dep properties indicate that this module needs to be built with LTO 49 // since it is an object dependency of an LTO module. 50 FullDep bool `blueprint:"mutated"` 51 ThinDep bool `blueprint:"mutated"` 52 } 53 54 type lto struct { 55 Properties LTOProperties 56 } 57 58 func (lto *lto) props() []interface{} { 59 return []interface{}{<o.Properties} 60 } 61 62 func (lto *lto) begin(ctx BaseModuleContext) { 63 if ctx.Config().IsEnvTrue("DISABLE_LTO") { 64 lto.Properties.Lto.Never = boolPtr(true) 65 } 66 } 67 68 func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps { 69 return deps 70 } 71 72 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { 73 if lto.LTO() { 74 var ltoFlag string 75 if Bool(lto.Properties.Lto.Thin) { 76 ltoFlag = "-flto=thin" 77 } else { 78 ltoFlag = "-flto" 79 } 80 81 flags.CFlags = append(flags.CFlags, ltoFlag) 82 flags.LdFlags = append(flags.LdFlags, ltoFlag) 83 if ctx.Device() { 84 // Work around bug in Clang that doesn't pass correct emulated 85 // TLS option to target. See b/72706604 or 86 // https://github.com/android-ndk/ndk/issues/498. 87 flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls") 88 } 89 flags.ArGoldPlugin = true 90 91 // If the module does not have a profile, be conservative and do not inline 92 // or unroll loops during LTO, in order to prevent significant size bloat. 93 if !ctx.isPgoCompile() { 94 flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0") 95 flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0") 96 } 97 } 98 return flags 99 } 100 101 // Can be called with a null receiver 102 func (lto *lto) LTO() bool { 103 if lto == nil || lto.Disabled() { 104 return false 105 } 106 107 full := Bool(lto.Properties.Lto.Full) 108 thin := Bool(lto.Properties.Lto.Thin) 109 return full || thin 110 } 111 112 // Is lto.never explicitly set to true? 113 func (lto *lto) Disabled() bool { 114 return lto.Properties.Lto.Never != nil && *lto.Properties.Lto.Never 115 } 116 117 // Propagate lto requirements down from binaries 118 func ltoDepsMutator(mctx android.TopDownMutatorContext) { 119 if m, ok := mctx.Module().(*Module); ok && m.lto.LTO() { 120 full := Bool(m.lto.Properties.Lto.Full) 121 thin := Bool(m.lto.Properties.Lto.Thin) 122 if full && thin { 123 mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive") 124 } 125 126 mctx.WalkDeps(func(dep android.Module, parent android.Module) bool { 127 tag := mctx.OtherModuleDependencyTag(dep) 128 switch tag { 129 case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag: 130 if dep, ok := dep.(*Module); ok && dep.lto != nil && 131 !dep.lto.Disabled() { 132 if full && !Bool(dep.lto.Properties.Lto.Full) { 133 dep.lto.Properties.FullDep = true 134 } 135 if thin && !Bool(dep.lto.Properties.Lto.Thin) { 136 dep.lto.Properties.ThinDep = true 137 } 138 } 139 140 // Recursively walk static dependencies 141 return true 142 } 143 144 // Do not recurse down non-static dependencies 145 return false 146 }) 147 } 148 } 149 150 // Create lto variants for modules that need them 151 func ltoMutator(mctx android.BottomUpMutatorContext) { 152 if m, ok := mctx.Module().(*Module); ok && m.lto != nil { 153 // Create variations for LTO types required as static 154 // dependencies 155 variationNames := []string{""} 156 if m.lto.Properties.FullDep && !Bool(m.lto.Properties.Lto.Full) { 157 variationNames = append(variationNames, "lto-full") 158 } 159 if m.lto.Properties.ThinDep && !Bool(m.lto.Properties.Lto.Thin) { 160 variationNames = append(variationNames, "lto-thin") 161 } 162 163 // Use correct dependencies if LTO property is explicitly set 164 // (mutually exclusive) 165 if Bool(m.lto.Properties.Lto.Full) { 166 mctx.SetDependencyVariation("lto-full") 167 } 168 if Bool(m.lto.Properties.Lto.Thin) { 169 mctx.SetDependencyVariation("lto-thin") 170 } 171 172 if len(variationNames) > 1 { 173 modules := mctx.CreateVariations(variationNames...) 174 for i, name := range variationNames { 175 variation := modules[i].(*Module) 176 // Default module which will be 177 // installed. Variation set above according to 178 // explicit LTO properties 179 if name == "" { 180 continue 181 } 182 183 // LTO properties for dependencies 184 if name == "lto-full" { 185 variation.lto.Properties.Lto.Full = boolPtr(true) 186 variation.lto.Properties.Lto.Thin = boolPtr(false) 187 } 188 if name == "lto-thin" { 189 variation.lto.Properties.Lto.Full = boolPtr(false) 190 variation.lto.Properties.Lto.Thin = boolPtr(true) 191 } 192 variation.Properties.PreventInstall = true 193 variation.Properties.HideFromMake = true 194 variation.lto.Properties.FullDep = false 195 variation.lto.Properties.ThinDep = false 196 } 197 } 198 } 199 }