aboutsummaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorStephen Crane <sjc@immunant.com>2017-05-09 15:44:35 -0700
committerStephen Crane <sjc@immunant.com>2017-08-15 12:54:12 -0700
commitba090d16c2c92f4711860f0a56752a917f8daad0 (patch)
tree2dde51f9c78ae2adbe070961b8643d0c035978f0 /cc
parentb3c2154f2afc419c8d6bc92c812eff0113e9f692 (diff)
downloadbuild_soong-ba090d16c2c92f4711860f0a56752a917f8daad0.tar.gz
build_soong-ba090d16c2c92f4711860f0a56752a917f8daad0.tar.bz2
build_soong-ba090d16c2c92f4711860f0a56752a917f8daad0.zip
Add LTO support to soong
Enabling the lto property for a module builds that module and all static dependencies with LTO. LTO (link-time optimization) allows the compiler to optimize and generate code for the entire module at link time, rather than per-compilation unit. LTO is required for Clang CFI and other whole-program optimization techniques. LTO also allows cross-compilation unit optimizations that should result in faster and smaller code, at the expense of additional compilation time. Test: make -j12 libc with lto: true for libc Change-Id: Ib8baefedf60e02701d44673a7c473e0845730101
Diffstat (limited to 'cc')
-rw-r--r--cc/cc.go18
-rw-r--r--cc/config/global.go6
-rw-r--r--cc/lto.go112
3 files changed, 136 insertions, 0 deletions
diff --git a/cc/cc.go b/cc/cc.go
index 983ffc0e..ba06be24 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -51,6 +51,9 @@ func init() {
ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
ctx.TopDown("vndk_deps", sabiDepsMutator)
+
+ ctx.TopDown("lto_deps", ltoDepsMutator)
+ ctx.BottomUp("lto", ltoMutator).Parallel()
})
pctx.Import("android/soong/cc/config")
@@ -295,6 +298,7 @@ type Module struct {
coverage *coverage
sabi *sabi
vndkdep *vndkdep
+ lto *lto
androidMkSharedLibDeps []string
@@ -334,6 +338,9 @@ func (c *Module) Init() android.Module {
if c.vndkdep != nil {
c.AddProperties(c.vndkdep.props()...)
}
+ if c.lto != nil {
+ c.AddProperties(c.lto.props()...)
+ }
for _, feature := range c.features {
c.AddProperties(feature.props()...)
}
@@ -489,6 +496,7 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo
module.coverage = &coverage{}
module.sabi = &sabi{}
module.vndkdep = &vndkdep{}
+ module.lto = &lto{}
return module
}
@@ -537,6 +545,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
if c.coverage != nil {
flags = c.coverage.flags(ctx, flags)
}
+ if c.lto != nil {
+ flags = c.lto.flags(ctx, flags)
+ }
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
@@ -620,6 +631,9 @@ func (c *Module) begin(ctx BaseModuleContext) {
if c.vndkdep != nil {
c.vndkdep.begin(ctx)
}
+ if c.lto != nil {
+ c.lto.begin(ctx)
+ }
for _, feature := range c.features {
feature.begin(ctx)
}
@@ -656,6 +670,9 @@ func (c *Module) deps(ctx DepsContext) Deps {
if c.vndkdep != nil {
deps = c.vndkdep.deps(ctx, deps)
}
+ if c.lto != nil {
+ deps = c.lto.deps(ctx, deps)
+ }
for _, feature := range c.features {
deps = feature.deps(ctx, deps)
}
@@ -1191,6 +1208,7 @@ func DefaultsFactory(props ...interface{}) android.Module {
&CoverageProperties{},
&SAbiProperties{},
&VndkProperties{},
+ &LTOProperties{},
)
android.InitDefaultsModule(module)
diff --git a/cc/config/global.go b/cc/config/global.go
index 56de3513..82a44e61 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -16,6 +16,7 @@ package config
import (
"fmt"
+ "runtime"
"strings"
"android/soong/android"
@@ -149,6 +150,11 @@ func init() {
return ClangDefaultShortVersion, nil
})
pctx.StaticVariable("ClangAsanLibDir", "${ClangPath}/lib64/clang/${ClangShortVersion}/lib/linux")
+ if runtime.GOOS == "darwin" {
+ pctx.StaticVariable("LLVMGoldPlugin", "${ClangPath}/lib64/LLVMgold.dylib")
+ } else {
+ pctx.StaticVariable("LLVMGoldPlugin", "${ClangPath}/lib64/LLVMgold.so")
+ }
// These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts
// being used for the rest of the build process.
diff --git a/cc/lto.go b/cc/lto.go
new file mode 100644
index 00000000..b6bc9961
--- /dev/null
+++ b/cc/lto.go
@@ -0,0 +1,112 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+)
+
+// LTO (link-time optimization) allows the compiler to optimize and generate
+// code for the entire module at link time, rather than per-compilation
+// unit. LTO is required for Clang CFI and other whole-program optimization
+// techniques. LTO also allows cross-compilation unit optimizations that should
+// result in faster and smaller code, at the expense of additional compilation
+// time.
+//
+// To properly build a module with LTO, the module and all recursive static
+// dependencies should be compiled with -flto which directs the compiler to emit
+// bitcode rather than native object files. These bitcode files are then passed
+// by the linker to the LLVM plugin for compilation at link time. Static
+// dependencies not built as bitcode will still function correctly but cannot be
+// optimized at link time and may not be compatible with features that require
+// LTO, such as CFI.
+//
+// This file adds support to soong to automatically propogate LTO options to a
+// new variant of all static dependencies for each module with LTO enabled.
+
+type LTOProperties struct {
+ // Lto must violate capitialization style for acronyms so that it can be
+ // referred to in blueprint files as "lto"
+ Lto *bool `android:"arch_variant"`
+ LTODep bool `blueprint:"mutated"`
+}
+
+type lto struct {
+ Properties LTOProperties
+}
+
+func (lto *lto) props() []interface{} {
+ return []interface{}{&lto.Properties}
+}
+
+func (lto *lto) begin(ctx BaseModuleContext) {
+}
+
+func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps {
+ return deps
+}
+
+func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
+ if Bool(lto.Properties.Lto) {
+ flags.CFlags = append(flags.CFlags, "-flto")
+ flags.LdFlags = append(flags.LdFlags, "-flto")
+ flags.ArFlags = append(flags.ArFlags, " --plugin ${config.LLVMGoldPlugin}")
+ }
+ return flags
+}
+
+// Can be called with a null receiver
+func (lto *lto) LTO() bool {
+ if lto == nil {
+ return false
+ }
+
+ return Bool(lto.Properties.Lto)
+}
+
+// Propagate lto requirements down from binaries
+func ltoDepsMutator(mctx android.TopDownMutatorContext) {
+ if c, ok := mctx.Module().(*Module); ok && c.lto.LTO() {
+ mctx.VisitDepsDepthFirst(func(m blueprint.Module) {
+ tag := mctx.OtherModuleDependencyTag(m)
+ switch tag {
+ case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
+ if cc, ok := m.(*Module); ok && cc.lto != nil {
+ cc.lto.Properties.LTODep = true
+ }
+ }
+ })
+ }
+}
+
+// Create lto variants for modules that need them
+func ltoMutator(mctx android.BottomUpMutatorContext) {
+ if c, ok := mctx.Module().(*Module); ok && c.lto != nil {
+ if c.lto.LTO() {
+ mctx.SetDependencyVariation("lto")
+ } else if c.lto.Properties.LTODep {
+ modules := mctx.CreateVariations("", "lto")
+ modules[0].(*Module).lto.Properties.Lto = boolPtr(false)
+ modules[1].(*Module).lto.Properties.Lto = boolPtr(true)
+ modules[0].(*Module).lto.Properties.LTODep = false
+ modules[1].(*Module).lto.Properties.LTODep = false
+ modules[1].(*Module).Properties.PreventInstall = true
+ modules[1].(*Module).Properties.HideFromMake = true
+ }
+ c.lto.Properties.LTODep = false
+ }
+}