Home | History | Annotate | Download | only in cc
      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 
     15 package cc
     16 
     17 import (
     18 	"android/soong/android"
     19 )
     20 
     21 // LTO (link-time optimization) allows the compiler to optimize and generate
     22 // code for the entire module at link time, rather than per-compilation
     23 // unit. LTO is required for Clang CFI and other whole-program optimization
     24 // techniques. LTO also allows cross-compilation unit optimizations that should
     25 // result in faster and smaller code, at the expense of additional compilation
     26 // time.
     27 //
     28 // To properly build a module with LTO, the module and all recursive static
     29 // dependencies should be compiled with -flto which directs the compiler to emit
     30 // bitcode rather than native object files. These bitcode files are then passed
     31 // by the linker to the LLVM plugin for compilation at link time. Static
     32 // dependencies not built as bitcode will still function correctly but cannot be
     33 // optimized at link time and may not be compatible with features that require
     34 // LTO, such as CFI.
     35 //
     36 // This file adds support to soong to automatically propogate LTO options to a
     37 // new variant of all static dependencies for each module with LTO enabled.
     38 
     39 type LTOProperties struct {
     40 	// Lto must violate capitialization style for acronyms so that it can be
     41 	// referred to in blueprint files as "lto"
     42 	Lto struct {
     43 		Never *bool `android:"arch_variant"`
     44 		Full  *bool `android:"arch_variant"`
     45 		Thin  *bool `android:"arch_variant"`
     46 	} `android:"arch_variant"`
     47 
     48 	// Dep properties indicate that this module needs to be built with LTO
     49 	// since it is an object dependency of an LTO module.
     50 	FullDep bool `blueprint:"mutated"`
     51 	ThinDep bool `blueprint:"mutated"`
     52 }
     53 
     54 type lto struct {
     55 	Properties LTOProperties
     56 }
     57 
     58 func (lto *lto) props() []interface{} {
     59 	return []interface{}{&lto.Properties}
     60 }
     61 
     62 func (lto *lto) begin(ctx BaseModuleContext) {
     63 	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
     64 		lto.Properties.Lto.Never = boolPtr(true)
     65 	}
     66 }
     67 
     68 func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps {
     69 	return deps
     70 }
     71 
     72 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
     73 	if lto.LTO() {
     74 		var ltoFlag string
     75 		if Bool(lto.Properties.Lto.Thin) {
     76 			ltoFlag = "-flto=thin"
     77 		} else {
     78 			ltoFlag = "-flto"
     79 		}
     80 
     81 		flags.CFlags = append(flags.CFlags, ltoFlag)
     82 		flags.LdFlags = append(flags.LdFlags, ltoFlag)
     83 		if ctx.Device() {
     84 			// Work around bug in Clang that doesn't pass correct emulated
     85 			// TLS option to target. See b/72706604 or
     86 			// https://github.com/android-ndk/ndk/issues/498.
     87 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls")
     88 		}
     89 		flags.ArGoldPlugin = true
     90 
     91 		// If the module does not have a profile, be conservative and do not inline
     92 		// or unroll loops during LTO, in order to prevent significant size bloat.
     93 		if !ctx.isPgoCompile() {
     94 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0")
     95 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0")
     96 		}
     97 	}
     98 	return flags
     99 }
    100 
    101 // Can be called with a null receiver
    102 func (lto *lto) LTO() bool {
    103 	if lto == nil || lto.Disabled() {
    104 		return false
    105 	}
    106 
    107 	full := Bool(lto.Properties.Lto.Full)
    108 	thin := Bool(lto.Properties.Lto.Thin)
    109 	return full || thin
    110 }
    111 
    112 // Is lto.never explicitly set to true?
    113 func (lto *lto) Disabled() bool {
    114 	return lto.Properties.Lto.Never != nil && *lto.Properties.Lto.Never
    115 }
    116 
    117 // Propagate lto requirements down from binaries
    118 func ltoDepsMutator(mctx android.TopDownMutatorContext) {
    119 	if m, ok := mctx.Module().(*Module); ok && m.lto.LTO() {
    120 		full := Bool(m.lto.Properties.Lto.Full)
    121 		thin := Bool(m.lto.Properties.Lto.Thin)
    122 		if full && thin {
    123 			mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
    124 		}
    125 
    126 		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
    127 			tag := mctx.OtherModuleDependencyTag(dep)
    128 			switch tag {
    129 			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
    130 				if dep, ok := dep.(*Module); ok && dep.lto != nil &&
    131 					!dep.lto.Disabled() {
    132 					if full && !Bool(dep.lto.Properties.Lto.Full) {
    133 						dep.lto.Properties.FullDep = true
    134 					}
    135 					if thin && !Bool(dep.lto.Properties.Lto.Thin) {
    136 						dep.lto.Properties.ThinDep = true
    137 					}
    138 				}
    139 
    140 				// Recursively walk static dependencies
    141 				return true
    142 			}
    143 
    144 			// Do not recurse down non-static dependencies
    145 			return false
    146 		})
    147 	}
    148 }
    149 
    150 // Create lto variants for modules that need them
    151 func ltoMutator(mctx android.BottomUpMutatorContext) {
    152 	if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
    153 		// Create variations for LTO types required as static
    154 		// dependencies
    155 		variationNames := []string{""}
    156 		if m.lto.Properties.FullDep && !Bool(m.lto.Properties.Lto.Full) {
    157 			variationNames = append(variationNames, "lto-full")
    158 		}
    159 		if m.lto.Properties.ThinDep && !Bool(m.lto.Properties.Lto.Thin) {
    160 			variationNames = append(variationNames, "lto-thin")
    161 		}
    162 
    163 		// Use correct dependencies if LTO property is explicitly set
    164 		// (mutually exclusive)
    165 		if Bool(m.lto.Properties.Lto.Full) {
    166 			mctx.SetDependencyVariation("lto-full")
    167 		}
    168 		if Bool(m.lto.Properties.Lto.Thin) {
    169 			mctx.SetDependencyVariation("lto-thin")
    170 		}
    171 
    172 		if len(variationNames) > 1 {
    173 			modules := mctx.CreateVariations(variationNames...)
    174 			for i, name := range variationNames {
    175 				variation := modules[i].(*Module)
    176 				// Default module which will be
    177 				// installed. Variation set above according to
    178 				// explicit LTO properties
    179 				if name == "" {
    180 					continue
    181 				}
    182 
    183 				// LTO properties for dependencies
    184 				if name == "lto-full" {
    185 					variation.lto.Properties.Lto.Full = boolPtr(true)
    186 					variation.lto.Properties.Lto.Thin = boolPtr(false)
    187 				}
    188 				if name == "lto-thin" {
    189 					variation.lto.Properties.Lto.Full = boolPtr(false)
    190 					variation.lto.Properties.Lto.Thin = boolPtr(true)
    191 				}
    192 				variation.Properties.PreventInstall = true
    193 				variation.Properties.HideFromMake = true
    194 				variation.lto.Properties.FullDep = false
    195 				variation.lto.Properties.ThinDep = false
    196 			}
    197 		}
    198 	}
    199 }
    200