blob: 60eb4d6b16f4284161431c3835308dd3fcb5f87b [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
Yi Kongadd63752023-06-26 17:39:46 +090093 }
94
95 lto.Properties.LtoDefault = ltoDefault
96 lto.Properties.LtoEnabled = ltoEnabled
Stephen Craneba090d12017-05-09 15:44:35 -070097}
98
Colin Cross3513fb12024-01-24 14:44:47 -080099func (lto *lto) flags(ctx ModuleContext, flags Flags) Flags {
Yi Kong895d2412023-06-08 01:48:42 +0900100 // TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
101 // This has be checked late because these properties can be mutated.
102 if ctx.isCfi() || ctx.isFuzzer() {
Mitch Phillips5007c4a2022-03-02 01:25:22 +0000103 return flags
104 }
Yi Kong895d2412023-06-08 01:48:42 +0900105 if lto.Properties.LtoEnabled {
Yi Kongb9d50462023-07-03 16:59:33 +0900106 ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
107 var ltoLdFlags []string
108
Chungro Lee97f68582024-03-28 01:13:59 +0000109 // The module did not explicitly turn on LTO. Only leverage LTO's
110 // better dead code elimination and CFG simplification, but do
111 // not perform costly optimizations for a balance between compile
112 // time, binary size and performance.
113 // Apply the same for Eng builds as well.
114 if !lto.ThinLTO() || ctx.Config().Eng() {
Yi Kongb9d50462023-07-03 16:59:33 +0900115 ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
Yi Kong244bf072017-08-29 11:10:09 +0800116 }
117
Yi Kong2d01fe22020-09-21 01:18:32 +0800118 if Bool(lto.Properties.Whole_program_vtables) {
Yi Kongb9d50462023-07-03 16:59:33 +0900119 ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables")
Yi Kong2d01fe22020-09-21 01:18:32 +0800120 }
121
Yi Kong895d2412023-06-08 01:48:42 +0900122 if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
Yi Kong8aeaa712018-02-16 20:36:16 +0800123 // Set appropriate ThinLTO cache policy
Yi Kong630b9602019-03-22 21:28:39 -0700124 cacheDirFormat := "-Wl,--thinlto-cache-dir="
Yi Kong8aeaa712018-02-16 20:36:16 +0800125 cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
Yi Kongb9d50462023-07-03 16:59:33 +0900126 ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir)
Yi Kong8aeaa712018-02-16 20:36:16 +0800127
128 // Limit the size of the ThinLTO cache to the lesser of 10% of available
129 // disk space and 10GB.
Yi Kong630b9602019-03-22 21:28:39 -0700130 cachePolicyFormat := "-Wl,--thinlto-cache-policy="
Yi Kong8aeaa712018-02-16 20:36:16 +0800131 policy := "cache_size=10%:cache_size_bytes=10g"
Yi Kongb9d50462023-07-03 16:59:33 +0900132 ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
Yi Kong8aeaa712018-02-16 20:36:16 +0800133 }
134
Yi Kongd6ab48c2023-08-01 14:12:39 +0900135 // Reduce the inlining threshold for a better balance of binary size and
136 // performance.
137 if !ctx.Darwin() {
Colin Cross3513fb12024-01-24 14:44:47 -0800138 if ctx.isAfdoCompile(ctx) {
Yi Kongd6ab48c2023-08-01 14:12:39 +0900139 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40")
140 } else {
141 ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
142 }
Yi Kong7e53c572018-02-14 18:16:12 +0800143 }
Yi Kongb9d50462023-07-03 16:59:33 +0900144
AdityaK76c73852023-11-14 10:24:59 -0800145 if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
146 // Register allocation MLGO flags for ARM64.
Yi Kong2cd77d62024-06-06 03:05:04 +0900147 if ctx.Arch().ArchType == android.Arm64 && !ctx.optimizeForSize() {
AdityaK76c73852023-11-14 10:24:59 -0800148 ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
149 }
Yi Kong0fa503d2023-11-07 14:12:51 +0900150 // Flags for training MLGO model.
151 if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
152 ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
153 ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
154 }
Yi Kongb8eaee62023-10-31 21:58:42 +0900155 }
156
Yi Kongb9d50462023-07-03 16:59:33 +0900157 flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
158 flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
159 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
160 flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...)
Stephen Craneba090d12017-05-09 15:44:35 -0700161 }
162 return flags
163}
164
Yi Kong93718e02020-09-21 21:41:03 +0800165func (lto *lto) ThinLTO() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900166 return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
Stephen Craneba090d12017-05-09 15:44:35 -0700167}
168
Yi Kongf43ff052020-09-28 14:41:50 +0800169func (lto *lto) Never() bool {
Yi Kong895d2412023-06-08 01:48:42 +0900170 return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
Yi Kong8ea56f92021-10-14 01:07:42 +0800171}
172
Colin Cross6ac83a82024-01-23 11:23:10 -0800173func ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
174 libTag, isLibTag := tag.(libraryDependencyTag)
175 // Do not recurse down non-static dependencies
176 if isLibTag {
177 return libTag.static()
178 } else {
179 return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
Stephen Craneba090d12017-05-09 15:44:35 -0700180 }
181}
182
Colin Cross6ac83a82024-01-23 11:23:10 -0800183// ltoTransitionMutator creates LTO variants of cc modules. Variant "" is the default variant, which may
184// or may not have LTO enabled depending on the config and the module's type and properties. "lto-thin" or
185// "lto-none" variants are created when a module needs to compile in the non-default state for that module.
186type ltoTransitionMutator struct{}
187
188const LTO_NONE_VARIATION = "lto-none"
189const LTO_THIN_VARIATION = "lto-thin"
190
191func (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
192 return []string{""}
193}
194
195func (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
196 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
197 if !ltoPropagateViaDepTag(ctx.DepTag()) {
198 return ""
Yi Kong8ea56f92021-10-14 01:07:42 +0800199 }
Stephen Crane10cd1872017-09-27 17:01:15 -0700200
Colin Cross6ac83a82024-01-23 11:23:10 -0800201 if sourceVariation != "" {
202 return sourceVariation
Yi Kong8ea56f92021-10-14 01:07:42 +0800203 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800204
205 // Always request an explicit variation, IncomingTransition will rewrite it back to the default variation
206 // if necessary.
Yi Kong950c1742023-10-09 19:49:45 +0900207 if m.lto.Properties.LtoEnabled {
Colin Cross6ac83a82024-01-23 11:23:10 -0800208 return LTO_THIN_VARIATION
209 } else {
210 return LTO_NONE_VARIATION
Yi Kong895d2412023-06-08 01:48:42 +0900211 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800212 }
213 return ""
214}
Stephen Crane10cd1872017-09-27 17:01:15 -0700215
Colin Cross6ac83a82024-01-23 11:23:10 -0800216func (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
217 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
218 if m.lto.Never() {
219 return ""
Stephen Crane10cd1872017-09-27 17:01:15 -0700220 }
Colin Cross6ac83a82024-01-23 11:23:10 -0800221 // Rewrite explicit variations back to the default variation if the default variation matches.
222 if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault {
223 return ""
224 } else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault {
225 return ""
226 }
227 return incomingVariation
228 }
229 return ""
230}
231
232func (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
233 // Default module which will be installed. Variation set above according to explicit LTO properties.
234 if variation == "" {
235 return
236 }
237
238 if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
239 // Non-default variation, set the LTO properties to match the variation.
240 switch variation {
241 case LTO_THIN_VARIATION:
242 m.lto.Properties.LtoEnabled = true
243 case LTO_NONE_VARIATION:
244 m.lto.Properties.LtoEnabled = false
245 default:
246 panic(fmt.Errorf("unknown variation %s", variation))
247 }
248 // Non-default variations are never installed.
249 m.Properties.PreventInstall = true
250 m.Properties.HideFromMake = true
Stephen Craneba090d12017-05-09 15:44:35 -0700251 }
252}