github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cc/lto.go (about)

     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  }