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>
This commit is contained in:
James Price 2021-07-12 16:11:41 +00:00 committed by Tint LUCI CQ
parent fd5829e5ea
commit 2c2aa2a76a
9 changed files with 147 additions and 25 deletions

View File

@ -84,9 +84,9 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
for (auto* member : struct_ty->members()) { for (auto* member : struct_ty->members()) {
ast::DecorationList new_decorations = RemoveDecorations( ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->decorations(), [](const ast::Decoration* deco) { &ctx, member->decorations(), [](const ast::Decoration* deco) {
return deco return deco->IsAnyOf<
->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration, ast::BuiltinDecoration, ast::InterpolateDecoration,
ast::LocationDecoration>(); ast::InvariantDecoration, ast::LocationDecoration>();
}); });
new_struct_members.push_back( new_struct_members.push_back(
ctx.dst->Member(ctx.Clone(member->symbol()), ctx.dst->Member(ctx.Clone(member->symbol()),
@ -156,9 +156,9 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
ast::DecorationList new_decorations = RemoveDecorations( ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->Declaration()->decorations(), &ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) { [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<
ast::InterpolateDecoration, ast::BuiltinDecoration, ast::InterpolateDecoration,
ast::LocationDecoration>(); ast::InvariantDecoration, ast::LocationDecoration>();
}); });
if (cfg->builtin_style == BuiltinStyle::kParameter && if (cfg->builtin_style == BuiltinStyle::kParameter &&
@ -246,9 +246,9 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
ast::DecorationList new_decorations = RemoveDecorations( ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->Declaration()->decorations(), &ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) { [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<
ast::InterpolateDecoration, ast::BuiltinDecoration, ast::InterpolateDecoration,
ast::LocationDecoration>(); ast::InvariantDecoration, ast::LocationDecoration>();
}); });
auto symbol = ctx.Clone(member->Declaration()->symbol()); auto symbol = ctx.Clone(member->Declaration()->symbol());
auto* member_ty = ctx.Clone(member->Declaration()->type()); auto* member_ty = ctx.Clone(member->Declaration()->type());

View File

@ -691,6 +691,58 @@ fn frag_main(tint_symbol_2 : tint_symbol_3) {
EXPECT_EQ(expect, str(got)); 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) { TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutDecorations) {
auto* src = R"( auto* src = R"(
[[block]] [[block]]

View File

@ -48,6 +48,7 @@ Result Generate(const Program* program, const Options& options) {
result.success = impl->Generate(); result.success = impl->Generate();
result.error = impl->error(); result.error = impl->error();
result.msl = impl->result(); result.msl = impl->result();
result.has_invariant_attribute = impl->HasInvariant();
return result; return result;
} }

View File

@ -63,6 +63,9 @@ struct Result {
/// True if the shader needs a UBO of buffer sizes. /// True if the shader needs a UBO of buffer sizes.
bool needs_storage_buffer_sizes = false; 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 /// Generate MSL for a program, according to a set of configuration options. The

View File

@ -2134,6 +2134,9 @@ bool GeneratorImpl::EmitStructType(const sem::Struct* str) {
return false; return false;
} }
out << " [[" << attr << "]]"; out << " [[" << attr << "]]";
} else if (deco->Is<ast::InvariantDecoration>()) {
out << " [[invariant]]";
has_invariant_ = true;
} else if (!deco->IsAnyOf<ast::StructMemberOffsetDecoration, } else if (!deco->IsAnyOf<ast::StructMemberOffsetDecoration,
ast::StructMemberAlignDecoration, ast::StructMemberAlignDecoration,
ast::StructMemberSizeDecoration>()) { ast::StructMemberSizeDecoration>()) {

View File

@ -61,6 +61,9 @@ class GeneratorImpl : public TextGenerator {
/// @returns true on successful generation; false otherwise /// @returns true on successful generation; false otherwise
bool Generate(); bool Generate();
/// @returns true if an invariant attribute was generated
bool HasInvariant() { return has_invariant_; }
/// Handles generating a declared type /// Handles generating a declared type
/// @param ty the declared type to generate /// @param ty the declared type to generate
/// @returns true if the declared type was emitted /// @returns true if the declared type was emitted
@ -302,6 +305,9 @@ class GeneratorImpl : public TextGenerator {
/// Name of atomicCompareExchangeWeak() helper for the given pointer storage /// Name of atomicCompareExchangeWeak() helper for the given pointer storage
/// class. /// class.
StorageClassToString atomicCompareExchangeWeak_; StorageClassToString atomicCompareExchangeWeak_;
/// True if an invariant attribute has been generated.
bool has_invariant_ = false;
}; };
} // namespace msl } // namespace msl

View File

@ -88,6 +88,55 @@ INSTANTIATE_TEST_SUITE_P(
MslBuiltinData{ast::Builtin::kSampleIndex, "sample_id"}, MslBuiltinData{ast::Builtin::kSampleIndex, "sample_id"},
MslBuiltinData{ast::Builtin::kSampleMask, "sample_mask"})); 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
} // namespace msl } // namespace msl
} // namespace writer } // namespace writer

View File

@ -1,10 +1,12 @@
SKIP: FAILED #include <metal_stdlib>
../../src/writer/msl/generator_impl.cc:1990 internal compiler error: unhandled struct member attribute: invariant using namespace metal;
******************************************************************** struct tint_symbol_1 {
* The tint shader compiler has encountered an unexpected error. * float4 value [[position]] [[invariant]];
* * };
* Please help us fix this issue by submitting a bug report at *
* crbug.com/tint with the source program that triggered the bug. * vertex tint_symbol_1 tint_symbol() {
******************************************************************** tint_symbol_1 const tint_symbol_2 = {.value=float4()};
return tint_symbol_2;
}

View File

@ -1,10 +1,16 @@
SKIP: FAILED #include <metal_stdlib>
../../src/writer/msl/generator_impl.cc:1990 internal compiler error: unhandled struct member attribute: invariant using namespace metal;
******************************************************************** struct Out {
* The tint shader compiler has encountered an unexpected error. * float4 pos;
* * };
* Please help us fix this issue by submitting a bug report at * struct tint_symbol_1 {
* crbug.com/tint with the source program that triggered the bug. * 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;
}