diff --git a/cc/afdo_test.go b/cc/afdo_test.go index 551546424..fe3392ad3 100644 --- a/cc/afdo_test.go +++ b/cc/afdo_test.go @@ -15,28 +15,46 @@ package cc import ( + "strings" "testing" "android/soong/android" + "github.com/google/blueprint" ) +type visitDirectDepsInterface interface { + VisitDirectDeps(blueprint.Module, func(dep blueprint.Module)) +} + +func hasDirectDep(ctx visitDirectDepsInterface, m android.Module, wantDep android.Module) bool { + var found bool + ctx.VisitDirectDeps(m, func(dep blueprint.Module) { + if dep == wantDep { + found = true + } + }) + return found +} + func TestAfdoDeps(t *testing.T) { bp := ` - cc_library { + cc_library_shared { name: "libTest", - srcs: ["foo.c"], + srcs: ["test.c"], static_libs: ["libFoo"], afdo: true, } - cc_library { + cc_library_static { name: "libFoo", + srcs: ["foo.c"], static_libs: ["libBar"], } - cc_library { + cc_library_static { name: "libBar", + srcs: ["bar.c"], } ` prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libTest.afdo", "TEST") @@ -46,25 +64,89 @@ func TestAfdoDeps(t *testing.T) { prepareForAfdoTest, ).RunTestWithBp(t, bp) - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared").Module() - libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest").Module() - libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest").Module() + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest") + libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest") - hasDep := func(m android.Module, wantDep android.Module) bool { - var found bool - result.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - - if !hasDep(libTest, libFoo) { + if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { t.Errorf("libTest missing dependency on afdo variant of libFoo") } - if !hasDep(libFoo, libBar) { + if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libTest missing dependency on afdo variant of libBar") } + + cFlags := libTest.Rule("cc").Args["cFlags"] + if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) { + t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", w, cFlags) + } + + cFlags = libFoo.Rule("cc").Args["cFlags"] + if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) { + t.Errorf("Expected 'libFoo' to enable afdo, but did not find %q in cflags %q", w, cFlags) + } + + cFlags = libBar.Rule("cc").Args["cFlags"] + if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) { + t.Errorf("Expected 'libBar' to enable afdo, but did not find %q in cflags %q", w, cFlags) + } +} + +func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) { + bp := ` + cc_library_shared { + name: "libTest", + srcs: ["foo.c"], + static_libs: ["libFoo"], + } + + cc_library_static { + name: "libFoo", + srcs: ["foo.c"], + static_libs: ["libBar"], + afdo: true, // TODO(b/256670524): remove support for enabling afdo from static only libraries, this can only propagate from shared libraries/binaries + } + + cc_library_static { + name: "libBar", + } + ` + prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libFoo.afdo", "TEST") + + result := android.GroupFixturePreparers( + prepareForCcTest, + prepareForAfdoTest, + ).RunTestWithBp(t, bp) + + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared").Module() + libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static").Module() + + if !hasDirectDep(result, libTest, libFoo.Module()) { + t.Errorf("libTest missing dependency on afdo variant of libFoo") + } + + if !hasDirectDep(result, libFoo.Module(), libBar) { + t.Errorf("libFoo missing dependency on afdo variant of libBar") + } + + fooVariants := result.ModuleVariantsForTests("foo") + for _, v := range fooVariants { + if strings.Contains(v, "afdo-") { + t.Errorf("Expected no afdo variant of 'foo', got %q", v) + } + } + + cFlags := libFoo.Rule("cc").Args["cFlags"] + if w := "-fprofile-sample-accurate"; strings.Contains(cFlags, w) { + t.Errorf("Expected 'foo' to not enable afdo, but found %q in cflags %q", w, cFlags) + } + + barVariants := result.ModuleVariantsForTests("bar") + for _, v := range barVariants { + if strings.Contains(v, "afdo-") { + t.Errorf("Expected no afdo variant of 'bar', got %q", v) + } + } + } diff --git a/cc/lto_test.go b/cc/lto_test.go index b52f2b6a3..afd2c774e 100644 --- a/cc/lto_test.go +++ b/cc/lto_test.go @@ -24,29 +24,35 @@ import ( func TestThinLtoDeps(t *testing.T) { bp := ` - cc_library { + cc_library_shared { name: "lto_enabled", srcs: ["src.c"], - static_libs: ["foo"], + static_libs: ["foo", "lib_never_lto"], shared_libs: ["bar"], lto: { thin: true, } } - cc_library { + cc_library_static { name: "foo", static_libs: ["baz"], } - cc_library { + cc_library_shared { name: "bar", static_libs: ["qux"], } - cc_library { + cc_library_static { name: "baz", } - cc_library { + cc_library_static { name: "qux", } + cc_library_static { + name: "lib_never_lto", + lto: { + never: true, + }, + } ` result := android.GroupFixturePreparers( @@ -54,8 +60,6 @@ func TestThinLtoDeps(t *testing.T) { ).RunTestWithBp(t, bp) libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module() - libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module() - libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module() hasDep := func(m android.Module, wantDep android.Module) bool { var found bool @@ -67,12 +71,24 @@ func TestThinLtoDeps(t *testing.T) { return found } + libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module() if !hasDep(libLto, libFoo) { t.Errorf("'lto_enabled' missing dependency on thin lto variant of 'foo'") } + libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module() if !hasDep(libFoo, libBaz) { - t.Errorf("'lto_enabled' missing dependency on thin lto variant of transitive dep 'baz'") + t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'") + } + + libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static_lto-thin").Module() + if !hasDep(libLto, libNeverLto) { + t.Errorf("'lto_enabled' missing dependency on NO-thin lto variant of 'lib_never_lto'") + } + + libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module() + if !hasDep(libLto, libBar) { + t.Errorf("'lto_enabled' missing dependency on non-thin lto variant of 'bar'") } barVariants := result.ModuleVariantsForTests("bar") @@ -88,3 +104,74 @@ func TestThinLtoDeps(t *testing.T) { } } } + +func TestThinLtoOnlyOnStaticDep(t *testing.T) { + bp := ` + cc_library_shared { + name: "root", + srcs: ["src.c"], + static_libs: ["foo"], + } + cc_library_shared { + name: "root_no_lto", + srcs: ["src.c"], + static_libs: ["foo"], + lto: { + never: true, + } + } + cc_library_static { + name: "foo", + srcs: ["foo.c"], + static_libs: ["baz"], + lto: { + thin: true, + } + } + cc_library_static { + name: "baz", + srcs: ["baz.c"], + } +` + + result := android.GroupFixturePreparers( + prepareForCcTest, + ).RunTestWithBp(t, bp) + + libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module() + libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module() + + hasDep := func(m android.Module, wantDep android.Module) bool { + var found bool + result.VisitDirectDeps(m, func(dep blueprint.Module) { + if dep == wantDep { + found = true + } + }) + return found + } + + libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static") + if !hasDep(libRoot, libFoo.Module()) { + t.Errorf("'root' missing dependency on thin lto variant of 'foo'") + } + + if !hasDep(libRootLtoNever, libFoo.Module()) { + t.Errorf("'root_no_lto' missing dependency on thin lto variant of 'foo'") + } + + libFooCFlags := libFoo.Rule("cc").Args["cFlags"] + if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libFooCFlags, w) { + t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags) + } + + libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin") + if !hasDep(libFoo.Module(), libBaz.Module()) { + t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'") + } + + libBazCFlags := libFoo.Rule("cc").Args["cFlags"] + if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libBazCFlags, w) { + t.Errorf("'baz' expected to have flags %q, but got %q", w, libFooCFlags) + } +}