Disable inlining and loop unrolling in LTO without PGO profile

Such optimisations may significantly increase the binary size when
compiler heuristics are off. Disabling these helps cut down the
binary sizes with negligible decrease in performance, but allows us to
be more comfortable enabling LTO across various projects.

Test: m
Test: dex2oat, hwui, skia benchmark
Bug: 62839002
Change-Id: Id63e8dd295df2972f76ae4e29ee367080fff8429
diff --git a/cc/cc.go b/cc/cc.go
index 49fefe9..f65441f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -211,6 +211,7 @@
 	selectedStl() string
 	baseModuleName() string
 	getVndkExtendsModuleName() string
+	isPgoCompile() bool
 }
 
 type ModuleContext interface {
@@ -408,6 +409,13 @@
 	return false
 }
 
+func (c *Module) isPgoCompile() bool {
+	if pgo := c.pgo; pgo != nil {
+		return pgo.Properties.PgoCompile
+	}
+	return false
+}
+
 func (c *Module) isVndkSp() bool {
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		return vndkdep.isVndkSp()
@@ -507,6 +515,10 @@
 	return ctx.mod.isVndk()
 }
 
+func (ctx *moduleContextImpl) isPgoCompile() bool {
+	return ctx.mod.isPgoCompile()
+}
+
 func (ctx *moduleContextImpl) isVndkSp() bool {
 	return ctx.mod.isVndkSp()
 }
diff --git a/cc/lto.go b/cc/lto.go
index 4757fc7..2ced124 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -87,6 +87,13 @@
 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls")
 		}
 		flags.ArGoldPlugin = true
+
+		// If the module does not have a profile, be conservative and do not inline
+		// or unroll loops during LTO, in order to prevent significant size bloat.
+		if !ctx.isPgoCompile() {
+			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0")
+			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0")
+		}
 	}
 	return flags
 }
diff --git a/cc/pgo.go b/cc/pgo.go
index 1e70339..779ef39 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -45,7 +45,7 @@
 	})
 }
 
-func recordMissingProfileFile(ctx ModuleContext, missing string) {
+func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
 	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFile).Store(missing, true)
 }
 
@@ -63,6 +63,7 @@
 
 	PgoPresent          bool `blueprint:"mutated"`
 	ShouldProfileModule bool `blueprint:"mutated"`
+	PgoCompile          bool `blueprint:"mutated"`
 }
 
 type pgo struct {
@@ -98,7 +99,7 @@
 	return flags
 }
 
-func (props *PgoProperties) getPgoProfileFile(ctx ModuleContext) android.OptionalPath {
+func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
 	// Test if the profile_file is present in any of the PGO profile projects
 	for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
 		path := android.ExistentPathForSource(ctx, "", profileProject, *props.Pgo.Profile_file)
@@ -232,6 +233,12 @@
 			}
 		}
 	}
+
+	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
+		if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
+			pgo.Properties.PgoCompile = true
+		}
+	}
 }
 
 func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {