blob: b2b45706d143a58e96e4d68d29f3d6ff1ef993d8 [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
Stephen Craneba090d12017-05-09 15:44:35 -070057}
58
59type lto struct {
60 Properties LTOProperties
61}
62
63func (lto *lto) props() []interface{} {
64 return []interface{}{&lto.Properties}
65}
66
67func (lto *lto) begin(ctx BaseModuleContext) {
Yi Kong577a73a2023-10-05 05:03:42 +000068 // First, determine the module independent default LTO mode.
Yi Kong950c1742023-10-09 19:49:45 +090069 ltoDefault := true
Yi Kongadd63752023-06-26 17:39:46 +090070 if ctx.Config().IsEnvTrue("DISABLE_LTO") {
71 ltoDefault = false
Yi Kong577a73a2023-10-05 05:03:42 +000072 } else if lto.Never() {
73 ltoDefault = false
Yi Kongadd63752023-06-26 17:39:46 +090074 } else if ctx.Host() {
75 // Performance and binary size are less important for host binaries.
76 ltoDefault = false
Yi Kong13beeed2023-07-15 03:09:00 +090077 } else if ctx.Arch().ArchType.Multilib == "lib32" {
78 // LP32 has many subtle issues and less test coverage.
79 ltoDefault = false
Yi Kongadd63752023-06-26 17:39:46 +090080 }
81
82 // Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs
83 // to be created.
84 ltoEnabled := ltoDefault
85 if lto.Never() {
86 ltoEnabled = false
87 } else if lto.ThinLTO() {
88 // Module explicitly requests for LTO.
89 ltoEnabled = true
90 } else if ctx.testBinary() || ctx.testLibrary() {
91 // Do not enable LTO for tests for better debugging.
92 ltoEnabled = false
93 } else if ctx.isVndk() {
94 // FIXME: ThinLTO for VNDK produces different output.
95 // b/169217596
96 ltoEnabled = false
97 }
98
99 lto.Properties.LtoDefault = ltoDefault
100 lto.Properties.LtoEnabled = ltoEnabled
Stephen Craneba090d12017-05-09 15:44:35 -0700101}
102
Stephen Craneba090d12017-05-09 15:44:35 -0700103func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
Yi Kong895d2412023-06-08 01:48:42 +0900104 // TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
105 // This has be checked late because these properties can be mutated.
106 if ctx.isCfi() || ctx.isFuzzer() {
Mitch Phillips5007c4a2022-03-02 01:25:22 +0000107 return flags
108 }
Yi Kong895d2412023-06-08 01:48:42 +0900109 if lto.Properties.LtoEnabled {
Yi Kongb9d50462023-07-03 16:59:33 +0900110 ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
111 var ltoLdFlags []string
112
113 // The module did not explicitly turn on LTO. Only leverage LTO's
Yi Kong8f9ca232023-07-14 06:15:51 +0000114 // better dead code elimination and CFG simplification, but do
Yi Kongb9d50462023-07-03 16:59:33 +0900115 // not perform costly optimizations for a balance between compile
116 // time, binary size and performance.
Yi Kong9723e332023-12-04 14:52:53 +0900117 // Apply the same for Eng builds as well.
118 if !lto.ThinLTO() || ctx.Config().Eng() {
Yi Kongb9d50462023-07-03 16:59:33 +0900119 ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
Yi Kong244bf072017-08-29 11:10:09 +0800120 }
121
Yi Kong2d01fe22020-09-21 01:18:32 +0800122 if Bool(lto.Properties.Whole_program_vtables) {
Yi Kongb9d50462023-07-03 16:59:33 +0900123 ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables")
Yi Kong2d01fe22020-09-21 01:18:32 +0800124 }
125
Yi Kong895d2412023-06-08 01:48:42 +0900126 if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
Yi Kong8aeaa712018-02-16 20:36:16 +0800127 // Set appropriate ThinLTO cache policy
Yi Kong630b9602019-03-22 21:28:39 -0700128 cacheDirFormat := "-Wl,--thinlto-cache-dir="
Yi Kong8aeaa712018-02-16 20:36:16 +0800129 cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
Yi Kongb9d50462023-07-03 16:59:33 +0900130 ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir)
Yi Kong8aeaa712018-02-16 20:36:16 +0800131
132 // Limit the size of the ThinLTO cache to the lesser of 10% of available
133 // disk space and 10GB.
Yi Kong630b9602019-03-22 21:28:39 -0700134 cachePolicyFormat := "-Wl,--thinlto-cache-policy="
Yi Kong8aeaa712018-02-16 20:36:16 +0800135 policy := "cache_size=10%:cache_size_bytes=10g"
Yi Kongb9d50462023-07-03 16:59:33 +0900136 ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
Yi Kong8aeaa712018-02-16 20:36:16 +0800137 }
138
Yi Kongd6ab48c2023-08-01 14:12:39 +0900139 // Reduce the inlining threshold for a better balance of binary size and
140 // performance.
141 if !ctx.Darwin() {
Yi Kong9c3f4332023-11-24 17:14:27 +0900142 if ctx.isAfdoCompile() {
Yi Kongd6ab48c2023-08-01 14:12:39 +0900143 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40")
144 } else {
145 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
146 }
Yi Kong7e53c572018-02-14 18:16:12 +0800147 }
Yi Kongb9d50462023-07-03 16:59:33 +0900148
AdityaK76c73852023-11-14 10:24:59 -0800149 if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
150 // Register allocation MLGO flags for ARM64.
151 if ctx.Arch().ArchType == android.Arm64 {
AdityaK76c73852023-11-14 10:24:59 -0800152 ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
153 }
Yi Kong0fa503d2023-11-07 14:12:51 +0900154 // Flags for training MLGO model.
155 if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
156 ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
157 ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
158 }
Yi Kongb8eaee62023-10-31 21:58:42 +0900159 }
160
Yi Kongb9d50462023-07-03 16:59:33 +0900161 flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
162 flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
163 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
164 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...)
Stephen Craneba090d12017-05-09 15:44:35 -0700165 }
166 return flags
167}
168
Yi Kong93718e02020-09-21 21:41:03 +0800169func (lto *lto) ThinLTO() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900170 return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
Stephen Craneba090d12017-05-09 15:44:35 -0700171}
172
Yi Kongf43ff052020-09-28 14:41:50 +0800173func (lto *lto) Never() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900174 return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
Yi Kong8ea56f92021-10-14 01:07:42 +0800175}
176
Colin Cross6ac83a82024-01-23 11:23:10 -0800177func ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
178 libTag, isLibTag := tag.(libraryDependencyTag)
179 // Do not recurse down non-static dependencies
180 if isLibTag {
181 return libTag.static()
182 } else {
183 return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
Stephen Craneba090d12017-05-09 15:44:35 -0700184 }
185}
186
Colin Cross6ac83a82024-01-23 11:23:10 -0800187// ltoTransitionMutator creates LTO variants of cc modules. Variant "" is the default variant, which may
188// or may not have LTO enabled depending on the config and the module's type and properties. "lto-thin" or
189// "lto-none" variants are created when a module needs to compile in the non-default state for that module.
190type ltoTransitionMutator struct{}
191
192const LTO_NONE_VARIATION = "lto-none"
193const LTO_THIN_VARIATION = "lto-thin"
194
195func (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
196 return []string{""}
197}
198
199func (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
200 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
201 if !ltoPropagateViaDepTag(ctx.DepTag()) {
202 return ""
Yi Kong8ea56f92021-10-14 01:07:42 +0800203 }
Stephen Crane10cd1872017-09-27 17:01:15 -0700204
Colin Cross6ac83a82024-01-23 11:23:10 -0800205 if sourceVariation != "" {
206 return sourceVariation
Yi Kong8ea56f92021-10-14 01:07:42 +0800207 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800208
209 // Always request an explicit variation, IncomingTransition will rewrite it back to the default variation
210 // if necessary.
Yi Kong950c1742023-10-09 19:49:45 +0900211 if m.lto.Properties.LtoEnabled {
Colin Cross6ac83a82024-01-23 11:23:10 -0800212 return LTO_THIN_VARIATION
213 } else {
214 return LTO_NONE_VARIATION
Yi Kong895d2412023-06-08 01:48:42 +0900215 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800216 }
217 return ""
218}
Stephen Crane10cd1872017-09-27 17:01:15 -0700219
Colin Cross6ac83a82024-01-23 11:23:10 -0800220func (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
221 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
222 if m.lto.Never() {
223 return ""
Stephen Crane10cd1872017-09-27 17:01:15 -0700224 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800225 // Rewrite explicit variations back to the default variation if the default variation matches.
226 if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault {
227 return ""
228 } else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault {
229 return ""
230 }
231 return incomingVariation
232 }
233 return ""
234}
235
236func (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
237 // Default module which will be installed. Variation set above according to explicit LTO properties.
238 if variation == "" {
239 return
240 }
241
242 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
243 // Non-default variation, set the LTO properties to match the variation.
244 switch variation {
245 case LTO_THIN_VARIATION:
246 m.lto.Properties.LtoEnabled = true
247 case LTO_NONE_VARIATION:
248 m.lto.Properties.LtoEnabled = false
249 default:
250 panic(fmt.Errorf("unknown variation %s", variation))
251 }
252 // Non-default variations are never installed.
253 m.Properties.PreventInstall = true
254 m.Properties.HideFromMake = true
Stephen Craneba090d12017-05-09 15:44:35 -0700255 }
256}