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()) {
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 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
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 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
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());

View File

@ -691,6 +691,58 @@ fn frag_main(tint_symbol_2 : tint_symbol_3) {
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]]

View File

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

View File

@ -63,6 +63,9 @@ struct Result {
/// 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

View File

@ -2134,6 +2134,9 @@ bool GeneratorImpl::EmitStructType(const sem::Struct* str) {
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>()) {

View File

@ -61,6 +61,9 @@ class GeneratorImpl : public TextGenerator {
/// @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 @@ class GeneratorImpl : public TextGenerator {
/// 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

View File

@ -88,6 +88,55 @@ INSTANTIATE_TEST_SUITE_P(
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

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
********************************************************************
* 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;
}

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
********************************************************************
* 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;
}