lto.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. package cc
  15. import (
  16. "android/soong/android"
  17. "github.com/google/blueprint/proptools"
  18. )
  19. // LTO (link-time optimization) allows the compiler to optimize and generate
  20. // code for the entire module at link time, rather than per-compilation
  21. // unit. LTO is required for Clang CFI and other whole-program optimization
  22. // techniques. LTO also allows cross-compilation unit optimizations that should
  23. // result in faster and smaller code, at the expense of additional compilation
  24. // time.
  25. //
  26. // To properly build a module with LTO, the module and all recursive static
  27. // dependencies should be compiled with -flto which directs the compiler to emit
  28. // bitcode rather than native object files. These bitcode files are then passed
  29. // by the linker to the LLVM plugin for compilation at link time. Static
  30. // dependencies not built as bitcode will still function correctly but cannot be
  31. // optimized at link time and may not be compatible with features that require
  32. // LTO, such as CFI.
  33. //
  34. // This file adds support to soong to automatically propogate LTO options to a
  35. // new variant of all static dependencies for each module with LTO enabled.
  36. type LTOProperties struct {
  37. // Lto must violate capitialization style for acronyms so that it can be
  38. // referred to in blueprint files as "lto"
  39. Lto struct {
  40. Never *bool `android:"arch_variant"`
  41. Thin *bool `android:"arch_variant"`
  42. } `android:"arch_variant"`
  43. LtoEnabled bool `blueprint:"mutated"`
  44. // Dep properties indicate that this module needs to be built with LTO
  45. // since it is an object dependency of an LTO module.
  46. LtoDep bool `blueprint:"mutated"`
  47. NoLtoDep bool `blueprint:"mutated"`
  48. // Use -fwhole-program-vtables cflag.
  49. Whole_program_vtables *bool
  50. }
  51. type lto struct {
  52. Properties LTOProperties
  53. }
  54. func (lto *lto) props() []interface{} {
  55. return []interface{}{&lto.Properties}
  56. }
  57. func (lto *lto) begin(ctx BaseModuleContext) {
  58. lto.Properties.LtoEnabled = lto.LTO(ctx)
  59. }
  60. func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
  61. // TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
  62. // This has be checked late because these properties can be mutated.
  63. if ctx.isCfi() || ctx.isFuzzer() {
  64. return flags
  65. }
  66. if lto.Properties.LtoEnabled {
  67. var ltoCFlag string
  68. var ltoLdFlag string
  69. if lto.ThinLTO() {
  70. ltoCFlag = "-flto=thin -fsplit-lto-unit"
  71. } else {
  72. ltoCFlag = "-flto=thin -fsplit-lto-unit"
  73. ltoLdFlag = "-Wl,--lto-O0"
  74. }
  75. flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlag)
  76. flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlag)
  77. flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlag)
  78. flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlag)
  79. if Bool(lto.Properties.Whole_program_vtables) {
  80. flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
  81. }
  82. if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
  83. // Set appropriate ThinLTO cache policy
  84. cacheDirFormat := "-Wl,--thinlto-cache-dir="
  85. cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
  86. flags.Local.LdFlags = append(flags.Local.LdFlags, cacheDirFormat+cacheDir)
  87. // Limit the size of the ThinLTO cache to the lesser of 10% of available
  88. // disk space and 10GB.
  89. cachePolicyFormat := "-Wl,--thinlto-cache-policy="
  90. policy := "cache_size=10%:cache_size_bytes=10g"
  91. flags.Local.LdFlags = append(flags.Local.LdFlags, cachePolicyFormat+policy)
  92. }
  93. // If the module does not have a profile, be conservative and limit cross TU inline
  94. // limit to 5 LLVM IR instructions, to balance binary size increase and performance.
  95. if !ctx.Darwin() && !ctx.isPgoCompile() && !ctx.isAfdoCompile() {
  96. flags.Local.LdFlags = append(flags.Local.LdFlags,
  97. "-Wl,-plugin-opt,-import-instr-limit=5")
  98. }
  99. }
  100. return flags
  101. }
  102. // Determine which LTO mode to use for the given module.
  103. func (lto *lto) LTO(ctx BaseModuleContext) bool {
  104. if lto.Never() {
  105. return false
  106. }
  107. if ctx.Config().IsEnvTrue("DISABLE_LTO") {
  108. return false
  109. }
  110. // Module explicitly requests for LTO.
  111. if lto.ThinLTO() {
  112. return true
  113. }
  114. // LP32 has many subtle issues and less test coverage.
  115. if ctx.Arch().ArchType.Multilib == "lib32" {
  116. return false
  117. }
  118. // Performance and binary size are less important for host binaries and tests.
  119. if ctx.Host() || ctx.testBinary() || ctx.testLibrary() {
  120. return false
  121. }
  122. // FIXME: ThinLTO for VNDK produces different output.
  123. // b/169217596
  124. if ctx.isVndk() {
  125. return false
  126. }
  127. return GlobalThinLTO(ctx)
  128. }
  129. func (lto *lto) ThinLTO() bool {
  130. return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
  131. }
  132. func (lto *lto) Never() bool {
  133. return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
  134. }
  135. func GlobalThinLTO(ctx android.BaseModuleContext) bool {
  136. return ctx.Config().IsEnvTrue("GLOBAL_THINLTO")
  137. }
  138. // Propagate lto requirements down from binaries
  139. func ltoDepsMutator(mctx android.TopDownMutatorContext) {
  140. defaultLTOMode := GlobalThinLTO(mctx)
  141. if m, ok := mctx.Module().(*Module); ok {
  142. if m.lto == nil || m.lto.Properties.LtoEnabled == defaultLTOMode {
  143. return
  144. }
  145. mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
  146. tag := mctx.OtherModuleDependencyTag(dep)
  147. libTag, isLibTag := tag.(libraryDependencyTag)
  148. // Do not recurse down non-static dependencies
  149. if isLibTag {
  150. if !libTag.static() {
  151. return false
  152. }
  153. } else {
  154. if tag != objDepTag && tag != reuseObjTag {
  155. return false
  156. }
  157. }
  158. if dep, ok := dep.(*Module); ok {
  159. if m.lto.Properties.LtoEnabled {
  160. dep.lto.Properties.LtoDep = true
  161. } else {
  162. dep.lto.Properties.NoLtoDep = true
  163. }
  164. }
  165. // Recursively walk static dependencies
  166. return true
  167. })
  168. }
  169. }
  170. // Create lto variants for modules that need them
  171. func ltoMutator(mctx android.BottomUpMutatorContext) {
  172. globalThinLTO := GlobalThinLTO(mctx)
  173. if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
  174. // Create variations for LTO types required as static
  175. // dependencies
  176. variationNames := []string{""}
  177. if m.lto.Properties.LtoDep {
  178. variationNames = append(variationNames, "lto-thin")
  179. }
  180. if m.lto.Properties.NoLtoDep {
  181. variationNames = append(variationNames, "lto-none")
  182. }
  183. if globalThinLTO && !m.lto.Properties.LtoEnabled {
  184. mctx.SetDependencyVariation("lto-none")
  185. }
  186. if !globalThinLTO && m.lto.Properties.LtoEnabled {
  187. mctx.SetDependencyVariation("lto-thin")
  188. }
  189. if len(variationNames) > 1 {
  190. modules := mctx.CreateVariations(variationNames...)
  191. for i, name := range variationNames {
  192. variation := modules[i].(*Module)
  193. // Default module which will be
  194. // installed. Variation set above according to
  195. // explicit LTO properties
  196. if name == "" {
  197. continue
  198. }
  199. // LTO properties for dependencies
  200. if name == "lto-thin" {
  201. variation.lto.Properties.LtoEnabled = true
  202. }
  203. if name == "lto-none" {
  204. variation.lto.Properties.LtoEnabled = false
  205. }
  206. variation.Properties.PreventInstall = true
  207. variation.Properties.HideFromMake = true
  208. variation.lto.Properties.LtoDep = false
  209. variation.lto.Properties.NoLtoDep = false
  210. }
  211. }
  212. }
  213. }