From 9536ced0148a1c645f595326201200bb1fbe6975 Mon Sep 17 00:00:00 2001 From: James Price Date: Wed, 15 Mar 2023 00:33:38 +0000 Subject: [PATCH] tint: Support @diagnostic on while statements Bug: tint:1809 Change-Id: I9593539d258d16a68c9ff1cfd2cad52e28fad65a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/124100 Commit-Queue: James Price Reviewed-by: Ben Clayton Kokoro: Kokoro --- src/tint/ast/while_statement.cc | 14 +++- src/tint/ast/while_statement.h | 7 +- src/tint/ast/while_statement_test.cc | 11 +++ src/tint/program_builder.h | 25 ++++-- src/tint/reader/wgsl/parser_impl.cc | 9 ++- src/tint/reader/wgsl/parser_impl.h | 5 +- .../reader/wgsl/parser_impl_statement_test.cc | 12 +++ .../wgsl/parser_impl_while_stmt_test.cc | 32 ++++++-- .../resolver/attribute_validation_test.cc | 33 ++++++++ src/tint/resolver/resolver.cc | 3 + src/tint/resolver/uniformity_test.cc | 49 ++++++++++++ src/tint/sem/diagnostic_severity_test.cc | 17 ++++- src/tint/writer/wgsl/generator_impl.cc | 8 ++ .../while_loop_attribute.wgsl | 7 ++ ...hile_loop_attribute.wgsl.expected.dxc.hlsl | 31 ++++++++ ...hile_loop_attribute.wgsl.expected.fxc.hlsl | 31 ++++++++ .../while_loop_attribute.wgsl.expected.glsl | 31 ++++++++ .../while_loop_attribute.wgsl.expected.msl | 30 ++++++++ .../while_loop_attribute.wgsl.expected.spvasm | 76 +++++++++++++++++++ .../while_loop_attribute.wgsl.expected.wgsl | 18 +++++ 20 files changed, 424 insertions(+), 25 deletions(-) create mode 100644 test/tint/diagnostic_filtering/while_loop_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.wgsl diff --git a/src/tint/ast/while_statement.cc b/src/tint/ast/while_statement.cc index 160af4b582..47cf2bbc1f 100644 --- a/src/tint/ast/while_statement.cc +++ b/src/tint/ast/while_statement.cc @@ -14,6 +14,8 @@ #include "src/tint/ast/while_statement.h" +#include + #include "src/tint/program_builder.h" TINT_INSTANTIATE_TYPEINFO(tint::ast::WhileStatement); @@ -24,13 +26,18 @@ WhileStatement::WhileStatement(ProgramID pid, NodeID nid, const Source& src, const Expression* cond, - const BlockStatement* b) - : Base(pid, nid, src), condition(cond), body(b) { + const BlockStatement* b, + utils::VectorRef attrs) + : Base(pid, nid, src), condition(cond), body(b), attributes(std::move(attrs)) { TINT_ASSERT(AST, cond); TINT_ASSERT(AST, body); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id); + for (auto* attr : attributes) { + TINT_ASSERT(AST, attr); + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id); + } } WhileStatement::WhileStatement(WhileStatement&&) = default; @@ -43,7 +50,8 @@ const WhileStatement* WhileStatement::Clone(CloneContext* ctx) const { auto* cond = ctx->Clone(condition); auto* b = ctx->Clone(body); - return ctx->dst->create(src, cond, b); + auto attrs = ctx->Clone(attributes); + return ctx->dst->create(src, cond, b, std::move(attrs)); } } // namespace tint::ast diff --git a/src/tint/ast/while_statement.h b/src/tint/ast/while_statement.h index 4e8dd7e2a1..b2b91dc8cf 100644 --- a/src/tint/ast/while_statement.h +++ b/src/tint/ast/while_statement.h @@ -30,11 +30,13 @@ class WhileStatement final : public Castable { /// @param source the for loop statement source /// @param condition the optional loop condition expression /// @param body the loop body + /// @param attributes the while statement attributes WhileStatement(ProgramID pid, NodeID nid, const Source& source, const Expression* condition, - const BlockStatement* body); + const BlockStatement* body, + utils::VectorRef attributes); /// Move constructor WhileStatement(WhileStatement&&); ~WhileStatement() override; @@ -50,6 +52,9 @@ class WhileStatement final : public Castable { /// The loop body block const BlockStatement* const body; + + /// The attribute list + const utils::Vector attributes; }; } // namespace tint::ast diff --git a/src/tint/ast/while_statement_test.cc b/src/tint/ast/while_statement_test.cc index 73c9e5614f..ef287fc131 100644 --- a/src/tint/ast/while_statement_test.cc +++ b/src/tint/ast/while_statement_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "gmock/gmock.h" #include "gtest/gtest-spi.h" #include "src/tint/ast/binary_expression.h" #include "src/tint/ast/test_helper.h" @@ -41,6 +42,16 @@ TEST_F(WhileStatementTest, Creation_WithSource) { EXPECT_EQ(src.range.begin.column, 2u); } +TEST_F(WhileStatementTest, Creation_WithAttributes) { + auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "foo"); + auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "bar"); + auto* cond = create(BinaryOp::kLessThan, Expr("i"), Expr(5_u)); + auto* body = Block(Return()); + auto* l = While(cond, body, utils::Vector{attr1, attr2}); + + EXPECT_THAT(l->attributes, testing::ElementsAre(attr1, attr2)); +} + TEST_F(WhileStatementTest, Assert_Null_Cond) { EXPECT_FATAL_FAILURE( { diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index a2d4f484b1..dc50acfb01 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -3311,25 +3311,34 @@ class ProgramBuilder { return create(init, Expr(std::forward(cond)), cont, body); } - /// Creates a ast::WhileStatement with input body and condition. + /// Creates a ast::WhileStatement with input body, condition, and optional attributes. /// @param source the source information /// @param cond the loop condition /// @param body the loop body + /// @param attributes optional attributes /// @returns the while statement pointer template - const ast::WhileStatement* While(const Source& source, - COND&& cond, - const ast::BlockStatement* body) { - return create(source, Expr(std::forward(cond)), body); + const ast::WhileStatement* While( + const Source& source, + COND&& cond, + const ast::BlockStatement* body, + utils::VectorRef attributes = utils::Empty) { + return create(source, Expr(std::forward(cond)), body, + std::move(attributes)); } - /// Creates a ast::WhileStatement with given condition and body. + /// Creates a ast::WhileStatement with input body, condition, and optional attributes. /// @param cond the condition /// @param body the loop body + /// @param attributes optional attributes /// @returns the while loop statement pointer template - const ast::WhileStatement* While(COND&& cond, const ast::BlockStatement* body) { - return create(Expr(std::forward(cond)), body); + const ast::WhileStatement* While( + COND&& cond, + const ast::BlockStatement* body, + utils::VectorRef attributes = utils::Empty) { + return create(Expr(std::forward(cond)), body, + std::move(attributes)); } /// Creates a ast::VariableDeclStatement for the input variable diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc index 5f901e0316..7936d658e4 100644 --- a/src/tint/reader/wgsl/parser_impl.cc +++ b/src/tint/reader/wgsl/parser_impl.cc @@ -1296,7 +1296,7 @@ Maybe ParserImpl::statement() { return stmt_for.value; } - auto stmt_while = while_statement(); + auto stmt_while = while_statement(attrs.value); if (stmt_while.errored) { return Failure::kErrored; } @@ -1902,8 +1902,8 @@ Maybe ParserImpl::for_statement() { } // while_statement -// : WHILE expression compound_statement -Maybe ParserImpl::while_statement() { +// : attribute* WHILE expression compound_statement +Maybe ParserImpl::while_statement(AttributeList& attrs) { Source source; if (!match(Token::Type::kWhile, &source)) { return Failure::kNoMatch; @@ -1922,7 +1922,8 @@ Maybe ParserImpl::while_statement() { return Failure::kErrored; } - return create(source, condition.value, body.value); + TINT_DEFER(attrs.Clear()); + return create(source, condition.value, body.value, std::move(attrs)); } // func_call_statement diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h index dd0a96c8d1..57550e057b 100644 --- a/src/tint/reader/wgsl/parser_impl.h +++ b/src/tint/reader/wgsl/parser_impl.h @@ -520,9 +520,10 @@ class ParserImpl { /// Parses a `for_statement` grammar element /// @returns the parsed for loop or nullptr Maybe for_statement(); - /// Parses a `while_statement` grammar element + /// Parses a `while_statement` grammar element, with the attribute list provided as `attrs`. + /// @param attrs the list of attributes for the statement /// @returns the parsed while loop or nullptr - Maybe while_statement(); + Maybe while_statement(AttributeList& attrs); /// Parses a `break_if_statement` grammar element /// @returns the parsed statement or nullptr Maybe break_if_statement(); diff --git a/src/tint/reader/wgsl/parser_impl_statement_test.cc b/src/tint/reader/wgsl/parser_impl_statement_test.cc index 8b50d10145..d10e54902a 100644 --- a/src/tint/reader/wgsl/parser_impl_statement_test.cc +++ b/src/tint/reader/wgsl/parser_impl_statement_test.cc @@ -350,6 +350,18 @@ TEST_F(ParserImplTest, Statement_ConsumedAttributes_Switch) { EXPECT_EQ(s->attributes.Length(), 1u); } +TEST_F(ParserImplTest, Statement_ConsumedAttributes_While) { + auto p = parser("@diagnostic(off, derivative_uniformity) while (false) {}"); + auto e = p->statement(); + ASSERT_FALSE(p->has_error()) << p->error(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + + auto* s = As(e.value); + ASSERT_NE(s, nullptr); + EXPECT_EQ(s->attributes.Length(), 1u); +} + TEST_F(ParserImplTest, Statement_UnexpectedAttributes) { auto p = parser("@diagnostic(off, derivative_uniformity) return;"); auto e = p->statement(); diff --git a/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc index d61843ea37..dcbb59b084 100644 --- a/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc +++ b/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc @@ -24,7 +24,8 @@ using WhileStmtTest = ParserImplTest; // Test an empty while loop. TEST_F(WhileStmtTest, Empty) { auto p = parser("while true { }"); - auto wl = p->while_statement(); + ParserImpl::AttributeList attrs; + auto wl = p->while_statement(attrs); EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(wl.errored); ASSERT_TRUE(wl.matched); @@ -35,7 +36,8 @@ TEST_F(WhileStmtTest, Empty) { // Test an empty while loop with parentheses. TEST_F(WhileStmtTest, EmptyWithParentheses) { auto p = parser("while (true) { }"); - auto wl = p->while_statement(); + ParserImpl::AttributeList attrs; + auto wl = p->while_statement(attrs); EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(wl.errored); ASSERT_TRUE(wl.matched); @@ -46,7 +48,8 @@ TEST_F(WhileStmtTest, EmptyWithParentheses) { // Test a while loop with non-empty body. TEST_F(WhileStmtTest, Body) { auto p = parser("while (true) { discard; }"); - auto wl = p->while_statement(); + ParserImpl::AttributeList attrs; + auto wl = p->while_statement(attrs); EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(wl.errored); ASSERT_TRUE(wl.matched); @@ -58,7 +61,8 @@ TEST_F(WhileStmtTest, Body) { // Test a while loop with complex condition. TEST_F(WhileStmtTest, ComplexCondition) { auto p = parser("while (a + 1 - 2) == 3 { }"); - auto wl = p->while_statement(); + ParserImpl::AttributeList attrs; + auto wl = p->while_statement(attrs); EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(wl.errored); ASSERT_TRUE(wl.matched); @@ -69,7 +73,8 @@ TEST_F(WhileStmtTest, ComplexCondition) { // Test a while loop with complex condition, with parentheses. TEST_F(WhileStmtTest, ComplexConditionWithParentheses) { auto p = parser("while ((a + 1 - 2) == 3) { }"); - auto wl = p->while_statement(); + ParserImpl::AttributeList attrs; + auto wl = p->while_statement(attrs); EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(wl.errored); ASSERT_TRUE(wl.matched); @@ -77,11 +82,26 @@ TEST_F(WhileStmtTest, ComplexConditionWithParentheses) { EXPECT_TRUE(wl->body->Empty()); } +// Test a while loop with attributes. +TEST_F(WhileStmtTest, WithAttributes) { + auto p = parser("@diagnostic(off, derivative_uniformity) while true { }"); + auto attrs = p->attribute_list(); + auto wl = p->while_statement(attrs.value); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_FALSE(wl.errored); + ASSERT_TRUE(wl.matched); + + EXPECT_TRUE(attrs->IsEmpty()); + ASSERT_EQ(wl->attributes.Length(), 1u); + EXPECT_TRUE(wl->attributes[0]->Is()); +} + class WhileStmtErrorTest : public ParserImplTest { public: void TestWhileWithError(std::string for_str, std::string error_str) { auto p_for = parser(for_str); - auto e_for = p_for->while_statement(); + ParserImpl::AttributeList attrs; + auto e_for = p_for->while_statement(attrs); EXPECT_FALSE(e_for.matched); EXPECT_TRUE(e_for.errored); diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc index 1a8de3bff8..0b80300f70 100644 --- a/src/tint/resolver/attribute_validation_test.cc +++ b/src/tint/resolver/attribute_validation_test.cc @@ -1111,6 +1111,39 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest, TestParams{AttributeKind::kWorkgroup, false}, TestParams{AttributeKind::kBindingAndGroup, false})); +using WhileStatementAttributeTest = TestWithParams; +TEST_P(WhileStatementAttributeTest, IsValid) { + auto& params = GetParam(); + + WrapInFunction( + While(Expr(false), Block(), createAttributes(Source{{12, 34}}, *this, params.kind))); + + if (params.should_pass) { + EXPECT_TRUE(r()->Resolve()) << r()->error(); + } else { + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for while statements"); + } +} +INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest, + WhileStatementAttributeTest, + testing::Values(TestParams{AttributeKind::kAlign, false}, + TestParams{AttributeKind::kBinding, false}, + TestParams{AttributeKind::kBuiltin, false}, + TestParams{AttributeKind::kDiagnostic, true}, + TestParams{AttributeKind::kGroup, false}, + TestParams{AttributeKind::kId, false}, + TestParams{AttributeKind::kInterpolate, false}, + TestParams{AttributeKind::kInvariant, false}, + TestParams{AttributeKind::kLocation, false}, + TestParams{AttributeKind::kMustUse, false}, + TestParams{AttributeKind::kOffset, false}, + TestParams{AttributeKind::kSize, false}, + TestParams{AttributeKind::kStage, false}, + TestParams{AttributeKind::kStride, false}, + TestParams{AttributeKind::kWorkgroup, false}, + TestParams{AttributeKind::kBindingAndGroup, false})); + namespace BlockStatementTests { class BlockStatementTest : public TestWithParams { protected: diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 1b5c71aaf7..2425f518ac 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -4278,6 +4278,9 @@ SEM* Resolver::StatementScope(const ast::Statement* ast, SEM* sem, F&& callback) [&](const ast::SwitchStatement* s) { return handle_attributes(s, sem, "switch statements"); }, + [&](const ast::WhileStatement* w) { + return handle_attributes(w, sem, "while statements"); + }, [&](Default) { return true; })) { return nullptr; } diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc index e7ee8cd7f8..274e5ad06a 100644 --- a/src/tint/resolver/uniformity_test.cc +++ b/src/tint/resolver/uniformity_test.cc @@ -8504,6 +8504,55 @@ fn foo() { } } +TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnWhileStatement_CallInCondition) { + auto& param = GetParam(); + utils::StringStream ss; + ss << R"( +@group(0) @binding(0) var non_uniform : i32; +fn foo() { + )" + << "@diagnostic(" << param << ", derivative_uniformity)" + << R"(while (non_uniform == 42 && dpdx(1.0) > 0.0) { + } +} +)"; + + RunTest(ss.str(), param != builtin::DiagnosticSeverity::kError); + if (param == builtin::DiagnosticSeverity::kOff) { + EXPECT_TRUE(error_.empty()); + } else { + utils::StringStream err; + err << ToStr(param) << ": 'dpdx' must only be called"; + EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); + } +} + +TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnWhileStatement_CallInBody) { + auto& param = GetParam(); + utils::StringStream ss; + ss << R"( +@group(0) @binding(0) var non_uniform : i32; +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; +fn foo() { + )" + << "@diagnostic(" << param << ", derivative_uniformity)" + << R"(while (non_uniform == 42) { + let color = textureSample(t, s, vec2(0, 0)); + } +} +)"; + + RunTest(ss.str(), param != builtin::DiagnosticSeverity::kError); + if (param == builtin::DiagnosticSeverity::kOff) { + EXPECT_TRUE(error_.empty()); + } else { + utils::StringStream err; + err << ToStr(param) << ": 'textureSample' must only be called"; + EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); + } +} + INSTANTIATE_TEST_SUITE_P(UniformityAnalysisTest, UniformityAnalysisDiagnosticFilterTest, ::testing::Values(builtin::DiagnosticSeverity::kError, diff --git a/src/tint/sem/diagnostic_severity_test.cc b/src/tint/sem/diagnostic_severity_test.cc index 328e589b31..b48766350a 100644 --- a/src/tint/sem/diagnostic_severity_test.cc +++ b/src/tint/sem/diagnostic_severity_test.cc @@ -50,6 +50,11 @@ class DiagnosticSeverityTest : public TestHelper { // return; // } // } + // + // @diagnostic(error, chromium_unreachable_code) + // while (false) @diagnostic(warning, chromium_unreachable_code) { + // return; + // } // } // } // @@ -64,6 +69,8 @@ class DiagnosticSeverityTest : public TestHelper { auto else_body_severity = builtin::DiagnosticSeverity::kInfo; auto switch_severity = builtin::DiagnosticSeverity::kError; auto case_severity = builtin::DiagnosticSeverity::kWarning; + auto while_severity = builtin::DiagnosticSeverity::kError; + auto while_body_severity = builtin::DiagnosticSeverity::kWarning; auto attr = [&](auto severity) { return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")}; }; @@ -74,6 +81,7 @@ class DiagnosticSeverityTest : public TestHelper { auto* return_foo_block = Return(); auto* return_foo_case = Return(); auto* return_foo_default = Return(); + auto* return_foo_while = Return(); auto* else_stmt = Block(utils::Vector{return_foo_else}, attr(else_body_severity)); auto* elseif = If(Expr(false), Block(return_foo_elseif), Else(else_stmt)); auto* if_foo = If(Expr(true), Block(utils::Vector{return_foo_if}, attr(if_body_severity)), @@ -82,7 +90,10 @@ class DiagnosticSeverityTest : public TestHelper { Case(CaseSelector(0_a), Block(utils::Vector{return_foo_case}, attr(case_severity))); auto* swtch = Switch(42_a, utils::Vector{case_stmt, DefaultCase(Block(return_foo_default))}, attr(switch_severity)); - auto* block_1 = Block(utils::Vector{if_foo, return_foo_block, swtch}, attr(block_severity)); + auto* wl = While(false, Block(utils::Vector{return_foo_while}, attr(while_body_severity)), + attr(while_severity)); + auto* block_1 = + Block(utils::Vector{if_foo, return_foo_block, swtch, wl}, attr(block_severity)); auto* func_attr = DiagnosticAttribute(func_severity, "chromium_unreachable_code"); auto* foo = Func("foo", {}, ty.void_(), utils::Vector{block_1}, utils::Vector{func_attr}); @@ -110,6 +121,10 @@ class DiagnosticSeverityTest : public TestHelper { EXPECT_EQ(p.Sem().DiagnosticSeverity(case_stmt->body, rule), case_severity); EXPECT_EQ(p.Sem().DiagnosticSeverity(return_foo_case, rule), case_severity); EXPECT_EQ(p.Sem().DiagnosticSeverity(return_foo_default, rule), switch_severity); + EXPECT_EQ(p.Sem().DiagnosticSeverity(wl, rule), while_severity); + EXPECT_EQ(p.Sem().DiagnosticSeverity(wl->condition, rule), while_severity); + EXPECT_EQ(p.Sem().DiagnosticSeverity(wl->body, rule), while_body_severity); + EXPECT_EQ(p.Sem().DiagnosticSeverity(return_foo_while, rule), while_body_severity); EXPECT_EQ(p.Sem().DiagnosticSeverity(bar, rule), global_severity); EXPECT_EQ(p.Sem().DiagnosticSeverity(return_bar, rule), global_severity); diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc index 9b47f10e97..7446d3501d 100644 --- a/src/tint/writer/wgsl/generator_impl.cc +++ b/src/tint/writer/wgsl/generator_impl.cc @@ -1120,6 +1120,14 @@ bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) { bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) { { auto out = line(); + + if (!stmt->attributes.IsEmpty()) { + if (!EmitAttributes(out, stmt->attributes)) { + return false; + } + out << " "; + } + out << "while"; { ScopedParen sp(out); diff --git a/test/tint/diagnostic_filtering/while_loop_attribute.wgsl b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl new file mode 100644 index 0000000000..0c3458aad6 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl @@ -0,0 +1,7 @@ +@fragment +fn main(@location(0) x : f32) { + var v = vec4(0); + @diagnostic(warning, derivative_uniformity) + while (x > 0.0 && dpdx(1.0) > 0.0) { + } +} diff --git a/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..9d6319b374 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,31 @@ +diagnostic_filtering/while_loop_attribute.wgsl:5:21 warning: 'dpdx' must only be called from uniform control flow + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:3 note: control flow depends on possibly non-uniform value + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:21 note: return value of 'dpdx' may be non-uniform + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + float4 v = (0.0f).xxxx; + while (true) { + bool tint_tmp = (x > 0.0f); + if (tint_tmp) { + tint_tmp = (ddx(1.0f) > 0.0f); + } + if (!((tint_tmp))) { break; } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..9d6319b374 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,31 @@ +diagnostic_filtering/while_loop_attribute.wgsl:5:21 warning: 'dpdx' must only be called from uniform control flow + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:3 note: control flow depends on possibly non-uniform value + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:21 note: return value of 'dpdx' may be non-uniform + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + float4 v = (0.0f).xxxx; + while (true) { + bool tint_tmp = (x > 0.0f); + if (tint_tmp) { + tint_tmp = (ddx(1.0f) > 0.0f); + } + if (!((tint_tmp))) { break; } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..a37e0fb698 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.glsl @@ -0,0 +1,31 @@ +diagnostic_filtering/while_loop_attribute.wgsl:5:21 warning: 'dpdx' must only be called from uniform control flow + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:3 note: control flow depends on possibly non-uniform value + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:21 note: return value of 'dpdx' may be non-uniform + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +#version 310 es +precision highp float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + vec4 v = vec4(0.0f); + while (true) { + bool tint_tmp = (x > 0.0f); + if (tint_tmp) { + tint_tmp = (dFdx(1.0f) > 0.0f); + } + if (!((tint_tmp))) { break; } + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..2549ca8b78 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.msl @@ -0,0 +1,30 @@ +diagnostic_filtering/while_loop_attribute.wgsl:5:21 warning: 'dpdx' must only be called from uniform control flow + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:3 note: control flow depends on possibly non-uniform value + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:21 note: return value of 'dpdx' may be non-uniform + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + float4 v = float4(0.0f); + while(((x > 0.0f) && (dfdx(1.0f) > 0.0f))) { + } +} + +fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) { + tint_symbol_inner(tint_symbol_1.x); + return; +} + diff --git a/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..b4ed2fc490 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.spvasm @@ -0,0 +1,76 @@ +diagnostic_filtering/while_loop_attribute.wgsl:5:21 warning: 'dpdx' must only be called from uniform control flow + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:3 note: control flow depends on possibly non-uniform value + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:21 note: return value of 'dpdx' may be non-uniform + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 34 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %v "v" + OpName %main "main" + OpDecorate %x_1 Location 0 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %void = OpTypeVoid + %4 = OpTypeFunction %void %float + %v4float = OpTypeVector %float 4 + %10 = OpConstantNull %v4float +%_ptr_Function_v4float = OpTypePointer Function %v4float + %18 = OpConstantNull %float + %bool = OpTypeBool + %float_1 = OpConstant %float 1 + %29 = OpTypeFunction %void + %main_inner = OpFunction %void None %4 + %x = OpFunctionParameter %float + %8 = OpLabel + %v = OpVariable %_ptr_Function_v4float Function %10 + OpStore %v %10 + OpBranch %13 + %13 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %16 + %16 = OpLabel + %19 = OpFOrdGreaterThan %bool %x %18 + OpSelectionMerge %21 None + OpBranchConditional %19 %22 %21 + %22 = OpLabel + %23 = OpDPdx %float %float_1 + %25 = OpFOrdGreaterThan %bool %23 %18 + OpBranch %21 + %21 = OpLabel + %26 = OpPhi %bool %19 %16 %25 %22 + %17 = OpLogicalNot %bool %26 + OpSelectionMerge %27 None + OpBranchConditional %17 %28 %27 + %28 = OpLabel + OpBranch %14 + %27 = OpLabel + OpBranch %15 + %15 = OpLabel + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %29 + %31 = OpLabel + %33 = OpLoad %float %x_1 + %32 = OpFunctionCall %void %main_inner %33 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..fb738cec2a --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_attribute.wgsl.expected.wgsl @@ -0,0 +1,18 @@ +diagnostic_filtering/while_loop_attribute.wgsl:5:21 warning: 'dpdx' must only be called from uniform control flow + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:3 note: control flow depends on possibly non-uniform value + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^ + +diagnostic_filtering/while_loop_attribute.wgsl:5:21 note: return value of 'dpdx' may be non-uniform + while (x > 0.0 && dpdx(1.0) > 0.0) { + ^^^^^^^^^ + +@fragment +fn main(@location(0) x : f32) { + var v = vec4(0); + @diagnostic(warning, derivative_uniformity) while(((x > 0.0) && (dpdx(1.0) > 0.0))) { + } +}