[tint][ast][msl] Remove the need for SingleEntryPoint to be run
Before the PixelLocal transform. As chromium:343072269 points out, this dependency wasn't really required.
Fixed: 343072269
Change-Id: Ic4de89ffbda2fc1b7e5d1f9cff95dc2b98584e5e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/190401
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
index 16d849b..63c58b2 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
@@ -89,25 +89,26 @@
}
}
- // Find the single entry point
- const sem::Function* entry_point = nullptr;
+ /// The pixel local struct
+ Hashset<const sem::Struct*, 1> pixel_local_structs;
+
+ // Find the entry points
for (auto* fn : src.AST().Functions()) {
- if (fn->IsEntryPoint()) {
- if (entry_point != nullptr) {
- TINT_ICE() << "PixelLocal transform requires that the SingleEntryPoint "
- "transform has already been run";
+ if (!fn->IsEntryPoint()) {
+ continue;
+ }
+
+ auto* entry_point = sem.Get(fn);
+
+ // Look for a `var<pixel_local>` used by the entry point...
+ for (auto* global : entry_point->TransitivelyReferencedGlobals()) {
+ if (global->AddressSpace() != core::AddressSpace::kPixelLocal) {
+ continue;
}
- entry_point = sem.Get(fn);
- // Look for a `var<pixel_local>` used by the entry point...
- for (auto* global : entry_point->TransitivelyReferencedGlobals()) {
- if (global->AddressSpace() != core::AddressSpace::kPixelLocal) {
- continue;
- }
-
- // Obtain struct of the pixel local.
- auto* pixel_local_str = global->Type()->UnwrapRef()->As<sem::Struct>();
-
+ // Obtain struct of the pixel local.
+ auto* pixel_local_str = global->Type()->UnwrapRef()->As<sem::Struct>();
+ if (pixel_local_structs.Add(pixel_local_str)) {
// Add an Color attribute to each member of the pixel_local structure.
for (auto* member : pixel_local_str->Members()) {
ctx.InsertBack(member->Declaration()->attributes,
@@ -115,12 +116,11 @@
ctx.InsertBack(member->Declaration()->attributes,
b.Disable(ast::DisabledValidation::kEntryPointParameter));
}
-
- TransformEntryPoint(entry_point, global, pixel_local_str);
- made_changes = true;
-
- break; // Only a single `var<pixel_local>` can be used by an entry point.
}
+
+ TransformEntryPoint(entry_point, global, pixel_local_str);
+ made_changes = true;
+ break; // Only a single `var<pixel_local>` can be used by an entry point.
}
}
@@ -217,14 +217,6 @@
auto& member_attrs = member->Declaration()->attributes;
add_member(member->Type(), ctx.Clone(member_attrs));
return_args.Push(b.MemberAccessor(call_result, ctx.Clone(member->Name())));
- if (auto* location = ast::GetAttribute<ast::LocationAttribute>(member_attrs)) {
- // Remove the @location attribute from the member of the inner function's
- // output structure.
- // Note: This will break other entry points that share the same output
- // structure, however this transform assumes that the SingleEntryPoint
- // transform will have already been run.
- ctx.Remove(member_attrs, location);
- }
}
} else {
// The entry point returned a non-structure
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local.h b/src/tint/lang/msl/writer/ast_raise/pixel_local.h
index 4459e59..2fa06d5 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local.h
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local.h
@@ -48,7 +48,6 @@
/// copied to the module-scope var before calling the 'inner' function.
/// * The outer function will have a new struct return type which holds both the pixel local members
/// and the returned value(s) of the 'inner' function.
-/// @note PixelLocal requires that the SingleEntryPoint transform has already been run
class PixelLocal final : public Castable<PixelLocal, ast::transform::Transform> {
public:
/// Transform configuration options
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc b/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc
index fba0af3..09776c1 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc
@@ -84,7 +84,7 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PixelLocalTest, UseInEntryPoint) {
+TEST_F(PixelLocalTest, UsedInSingleEntryPoint) {
auto* src = R"(
enable chromium_experimental_pixel_local;
@@ -133,6 +133,231 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(PixelLocalTest, SameVarUsedInMultipleEntryPoints) {
+ auto* src = R"(
+enable chromium_experimental_pixel_local;
+
+struct PixelLocal {
+ a : u32,
+}
+
+var<pixel_local> P : PixelLocal;
+
+@fragment
+fn F1() {
+ P.a += 10;
+}
+
+@fragment
+fn F2() {
+ P.a += 20;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_experimental_framebuffer_fetch;
+
+struct F1_res {
+ @location(1)
+ output_0 : u32,
+}
+
+@fragment
+fn F1(pixel_local_1 : PixelLocal) -> F1_res {
+ P = pixel_local_1;
+ F1_inner();
+ return F1_res(P.a);
+}
+
+struct F2_res {
+ @location(1)
+ output_0 : u32,
+}
+
+@fragment
+fn F2(pixel_local_2 : PixelLocal) -> F2_res {
+ P = pixel_local_2;
+ F2_inner();
+ return F2_res(P.a);
+}
+
+struct PixelLocal {
+ @color(1u) @internal(disable_validation__entry_point_parameter)
+ a : u32,
+}
+
+var<private> P : PixelLocal;
+
+fn F1_inner() {
+ P.a += 10;
+}
+
+fn F2_inner() {
+ P.a += 20;
+}
+)";
+
+ auto got = Run<PixelLocal>(src, Bindings({{0, 1}}));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PixelLocalTest, DifferentVarUsedInMultipleEntryPoints) {
+ auto* src = R"(
+enable chromium_experimental_pixel_local;
+
+struct PixelLocal {
+ a : u32,
+}
+
+var<pixel_local> P1 : PixelLocal;
+var<pixel_local> P2 : PixelLocal;
+
+@fragment
+fn F1() {
+ P1.a += 10;
+}
+
+@fragment
+fn F2() {
+ P2.a += 20;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_experimental_framebuffer_fetch;
+
+struct F1_res {
+ @location(1)
+ output_0 : u32,
+}
+
+@fragment
+fn F1(pixel_local_1 : PixelLocal) -> F1_res {
+ P1 = pixel_local_1;
+ F1_inner();
+ return F1_res(P1.a);
+}
+
+struct F2_res {
+ @location(1)
+ output_0 : u32,
+}
+
+@fragment
+fn F2(pixel_local_2 : PixelLocal) -> F2_res {
+ P2 = pixel_local_2;
+ F2_inner();
+ return F2_res(P2.a);
+}
+
+struct PixelLocal {
+ @color(1u) @internal(disable_validation__entry_point_parameter)
+ a : u32,
+}
+
+var<private> P1 : PixelLocal;
+
+var<private> P2 : PixelLocal;
+
+fn F1_inner() {
+ P1.a += 10;
+}
+
+fn F2_inner() {
+ P2.a += 20;
+}
+)";
+
+ auto got = Run<PixelLocal>(src, Bindings({{0, 1}}));
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PixelLocalTest, DifferentStructUsedInMultipleEntryPoints) {
+ auto* src = R"(
+enable chromium_experimental_pixel_local;
+
+struct PixelLocal1 {
+ a : u32,
+}
+
+struct PixelLocal2 {
+ a : u32,
+}
+
+var<pixel_local> P1 : PixelLocal1;
+var<pixel_local> P2 : PixelLocal2;
+
+@fragment
+fn F1() {
+ P1.a += 10;
+}
+
+@fragment
+fn F2() {
+ P2.a += 20;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_experimental_framebuffer_fetch;
+
+struct F1_res {
+ @location(1)
+ output_0 : u32,
+}
+
+@fragment
+fn F1(pixel_local_1 : PixelLocal1) -> F1_res {
+ P1 = pixel_local_1;
+ F1_inner();
+ return F1_res(P1.a);
+}
+
+struct F2_res {
+ @location(1)
+ output_0 : u32,
+}
+
+@fragment
+fn F2(pixel_local_2 : PixelLocal2) -> F2_res {
+ P2 = pixel_local_2;
+ F2_inner();
+ return F2_res(P2.a);
+}
+
+struct PixelLocal1 {
+ @color(1u) @internal(disable_validation__entry_point_parameter)
+ a : u32,
+}
+
+struct PixelLocal2 {
+ @color(1u) @internal(disable_validation__entry_point_parameter)
+ a : u32,
+}
+
+var<private> P1 : PixelLocal1;
+
+var<private> P2 : PixelLocal2;
+
+fn F1_inner() {
+ P1.a += 10;
+}
+
+fn F2_inner() {
+ P2.a += 20;
+}
+)";
+
+ auto got = Run<PixelLocal>(src, Bindings({{0, 1}}));
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(PixelLocalTest, UseInCallee) {
auto* src = R"(
enable chromium_experimental_pixel_local;
@@ -793,7 +1018,9 @@
var<private> P : PixelLocal;
struct Output {
+ @location(0)
x : vec4f,
+ @location(2)
y : vec4f,
}
@@ -808,5 +1035,87 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(PixelLocalTest, OutputStructUsedByMultipleEntryPoints) {
+ auto* src = R"(
+enable chromium_experimental_pixel_local;
+
+struct PixelLocal {
+ a : u32,
+ b : u32,
+}
+
+var<pixel_local> P : PixelLocal;
+
+struct Output {
+ @location(0) x : vec4f,
+ @location(2) y : vec4f,
+}
+
+@fragment
+fn F1() -> Output {
+ P.a += 42;
+ return Output(vec4f(1), vec4f(9));
+}
+
+@fragment
+fn F2() -> Output {
+ return Output(vec4f(1), vec4f(9));
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_experimental_framebuffer_fetch;
+
+struct F1_res {
+ @location(1)
+ output_0 : u32,
+ @location(5)
+ output_1 : u32,
+ @location(0)
+ output_2 : vec4<f32>,
+ @location(2)
+ output_3 : vec4<f32>,
+}
+
+@fragment
+fn F1(pixel_local_1 : PixelLocal) -> F1_res {
+ P = pixel_local_1;
+ let result = F1_inner();
+ return F1_res(P.a, P.b, result.x, result.y);
+}
+
+struct PixelLocal {
+ @color(1u) @internal(disable_validation__entry_point_parameter)
+ a : u32,
+ @color(5u) @internal(disable_validation__entry_point_parameter)
+ b : u32,
+}
+
+var<private> P : PixelLocal;
+
+struct Output {
+ @location(0)
+ x : vec4f,
+ @location(2)
+ y : vec4f,
+}
+
+fn F1_inner() -> Output {
+ P.a += 42;
+ return Output(vec4f(1), vec4f(9));
+}
+
+@fragment
+fn F2() -> Output {
+ return Output(vec4f(1), vec4f(9));
+}
+)";
+
+ auto got = Run<PixelLocal>(src, Bindings({{0, 1}, {1, 5}}));
+
+ EXPECT_EQ(expect, str(got));
+}
+
} // namespace
} // namespace tint::msl::writer
diff --git a/src/tint/lang/msl/writer/writer_ast_fuzz.cc b/src/tint/lang/msl/writer/writer_ast_fuzz.cc
index 12c1a55..1c6e09a 100644
--- a/src/tint/lang/msl/writer/writer_ast_fuzz.cc
+++ b/src/tint/lang/msl/writer/writer_ast_fuzz.cc
@@ -36,8 +36,7 @@
namespace {
void ASTFuzzer(const tint::Program& program, const fuzz::wgsl::Context& context, Options options) {
- if (program.AST().HasOverrides() ||
- context.program_properties.Contains(fuzz::wgsl::ProgramProperties::kMultipleEntryPoints)) {
+ if (program.AST().HasOverrides()) {
// MSL writer assumes the SubstituteOverride and SingleEntryPoint transforms have been run
return;
}