Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 895d2410 authored by Yi Kong's avatar Yi Kong
Browse files

Refactor LTO

We removed Full LTO support, now LTO is a binary choice. This allows us
to greatly simplify the LTO propagation logic.

Test: m
Test: GLBOAL_THINLTO=true m
Bug: 169004486
Change-Id: Ie4e453d7518c7069a7c755734dab1e776c16e656
parent 4ead3a80
Loading
Loading
Loading
Loading
+49 −45
Original line number Diff line number Diff line
@@ -46,11 +46,11 @@ type LTOProperties struct {
		Thin  *bool `android:"arch_variant"`
	} `android:"arch_variant"`

	LtoEnabled 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.
	ThinEnabled  bool `blueprint:"mutated"`
	NoLtoEnabled bool `blueprint:"mutated"`
	ThinDep      bool `blueprint:"mutated"`
	LtoDep   bool `blueprint:"mutated"`
	NoLtoDep bool `blueprint:"mutated"`

	// Use -fwhole-program-vtables cflag.
@@ -66,19 +66,16 @@ func (lto *lto) props() []interface{} {
}

func (lto *lto) begin(ctx BaseModuleContext) {
	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
		lto.Properties.NoLtoEnabled = true
	}
	lto.Properties.LtoEnabled = lto.LTO(ctx)
}

func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
	// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
	// LTO breaks fuzzer builds.
	if ctx.isFuzzer() {
	// TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
	// This has be checked late because these properties can be mutated.
	if ctx.isCfi() || ctx.isFuzzer() {
		return flags
	}

	if lto.LTO(ctx) {
	if lto.Properties.LtoEnabled {
		var ltoCFlag string
		var ltoLdFlag string
		if lto.ThinLTO() {
@@ -97,7 +94,7 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
			flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
		}

		if (lto.DefaultThinLTO(ctx) || lto.ThinLTO()) && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
			// Set appropriate ThinLTO cache policy
			cacheDirFormat := "-Wl,--thinlto-cache-dir="
			cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
@@ -120,30 +117,40 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
	return flags
}

// Determine which LTO mode to use for the given module.
func (lto *lto) LTO(ctx BaseModuleContext) bool {
	return lto.ThinLTO() || lto.DefaultThinLTO(ctx)
	if lto.Never() {
		return false
	}
	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
		return false
	}
	// Module explicitly requests for LTO.
	if lto.ThinLTO() {
		return true
	}

func (lto *lto) DefaultThinLTO(ctx BaseModuleContext) bool {
	// LP32 has many subtle issues and less test coverage.
	lib32 := ctx.Arch().ArchType.Multilib == "lib32"
	// CFI adds LTO flags by itself.
	cfi := ctx.isCfi()
	if ctx.Arch().ArchType.Multilib == "lib32" {
		return false
	}
	// Performance and binary size are less important for host binaries and tests.
	host := ctx.Host()
	test := ctx.testBinary() || ctx.testLibrary()
	if ctx.Host() || ctx.testBinary() || ctx.testLibrary() {
		return false
	}
	// FIXME: ThinLTO for VNDK produces different output.
	// b/169217596
	vndk := ctx.isVndk()
	return GlobalThinLTO(ctx) && !lto.Never() && !lib32 && !cfi && !host && !test && !vndk
	if ctx.isVndk() {
		return false
	}
	return GlobalThinLTO(ctx)
}

func (lto *lto) ThinLTO() bool {
	return lto != nil && (proptools.Bool(lto.Properties.Lto.Thin) || lto.Properties.ThinEnabled)
	return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
}

func (lto *lto) Never() bool {
	return lto != nil && (proptools.Bool(lto.Properties.Lto.Never) || lto.Properties.NoLtoEnabled)
	return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
}

func GlobalThinLTO(ctx android.BaseModuleContext) bool {
@@ -152,11 +159,12 @@ func GlobalThinLTO(ctx android.BaseModuleContext) bool {

// Propagate lto requirements down from binaries
func ltoDepsMutator(mctx android.TopDownMutatorContext) {
	globalThinLTO := GlobalThinLTO(mctx)
	defaultLTOMode := GlobalThinLTO(mctx)

	if m, ok := mctx.Module().(*Module); ok {
		thin := m.lto.ThinLTO()
		never := m.lto.Never()
		if m.lto == nil || m.lto.Properties.LtoEnabled == defaultLTOMode {
			return
		}

		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
			tag := mctx.OtherModuleDependencyTag(dep)
@@ -174,10 +182,9 @@ func ltoDepsMutator(mctx android.TopDownMutatorContext) {
			}

			if dep, ok := dep.(*Module); ok {
				if !globalThinLTO && thin && !dep.lto.ThinLTO() {
					dep.lto.Properties.ThinDep = true
				}
				if globalThinLTO && never && !dep.lto.Never() {
				if m.lto.Properties.LtoEnabled {
					dep.lto.Properties.LtoDep = true
				} else {
					dep.lto.Properties.NoLtoDep = true
				}
			}
@@ -196,22 +203,19 @@ func ltoMutator(mctx android.BottomUpMutatorContext) {
		// Create variations for LTO types required as static
		// dependencies
		variationNames := []string{""}
		if !globalThinLTO && m.lto.Properties.ThinDep && !m.lto.ThinLTO() {
		if m.lto.Properties.LtoDep {
			variationNames = append(variationNames, "lto-thin")
		}
		if globalThinLTO && m.lto.Properties.NoLtoDep && !m.lto.Never() {
		if m.lto.Properties.NoLtoDep {
			variationNames = append(variationNames, "lto-none")
		}

		// Use correct dependencies if LTO property is explicitly set
		// (mutually exclusive)
		if !globalThinLTO && m.lto.ThinLTO() {
			mctx.SetDependencyVariation("lto-thin")
		}
		// Never must be the last, it overrides Thin.
		if globalThinLTO && m.lto.Never() {
		if globalThinLTO && !m.lto.Properties.LtoEnabled {
			mctx.SetDependencyVariation("lto-none")
		}
		if !globalThinLTO && m.lto.Properties.LtoEnabled {
			mctx.SetDependencyVariation("lto-thin")
		}

		if len(variationNames) > 1 {
			modules := mctx.CreateVariations(variationNames...)
@@ -226,14 +230,14 @@ func ltoMutator(mctx android.BottomUpMutatorContext) {

				// LTO properties for dependencies
				if name == "lto-thin" {
					variation.lto.Properties.ThinEnabled = true
					variation.lto.Properties.LtoEnabled = true
				}
				if name == "lto-none" {
					variation.lto.Properties.NoLtoEnabled = true
					variation.lto.Properties.LtoEnabled = false
				}
				variation.Properties.PreventInstall = true
				variation.Properties.HideFromMake = true
				variation.lto.Properties.ThinDep = false
				variation.lto.Properties.LtoDep = false
				variation.lto.Properties.NoLtoDep = false
			}
		}