blob: e2d99ebd12abd53a90a022af58df730b5d796abe [file] [log] [blame]
Stephen Craneba090d12017-05-09 15:44:35 -07001// 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
15package cc
16
17import (
Colin Cross6ac83a82024-01-23 11:23:10 -080018 "fmt"
Liz Kammer729aaf42022-09-16 12:39:42 -040019
Colin Cross6ac83a82024-01-23 11:23:10 -080020 "github.com/google/blueprint"
Liz Kammer729aaf42022-09-16 12:39:42 -040021 "github.com/google/blueprint/proptools"
Colin Cross6ac83a82024-01-23 11:23:10 -080022
23 "android/soong/android"
Stephen Craneba090d12017-05-09 15:44:35 -070024)
25
26// LTO (link-time optimization) allows the compiler to optimize and generate
27// code for the entire module at link time, rather than per-compilation
28// unit. LTO is required for Clang CFI and other whole-program optimization
29// techniques. LTO also allows cross-compilation unit optimizations that should
30// result in faster and smaller code, at the expense of additional compilation
31// time.
32//
33// To properly build a module with LTO, the module and all recursive static
34// dependencies should be compiled with -flto which directs the compiler to emit
35// bitcode rather than native object files. These bitcode files are then passed
36// by the linker to the LLVM plugin for compilation at link time. Static
37// dependencies not built as bitcode will still function correctly but cannot be
38// optimized at link time and may not be compatible with features that require
39// LTO, such as CFI.
40//
Yi Kong577a73a2023-10-05 05:03:42 +000041// This file adds support to soong to automatically propagate LTO options to a
Stephen Craneba090d12017-05-09 15:44:35 -070042// new variant of all static dependencies for each module with LTO enabled.
43
44type LTOProperties struct {
Yi Kong577a73a2023-10-05 05:03:42 +000045 // Lto must violate capitalization style for acronyms so that it can be
Stephen Craneba090d12017-05-09 15:44:35 -070046 // referred to in blueprint files as "lto"
Yi Kong244bf072017-08-29 11:10:09 +080047 Lto struct {
Stephen Crane10cd1872017-09-27 17:01:15 -070048 Never *bool `android:"arch_variant"`
Stephen Crane10cd1872017-09-27 17:01:15 -070049 Thin *bool `android:"arch_variant"`
Yi Kong244bf072017-08-29 11:10:09 +080050 } `android:"arch_variant"`
Stephen Crane10cd1872017-09-27 17:01:15 -070051
Yi Kong895d2412023-06-08 01:48:42 +090052 LtoEnabled bool `blueprint:"mutated"`
Yi Kongadd63752023-06-26 17:39:46 +090053 LtoDefault bool `blueprint:"mutated"`
Yi Kong895d2412023-06-08 01:48:42 +090054
Yi Kong2d01fe22020-09-21 01:18:32 +080055 // Use -fwhole-program-vtables cflag.
56 Whole_program_vtables *bool
Yi Kong75499902024-03-22 11:30:46 +000057
58 // Use --lto-O0 flag.
59 Lto_O0 *bool
Stephen Craneba090d12017-05-09 15:44:35 -070060}
61
62type lto struct {
63 Properties LTOProperties
64}
65
66func (lto *lto) props() []interface{} {
67 return []interface{}{&lto.Properties}
68}
69
70func (lto *lto) begin(ctx BaseModuleContext) {
Yi Kong577a73a2023-10-05 05:03:42 +000071 // First, determine the module independent default LTO mode.
Yi Kong950c1742023-10-09 19:49:45 +090072 ltoDefault := true
Yi Kongadd63752023-06-26 17:39:46 +090073 if ctx.Config().IsEnvTrue("DISABLE_LTO") {
74 ltoDefault = false
Yi Kong577a73a2023-10-05 05:03:42 +000075 } else if lto.Never() {
76 ltoDefault = false
Yi Kongadd63752023-06-26 17:39:46 +090077 } else if ctx.Host() {
78 // Performance and binary size are less important for host binaries.
79 ltoDefault = false
Yi Kong13beeed2023-07-15 03:09:00 +090080 } else if ctx.Arch().ArchType.Multilib == "lib32" {
81 // LP32 has many subtle issues and less test coverage.
82 ltoDefault = false
Yi Kongadd63752023-06-26 17:39:46 +090083 }
84
85 // Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs
86 // to be created.
87 ltoEnabled := ltoDefault
88 if lto.Never() {
89 ltoEnabled = false
90 } else if lto.ThinLTO() {
91 // Module explicitly requests for LTO.
92 ltoEnabled = true
93 } else if ctx.testBinary() || ctx.testLibrary() {
94 // Do not enable LTO for tests for better debugging.
95 ltoEnabled = false
96 } else if ctx.isVndk() {
97 // FIXME: ThinLTO for VNDK produces different output.
98 // b/169217596
99 ltoEnabled = false
100 }
101
102 lto.Properties.LtoDefault = ltoDefault
103 lto.Properties.LtoEnabled = ltoEnabled
Stephen Craneba090d12017-05-09 15:44:35 -0700104}
105
Colin Cross3513fb12024-01-24 14:44:47 -0800106func (lto *lto) flags(ctx ModuleContext, flags Flags) Flags {
Yi Kong895d2412023-06-08 01:48:42 +0900107 // TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
108 // This has be checked late because these properties can be mutated.
109 if ctx.isCfi() || ctx.isFuzzer() {
Mitch Phillips5007c4a2022-03-02 01:25:22 +0000110 return flags
111 }
Yi Kong895d2412023-06-08 01:48:42 +0900112 if lto.Properties.LtoEnabled {
Yi Kongb9d50462023-07-03 16:59:33 +0900113 ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
114 var ltoLdFlags []string
115
Yi Kong75499902024-03-22 11:30:46 +0000116 // Do not perform costly LTO optimizations for Eng builds.
117 if Bool(lto.Properties.Lto_O0) || ctx.Config().Eng() {
Yi Kongb9d50462023-07-03 16:59:33 +0900118 ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
Yi Kong244bf072017-08-29 11:10:09 +0800119 }
120
Yi Kong2d01fe22020-09-21 01:18:32 +0800121 if Bool(lto.Properties.Whole_program_vtables) {
Yi Kongb9d50462023-07-03 16:59:33 +0900122 ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables")
Yi Kong2d01fe22020-09-21 01:18:32 +0800123 }
124
Yi Kong895d2412023-06-08 01:48:42 +0900125 if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
Yi Kong8aeaa712018-02-16 20:36:16 +0800126 // Set appropriate ThinLTO cache policy
Yi Kong630b9602019-03-22 21:28:39 -0700127 cacheDirFormat := "-Wl,--thinlto-cache-dir="
Yi Kong8aeaa712018-02-16 20:36:16 +0800128 cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
Yi Kongb9d50462023-07-03 16:59:33 +0900129 ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir)
Yi Kong8aeaa712018-02-16 20:36:16 +0800130
131 // Limit the size of the ThinLTO cache to the lesser of 10% of available
132 // disk space and 10GB.
Yi Kong630b9602019-03-22 21:28:39 -0700133 cachePolicyFormat := "-Wl,--thinlto-cache-policy="
Yi Kong8aeaa712018-02-16 20:36:16 +0800134 policy := "cache_size=10%:cache_size_bytes=10g"
Yi Kongb9d50462023-07-03 16:59:33 +0900135 ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
Yi Kong8aeaa712018-02-16 20:36:16 +0800136 }
137
Yi Kongd6ab48c2023-08-01 14:12:39 +0900138 // Reduce the inlining threshold for a better balance of binary size and
139 // performance.
140 if !ctx.Darwin() {
Colin Cross3513fb12024-01-24 14:44:47 -0800141 if ctx.isAfdoCompile(ctx) {
Yi Kongd6ab48c2023-08-01 14:12:39 +0900142 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40")
143 } else {
144 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
145 }
Yi Kong7e53c572018-02-14 18:16:12 +0800146 }
Yi Kongb9d50462023-07-03 16:59:33 +0900147
AdityaK76c73852023-11-14 10:24:59 -0800148 if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
149 // Register allocation MLGO flags for ARM64.
150 if ctx.Arch().ArchType == android.Arm64 {
AdityaK76c73852023-11-14 10:24:59 -0800151 ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
152 }
Yi Kong0fa503d2023-11-07 14:12:51 +0900153 // Flags for training MLGO model.
154 if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
155 ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
156 ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
157 }
Yi Kongb8eaee62023-10-31 21:58:42 +0900158 }
159
Yi Kongb9d50462023-07-03 16:59:33 +0900160 flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
161 flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
162 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
163 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...)
Stephen Craneba090d12017-05-09 15:44:35 -0700164 }
165 return flags
166}
167
Yi Kong93718e02020-09-21 21:41:03 +0800168func (lto *lto) ThinLTO() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900169 return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
Stephen Craneba090d12017-05-09 15:44:35 -0700170}
171
Yi Kongf43ff052020-09-28 14:41:50 +0800172func (lto *lto) Never() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900173 return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
Yi Kong8ea56f92021-10-14 01:07:42 +0800174}
175
Colin Cross6ac83a82024-01-23 11:23:10 -0800176func ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
177 libTag, isLibTag := tag.(libraryDependencyTag)
178 // Do not recurse down non-static dependencies
179 if isLibTag {
180 return libTag.static()
181 } else {
182 return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
Stephen Craneba090d12017-05-09 15:44:35 -0700183 }
184}
185
Colin Cross6ac83a82024-01-23 11:23:10 -0800186// ltoTransitionMutator creates LTO variants of cc modules. Variant "" is the default variant, which may
187// or may not have LTO enabled depending on the config and the module's type and properties. "lto-thin" or
188// "lto-none" variants are created when a module needs to compile in the non-default state for that module.
189type ltoTransitionMutator struct{}
190
191const LTO_NONE_VARIATION = "lto-none"
192const LTO_THIN_VARIATION = "lto-thin"
193
194func (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
195 return []string{""}
196}
197
198func (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
199 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
200 if !ltoPropagateViaDepTag(ctx.DepTag()) {
201 return ""
Yi Kong8ea56f92021-10-14 01:07:42 +0800202 }
Stephen Crane10cd1872017-09-27 17:01:15 -0700203
Colin Cross6ac83a82024-01-23 11:23:10 -0800204 if sourceVariation != "" {
205 return sourceVariation
Yi Kong8ea56f92021-10-14 01:07:42 +0800206 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800207
208 // Always request an explicit variation, IncomingTransition will rewrite it back to the default variation
209 // if necessary.
Yi Kong950c1742023-10-09 19:49:45 +0900210 if m.lto.Properties.LtoEnabled {
Colin Cross6ac83a82024-01-23 11:23:10 -0800211 return LTO_THIN_VARIATION
212 } else {
213 return LTO_NONE_VARIATION
Yi Kong895d2412023-06-08 01:48:42 +0900214 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800215 }
216 return ""
217}
Stephen Crane10cd1872017-09-27 17:01:15 -0700218
Colin Cross6ac83a82024-01-23 11:23:10 -0800219func (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
220 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
221 if m.lto.Never() {
222 return ""
Stephen Crane10cd1872017-09-27 17:01:15 -0700223 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800224 // Rewrite explicit variations back to the default variation if the default variation matches.
225 if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault {
226 return ""
227 } else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault {
228 return ""
229 }
230 return incomingVariation
231 }
232 return ""
233}
234
235func (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
236 // Default module which will be installed. Variation set above according to explicit LTO properties.
237 if variation == "" {
238 return
239 }
240
241 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
242 // Non-default variation, set the LTO properties to match the variation.
243 switch variation {
244 case LTO_THIN_VARIATION:
245 m.lto.Properties.LtoEnabled = true
246 case LTO_NONE_VARIATION:
247 m.lto.Properties.LtoEnabled = false
248 default:
249 panic(fmt.Errorf("unknown variation %s", variation))
250 }
251 // Non-default variations are never installed.
252 m.Properties.PreventInstall = true
253 m.Properties.HideFromMake = true
Stephen Craneba090d12017-05-09 15:44:35 -0700254 }
255}