diff --git a/src/tint/ast/block_statement.cc b/src/tint/ast/block_statement.cc index 430dbbaa0e..5d75d27de2 100644 --- a/src/tint/ast/block_statement.cc +++ b/src/tint/ast/block_statement.cc @@ -23,12 +23,17 @@ namespace tint::ast { BlockStatement::BlockStatement(ProgramID pid, NodeID nid, const Source& src, - utils::VectorRef stmts) - : Base(pid, nid, src), statements(std::move(stmts)) { + utils::VectorRef stmts, + utils::VectorRef attrs) + : Base(pid, nid, src), statements(std::move(stmts)), attributes(attrs) { for (auto* stmt : statements) { TINT_ASSERT(AST, stmt); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, stmt, program_id); } + for (auto* attr : attributes) { + TINT_ASSERT(AST, attr); + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id); + } } BlockStatement::BlockStatement(BlockStatement&&) = default; @@ -39,7 +44,8 @@ const BlockStatement* BlockStatement::Clone(CloneContext* ctx) const { // Clone arguments outside of create() call to have deterministic ordering auto src = ctx->Clone(source); auto stmts = ctx->Clone(statements); - return ctx->dst->create(src, std::move(stmts)); + auto attrs = ctx->Clone(attributes); + return ctx->dst->create(src, std::move(stmts), std::move(attrs)); } } // namespace tint::ast diff --git a/src/tint/ast/block_statement.h b/src/tint/ast/block_statement.h index 22d0a65e5b..87989d8394 100644 --- a/src/tint/ast/block_statement.h +++ b/src/tint/ast/block_statement.h @@ -19,6 +19,11 @@ #include "src/tint/ast/statement.h" +// Forward declarations +namespace tint::ast { +class Attribute; +} // namespace tint::ast + namespace tint::ast { /// A block statement @@ -29,10 +34,12 @@ class BlockStatement final : public Castable { /// @param nid the unique node identifier /// @param source the block statement source /// @param statements the statements + /// @param attributes the block statement attributes BlockStatement(ProgramID pid, NodeID nid, const Source& source, - utils::VectorRef statements); + utils::VectorRef statements, + utils::VectorRef attributes); /// Move constructor BlockStatement(BlockStatement&&); ~BlockStatement() override; @@ -51,6 +58,9 @@ class BlockStatement final : public Castable { /// the statement list const utils::Vector statements; + + /// the attribute list + const utils::Vector attributes; }; } // namespace tint::ast diff --git a/src/tint/ast/block_statement_test.cc b/src/tint/ast/block_statement_test.cc index ec92c3f9d2..f88aa4c0d3 100644 --- a/src/tint/ast/block_statement_test.cc +++ b/src/tint/ast/block_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/discard_statement.h" #include "src/tint/ast/if_statement.h" @@ -26,21 +27,35 @@ TEST_F(BlockStatementTest, Creation) { auto* d = create(); auto* ptr = d; - auto* b = create(utils::Vector{d}); + auto* b = create(utils::Vector{d}, utils::Empty); ASSERT_EQ(b->statements.Length(), 1u); EXPECT_EQ(b->statements[0], ptr); + EXPECT_EQ(b->attributes.Length(), 0u); } TEST_F(BlockStatementTest, Creation_WithSource) { - auto* b = create(Source{Source::Location{20, 2}}, utils::Empty); + auto* b = create(Source{Source::Location{20, 2}}, utils::Empty, utils::Empty); auto src = b->source; EXPECT_EQ(src.range.begin.line, 20u); EXPECT_EQ(src.range.begin.column, 2u); } +TEST_F(BlockStatementTest, Creation_WithAttributes) { + auto* d = create(); + auto* ptr = d; + + auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("foo")); + auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("bar")); + auto* b = create(utils::Vector{d}, utils::Vector{attr1, attr2}); + + ASSERT_EQ(b->statements.Length(), 1u); + EXPECT_EQ(b->statements[0], ptr); + EXPECT_THAT(b->attributes, testing::ElementsAre(attr1, attr2)); +} + TEST_F(BlockStatementTest, IsBlock) { - auto* b = create(utils::Empty); + auto* b = create(utils::Empty, utils::Empty); EXPECT_TRUE(b->Is()); } @@ -48,7 +63,8 @@ TEST_F(BlockStatementTest, Assert_Null_Statement) { EXPECT_FATAL_FAILURE( { ProgramBuilder b; - b.create(utils::Vector{nullptr}); + b.create(utils::Vector{nullptr}, + utils::Empty); }, "internal compiler error"); } @@ -58,7 +74,7 @@ TEST_F(BlockStatementTest, Assert_DifferentProgramID_Statement) { { ProgramBuilder b1; ProgramBuilder b2; - b1.create(utils::Vector{b2.create()}); + b1.create(utils::Vector{b2.create()}, utils::Empty); }, "internal compiler error"); } diff --git a/src/tint/ast/case_statement_test.cc b/src/tint/ast/case_statement_test.cc index 04b887bda2..af0fb33b93 100644 --- a/src/tint/ast/case_statement_test.cc +++ b/src/tint/ast/case_statement_test.cc @@ -31,7 +31,7 @@ TEST_F(CaseStatementTest, Creation_i32) { utils::Vector b{selector}; auto* discard = create(); - auto* body = create(utils::Vector{discard}); + auto* body = create(utils::Vector{discard}, utils::Empty); auto* c = create(b, body); ASSERT_EQ(c->selectors.Length(), 1u); @@ -45,7 +45,7 @@ TEST_F(CaseStatementTest, Creation_u32) { utils::Vector b{selector}; auto* discard = create(); - auto* body = create(utils::Vector{discard}); + auto* body = create(utils::Vector{discard}, utils::Empty); auto* c = create(b, body); ASSERT_EQ(c->selectors.Length(), 1u); @@ -56,22 +56,24 @@ TEST_F(CaseStatementTest, Creation_u32) { TEST_F(CaseStatementTest, ContainsDefault_WithDefault) { utils::Vector b{CaseSelector(2_u), DefaultCaseSelector()}; - auto* c = create(b, create(utils::Empty)); + auto* c = create(b, create(utils::Empty, utils::Empty)); EXPECT_TRUE(c->ContainsDefault()); } TEST_F(CaseStatementTest, ContainsDefault_WithOutDefault) { utils::Vector b{CaseSelector(2_u), CaseSelector(3_u)}; - auto* c = create(b, create(utils::Empty)); + auto* c = create(b, create(utils::Empty, utils::Empty)); EXPECT_FALSE(c->ContainsDefault()); } TEST_F(CaseStatementTest, Creation_WithSource) { utils::Vector b{CaseSelector(2_i)}; - auto* body = create(utils::Vector{ - create(), - }); + auto* body = create( + utils::Vector{ + create(), + }, + utils::Empty); auto* c = create(Source{Source::Location{20, 2}}, b, body); auto src = c->source; EXPECT_EQ(src.range.begin.line, 20u); @@ -80,7 +82,7 @@ TEST_F(CaseStatementTest, Creation_WithSource) { TEST_F(CaseStatementTest, IsCase) { auto* c = create(utils::Vector{DefaultCaseSelector()}, - create(utils::Empty)); + create(utils::Empty, utils::Empty)); EXPECT_TRUE(c->Is()); } @@ -98,7 +100,7 @@ TEST_F(CaseStatementTest, Assert_Null_Selector) { { ProgramBuilder b; b.create(utils::Vector{nullptr}, - b.create(utils::Empty)); + b.create(utils::Empty, utils::Empty)); }, "internal compiler error"); } @@ -109,7 +111,7 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Call) { ProgramBuilder b1; ProgramBuilder b2; b1.create(utils::Vector{b1.DefaultCaseSelector()}, - b2.create(utils::Empty)); + b2.create(utils::Empty, utils::Empty)); }, "internal compiler error"); } @@ -120,7 +122,7 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Selector) { ProgramBuilder b1; ProgramBuilder b2; b1.create(utils::Vector{b2.CaseSelector(b2.Expr(2_i))}, - b1.create(utils::Empty)); + b1.create(utils::Empty, utils::Empty)); }, "internal compiler error"); } diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index c05abf9c0d..1c60784588 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -2456,7 +2456,8 @@ class ProgramBuilder { /// @param type the function return type /// @param body the function body /// @param attributes the optional function attributes - /// @param return_type_attributes the optional function return type + /// @param return_type_attributes the optional function return type attributes + /// @param body_attributes the optional function body attributes /// attributes /// @returns the function pointer template @@ -2467,11 +2468,12 @@ class ProgramBuilder { const ast::Type* type, utils::VectorRef body, utils::VectorRef attributes = utils::Empty, - utils::VectorRef return_type_attributes = utils::Empty) { - auto* func = - create(source, Sym(std::forward(name)), std::move(params), type, - create(std::move(body)), - std::move(attributes), std::move(return_type_attributes)); + utils::VectorRef return_type_attributes = utils::Empty, + utils::VectorRef body_attributes = utils::Empty) { + auto* func = create( + source, Sym(std::forward(name)), std::move(params), type, + create(std::move(body), std::move(body_attributes)), + std::move(attributes), std::move(return_type_attributes)); AST().AddFunction(func); return func; } @@ -2482,7 +2484,8 @@ class ProgramBuilder { /// @param type the function return type /// @param body the function body /// @param attributes the optional function attributes - /// @param return_type_attributes the optional function return type + /// @param return_type_attributes the optional function return type attributes + /// @param body_attributes the optional function body attributes /// attributes /// @returns the function pointer template @@ -2492,11 +2495,12 @@ class ProgramBuilder { const ast::Type* type, utils::VectorRef body, utils::VectorRef attributes = utils::Empty, - utils::VectorRef return_type_attributes = utils::Empty) { - auto* func = - create(Sym(std::forward(name)), std::move(params), type, - create(std::move(body)), - std::move(attributes), std::move(return_type_attributes)); + utils::VectorRef return_type_attributes = utils::Empty, + utils::VectorRef body_attributes = utils::Empty) { + auto* func = create( + Sym(std::forward(name)), std::move(params), type, + create(std::move(body), std::move(body_attributes)), + std::move(attributes), std::move(return_type_attributes)); AST().AddFunction(func); return func; } @@ -2676,23 +2680,50 @@ class ProgramBuilder { /// @param source the source information for the block /// @param statements statements of block /// @returns the block statement pointer - template - const ast::BlockStatement* Block(const Source& source, Statements&&... statements) { + template > + const ast::BlockStatement* Block(const Source& source, STATEMENTS&&... statements) { return create( - source, utils::Vector{ - std::forward(statements)..., - }); + source, + utils::Vector{ + std::forward(statements)..., + }, + utils::Empty); } /// Creates a ast::BlockStatement with input statements /// @param statements statements of block /// @returns the block statement pointer - template > + template , + typename = DisableIfVectorLike> const ast::BlockStatement* Block(STATEMENTS&&... statements) { return create( utils::Vector{ std::forward(statements)..., - }); + }, + utils::Empty); + } + + /// Creates a ast::BlockStatement with input statements and attributes + /// @param source the source information for the block + /// @param statements statements of block + /// @param attributes the attributes + /// @returns the block statement pointer + const ast::BlockStatement* Block( + const Source& source, + utils::VectorRef statements, + utils::VectorRef attributes = utils::Empty) { + return create(source, std::move(statements), std::move(attributes)); + } + + /// Creates a ast::BlockStatement with input statements and attributes + /// @param statements statements of block + /// @param attributes the attributes + /// @returns the block statement pointer + const ast::BlockStatement* Block( + utils::VectorRef statements, + utils::VectorRef attributes = utils::Empty) { + return create(std::move(statements), std::move(attributes)); } /// A wrapper type for the Else statement used to create If statements. diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc index 9ea9866289..bf4088a182 100644 --- a/src/tint/reader/spirv/function.cc +++ b/src/tint/reader/spirv/function.cc @@ -882,7 +882,7 @@ void FunctionEmitter::PushGuard(const std::string& guard_name, uint32_t end_id) auto* builder = AddStatementBuilder(cond); PushNewStatementBlock(top.GetConstruct(), end_id, [=](const StatementList& stmts) { - builder->body = create(Source{}, stmts); + builder->body = create(Source{}, stmts, utils::Empty); }); } @@ -894,7 +894,7 @@ void FunctionEmitter::PushTrueGuard(uint32_t end_id) { auto* builder = AddStatementBuilder(cond); PushNewStatementBlock(top.GetConstruct(), end_id, [=](const StatementList& stmts) { - builder->body = create(Source{}, stmts); + builder->body = create(Source{}, stmts, utils::Empty); }); } @@ -985,7 +985,7 @@ const ast::BlockStatement* FunctionEmitter::MakeFunctionBody() { statements_stack_[0].Finalize(&builder_); auto& statements = statements_stack_[0].GetStatements(); - auto* body = create(Source{}, statements); + auto* body = create(Source{}, statements, utils::Empty); // Maintain the invariant by repopulating the one and only element. statements_stack_.Clear(); @@ -1407,7 +1407,7 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() { } } - auto* body = create(source, stmts); + auto* body = create(source, stmts, utils::Empty); AttributeList fn_attrs; fn_attrs.Push(create(source, ep_info_->stage)); @@ -2938,7 +2938,7 @@ bool FunctionEmitter::EmitIfStart(const BlockInfo& block_info) { if (!stmts.IsEmpty()) { // The "else" consists of the statement list from the top of // statements stack, without an "else if" condition. - builder->else_stmt = create(Source{}, stmts); + builder->else_stmt = create(Source{}, stmts, utils::Empty); } }); if (false_is_break) { @@ -2985,7 +2985,7 @@ bool FunctionEmitter::EmitIfStart(const BlockInfo& block_info) { // Push the then clause onto the stack. PushNewStatementBlock(construct, then_end, [=](const StatementList& stmts) { - builder->body = create(Source{}, stmts); + builder->body = create(Source{}, stmts, utils::Empty); }); if (true_is_break) { AddStatement(create(Source{})); @@ -3098,7 +3098,7 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) { auto case_idx = swch->cases.Length(); swch->cases.Push(nullptr); PushNewStatementBlock(construct, end_id, [=](const StatementList& stmts) { - auto* body = create(Source{}, stmts); + auto* body = create(Source{}, stmts, utils::Empty); swch->cases[case_idx] = create(Source{}, selectors, body); }); @@ -3113,7 +3113,7 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) { bool FunctionEmitter::EmitLoopStart(const Construct* construct) { auto* builder = AddStatementBuilder(); PushNewStatementBlock(construct, construct->end_id, [=](const StatementList& stmts) { - builder->body = create(Source{}, stmts); + builder->body = create(Source{}, stmts, utils::Empty); }); return success(); } @@ -3128,7 +3128,7 @@ bool FunctionEmitter::EmitContinuingStart(const Construct* construct) { "expected loop on top of stack"; } PushNewStatementBlock(construct, construct->end_id, [=](const StatementList& stmts) { - loop->continuing = create(Source{}, stmts); + loop->continuing = create(Source{}, stmts, utils::Empty); }); return success(); @@ -3354,11 +3354,11 @@ const ast::Statement* FunctionEmitter::MakeSimpleIf(const ast::Expression* condi if (then_stmt != nullptr) { if_stmts.Push(then_stmt); } - auto* if_block = create(Source{}, if_stmts); + auto* if_block = create(Source{}, if_stmts, utils::Empty); const ast::Statement* else_block = nullptr; if (else_stmt) { - else_block = create(StatementList{else_stmt}); + else_block = create(StatementList{else_stmt}, utils::Empty); } auto* if_stmt = create(Source{}, condition, if_block, else_block); diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc index f7aa4b8aa3..5d056aec03 100644 --- a/src/tint/reader/wgsl/parser_impl.cc +++ b/src/tint/reader/wgsl/parser_impl.cc @@ -1500,7 +1500,7 @@ Maybe ParserImpl::function_decl(AttributeList& attrs) { // function body. The AST isn't used as we've already errored, but this // catches any errors inside the body, and can help keep the parser in // sync. - expect_compound_statement(); + expect_compound_statement("function body"); } return Failure::kErrored; } @@ -1510,7 +1510,7 @@ Maybe ParserImpl::function_decl(AttributeList& attrs) { bool errored = false; - auto body = expect_compound_statement(); + auto body = expect_compound_statement("function body"); if (body.errored) { errored = true; } @@ -1666,14 +1666,26 @@ Expect ParserImpl::expect_builtin() { } // compound_statement -// : BRACE_LEFT statement* BRACE_RIGHT -Expect ParserImpl::expect_compound_statement() { - return expect_brace_block("", [&]() -> Expect { +// : attribute* BRACE_LEFT statement* BRACE_RIGHT +Expect ParserImpl::expect_compound_statement(std::string_view use) { + auto attrs = attribute_list(); + if (attrs.errored) { + return Failure::kErrored; + } + return expect_compound_statement(attrs.value, use); +} + +// compound_statement +// : attribute* BRACE_LEFT statement* BRACE_RIGHT +Expect ParserImpl::expect_compound_statement(AttributeList& attrs, + std::string_view use) { + return expect_brace_block(use, [&]() -> Expect { auto stmts = expect_statements(); if (stmts.errored) { return Failure::kErrored; } - return create(Source{}, stmts.value); + TINT_DEFER(attrs.Clear()); + return create(Source{}, stmts.value, std::move(attrs)); }); } @@ -1731,6 +1743,12 @@ Maybe ParserImpl::statement() { // Skip empty statements } + auto attrs = attribute_list(); + if (attrs.errored) { + return Failure::kErrored; + } + TINT_DEFER(expect_attributes_consumed(attrs.value)); + // Non-block statements that error can resynchronize on semicolon. auto stmt = sync(Token::Type::kSemicolon, [&] { return non_block_statement(); }); if (stmt.errored) { @@ -1781,7 +1799,7 @@ Maybe ParserImpl::statement() { } if (peek_is(Token::Type::kBraceLeft)) { - auto body = expect_compound_statement(); + auto body = expect_compound_statement(attrs.value, "block statement"); if (body.errored) { return Failure::kErrored; } @@ -2023,7 +2041,7 @@ Maybe ParserImpl::if_statement() { return add_error(peek(), "unable to parse condition expression"); } - auto body = expect_compound_statement(); + auto body = expect_compound_statement("if statement"); if (body.errored) { return Failure::kErrored; } @@ -2059,7 +2077,7 @@ Maybe ParserImpl::if_statement() { } // If it wasn't an "else if", it must just be an "else". - auto else_body = expect_compound_statement(); + auto else_body = expect_compound_statement("else statement"); if (else_body.errored) { return Failure::kErrored; } @@ -2119,8 +2137,8 @@ Maybe ParserImpl::switch_statement() { } // switch_body -// : CASE case_selectors COLON? BRACKET_LEFT case_body BRACKET_RIGHT -// | DEFAULT COLON? BRACKET_LEFT case_body BRACKET_RIGHT +// : CASE case_selectors COLON? compound_statement +// | DEFAULT COLON? compound_statement Maybe ParserImpl::switch_body() { if (!peek_is(Token::Type::kCase) && !peek_is(Token::Type::kDefault)) { return Failure::kNoMatch; @@ -2145,14 +2163,10 @@ Maybe ParserImpl::switch_body() { match(Token::Type::kColon); const char* use = "case statement"; - auto body = expect_brace_block(use, [&] { return case_body(); }); - + auto body = expect_compound_statement(use); if (body.errored) { return Failure::kErrored; } - if (!body.matched) { - return add_error(body.source, "expected case body"); - } return create(t.source(), selector_list, body.value); } @@ -2231,7 +2245,7 @@ Maybe ParserImpl::case_body() { stmts.Push(stmt.value); } - return create(Source{}, stmts); + return create(Source{}, stmts, utils::Empty); } // loop_statement @@ -2253,7 +2267,7 @@ Maybe ParserImpl::loop_statement() { return Failure::kErrored; } - auto* body = create(source, stmts.value); + auto* body = create(source, stmts.value, utils::Empty); return create(source, body, continuing.value); }); } @@ -2345,7 +2359,7 @@ Expect> ParserImpl::expect_for_header() { } // for_statement -// : FOR PAREN_LEFT for_header PAREN_RIGHT BRACE_LEFT statements BRACE_RIGHT +// : FOR PAREN_LEFT for_header PAREN_RIGHT compound_statement Maybe ParserImpl::for_statement() { Source source; if (!match(Token::Type::kFor, &source)) { @@ -2357,14 +2371,13 @@ Maybe ParserImpl::for_statement() { return Failure::kErrored; } - auto stmts = expect_brace_block("for loop", [&] { return expect_statements(); }); - if (stmts.errored) { + auto body = expect_compound_statement("for loop"); + if (body.errored) { return Failure::kErrored; } return create(source, header->initializer, header->condition, - header->continuing, - create(stmts.value)); + header->continuing, body.value); } // while_statement @@ -2383,7 +2396,7 @@ Maybe ParserImpl::while_statement() { return add_error(peek(), "unable to parse while condition expression"); } - auto body = expect_compound_statement(); + auto body = expect_compound_statement("while loop"); if (body.errored) { return Failure::kErrored; } @@ -2491,7 +2504,7 @@ Maybe ParserImpl::continuing_compound_statement() { stmts.Push(stmt.value); } - return create(Source{}, stmts); + return create(Source{}, stmts, utils::Empty); }); } @@ -2499,7 +2512,7 @@ Maybe ParserImpl::continuing_compound_statement() { // : CONTINUING continuing_compound_statement Maybe ParserImpl::continuing_statement() { if (!match(Token::Type::kContinuing)) { - return create(Source{}, utils::Empty); + return create(Source{}, utils::Empty, utils::Empty); } return continuing_compound_statement(); diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h index 8101261437..0936f6a29b 100644 --- a/src/tint/reader/wgsl/parser_impl.h +++ b/src/tint/reader/wgsl/parser_impl.h @@ -542,8 +542,15 @@ class ParserImpl { /// @returns the parsed builtin. Expect expect_builtin(); /// Parses a `compound_statement` grammar element, erroring on parse failure. + /// @param use a description of what was being parsed if an error was raised /// @returns the parsed statements - Expect expect_compound_statement(); + Expect expect_compound_statement(std::string_view use); + /// Parses a `compound_statement` grammar element, with the attribute list provided as `attrs`. + /// @param attrs the list of attributes for the statement + /// @param use a description of what was being parsed if an error was raised + /// @returns the parsed statements + Expect expect_compound_statement(AttributeList& attrs, + std::string_view use); /// Parses a `paren_expression` grammar element, erroring on parse failure. /// @returns the parsed element or nullptr Expect expect_paren_expression(); diff --git a/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc index 947cb481c7..f096fd670f 100644 --- a/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc +++ b/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc @@ -23,7 +23,7 @@ TEST_F(ParserImplTest, CompoundStmt) { discard; return 1 + b / 2; })"); - auto e = p->expect_compound_statement(); + auto e = p->expect_compound_statement(""); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(e.errored); ASSERT_EQ(e->statements.Length(), 2u); @@ -33,7 +33,7 @@ TEST_F(ParserImplTest, CompoundStmt) { TEST_F(ParserImplTest, CompoundStmt_Empty) { auto p = parser("{}"); - auto e = p->expect_compound_statement(); + auto e = p->expect_compound_statement(""); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(e.errored); EXPECT_EQ(e->statements.Length(), 0u); @@ -41,7 +41,7 @@ TEST_F(ParserImplTest, CompoundStmt_Empty) { TEST_F(ParserImplTest, CompoundStmt_InvalidStmt) { auto p = parser("{fn main() {}}"); - auto e = p->expect_compound_statement(); + auto e = p->expect_compound_statement(""); ASSERT_TRUE(p->has_error()); ASSERT_TRUE(e.errored); EXPECT_EQ(p->error(), "1:2: expected '}'"); @@ -49,7 +49,7 @@ TEST_F(ParserImplTest, CompoundStmt_InvalidStmt) { TEST_F(ParserImplTest, CompoundStmt_MissingRightParen) { auto p = parser("{return;"); - auto e = p->expect_compound_statement(); + auto e = p->expect_compound_statement(""); ASSERT_TRUE(p->has_error()); ASSERT_TRUE(e.errored); EXPECT_EQ(p->error(), "1:9: expected '}'"); diff --git a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc index 5337c3cdb4..9e5d1a77a3 100644 --- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc +++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc @@ -489,7 +489,7 @@ fn f( {} } TEST_F(ParserImplErrorTest, FunctionDeclMissingArrow) { - EXPECT("fn f() f32 {}", R"(test.wgsl:1:8 error: expected '{' + EXPECT("fn f() f32 {}", R"(test.wgsl:1:8 error: expected '{' for function body fn f() f32 {} ^^^ )"); @@ -526,14 +526,14 @@ fn f(x : i32, ,) {} } TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) { - EXPECT("fn f() }", R"(test.wgsl:1:8 error: expected '{' + EXPECT("fn f() }", R"(test.wgsl:1:8 error: expected '{' for function body fn f() } ^ )"); } TEST_F(ParserImplErrorTest, FunctionDeclMissingRBrace) { - EXPECT("fn f() {", R"(test.wgsl:1:9 error: expected '}' + EXPECT("fn f() {", R"(test.wgsl:1:9 error: expected '}' for function body fn f() { ^ )"); @@ -541,9 +541,9 @@ fn f() { TEST_F(ParserImplErrorTest, FunctionScopeUnusedDecl) { EXPECT("fn f(a:i32)->i32{return a;@size(1)}", - R"(test.wgsl:1:27 error: expected '}' + R"(test.wgsl:1:28 error: unexpected attributes fn f(a:i32)->i32{return a;@size(1)} - ^ + ^^^^ )"); } diff --git a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc index c9f55cfb50..a761dde9d0 100644 --- a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc +++ b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc @@ -305,7 +305,7 @@ TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) { EXPECT_FALSE(f.matched); EXPECT_TRUE(p->has_error()); EXPECT_EQ(f.value, nullptr); - EXPECT_EQ(p->error(), "1:11: expected '{'"); + EXPECT_EQ(p->error(), "1:11: expected '{' for function body"); } } // namespace diff --git a/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc index 59e5ad38ba..55effc701c 100644 --- a/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc +++ b/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc @@ -85,7 +85,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidCondition) { EXPECT_TRUE(e.errored); EXPECT_EQ(e.value, nullptr); EXPECT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:6: expected '{'"); + EXPECT_EQ(p->error(), "1:6: expected '{' for if statement"); } TEST_F(ParserImplTest, IfStmt_MissingCondition) { @@ -105,7 +105,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidBody) { EXPECT_TRUE(e.errored); EXPECT_EQ(e.value, nullptr); EXPECT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:8: expected '}'"); + EXPECT_EQ(p->error(), "1:8: expected '}' for if statement"); } TEST_F(ParserImplTest, IfStmt_MissingBody) { @@ -115,7 +115,7 @@ TEST_F(ParserImplTest, IfStmt_MissingBody) { EXPECT_TRUE(e.errored); EXPECT_EQ(e.value, nullptr); EXPECT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:5: expected '{'"); + EXPECT_EQ(p->error(), "1:5: expected '{' for if statement"); } TEST_F(ParserImplTest, IfStmt_InvalidElseif) { @@ -125,7 +125,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidElseif) { EXPECT_TRUE(e.errored); EXPECT_EQ(e.value, nullptr); EXPECT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:21: expected '}'"); + EXPECT_EQ(p->error(), "1:21: expected '}' for if statement"); } TEST_F(ParserImplTest, IfStmt_InvalidElse) { @@ -135,7 +135,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidElse) { EXPECT_TRUE(e.errored); EXPECT_EQ(e.value, nullptr); EXPECT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:16: expected '}'"); + EXPECT_EQ(p->error(), "1:16: expected '}' for else statement"); } } // namespace diff --git a/src/tint/reader/wgsl/parser_impl_statement_test.cc b/src/tint/reader/wgsl/parser_impl_statement_test.cc index f21a4e7567..7371b81557 100644 --- a/src/tint/reader/wgsl/parser_impl_statement_test.cc +++ b/src/tint/reader/wgsl/parser_impl_statement_test.cc @@ -95,7 +95,7 @@ TEST_F(ParserImplTest, Statement_If_Invalid) { EXPECT_TRUE(e.errored); EXPECT_FALSE(e.matched); EXPECT_EQ(e.value, nullptr); - EXPECT_EQ(p->error(), "1:10: expected '}'"); + EXPECT_EQ(p->error(), "1:10: expected '}' for if statement"); } TEST_F(ParserImplTest, Statement_Variable) { @@ -269,7 +269,7 @@ TEST_F(ParserImplTest, Statement_Body_Invalid) { EXPECT_TRUE(e.errored); EXPECT_FALSE(e.matched); EXPECT_EQ(e.value, nullptr); - EXPECT_EQ(p->error(), "1:3: expected '}'"); + EXPECT_EQ(p->error(), "1:3: expected '}' for block statement"); } TEST_F(ParserImplTest, Statement_ConstAssert_WithParen) { @@ -358,5 +358,15 @@ TEST_F(ParserImplTest, DEPRECATED_Statement_StaticAssert_WithoutParen) { EXPECT_EQ(sa->condition->source.range.end.column, 20u); } +TEST_F(ParserImplTest, Statement_UnexpectedAttributes) { + auto p = parser("@diagnostic(off, derivative_uniformity) return;"); + auto e = p->statement(); + EXPECT_TRUE(p->has_error()); + EXPECT_FALSE(e.errored); + EXPECT_TRUE(e.matched); + EXPECT_NE(e.value, nullptr); + EXPECT_EQ(p->error(), "1:2: unexpected attributes"); +} + } // namespace } // namespace tint::reader::wgsl 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 e516267c2b..5cc168d854 100644 --- a/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc +++ b/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc @@ -118,7 +118,7 @@ TEST_F(WhileStmtErrorTest, MissingRightParen) { // Test a while loop with missing left brace is invalid. TEST_F(WhileStmtErrorTest, MissingLeftBrace) { std::string while_str = "while (true) }"; - std::string error_str = "1:14: expected '{'"; + std::string error_str = "1:14: expected '{' for while loop"; TestWhileWithError(while_str, error_str); } @@ -126,7 +126,7 @@ TEST_F(WhileStmtErrorTest, MissingLeftBrace) { // Test a for loop with missing right brace is invalid. TEST_F(WhileStmtErrorTest, MissingRightBrace) { std::string while_str = "while (true) {"; - std::string error_str = "1:15: expected '}'"; + std::string error_str = "1:15: expected '}' for while loop"; TestWhileWithError(while_str, error_str); } @@ -159,7 +159,7 @@ TEST_F(WhileStmtErrorTest, InvalidBody) { // Test a for loop with a body not matching statements TEST_F(WhileStmtErrorTest, InvalidBodyMatch) { std::string while_str = "while (true) { fn main() {} }"; - std::string error_str = "1:16: expected '}'"; + std::string error_str = "1:16: expected '}' for while loop"; TestWhileWithError(while_str, error_str); } diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc index 18200d4214..a50406805c 100644 --- a/src/tint/resolver/attribute_validation_test.cc +++ b/src/tint/resolver/attribute_validation_test.cc @@ -1030,6 +1030,104 @@ TEST_F(OverrideAttributeTest, DuplicateAttribute) { 12:34 note: first attribute declared here)"); } +namespace BlockStatementTests { +class BlockStatementTest : public TestWithParams { + protected: + void Check() { + if (GetParam().should_pass) { + EXPECT_TRUE(r()->Resolve()) << r()->error(); + } else { + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), "error: attribute is not valid for block statements"); + } + } +}; +TEST_P(BlockStatementTest, CompoundStatement) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + Block(utils::Vector{Return()}, createAttributes({}, *this, GetParam().kind)), + }); + Check(); +} +TEST_P(BlockStatementTest, FunctionBody) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + Block(utils::Vector{Return()}), + }, + utils::Empty, utils::Empty, createAttributes({}, *this, GetParam().kind)); + Check(); +} +TEST_P(BlockStatementTest, IfStatementBody) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + If(Expr(true), + Block(utils::Vector{Return()}, createAttributes({}, *this, GetParam().kind))), + }); + Check(); +} +TEST_P(BlockStatementTest, ElseStatementBody) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + If(Expr(true), Block(utils::Vector{Return()}), + Else(Block(utils::Vector{Return()}, createAttributes({}, *this, GetParam().kind)))), + }); + Check(); +} +TEST_P(BlockStatementTest, ForStatementBody) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + For(nullptr, Expr(true), nullptr, + Block(utils::Vector{Break()}, createAttributes({}, *this, GetParam().kind))), + }); + Check(); +} +TEST_P(BlockStatementTest, WhileStatementBody) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + While(Expr(true), + Block(utils::Vector{Break()}, createAttributes({}, *this, GetParam().kind))), + }); + Check(); +} +TEST_P(BlockStatementTest, CaseStatementBody) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + Switch(1_a, + Case(CaseSelector(1_a), Block(utils::Vector{Break()}, + createAttributes({}, *this, GetParam().kind))), + DefaultCase(Block({}))), + }); + Check(); +} +TEST_P(BlockStatementTest, DefaultStatementBody) { + Func("foo", utils::Empty, ty.void_(), + utils::Vector{ + Switch(1_a, Case(CaseSelector(1_a), Block()), + DefaultCase(Block(utils::Vector{Break()}, + createAttributes({}, *this, GetParam().kind)))), + }); + Check(); +} +INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest, + BlockStatementTest, + 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::kOffset, false}, + TestParams{AttributeKind::kSize, false}, + TestParams{AttributeKind::kStage, false}, + TestParams{AttributeKind::kStride, false}, + TestParams{AttributeKind::kWorkgroup, false}, + TestParams{AttributeKind::kBindingAndGroup, false})); + +} // namespace BlockStatementTests + } // namespace } // namespace AttributeTests diff --git a/src/tint/resolver/diagnostic_control_test.cc b/src/tint/resolver/diagnostic_control_test.cc index 568dc23ab7..4cf2b476f2 100644 --- a/src/tint/resolver/diagnostic_control_test.cc +++ b/src/tint/resolver/diagnostic_control_test.cc @@ -181,6 +181,66 @@ TEST_F(ResolverDiagnosticControlTest, FunctionAttributeScope) { 89:10 note: code is unreachable)"); } +TEST_F(ResolverDiagnosticControlTest, BlockAttributeScope) { + // fn foo() @diagnostic(off, chromium_unreachable_code) { + // { + // return; + // return; // Should not produce a diagnostic + // } + // @diagnostic(warning, chromium_unreachable_code) { + // if (true) @diagnostic(info, chromium_unreachable_code) { + // return; + // return; // Should produce an info + // } else { + // while (true) @diagnostic(off, chromium_unreachable_code) { + // return; + // return; // Should not produce a diagnostic + // } + // return; + // return; // Should produce an warning + // } + // } + // } + + auto attr = [&](auto severity) { + return utils::Vector{DiagnosticAttribute(severity, Expr("chromium_unreachable_code"))}; + }; + Func("foo", {}, ty.void_(), + utils::Vector{ + Return(), + Return(Source{{12, 21}}), + Block(utils::Vector{ + Block( + utils::Vector{ + If(Expr(true), + Block( + utils::Vector{ + Return(), + Return(Source{{34, 43}}), + }, + attr(ast::DiagnosticSeverity::kInfo)), + Else(Block(utils::Vector{ + While( + Expr(true), Block( + utils::Vector{ + Return(), + Return(Source{{56, 65}}), + }, + attr(ast::DiagnosticSeverity::kOff))), + Return(), + Return(Source{{78, 87}}), + }))), + }, + attr(ast::DiagnosticSeverity::kWarning)), + }), + }, + attr(ast::DiagnosticSeverity::kOff)); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + EXPECT_EQ(r()->error(), R"(34:43 note: code is unreachable +78:87 warning: code is unreachable)"); +} + TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Directive) { DiagnosticDirective(ast::DiagnosticSeverity::kError, Expr(Source{{12, 34}}, "chromium_unreachable_cod")); diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 9c592fce55..ac45aacaf5 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -3845,6 +3845,43 @@ SEM* Resolver::StatementScope(const ast::Statement* ast, SEM* sem, F&& callback) auto* as_compound = As(sem); + // Helper to handle attributes that are supported on certain types of statement. + auto handle_attributes = [&](auto* stmt, sem::Statement* sem_stmt, const char* use) { + for (auto* attr : stmt->attributes) { + Mark(attr); + if (auto* dc = attr->template As()) { + Mark(dc->control); + if (!DiagnosticControl(dc->control)) { + return false; + } + } else { + std::ostringstream ss; + ss << "attribute is not valid for " << use; + AddError(ss.str(), attr->source); + return false; + } + } + if (!validator_.NoDuplicateAttributes(stmt->attributes)) { + return false; + } + ApplyDiagnosticSeverities(sem_stmt); + return true; + }; + + // Handle attributes, if necessary. + // Some statements can take diagnostic filtering attributes, so push a new diagnostic filter + // scope to capture them. + validator_.DiagnosticFilters().Push(); + TINT_DEFER(validator_.DiagnosticFilters().Pop()); + if (!Switch( + ast, // + [&](const ast::BlockStatement* block) { + return handle_attributes(block, sem, "block statements"); + }, + [&](Default) { return true; })) { + return nullptr; + } + TINT_SCOPED_ASSIGNMENT(current_statement_, sem); TINT_SCOPED_ASSIGNMENT(current_compound_statement_, as_compound ? as_compound : current_compound_statement_); diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc index 274287a220..59e42df4f1 100644 --- a/src/tint/resolver/uniformity_test.cc +++ b/src/tint/resolver/uniformity_test.cc @@ -7942,6 +7942,32 @@ TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) { } } +TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnBlock) { + auto& param = GetParam(); + std::ostringstream 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() { + if (non_uniform == 42))" + << "@diagnostic(" << param << ", derivative_uniformity)" + << R"({ + let color = textureSample(t, s, vec2(0, 0)); + } +} +)"; + + RunTest(ss.str(), param != ast::DiagnosticSeverity::kError); + if (param == ast::DiagnosticSeverity::kOff) { + EXPECT_TRUE(error_.empty()); + } else { + std::ostringstream err; + err << ToStr(param) << ": 'textureSample' must only be called"; + EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); + } +} + INSTANTIATE_TEST_SUITE_P(UniformityAnalysisTest, UniformityAnalysisDiagnosticFilterTest, ::testing::Values(ast::DiagnosticSeverity::kError, diff --git a/src/tint/sem/diagnostic_severity_test.cc b/src/tint/sem/diagnostic_severity_test.cc index 7ede2bc402..cbb37b6334 100644 --- a/src/tint/sem/diagnostic_severity_test.cc +++ b/src/tint/sem/diagnostic_severity_test.cc @@ -30,26 +30,44 @@ class DiagnosticSeverityTest : public TestHelper { void Run(ast::DiagnosticSeverity global_severity) { // @diagnostic(off, chromium_unreachable_code) // fn foo() { - // return; + // @diagnostic(info, chromium_unreachable_code) { + // if (true) @diagnostic(warning, chromium_unreachable_code) { + // return; + // } + // } // } // // fn bar() { - // return; + // { + // if (true) { + // return; + // } + // } // } auto rule = ast::DiagnosticRule::kChromiumUnreachableCode; auto func_severity = ast::DiagnosticSeverity::kOff; + auto block_severity = ast::DiagnosticSeverity::kInfo; + auto if_severity = ast::DiagnosticSeverity::kInfo; + auto attr = [&](auto severity) { + return utils::Vector{DiagnosticAttribute(severity, Expr("chromium_unreachable_code"))}; + }; auto* return_1 = Return(); - auto* return_2 = Return(); + auto* if_1 = If(Expr(true), Block(utils::Vector{return_1}, attr(if_severity))); + auto* block_1 = Block(utils::Vector{if_1}, attr(block_severity)); auto* func_attr = DiagnosticAttribute(func_severity, Expr("chromium_unreachable_code")); - auto* foo = Func("foo", {}, ty.void_(), utils::Vector{return_1}, utils::Vector{func_attr}); + auto* foo = Func("foo", {}, ty.void_(), utils::Vector{block_1}, utils::Vector{func_attr}); + + auto* return_2 = Return(); auto* bar = Func("bar", {}, ty.void_(), utils::Vector{return_2}); auto p = Build(); EXPECT_TRUE(p.IsValid()) << p.Diagnostics().str(); EXPECT_EQ(p.Sem().DiagnosticSeverity(foo, rule), func_severity); - EXPECT_EQ(p.Sem().DiagnosticSeverity(return_1, rule), func_severity); + EXPECT_EQ(p.Sem().DiagnosticSeverity(block_1, rule), block_severity); + EXPECT_EQ(p.Sem().DiagnosticSeverity(if_1, rule), block_severity); + EXPECT_EQ(p.Sem().DiagnosticSeverity(return_1, rule), if_severity); EXPECT_EQ(p.Sem().DiagnosticSeverity(bar, rule), global_severity); EXPECT_EQ(p.Sem().DiagnosticSeverity(return_2, rule), global_severity); } diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc index bb91d9364e..4b9d51251e 100644 --- a/src/tint/writer/wgsl/generator_impl.cc +++ b/src/tint/writer/wgsl/generator_impl.cc @@ -353,7 +353,10 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) { } if (func->body) { - out << " {"; + out << " "; + if (!EmitBlockHeader(out, func->body)) { + return false; + } } } @@ -979,7 +982,12 @@ bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* } bool GeneratorImpl::EmitBlock(const ast::BlockStatement* stmt) { - line() << "{"; + { + auto out = line(); + if (!EmitBlockHeader(out, stmt)) { + return false; + } + } if (!EmitStatementsWithIndent(stmt->statements)) { return false; } @@ -988,6 +996,17 @@ bool GeneratorImpl::EmitBlock(const ast::BlockStatement* stmt) { return true; } +bool GeneratorImpl::EmitBlockHeader(std::ostream& out, const ast::BlockStatement* stmt) { + if (!stmt->attributes.IsEmpty()) { + if (!EmitAttributes(out, stmt->attributes)) { + return false; + } + out << " "; + } + out << "{"; + return true; +} + bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) { return Switch( stmt, // @@ -1072,7 +1091,11 @@ bool GeneratorImpl::EmitBreakIf(const ast::BreakIfStatement* b) { bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) { if (stmt->selectors.Length() == 1 && stmt->ContainsDefault()) { - line() << "default: {"; + auto out = line(); + out << "default: "; + if (!EmitBlockHeader(out, stmt->body)) { + return false; + } } else { auto out = line(); out << "case "; @@ -1091,7 +1114,10 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) { return false; } } - out << ": {"; + out << ": "; + if (!EmitBlockHeader(out, stmt->body)) { + return false; + } } if (!EmitStatementsWithIndent(stmt->body->statements)) { return false; @@ -1135,7 +1161,10 @@ bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) { if (!EmitExpression(out, stmt->condition)) { return false; } - out << ") {"; + out << ") "; + if (!EmitBlockHeader(out, stmt->body)) { + return false; + } } if (!EmitStatementsWithIndent(stmt->body->statements)) { @@ -1151,15 +1180,25 @@ bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) { if (!EmitExpression(out, elseif->condition)) { return false; } - out << ") {"; + out << ") "; + if (!EmitBlockHeader(out, elseif->body)) { + return false; + } } if (!EmitStatementsWithIndent(elseif->body->statements)) { return false; } e = elseif->else_statement; } else { - line() << "} else {"; - if (!EmitStatementsWithIndent(e->As()->statements)) { + auto* body = e->As(); + { + auto out = line(); + out << "} else "; + if (!EmitBlockHeader(out, body)) { + return false; + } + } + if (!EmitStatementsWithIndent(body->statements)) { return false; } break; @@ -1270,7 +1309,10 @@ bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) { break; } } - out << " {"; + out << " "; + if (!EmitBlockHeader(out, stmt->body)) { + return false; + } } if (!EmitStatementsWithIndent(stmt->body->statements)) { @@ -1294,7 +1336,10 @@ bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) { return false; } } - out << " {"; + out << " "; + if (!EmitBlockHeader(out, stmt->body)) { + return false; + } } if (!EmitStatementsWithIndent(stmt->body->statements)) { diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h index 87a1b54484..7a74d1e03c 100644 --- a/src/tint/writer/wgsl/generator_impl.h +++ b/src/tint/writer/wgsl/generator_impl.h @@ -93,6 +93,11 @@ class GeneratorImpl : public TextGenerator { /// @param stmt the statement to emit /// @returns true if the statement was emitted successfully bool EmitBlock(const ast::BlockStatement* stmt); + /// Handles emitting the start of a block statement (including attributes) + /// @param out the output stream to write the header to + /// @param stmt the block statement to emit the header for + /// @returns true if the statement was emitted successfully + bool EmitBlockHeader(std::ostream& out, const ast::BlockStatement* stmt); /// Handles a break statement /// @param stmt the statement to emit /// @returns true if the statement was emitted successfully diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl new file mode 100644 index 0000000000..2d059b01ba --- /dev/null +++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl @@ -0,0 +1,13 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + switch (i32(x)) { + case 0 @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } + default { + } + } +} diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..bd6e1038ed --- /dev/null +++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,34 @@ +diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + switch(int(x)) { + case 0: { + break; + } + default: { + break; + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..bd6e1038ed --- /dev/null +++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,34 @@ +diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + switch(int(x)) { + case 0: { + break; + } + default: { + break; + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..2bf3fa9141 --- /dev/null +++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl @@ -0,0 +1,31 @@ +diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + switch(int(x)) { + case 0: { + break; + } + default: { + break; + } + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..eba0e35dcd --- /dev/null +++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl @@ -0,0 +1,35 @@ +diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + switch(int(x)) { + case 0: { + break; + } + default: { + break; + } + } +} + +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/case_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..391ad2ec2c --- /dev/null +++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,64 @@ +diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 25 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %int = OpTypeInt 32 1 + %20 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %16 = OpConvertFToS %int %x + OpSelectionMerge %15 None + OpSwitch %16 %18 0 %19 + %19 = OpLabel + OpBranch %15 + %18 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %20 + %22 = OpLabel + %24 = OpLoad %float %x_1 + %23 = OpFunctionCall %void %main_inner %24 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..25abad683f --- /dev/null +++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,26 @@ +diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + switch(i32(x)) { + case 0: @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } + default: { + } + } +} diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl new file mode 100644 index 0000000000..63f5db448f --- /dev/null +++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl @@ -0,0 +1,11 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + @diagnostic(warning, derivative_uniformity) { + if (x > 0) { + _ = textureSample(t, s, vec2(0, 0)); + } + } +} diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..cc4ebfb577 --- /dev/null +++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,30 @@ +diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + { + if ((x > 0.0f)) { + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..cc4ebfb577 --- /dev/null +++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,30 @@ +diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + { + if ((x > 0.0f)) { + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..38aa2a0c38 --- /dev/null +++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.glsl @@ -0,0 +1,27 @@ +diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + { + if ((x > 0.0f)) { + } + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..00f0483cd3 --- /dev/null +++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.msl @@ -0,0 +1,31 @@ +diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + { + if ((x > 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/compound_statement_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..acad3a0109 --- /dev/null +++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.spvasm @@ -0,0 +1,63 @@ +diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 25 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %15 = OpConstantNull %float + %bool = OpTypeBool + %20 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %16 = OpFOrdGreaterThan %bool %x %15 + OpSelectionMerge %18 None + OpBranchConditional %16 %19 %18 + %19 = OpLabel + OpBranch %18 + %18 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %20 + %22 = OpLabel + %24 = OpLoad %float %x_1 + %23 = OpFunctionCall %void %main_inner %24 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..f1bf9d3752 --- /dev/null +++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.wgsl @@ -0,0 +1,24 @@ +diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + @diagnostic(warning, derivative_uniformity) { + if ((x > 0)) { + _ = textureSample(t, s, vec2(0, 0)); + } + } +} diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl new file mode 100644 index 0000000000..14942c6dde --- /dev/null +++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl @@ -0,0 +1,11 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + switch (i32(x)) { + default @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } + } +} diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..6e6406f658 --- /dev/null +++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,28 @@ +diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + do { + } while (false); +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..6e6406f658 --- /dev/null +++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,28 @@ +diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + do { + } while (false); +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..915923b9f1 --- /dev/null +++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl @@ -0,0 +1,28 @@ +diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + switch(int(x)) { + default: { + break; + } + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..b49fa2a12c --- /dev/null +++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl @@ -0,0 +1,32 @@ +diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + switch(int(x)) { + default: { + break; + } + } +} + +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/default_case_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..5364ca2f29 --- /dev/null +++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,62 @@ +diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 24 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %int = OpTypeInt 32 1 + %19 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %16 = OpConvertFToS %int %x + OpSelectionMerge %15 None + OpSwitch %16 %18 + %18 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %19 + %21 = OpLabel + %23 = OpLoad %float %x_1 + %22 = OpFunctionCall %void %main_inner %23 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..eceadbdae3 --- /dev/null +++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,24 @@ +diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + switch (i32(x)) { + ^^^^^^ + +diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform + switch (i32(x)) { + ^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + switch(i32(x)) { + default: @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } + } +} diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl new file mode 100644 index 0000000000..7f482ac44d --- /dev/null +++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl @@ -0,0 +1,10 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + if (x > 0) { + } else @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..9b566ce4d2 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,29 @@ +diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } else { + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..9b566ce4d2 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,29 @@ +diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } else { + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..cd89cc0105 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.glsl @@ -0,0 +1,26 @@ +diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + if ((x > 0.0f)) { + } else { + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..7374a36483 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.msl @@ -0,0 +1,30 @@ +diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + if ((x > 0.0f)) { + } else { + } +} + +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/else_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..961e1ad9b5 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,65 @@ +diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 26 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %15 = OpConstantNull %float + %bool = OpTypeBool + %21 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %16 = OpFOrdGreaterThan %bool %x %15 + OpSelectionMerge %18 None + OpBranchConditional %16 %19 %20 + %19 = OpLabel + OpBranch %18 + %20 = OpLabel + OpBranch %18 + %18 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %21 + %23 = OpLabel + %25 = OpLoad %float %x_1 + %24 = OpFunctionCall %void %main_inner %25 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..47b37b62dd --- /dev/null +++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,23 @@ +diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + if ((x > 0)) { + } else @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl new file mode 100644 index 0000000000..68fd217cad --- /dev/null +++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl @@ -0,0 +1,10 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + if (x > 0) { + } else if (x < 0) @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..2f00281b71 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,31 @@ +diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } else { + if ((x < 0.0f)) { + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..2f00281b71 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,31 @@ +diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } else { + if ((x < 0.0f)) { + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..6e4bec06df --- /dev/null +++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.glsl @@ -0,0 +1,28 @@ +diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + if ((x > 0.0f)) { + } else { + if ((x < 0.0f)) { + } + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..2c579f628e --- /dev/null +++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.msl @@ -0,0 +1,32 @@ +diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + if ((x > 0.0f)) { + } else { + if ((x < 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/else_if_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..587782202f --- /dev/null +++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,71 @@ +diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 29 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %15 = OpConstantNull %float + %bool = OpTypeBool + %24 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %16 = OpFOrdGreaterThan %bool %x %15 + OpSelectionMerge %18 None + OpBranchConditional %16 %19 %20 + %19 = OpLabel + OpBranch %18 + %20 = OpLabel + %21 = OpFOrdLessThan %bool %x %15 + OpSelectionMerge %22 None + OpBranchConditional %21 %23 %22 + %23 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %18 + %18 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %24 + %26 = OpLabel + %28 = OpLoad %float %x_1 + %27 = OpFunctionCall %void %main_inner %28 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..bde4aa6376 --- /dev/null +++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,23 @@ +diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + if ((x > 0)) { + } else if ((x < 0)) @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl new file mode 100644 index 0000000000..14db324ace --- /dev/null +++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl @@ -0,0 +1,10 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + var v = vec4(0); + for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) { + v = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..4498899398 --- /dev/null +++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,32 @@ +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) { + ^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + float4 v = (0.0f).xxxx; + { + for(; (x > v.x); ) { + v = t.Sample(s, (0.0f).xx); + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..775465350b --- /dev/null +++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,34 @@ +SKIP: FXC rejects non-uniform texture sample operation in output + +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) { + ^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + float4 v = (0.0f).xxxx; + { + for(; (x > v.x); ) { + v = t.Sample(s, (0.0f).xx); + } + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..ad2f02662b --- /dev/null +++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.glsl @@ -0,0 +1,31 @@ +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) { + ^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +uniform highp sampler2D t_s; + +void tint_symbol(float x) { + vec4 v = vec4(0.0f); + { + for(; (x > v.x); ) { + v = texture(t_s, vec2(0.0f)); + } + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..e7bb2ff9f4 --- /dev/null +++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.msl @@ -0,0 +1,31 @@ +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) { + ^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x, texture2d tint_symbol_3, sampler tint_symbol_4) { + float4 v = float4(0.0f); + for(; (x > v[0]); ) { + v = tint_symbol_3.sample(tint_symbol_4, float2(0.0f)); + } +} + +fragment void tint_symbol(texture2d tint_symbol_5 [[texture(0)]], sampler tint_symbol_6 [[sampler(0)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) { + tint_symbol_inner(tint_symbol_1.x, tint_symbol_5, tint_symbol_6); + return; +} + diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..ac9e7c3fa4 --- /dev/null +++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,91 @@ +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) { + ^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %v "v" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %v4float = OpTypeVector %float 4 + %16 = OpConstantNull %v4float +%_ptr_Function_v4float = OpTypePointer Function %v4float + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Function_float = OpTypePointer Function %float + %bool = OpTypeBool + %36 = OpTypeSampledImage %6 + %v2float = OpTypeVector %float 2 + %39 = OpConstantNull %v2float + %40 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %v = OpVariable %_ptr_Function_v4float Function %16 + OpStore %v %16 + OpBranch %19 + %19 = OpLabel + OpLoopMerge %20 %21 None + OpBranch %22 + %22 = OpLabel + %27 = OpAccessChain %_ptr_Function_float %v %uint_0 + %28 = OpLoad %float %27 + %29 = OpFOrdGreaterThan %bool %x %28 + %23 = OpLogicalNot %bool %29 + OpSelectionMerge %31 None + OpBranchConditional %23 %32 %31 + %32 = OpLabel + OpBranch %20 + %31 = OpLabel + %34 = OpLoad %9 %s + %35 = OpLoad %6 %t + %37 = OpSampledImage %36 %35 %34 + %33 = OpImageSampleImplicitLod %v4float %37 %39 + OpStore %v %33 + OpBranch %21 + %21 = OpLabel + OpBranch %19 + %20 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %40 + %42 = OpLabel + %44 = OpLoad %float %x_1 + %43 = OpFunctionCall %void %main_inner %44 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..4b788863a8 --- /dev/null +++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,23 @@ +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) { + ^^^ + +diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + var v = vec4(0); + for(; (x > v.x); ) @diagnostic(warning, derivative_uniformity) { + v = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl new file mode 100644 index 0000000000..2eb25176be --- /dev/null +++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl @@ -0,0 +1,9 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) @diagnostic(warning, derivative_uniformity) { + if (x > 0) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..2bc81b83e2 --- /dev/null +++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,28 @@ +diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..2bc81b83e2 --- /dev/null +++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,28 @@ +diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..8c6f30fabf --- /dev/null +++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.glsl @@ -0,0 +1,25 @@ +diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + if ((x > 0.0f)) { + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..582d57b5a8 --- /dev/null +++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.msl @@ -0,0 +1,29 @@ +diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + if ((x > 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/function_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..247e66ccee --- /dev/null +++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,63 @@ +diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 25 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %15 = OpConstantNull %float + %bool = OpTypeBool + %20 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %16 = OpFOrdGreaterThan %bool %x %15 + OpSelectionMerge %18 None + OpBranchConditional %16 %19 %18 + %19 = OpLabel + OpBranch %18 + %18 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %20 + %22 = OpLabel + %24 = OpLoad %float %x_1 + %23 = OpFunctionCall %void %main_inner %24 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..0887fe67f9 --- /dev/null +++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,22 @@ +diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) { + ^^ + +diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) { + ^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) @diagnostic(warning, derivative_uniformity) { + if ((x > 0)) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl new file mode 100644 index 0000000000..7f4ef9d7da --- /dev/null +++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl @@ -0,0 +1,9 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + if (x > 0) @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..36bf7b9d02 --- /dev/null +++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,28 @@ +diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..36bf7b9d02 --- /dev/null +++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,28 @@ +diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + if ((x > 0.0f)) { + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..b7d37e1a49 --- /dev/null +++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.glsl @@ -0,0 +1,25 @@ +diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +void tint_symbol(float x) { + if ((x > 0.0f)) { + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..ad671d2a88 --- /dev/null +++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.msl @@ -0,0 +1,29 @@ +diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x) { + if ((x > 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/if_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..61847a29c4 --- /dev/null +++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,63 @@ +diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 25 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %15 = OpConstantNull %float + %bool = OpTypeBool + %20 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %16 = OpFOrdGreaterThan %bool %x %15 + OpSelectionMerge %18 None + OpBranchConditional %16 %19 %18 + %19 = OpLabel + OpBranch %18 + %18 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %20 + %22 = OpLabel + %24 = OpLoad %float %x_1 + %23 = OpFunctionCall %void %main_inner %24 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..4cd063c733 --- /dev/null +++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,22 @@ +diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow + _ = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^^ + +diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform + if (x > 0) @diagnostic(warning, derivative_uniformity) { + ^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + if ((x > 0)) @diagnostic(warning, derivative_uniformity) { + _ = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl new file mode 100644 index 0000000000..19283335bc --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl @@ -0,0 +1,10 @@ +@group(0) @binding(1) var t : texture_2d; +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + var v = vec4(0); + while (x > v.x) @diagnostic(warning, derivative_uniformity) { + v = textureSample(t, s, vec2(0, 0)); + } +} diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..8a6d04b91b --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.dxc.hlsl @@ -0,0 +1,30 @@ +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + while (x > v.x) @diagnostic(warning, derivative_uniformity) { + ^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + float4 v = (0.0f).xxxx; + while((x > v.x)) { + v = t.Sample(s, (0.0f).xx); + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..0f012af4b3 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.fxc.hlsl @@ -0,0 +1,32 @@ +SKIP: FXC rejects non-uniform texture sample operation in output + +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + while (x > v.x) @diagnostic(warning, derivative_uniformity) { + ^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +Texture2D t : register(t1, space0); +SamplerState s : register(s2, space0); + +struct tint_symbol_1 { + float x : TEXCOORD0; +}; + +void main_inner(float x) { + float4 v = (0.0f).xxxx; + while((x > v.x)) { + v = t.Sample(s, (0.0f).xx); + } +} + +void main(tint_symbol_1 tint_symbol) { + main_inner(tint_symbol.x); + return; +} diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.glsl new file mode 100644 index 0000000000..9b9957d7a5 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.glsl @@ -0,0 +1,29 @@ +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + while (x > v.x) @diagnostic(warning, derivative_uniformity) { + ^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +#version 310 es +precision mediump float; + +layout(location = 0) in float x_1; +uniform highp sampler2D t_s; + +void tint_symbol(float x) { + vec4 v = vec4(0.0f); + while((x > v.x)) { + v = texture(t_s, vec2(0.0f)); + } +} + +void main() { + tint_symbol(x_1); + return; +} diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.msl new file mode 100644 index 0000000000..73a56be1a3 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.msl @@ -0,0 +1,31 @@ +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + while (x > v.x) @diagnostic(warning, derivative_uniformity) { + ^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +#include + +using namespace metal; +struct tint_symbol_2 { + float x [[user(locn0)]]; +}; + +void tint_symbol_inner(float x, texture2d tint_symbol_3, sampler tint_symbol_4) { + float4 v = float4(0.0f); + while((x > v[0])) { + v = tint_symbol_3.sample(tint_symbol_4, float2(0.0f)); + } +} + +fragment void tint_symbol(texture2d tint_symbol_5 [[texture(0)]], sampler tint_symbol_6 [[sampler(0)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) { + tint_symbol_inner(tint_symbol_1.x, tint_symbol_5, tint_symbol_6); + return; +} + diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.spvasm new file mode 100644 index 0000000000..f172769ad3 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.spvasm @@ -0,0 +1,91 @@ +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + while (x > v.x) @diagnostic(warning, derivative_uniformity) { + ^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %x_1 + OpExecutionMode %main OriginUpperLeft + OpName %x_1 "x_1" + OpName %t "t" + OpName %s "s" + OpName %main_inner "main_inner" + OpName %x "x" + OpName %v "v" + OpName %main "main" + OpDecorate %x_1 Location 0 + OpDecorate %t DescriptorSet 0 + OpDecorate %t Binding 1 + OpDecorate %s DescriptorSet 0 + OpDecorate %s Binding 2 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %x_1 = OpVariable %_ptr_Input_float Input + %6 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 + %t = OpVariable %_ptr_UniformConstant_6 UniformConstant + %9 = OpTypeSampler +%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9 + %s = OpVariable %_ptr_UniformConstant_9 UniformConstant + %void = OpTypeVoid + %10 = OpTypeFunction %void %float + %v4float = OpTypeVector %float 4 + %16 = OpConstantNull %v4float +%_ptr_Function_v4float = OpTypePointer Function %v4float + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Function_float = OpTypePointer Function %float + %bool = OpTypeBool + %36 = OpTypeSampledImage %6 + %v2float = OpTypeVector %float 2 + %39 = OpConstantNull %v2float + %40 = OpTypeFunction %void + %main_inner = OpFunction %void None %10 + %x = OpFunctionParameter %float + %14 = OpLabel + %v = OpVariable %_ptr_Function_v4float Function %16 + OpStore %v %16 + OpBranch %19 + %19 = OpLabel + OpLoopMerge %20 %21 None + OpBranch %22 + %22 = OpLabel + %27 = OpAccessChain %_ptr_Function_float %v %uint_0 + %28 = OpLoad %float %27 + %29 = OpFOrdGreaterThan %bool %x %28 + %23 = OpLogicalNot %bool %29 + OpSelectionMerge %31 None + OpBranchConditional %23 %32 %31 + %32 = OpLabel + OpBranch %20 + %31 = OpLabel + %34 = OpLoad %9 %s + %35 = OpLoad %6 %t + %37 = OpSampledImage %36 %35 %34 + %33 = OpImageSampleImplicitLod %v4float %37 %39 + OpStore %v %33 + OpBranch %21 + %21 = OpLabel + OpBranch %19 + %20 = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %40 + %42 = OpLabel + %44 = OpLoad %float %x_1 + %43 = OpFunctionCall %void %main_inner %44 + OpReturn + OpFunctionEnd diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.wgsl new file mode 100644 index 0000000000..b2238a1052 --- /dev/null +++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.wgsl @@ -0,0 +1,23 @@ +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value + while (x > v.x) @diagnostic(warning, derivative_uniformity) { + ^^^^^ + +diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform + v = textureSample(t, s, vec2(0, 0)); + ^^^^^^^^^^^^^ + +@group(0) @binding(1) var t : texture_2d; + +@group(0) @binding(2) var s : sampler; + +@fragment +fn main(@location(0) x : f32) { + var v = vec4(0); + while((x > v.x)) @diagnostic(warning, derivative_uniformity) { + v = textureSample(t, s, vec2(0, 0)); + } +}