writer/msl: Implement invariant attribute
Report whether one was generated so that Dawn knows to use the
`-fpreserve-invariance` compiler option.
Bug: tint:772
Change-Id: Ife1eb05265646727dc864f12f983781af4df3777
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57644
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/transform/canonicalize_entry_point_io.cc b/src/transform/canonicalize_entry_point_io.cc
index e8bc3dc..bd30b0d 100644
--- a/src/transform/canonicalize_entry_point_io.cc
+++ b/src/transform/canonicalize_entry_point_io.cc
@@ -84,9 +84,9 @@
for (auto* member : struct_ty->members()) {
ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->decorations(), [](const ast::Decoration* deco) {
- return deco
- ->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration,
- ast::LocationDecoration>();
+ return deco->IsAnyOf<
+ ast::BuiltinDecoration, ast::InterpolateDecoration,
+ ast::InvariantDecoration, ast::LocationDecoration>();
});
new_struct_members.push_back(
ctx.dst->Member(ctx.Clone(member->symbol()),
@@ -156,9 +156,9 @@
ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) {
- return !deco->IsAnyOf<ast::BuiltinDecoration,
- ast::InterpolateDecoration,
- ast::LocationDecoration>();
+ return !deco->IsAnyOf<
+ ast::BuiltinDecoration, ast::InterpolateDecoration,
+ ast::InvariantDecoration, ast::LocationDecoration>();
});
if (cfg->builtin_style == BuiltinStyle::kParameter &&
@@ -246,9 +246,9 @@
ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) {
- return !deco->IsAnyOf<ast::BuiltinDecoration,
- ast::InterpolateDecoration,
- ast::LocationDecoration>();
+ return !deco->IsAnyOf<
+ ast::BuiltinDecoration, ast::InterpolateDecoration,
+ ast::InvariantDecoration, ast::LocationDecoration>();
});
auto symbol = ctx.Clone(member->Declaration()->symbol());
auto* member_ty = ctx.Clone(member->Declaration()->type());
diff --git a/src/transform/canonicalize_entry_point_io_test.cc b/src/transform/canonicalize_entry_point_io_test.cc
index d0a59e3..1f12d40 100644
--- a/src/transform/canonicalize_entry_point_io_test.cc
+++ b/src/transform/canonicalize_entry_point_io_test.cc
@@ -691,6 +691,58 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(CanonicalizeEntryPointIOTest, InvariantAttributes) {
+ auto* src = R"(
+struct VertexOut {
+ [[builtin(position), invariant]] pos : vec4<f32>;
+};
+
+[[stage(vertex)]]
+fn main1() -> VertexOut {
+ return VertexOut();
+}
+
+[[stage(vertex)]]
+fn main2() -> [[builtin(position), invariant]] vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = R"(
+struct VertexOut {
+ pos : vec4<f32>;
+};
+
+struct tint_symbol {
+ [[builtin(position), invariant]]
+ pos : vec4<f32>;
+};
+
+[[stage(vertex)]]
+fn main1() -> tint_symbol {
+ let tint_symbol_1 : VertexOut = VertexOut();
+ return tint_symbol(tint_symbol_1.pos);
+}
+
+struct tint_symbol_2 {
+ [[builtin(position), invariant]]
+ value : vec4<f32>;
+};
+
+[[stage(vertex)]]
+fn main2() -> tint_symbol_2 {
+ return tint_symbol_2(vec4<f32>());
+}
+)";
+
+ DataMap data;
+ data.Add<CanonicalizeEntryPointIO::Config>(
+ CanonicalizeEntryPointIO::BuiltinStyle::kStructMember);
+ auto got = Run<CanonicalizeEntryPointIO>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutDecorations) {
auto* src = R"(
[[block]]
diff --git a/src/writer/msl/generator.cc b/src/writer/msl/generator.cc
index 45287fe..215d650 100644
--- a/src/writer/msl/generator.cc
+++ b/src/writer/msl/generator.cc
@@ -48,6 +48,7 @@
result.success = impl->Generate();
result.error = impl->error();
result.msl = impl->result();
+ result.has_invariant_attribute = impl->HasInvariant();
return result;
}
diff --git a/src/writer/msl/generator.h b/src/writer/msl/generator.h
index b4891c9..5028458 100644
--- a/src/writer/msl/generator.h
+++ b/src/writer/msl/generator.h
@@ -63,6 +63,9 @@
/// True if the shader needs a UBO of buffer sizes.
bool needs_storage_buffer_sizes = false;
+
+ /// True if the generated shader uses the invariant attribute.
+ bool has_invariant_attribute = false;
};
/// Generate MSL for a program, according to a set of configuration options. The
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 96ebba6..05768ae 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -2134,6 +2134,9 @@
return false;
}
out << " [[" << attr << "]]";
+ } else if (deco->Is<ast::InvariantDecoration>()) {
+ out << " [[invariant]]";
+ has_invariant_ = true;
} else if (!deco->IsAnyOf<ast::StructMemberOffsetDecoration,
ast::StructMemberAlignDecoration,
ast::StructMemberSizeDecoration>()) {
diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h
index 49333e3..fde3c9a 100644
--- a/src/writer/msl/generator_impl.h
+++ b/src/writer/msl/generator_impl.h
@@ -61,6 +61,9 @@
/// @returns true on successful generation; false otherwise
bool Generate();
+ /// @returns true if an invariant attribute was generated
+ bool HasInvariant() { return has_invariant_; }
+
/// Handles generating a declared type
/// @param ty the declared type to generate
/// @returns true if the declared type was emitted
@@ -302,6 +305,9 @@
/// Name of atomicCompareExchangeWeak() helper for the given pointer storage
/// class.
StorageClassToString atomicCompareExchangeWeak_;
+
+ /// True if an invariant attribute has been generated.
+ bool has_invariant_ = false;
};
} // namespace msl
diff --git a/src/writer/msl/generator_impl_test.cc b/src/writer/msl/generator_impl_test.cc
index 72f32b0..f7c23e5 100644
--- a/src/writer/msl/generator_impl_test.cc
+++ b/src/writer/msl/generator_impl_test.cc
@@ -88,6 +88,55 @@
MslBuiltinData{ast::Builtin::kSampleIndex, "sample_id"},
MslBuiltinData{ast::Builtin::kSampleMask, "sample_mask"}));
+TEST_F(MslGeneratorImplTest, HasInvariantAttribute_True) {
+ auto* out = Structure(
+ "Out", {Member("pos", ty.vec4<f32>(),
+ {Builtin(ast::Builtin::kPosition), Invariant()})});
+ Func("vert_main", ast::VariableList{}, ty.Of(out),
+ {Return(Construct(ty.Of(out)))}, {Stage(ast::PipelineStage::kVertex)});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_TRUE(gen.HasInvariant());
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+struct Out {
+ float4 pos [[position]] [[invariant]];
+};
+
+vertex Out vert_main() {
+ return {};
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, HasInvariantAttribute_False) {
+ auto* out = Structure("Out", {Member("pos", ty.vec4<f32>(),
+ {Builtin(ast::Builtin::kPosition)})});
+ Func("vert_main", ast::VariableList{}, ty.Of(out),
+ {Return(Construct(ty.Of(out)))}, {Stage(ast::PipelineStage::kVertex)});
+
+ GeneratorImpl& gen = Build();
+
+ ASSERT_TRUE(gen.Generate()) << gen.error();
+ EXPECT_FALSE(gen.HasInvariant());
+ EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+struct Out {
+ float4 pos [[position]];
+};
+
+vertex Out vert_main() {
+ return {};
+}
+
+)");
+}
+
} // namespace
} // namespace msl
} // namespace writer
diff --git a/test/shader_io/invariant.wgsl.expected.msl b/test/shader_io/invariant.wgsl.expected.msl
index 6e1ba46..5543bd0 100644
--- a/test/shader_io/invariant.wgsl.expected.msl
+++ b/test/shader_io/invariant.wgsl.expected.msl
@@ -1,10 +1,12 @@
-SKIP: FAILED
+#include <metal_stdlib>
-../../src/writer/msl/generator_impl.cc:1990 internal compiler error: unhandled struct member attribute: invariant
-********************************************************************
-* The tint shader compiler has encountered an unexpected error. *
-* *
-* Please help us fix this issue by submitting a bug report at *
-* crbug.com/tint with the source program that triggered the bug. *
-********************************************************************
+using namespace metal;
+struct tint_symbol_1 {
+ float4 value [[position]] [[invariant]];
+};
+
+vertex tint_symbol_1 tint_symbol() {
+ tint_symbol_1 const tint_symbol_2 = {.value=float4()};
+ return tint_symbol_2;
+}
diff --git a/test/shader_io/invariant_struct_member.wgsl.expected.msl b/test/shader_io/invariant_struct_member.wgsl.expected.msl
index 6e1ba46..545642e 100644
--- a/test/shader_io/invariant_struct_member.wgsl.expected.msl
+++ b/test/shader_io/invariant_struct_member.wgsl.expected.msl
@@ -1,10 +1,16 @@
-SKIP: FAILED
+#include <metal_stdlib>
-../../src/writer/msl/generator_impl.cc:1990 internal compiler error: unhandled struct member attribute: invariant
-********************************************************************
-* The tint shader compiler has encountered an unexpected error. *
-* *
-* Please help us fix this issue by submitting a bug report at *
-* crbug.com/tint with the source program that triggered the bug. *
-********************************************************************
+using namespace metal;
+struct Out {
+ float4 pos;
+};
+struct tint_symbol_1 {
+ float4 pos [[position]] [[invariant]];
+};
+
+vertex tint_symbol_1 tint_symbol() {
+ Out const tint_symbol_2 = {};
+ tint_symbol_1 const tint_symbol_3 = {.pos=tint_symbol_2.pos};
+ return tint_symbol_3;
+}