Turn on Global ThinLTO by default

Build C/C++ targets with ThinLTO with "--lto-O0" by default. This takes
advantage of better dead code elimination and CFG simplification due to
ThinLTO's global view of the program, but do not enable the costly LTO
optimizations. This also makes builds faster because we can avoid doing
codegen for the dead code.

Code size for panther-userdebug:
                   /system/bin  /system/lib  /system/lib64
Original           57648        86264        181700
Global ThinLTO     55764        84916        175728
                   -3.27%       -1.56%       -3.29%

Build time for aosp_arm64-userdebug:
                   clang time   linker time
Original           56993.87s    1712.36s
Global ThinLTO     52839.18s    3114.93s

saving 4.68% build time in total.

Bug: 169004486
Test: presubmit
Change-Id: Idb0f4675ca4750b8b12b24f4679579419d3448c8
diff --git a/cc/lto.go b/cc/lto.go
index 510dd79..ff2bf5a 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -47,6 +47,7 @@
 	} `android:"arch_variant"`
 
 	LtoEnabled bool `blueprint:"mutated"`
+	LtoDefault bool `blueprint:"mutated"`
 
 	// Dep properties indicate that this module needs to be built with LTO
 	// since it is an object dependency of an LTO module.
@@ -66,7 +67,34 @@
 }
 
 func (lto *lto) begin(ctx BaseModuleContext) {
-	lto.Properties.LtoEnabled = lto.LTO(ctx)
+	// First, determine the module indepedent default LTO mode.
+	ltoDefault := GlobalThinLTO(ctx)
+	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
+		ltoDefault = false
+	} else if ctx.Host() {
+		// Performance and binary size are less important for host binaries.
+		ltoDefault = false
+	}
+
+	// Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs
+	// to be created.
+	ltoEnabled := ltoDefault
+	if lto.Never() {
+		ltoEnabled = false
+	} else if lto.ThinLTO() {
+		// Module explicitly requests for LTO.
+		ltoEnabled = true
+	} else if ctx.testBinary() || ctx.testLibrary() {
+		// Do not enable LTO for tests for better debugging.
+		ltoEnabled = false
+	} else if ctx.isVndk() {
+		// FIXME: ThinLTO for VNDK produces different output.
+		// b/169217596
+		ltoEnabled = false
+	}
+
+	lto.Properties.LtoDefault = ltoDefault
+	lto.Properties.LtoEnabled = ltoEnabled
 }
 
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
@@ -118,34 +146,6 @@
 	return flags
 }
 
-// Determine which LTO mode to use for the given module.
-func (lto *lto) LTO(ctx BaseModuleContext) bool {
-	if lto.Never() {
-		return false
-	}
-	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
-		return false
-	}
-	// Module explicitly requests for LTO.
-	if lto.ThinLTO() {
-		return true
-	}
-	// LP32 has many subtle issues and less test coverage.
-	if ctx.Arch().ArchType.Multilib == "lib32" {
-		return false
-	}
-	// Performance and binary size are less important for host binaries and tests.
-	if ctx.Host() || ctx.testBinary() || ctx.testLibrary() {
-		return false
-	}
-	// FIXME: ThinLTO for VNDK produces different output.
-	// b/169217596
-	if ctx.isVndk() {
-		return false
-	}
-	return GlobalThinLTO(ctx)
-}
-
 func (lto *lto) ThinLTO() bool {
 	return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
 }
@@ -155,15 +155,13 @@
 }
 
 func GlobalThinLTO(ctx android.BaseModuleContext) bool {
-	return ctx.Config().IsEnvTrue("GLOBAL_THINLTO")
+	return !ctx.Config().IsEnvFalse("GLOBAL_THINLTO")
 }
 
 // Propagate lto requirements down from binaries
 func ltoDepsMutator(mctx android.TopDownMutatorContext) {
-	defaultLTOMode := GlobalThinLTO(mctx)
-
 	if m, ok := mctx.Module().(*Module); ok {
-		if m.lto == nil || m.lto.Properties.LtoEnabled == defaultLTOMode {
+		if m.lto == nil || m.lto.Properties.LtoEnabled == m.lto.Properties.LtoDefault {
 			return
 		}
 
@@ -238,6 +236,7 @@
 				}
 				variation.Properties.PreventInstall = true
 				variation.Properties.HideFromMake = true
+				variation.lto.Properties.LtoDefault = m.lto.Properties.LtoDefault
 				variation.lto.Properties.LtoDep = false
 				variation.lto.Properties.NoLtoDep = false
 			}