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

Commit 6ac83a8f authored by Colin Cross's avatar Colin Cross
Browse files

Convert LTO mutators to TransitionMutator

Convert ltoDepsMutator and ltoMutator to a TransitionMutator as a
step towards variants-on-demand.

Bug: 319288033
Test: lto_test.go
Change-Id: I2c9af73fd526adf58ff626831ababea466338205
parent f5f4ad3d
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -76,8 +76,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
		ctx.TopDown("orderfile_deps", orderfileDepsMutator)
		ctx.BottomUp("orderfile", orderfileMutator).Parallel()

		ctx.TopDown("lto_deps", ltoDepsMutator)
		ctx.BottomUp("lto", ltoMutator).Parallel()
		ctx.Transition("lto", &ltoTransitionMutator{})

		ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel()
		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
+70 −75
Original line number Diff line number Diff line
@@ -15,9 +15,12 @@
package cc

import (
	"android/soong/android"
	"fmt"

	"github.com/google/blueprint"
	"github.com/google/blueprint/proptools"

	"android/soong/android"
)

// LTO (link-time optimization) allows the compiler to optimize and generate
@@ -49,11 +52,6 @@ type LTOProperties struct {
	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.
	LtoDep   bool `blueprint:"mutated"`
	NoLtoDep bool `blueprint:"mutated"`

	// Use -fwhole-program-vtables cflag.
	Whole_program_vtables *bool
}
@@ -176,86 +174,83 @@ func (lto *lto) Never() bool {
	return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
}

// Propagate lto requirements down from binaries
func ltoDepsMutator(mctx android.TopDownMutatorContext) {
	if m, ok := mctx.Module().(*Module); ok {
		if m.lto == nil || m.lto.Properties.LtoEnabled == m.lto.Properties.LtoDefault {
			return
		}

		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
			tag := mctx.OtherModuleDependencyTag(dep)
func ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
	libTag, isLibTag := tag.(libraryDependencyTag)

	// Do not recurse down non-static dependencies
	if isLibTag {
				if !libTag.static() {
					return false
				}
		return libTag.static()
	} else {
				if tag != objDepTag && tag != reuseObjTag {
					return false
		return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
	}
}

			if dep, ok := dep.(*Module); ok {
				if m.lto.Properties.LtoEnabled {
					dep.lto.Properties.LtoDep = true
				} else {
					dep.lto.Properties.NoLtoDep = true
				}
			}
// ltoTransitionMutator creates LTO variants of cc modules.  Variant "" is the default variant, which may
// or may not have LTO enabled depending on the config and the module's type and properties.  "lto-thin" or
// "lto-none" variants are created when a module needs to compile in the non-default state for that module.
type ltoTransitionMutator struct{}

			// Recursively walk static dependencies
			return true
		})
	}
}
const LTO_NONE_VARIATION = "lto-none"
const LTO_THIN_VARIATION = "lto-thin"

// Create lto variants for modules that need them
func ltoMutator(mctx android.BottomUpMutatorContext) {
	if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
		// Create variations for LTO types required as static
		// dependencies
		variationNames := []string{""}
		if m.lto.Properties.LtoDep {
			variationNames = append(variationNames, "lto-thin")
func (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
	return []string{""}
}
		if m.lto.Properties.NoLtoDep {
			variationNames = append(variationNames, "lto-none")

func (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
	if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
		if !ltoPropagateViaDepTag(ctx.DepTag()) {
			return ""
		}

		if !m.lto.Properties.LtoEnabled {
			mctx.SetDependencyVariation("lto-none")
		if sourceVariation != "" {
			return sourceVariation
		}

		// Always request an explicit variation, IncomingTransition will rewrite it back to the default variation
		// if necessary.
		if m.lto.Properties.LtoEnabled {
			mctx.SetDependencyVariation("lto-thin")
			return LTO_THIN_VARIATION
		} else {
			return LTO_NONE_VARIATION
		}

		if len(variationNames) > 1 {
			modules := mctx.CreateVariations(variationNames...)
			for i, name := range variationNames {
				variation := modules[i].(*Module)
				// Default module which will be
				// installed. Variation set above according to
				// explicit LTO properties
				if name == "" {
					continue
	}
	return ""
}

				// LTO properties for dependencies
				if name == "lto-thin" {
					variation.lto.Properties.LtoEnabled = true
func (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
	if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
		if m.lto.Never() {
			return ""
		}
		// Rewrite explicit variations back to the default variation if the default variation matches.
		if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault {
			return ""
		} else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault {
			return ""
		}
		return incomingVariation
	}
				if name == "lto-none" {
					variation.lto.Properties.LtoEnabled = false
	return ""
}
				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

func (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
	// Default module which will be installed. Variation set above according to explicit LTO properties.
	if variation == "" {
		return
	}

	if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
		// Non-default variation, set the LTO properties to match the variation.
		switch variation {
		case LTO_THIN_VARIATION:
			m.lto.Properties.LtoEnabled = true
		case LTO_NONE_VARIATION:
			m.lto.Properties.LtoEnabled = false
		default:
			panic(fmt.Errorf("unknown variation %s", variation))
		}
		// Non-default variations are never installed.
		m.Properties.PreventInstall = true
		m.Properties.HideFromMake = true
	}
}
+3 −2
Original line number Diff line number Diff line
@@ -146,8 +146,9 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) {
		t.Errorf("'root' missing dependency on the default variant of 'foo'")
	}

	if !hasDep(result, libRootLtoNever, libFoo.Module()) {
		t.Errorf("'root_no_lto' missing dependency on the default variant of 'foo'")
	libFooNoLto := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-none")
	if !hasDep(result, libRootLtoNever, libFooNoLto.Module()) {
		t.Errorf("'root_no_lto' missing dependency on the lto_none variant of 'foo'")
	}

	libFooCFlags := libFoo.Rule("cc").Args["cFlags"]