blob: 44441527aa0c7a0af2c17b66f721d68d69602e70 [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 Kongdf0289b2024-03-28 06:10:30 +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
Yi Kongadd63752023-06-26 17:39:46 +090096 }
97
98 lto.Properties.LtoDefault = ltoDefault
99 lto.Properties.LtoEnabled = ltoEnabled
Stephen Craneba090d12017-05-09 15:44:35 -0700100}
101
Colin Cross3513fb12024-01-24 14:44:47 -0800102func (lto *lto) flags(ctx ModuleContext, flags Flags) Flags {
Yi Kong895d2412023-06-08 01:48:42 +0900103 // TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
104 // This has be checked late because these properties can be mutated.
105 if ctx.isCfi() || ctx.isFuzzer() {
Mitch Phillips5007c4a2022-03-02 01:25:22 +0000106 return flags
107 }
Yi Kong895d2412023-06-08 01:48:42 +0900108 if lto.Properties.LtoEnabled {
Yi Kongb9d50462023-07-03 16:59:33 +0900109 ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
110 var ltoLdFlags []string
111
Yi Kongdf0289b2024-03-28 06:10:30 +0000112 // Do not perform costly LTO optimizations for Eng builds.
Yi Kong6f016582024-08-26 15:35:14 +0900113 if Bool(lto.Properties.Lto_O0) || ctx.Config().Eng() {
Yi Kongb9d50462023-07-03 16:59:33 +0900114 ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
Yi Kong244bf072017-08-29 11:10:09 +0800115 }
116
Yi Kong2d01fe22020-09-21 01:18:32 +0800117 if Bool(lto.Properties.Whole_program_vtables) {
Yi Kongb9d50462023-07-03 16:59:33 +0900118 ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables")
Yi Kong2d01fe22020-09-21 01:18:32 +0800119 }
120
Yi Kong895d2412023-06-08 01:48:42 +0900121 if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
Yi Kong8aeaa712018-02-16 20:36:16 +0800122 // Set appropriate ThinLTO cache policy
Yi Kong630b9602019-03-22 21:28:39 -0700123 cacheDirFormat := "-Wl,--thinlto-cache-dir="
Yi Kong8aeaa712018-02-16 20:36:16 +0800124 cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
Yi Kongb9d50462023-07-03 16:59:33 +0900125 ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir)
Yi Kong8aeaa712018-02-16 20:36:16 +0800126
127 // Limit the size of the ThinLTO cache to the lesser of 10% of available
128 // disk space and 10GB.
Yi Kong630b9602019-03-22 21:28:39 -0700129 cachePolicyFormat := "-Wl,--thinlto-cache-policy="
Yi Kong8aeaa712018-02-16 20:36:16 +0800130 policy := "cache_size=10%:cache_size_bytes=10g"
Yi Kongb9d50462023-07-03 16:59:33 +0900131 ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
Yi Kong8aeaa712018-02-16 20:36:16 +0800132 }
133
Yi Kongd6ab48c2023-08-01 14:12:39 +0900134 // Reduce the inlining threshold for a better balance of binary size and
135 // performance.
136 if !ctx.Darwin() {
Colin Cross3513fb12024-01-24 14:44:47 -0800137 if ctx.isAfdoCompile(ctx) {
Yi Kongd6ab48c2023-08-01 14:12:39 +0900138 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40")
139 } else {
140 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
141 }
Yi Kong7e53c572018-02-14 18:16:12 +0800142 }
Yi Kongb9d50462023-07-03 16:59:33 +0900143
AdityaK76c73852023-11-14 10:24:59 -0800144 if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
145 // Register allocation MLGO flags for ARM64.
Yi Kong2cd77d62024-06-06 03:05:04 +0900146 if ctx.Arch().ArchType == android.Arm64 && !ctx.optimizeForSize() {
AdityaK76c73852023-11-14 10:24:59 -0800147 ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
148 }
Yi Kong0fa503d2023-11-07 14:12:51 +0900149 // Flags for training MLGO model.
150 if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
151 ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
152 ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
153 }
Yi Kongb8eaee62023-10-31 21:58:42 +0900154 }
155
Yi Kongb9d50462023-07-03 16:59:33 +0900156 flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
157 flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
158 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
159 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...)
Stephen Craneba090d12017-05-09 15:44:35 -0700160 }
161 return flags
162}
163
Yi Kong93718e02020-09-21 21:41:03 +0800164func (lto *lto) ThinLTO() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900165 return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
Stephen Craneba090d12017-05-09 15:44:35 -0700166}
167
Yi Kongf43ff052020-09-28 14:41:50 +0800168func (lto *lto) Never() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900169 return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
Yi Kong8ea56f92021-10-14 01:07:42 +0800170}
171
Colin Cross6ac83a82024-01-23 11:23:10 -0800172func ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
173 libTag, isLibTag := tag.(libraryDependencyTag)
174 // Do not recurse down non-static dependencies
175 if isLibTag {
176 return libTag.static()
177 } else {
178 return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
Stephen Craneba090d12017-05-09 15:44:35 -0700179 }
180}
181
Colin Cross6ac83a82024-01-23 11:23:10 -0800182// ltoTransitionMutator creates LTO variants of cc modules. Variant "" is the default variant, which may
183// or may not have LTO enabled depending on the config and the module's type and properties. "lto-thin" or
184// "lto-none" variants are created when a module needs to compile in the non-default state for that module.
185type ltoTransitionMutator struct{}
186
187const LTO_NONE_VARIATION = "lto-none"
188const LTO_THIN_VARIATION = "lto-thin"
189
190func (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
191 return []string{""}
192}
193
194func (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
195 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
196 if !ltoPropagateViaDepTag(ctx.DepTag()) {
197 return ""
Yi Kong8ea56f92021-10-14 01:07:42 +0800198 }
Stephen Crane10cd1872017-09-27 17:01:15 -0700199
Colin Cross6ac83a82024-01-23 11:23:10 -0800200 if sourceVariation != "" {
201 return sourceVariation
Yi Kong8ea56f92021-10-14 01:07:42 +0800202 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800203
204 // Always request an explicit variation, IncomingTransition will rewrite it back to the default variation
205 // if necessary.
Yi Kong950c1742023-10-09 19:49:45 +0900206 if m.lto.Properties.LtoEnabled {
Colin Cross6ac83a82024-01-23 11:23:10 -0800207 return LTO_THIN_VARIATION
208 } else {
209 return LTO_NONE_VARIATION
Yi Kong895d2412023-06-08 01:48:42 +0900210 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800211 }
212 return ""
213}
Stephen Crane10cd1872017-09-27 17:01:15 -0700214
Colin Cross6ac83a82024-01-23 11:23:10 -0800215func (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
216 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
217 if m.lto.Never() {
218 return ""
Stephen Crane10cd1872017-09-27 17:01:15 -0700219 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800220 // Rewrite explicit variations back to the default variation if the default variation matches.
221 if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault {
222 return ""
223 } else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault {
224 return ""
225 }
226 return incomingVariation
227 }
228 return ""
229}
230
231func (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
232 // Default module which will be installed. Variation set above according to explicit LTO properties.
233 if variation == "" {
234 return
235 }
236
237 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
238 // Non-default variation, set the LTO properties to match the variation.
239 switch variation {
240 case LTO_THIN_VARIATION:
241 m.lto.Properties.LtoEnabled = true
242 case LTO_NONE_VARIATION:
243 m.lto.Properties.LtoEnabled = false
244 default:
245 panic(fmt.Errorf("unknown variation %s", variation))
246 }
247 // Non-default variations are never installed.
248 m.Properties.PreventInstall = true
249 m.Properties.HideFromMake = true
Stephen Craneba090d12017-05-09 15:44:35 -0700250 }
251}