From d9f659670d1d72d33a803029729a7cbb6eb275cc Mon Sep 17 00:00:00 2001 From: James Price Date: Wed, 1 Feb 2023 23:14:10 +0000 Subject: [PATCH] tint: Handle @diagnostic on block statements Use expect_compound_statement() in all the places that use compound_statement in the WGSL grammar. Handle attributes on statements inside Resolver::StatementScope, so that the logic can be reused for the various places where block statements are used. This will also make it easier to reuse this logic when we allow these attributes on other types of statement in the future. Add an `EmitBlockHeader()` helper to the WGSL writer to reuse the logic for emitting attributes on block statements for all the places that use them. Bug: tint:1809 Change-Id: Iac3bb01f5031e6134c1798ddafdad080412c8bef Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/118000 Kokoro: Kokoro Reviewed-by: Ben Clayton Commit-Queue: James Price --- src/tint/ast/block_statement.cc | 12 ++- src/tint/ast/block_statement.h | 12 ++- src/tint/ast/block_statement_test.cc | 26 ++++- src/tint/ast/case_statement_test.cc | 24 ++--- src/tint/program_builder.h | 69 +++++++++---- src/tint/reader/spirv/function.cc | 22 ++--- src/tint/reader/wgsl/parser_impl.cc | 65 +++++++----- src/tint/reader/wgsl/parser_impl.h | 9 +- .../wgsl/parser_impl_compound_stmt_test.cc | 8 +- .../reader/wgsl/parser_impl_error_msg_test.cc | 10 +- .../wgsl/parser_impl_function_decl_test.cc | 2 +- .../reader/wgsl/parser_impl_if_stmt_test.cc | 10 +- .../reader/wgsl/parser_impl_statement_test.cc | 14 ++- .../wgsl/parser_impl_while_stmt_test.cc | 6 +- .../resolver/attribute_validation_test.cc | 98 +++++++++++++++++++ src/tint/resolver/diagnostic_control_test.cc | 60 ++++++++++++ src/tint/resolver/resolver.cc | 37 +++++++ src/tint/resolver/uniformity_test.cc | 26 +++++ src/tint/sem/diagnostic_severity_test.cc | 28 +++++- src/tint/writer/wgsl/generator_impl.cc | 65 ++++++++++-- src/tint/writer/wgsl/generator_impl.h | 5 + .../case_body_attribute.wgsl | 13 +++ ...case_body_attribute.wgsl.expected.dxc.hlsl | 34 +++++++ ...case_body_attribute.wgsl.expected.fxc.hlsl | 34 +++++++ .../case_body_attribute.wgsl.expected.glsl | 31 ++++++ .../case_body_attribute.wgsl.expected.msl | 35 +++++++ .../case_body_attribute.wgsl.expected.spvasm | 64 ++++++++++++ .../case_body_attribute.wgsl.expected.wgsl | 26 +++++ .../compound_statement_attribute.wgsl | 11 +++ ...statement_attribute.wgsl.expected.dxc.hlsl | 30 ++++++ ...statement_attribute.wgsl.expected.fxc.hlsl | 30 ++++++ ...und_statement_attribute.wgsl.expected.glsl | 27 +++++ ...ound_statement_attribute.wgsl.expected.msl | 31 ++++++ ...d_statement_attribute.wgsl.expected.spvasm | 63 ++++++++++++ ...und_statement_attribute.wgsl.expected.wgsl | 24 +++++ .../default_case_body_attribute.wgsl | 11 +++ ...case_body_attribute.wgsl.expected.dxc.hlsl | 28 ++++++ ...case_body_attribute.wgsl.expected.fxc.hlsl | 28 ++++++ ...ult_case_body_attribute.wgsl.expected.glsl | 28 ++++++ ...ault_case_body_attribute.wgsl.expected.msl | 32 ++++++ ...t_case_body_attribute.wgsl.expected.spvasm | 62 ++++++++++++ ...ult_case_body_attribute.wgsl.expected.wgsl | 24 +++++ .../else_body_attribute.wgsl | 10 ++ ...else_body_attribute.wgsl.expected.dxc.hlsl | 29 ++++++ ...else_body_attribute.wgsl.expected.fxc.hlsl | 29 ++++++ .../else_body_attribute.wgsl.expected.glsl | 26 +++++ .../else_body_attribute.wgsl.expected.msl | 30 ++++++ .../else_body_attribute.wgsl.expected.spvasm | 65 ++++++++++++ .../else_body_attribute.wgsl.expected.wgsl | 23 +++++ .../else_if_body_attribute.wgsl | 10 ++ ...e_if_body_attribute.wgsl.expected.dxc.hlsl | 31 ++++++ ...e_if_body_attribute.wgsl.expected.fxc.hlsl | 31 ++++++ .../else_if_body_attribute.wgsl.expected.glsl | 28 ++++++ .../else_if_body_attribute.wgsl.expected.msl | 32 ++++++ ...lse_if_body_attribute.wgsl.expected.spvasm | 71 ++++++++++++++ .../else_if_body_attribute.wgsl.expected.wgsl | 23 +++++ .../for_loop_body_attribute.wgsl | 10 ++ ...loop_body_attribute.wgsl.expected.dxc.hlsl | 32 ++++++ ...loop_body_attribute.wgsl.expected.fxc.hlsl | 34 +++++++ ...for_loop_body_attribute.wgsl.expected.glsl | 31 ++++++ .../for_loop_body_attribute.wgsl.expected.msl | 31 ++++++ ...r_loop_body_attribute.wgsl.expected.spvasm | 91 +++++++++++++++++ ...for_loop_body_attribute.wgsl.expected.wgsl | 23 +++++ .../function_body_attribute.wgsl | 9 ++ ...tion_body_attribute.wgsl.expected.dxc.hlsl | 28 ++++++ ...tion_body_attribute.wgsl.expected.fxc.hlsl | 28 ++++++ ...function_body_attribute.wgsl.expected.glsl | 25 +++++ .../function_body_attribute.wgsl.expected.msl | 29 ++++++ ...nction_body_attribute.wgsl.expected.spvasm | 63 ++++++++++++ ...function_body_attribute.wgsl.expected.wgsl | 22 +++++ .../if_body_attribute.wgsl | 9 ++ .../if_body_attribute.wgsl.expected.dxc.hlsl | 28 ++++++ .../if_body_attribute.wgsl.expected.fxc.hlsl | 28 ++++++ .../if_body_attribute.wgsl.expected.glsl | 25 +++++ .../if_body_attribute.wgsl.expected.msl | 29 ++++++ .../if_body_attribute.wgsl.expected.spvasm | 63 ++++++++++++ .../if_body_attribute.wgsl.expected.wgsl | 22 +++++ .../while_loop_body_attribute.wgsl | 10 ++ ...loop_body_attribute.wgsl.expected.dxc.hlsl | 30 ++++++ ...loop_body_attribute.wgsl.expected.fxc.hlsl | 32 ++++++ ...ile_loop_body_attribute.wgsl.expected.glsl | 29 ++++++ ...hile_loop_body_attribute.wgsl.expected.msl | 31 ++++++ ...e_loop_body_attribute.wgsl.expected.spvasm | 91 +++++++++++++++++ ...ile_loop_body_attribute.wgsl.expected.wgsl | 23 +++++ 84 files changed, 2506 insertions(+), 112 deletions(-) create mode 100644 test/tint/diagnostic_filtering/case_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/compound_statement_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/default_case_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/else_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/else_if_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/function_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/if_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.wgsl create mode 100644 test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl create mode 100644 test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.dxc.hlsl create mode 100644 test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.fxc.hlsl create mode 100644 test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.glsl create mode 100644 test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.msl create mode 100644 test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.spvasm create mode 100644 test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.wgsl 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)); + } +}