diff --git a/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp b/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp index 57069ed6c2..d6add45355 100644 --- a/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp +++ b/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp @@ -663,7 +663,7 @@ TEST_F(ShaderModuleValidationTest, MissingDecorations) { // Test that WGSL extension used by enable directives must be allowed by WebGPU. TEST_F(ShaderModuleValidationTest, ExtensionMustBeAllowed) { ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"( -enable InternalExtensionForTesting; +enable f16; @stage(compute) @workgroup_size(1) fn main() {})")); } diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 0cacca4681..2f4fd62730 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -226,6 +226,8 @@ libtint_source_set("libtint_core_all_src") { "ast/enable.h", "ast/expression.cc", "ast/expression.h", + "ast/extension.cc", + "ast/extension.h", "ast/external_texture.cc", "ast/external_texture.h", "ast/f16.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index f4c38840c0..2c03e8130b 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -114,6 +114,8 @@ set(TINT_LIB_SRCS ast/enable.h ast/expression.cc ast/expression.h + ast/extension.cc + ast/extension.h ast/external_texture.cc ast/external_texture.h ast/f16.cc @@ -691,6 +693,7 @@ if(TINT_BUILD_TESTS) ast/depth_texture_test.cc ast/discard_statement_test.cc ast/enable_test.cc + ast/extension_test.cc ast/external_texture_test.cc ast/f16_test.cc ast/f32_test.cc diff --git a/src/tint/ast/enable.cc b/src/tint/ast/enable.cc index 200c2bec00..ef43200c05 100644 --- a/src/tint/ast/enable.cc +++ b/src/tint/ast/enable.cc @@ -21,47 +21,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Enable); namespace tint::ast { -Enable::ExtensionKind Enable::NameToKind(const std::string& name) { - if (name == "chromium_experimental_dp4a") { - return Enable::ExtensionKind::kChromiumExperimentalDP4a; - } - if (name == "chromium_disable_uniformity_analysis") { - return Enable::ExtensionKind::kChromiumDisableUniformityAnalysis; - } - if (name == "f16") { - return Enable::ExtensionKind::kF16; - } - - // The reserved internal extension name for testing - if (name == "InternalExtensionForTesting") { - return Enable::ExtensionKind::kInternalExtensionForTesting; - } - - return Enable::ExtensionKind::kNoExtension; -} - -std::string Enable::KindToName(ExtensionKind kind) { - switch (kind) { - case ExtensionKind::kChromiumExperimentalDP4a: - return "chromium_experimental_dp4a"; - case ExtensionKind::kChromiumDisableUniformityAnalysis: - return "chromium_disable_uniformity_analysis"; - case ExtensionKind::kF16: - return "f16"; - // The reserved internal extension for testing - case ExtensionKind::kInternalExtensionForTesting: - return "InternalExtensionForTesting"; - case ExtensionKind::kNoExtension: - // Return an empty string for kNoExtension - return {}; - // No default case, as this switch must cover all ExtensionKind values. - } - // This return shall never get hit. - return {}; -} - -Enable::Enable(ProgramID pid, const Source& src, const std::string& ext_name) - : Base(pid, src), name(ext_name), kind(NameToKind(ext_name)) {} +Enable::Enable(ProgramID pid, const Source& src, Extension ext) : Base(pid, src), extension(ext) {} Enable::Enable(Enable&&) = default; @@ -69,6 +29,6 @@ Enable::~Enable() = default; const Enable* Enable::Clone(CloneContext* ctx) const { auto src = ctx->Clone(source); - return ctx->dst->create(src, name); + return ctx->dst->create(src, extension); } } // namespace tint::ast diff --git a/src/tint/ast/enable.h b/src/tint/ast/enable.h index f190b0a792..674d9cb42f 100644 --- a/src/tint/ast/enable.h +++ b/src/tint/ast/enable.h @@ -16,63 +16,26 @@ #define SRC_TINT_AST_ENABLE_H_ #include -#include #include +#include -#include "src/tint/ast/access.h" -#include "src/tint/ast/expression.h" +#include "src/tint/ast/extension.h" +#include "src/tint/ast/node.h" namespace tint::ast { -/// An instance of this class represents one extension mentioned in a -/// "enable" derictive. Example: -/// // Enable an extension named "f16" -/// enable f16; -class Enable : public Castable { +/// An "enable" directive. Example: +/// ``` +/// // Enable an extension named "f16" +/// enable f16; +/// ``` +class Enable final : public Castable { public: - /// The enum class identifing each supported WGSL extension - enum class ExtensionKind { - /// An internal reserved extension for test, named - /// "InternalExtensionForTesting". - kInternalExtensionForTesting, - /// WGSL Extension "f16" - kF16, - - /// An extension for the experimental feature - /// "chromium_experimental_dp4a". - /// See crbug.com/tint/1497 for more details - kChromiumExperimentalDP4a, - /// A Chromium-specific extension for disabling uniformity analysis. - kChromiumDisableUniformityAnalysis, - - /// Reserved for representing "No extension required" or "Not a valid extension". - kNoExtension, - }; - - /// Convert a string of extension name into one of ExtensionKind enum value, - /// the result will be ExtensionKind::kNoExtension if the name is not a - /// known extension name. A extension node of kind kNoExtension must not - /// exist in the AST tree, and using a unknown extension name in WGSL code - /// should result in a shader-creation error. - /// @param name string of the extension name - /// @return the ExtensionKind enum value for the extension of given name, or - /// kNoExtension if no known extension has the given name - static ExtensionKind NameToKind(const std::string& name); - - /// Convert the ExtensionKind enum value to corresponding extension name - /// string. If the given enum value is kNoExtension or don't have a known - /// name, return an empty string instead. - /// @param kind the ExtensionKind enum value - /// @return string of the extension name corresponding to the given kind, or - /// an empty string if the given enum value is kNoExtension or don't have a - /// known corresponding name - static std::string KindToName(ExtensionKind kind); - /// Create a extension /// @param pid the identifier of the program that owns this node /// @param src the source of this node - /// @param name the name of extension - Enable(ProgramID pid, const Source& src, const std::string& name); + /// @param ext the extension + Enable(ProgramID pid, const Source& src, Extension ext); /// Move constructor Enable(Enable&&); @@ -85,14 +48,11 @@ class Enable : public Castable { const Enable* Clone(CloneContext* ctx) const override; /// The extension name - const std::string name; - - /// The extension kind - const ExtensionKind kind; + const Extension extension; }; -/// A set of extension kinds -using ExtensionSet = std::unordered_set; +/// A list of enables +using EnableList = std::vector; } // namespace tint::ast diff --git a/src/tint/ast/enable_test.cc b/src/tint/ast/enable_test.cc index 208c85df89..e8b6e5c20f 100644 --- a/src/tint/ast/enable_test.cc +++ b/src/tint/ast/enable_test.cc @@ -19,40 +19,15 @@ namespace tint::ast { namespace { -using AstExtensionTest = TestHelper; +using EnableTest = TestHelper; -TEST_F(AstExtensionTest, Creation) { - auto* ext = - create(Source{Source::Range{Source::Location{20, 2}, Source::Location{20, 5}}}, - "InternalExtensionForTesting"); +TEST_F(EnableTest, Creation) { + auto* ext = create(Source{{{20, 2}, {20, 5}}}, Extension::kF16); EXPECT_EQ(ext->source.range.begin.line, 20u); EXPECT_EQ(ext->source.range.begin.column, 2u); EXPECT_EQ(ext->source.range.end.line, 20u); EXPECT_EQ(ext->source.range.end.column, 5u); - EXPECT_EQ(ext->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting); -} - -TEST_F(AstExtensionTest, Creation_InvalidName) { - auto* ext = create( - Source{Source::Range{Source::Location{20, 2}, Source::Location{20, 5}}}, std::string()); - EXPECT_EQ(ext->source.range.begin.line, 20u); - EXPECT_EQ(ext->source.range.begin.column, 2u); - EXPECT_EQ(ext->source.range.end.line, 20u); - EXPECT_EQ(ext->source.range.end.column, 5u); - EXPECT_EQ(ext->kind, ast::Enable::ExtensionKind::kNoExtension); -} - -TEST_F(AstExtensionTest, NameToKind_InvalidName) { - EXPECT_EQ(ast::Enable::NameToKind(std::string()), ast::Enable::ExtensionKind::kNoExtension); - EXPECT_EQ(ast::Enable::NameToKind("__ImpossibleExtensionName"), - ast::Enable::ExtensionKind::kNoExtension); - EXPECT_EQ(ast::Enable::NameToKind("123"), ast::Enable::ExtensionKind::kNoExtension); -} - -TEST_F(AstExtensionTest, KindToName) { - EXPECT_EQ(ast::Enable::KindToName(ast::Enable::ExtensionKind::kInternalExtensionForTesting), - "InternalExtensionForTesting"); - EXPECT_EQ(ast::Enable::KindToName(ast::Enable::ExtensionKind::kNoExtension), std::string()); + EXPECT_EQ(ext->extension, Extension::kF16); } } // namespace diff --git a/src/tint/ast/extension.cc b/src/tint/ast/extension.cc new file mode 100644 index 0000000000..f03e3a0298 --- /dev/null +++ b/src/tint/ast/extension.cc @@ -0,0 +1,51 @@ +// Copyright 2022 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/tint/ast/extension.h" + +namespace tint::ast { + +Extension ParseExtension(const std::string& name) { + if (name == "chromium_experimental_dp4a") { + return Extension::kChromiumExperimentalDP4a; + } + if (name == "chromium_disable_uniformity_analysis") { + return Extension::kChromiumDisableUniformityAnalysis; + } + if (name == "f16") { + return Extension::kF16; + } + return Extension::kNone; +} + +const char* str(Extension ext) { + switch (ext) { + case Extension::kChromiumExperimentalDP4a: + return "chromium_experimental_dp4a"; + case Extension::kChromiumDisableUniformityAnalysis: + return "chromium_disable_uniformity_analysis"; + case Extension::kF16: + return "f16"; + case Extension::kNone: + return ""; + } + return ""; +} + +std::ostream& operator<<(std::ostream& out, Extension i) { + out << str(i); + return out; +} + +} // namespace tint::ast diff --git a/src/tint/ast/extension.h b/src/tint/ast/extension.h new file mode 100644 index 0000000000..21e9ac15b3 --- /dev/null +++ b/src/tint/ast/extension.h @@ -0,0 +1,68 @@ +// Copyright 2022 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_TINT_AST_EXTENSION_H_ +#define SRC_TINT_AST_EXTENSION_H_ + +#include +#include + +#include "src/tint/utils/unique_vector.h" + +namespace tint::ast { + +/// An enumerator of WGSL extensions +enum class Extension { + /// WGSL Extension "f16" + kF16, + + /// An extension for the experimental feature + /// "chromium_experimental_dp4a". + /// See crbug.com/tint/1497 for more details + kChromiumExperimentalDP4a, + /// A Chromium-specific extension for disabling uniformity analysis. + kChromiumDisableUniformityAnalysis, + + /// Reserved for representing "No extension required" or "Not a valid extension". + kNone, +}; + +/// Convert a string of extension name into one of Extension enum value, the result will be +/// Extension::kNone if the name is not a known extension name. A extension node of kind +/// kNone must not exist in the AST tree, and using a unknown extension name in WGSL code +/// should result in a shader-creation error. +/// @param name string of the extension name +/// @return the Extension enum value for the extension of given name, or kNone if no known extension +/// has the given name +Extension ParseExtension(const std::string& name); + +/// Convert the Extension enum value to corresponding extension name string. +/// @param ext the Extension enum value +/// @return string of the extension name corresponding to the given kind, or +/// an empty string if the given enum value is kNone or don't have a +/// known corresponding name +const char* ExtensionName(Extension ext); + +/// @returns the name of the extension. +const char* str(Extension i); + +/// Emits the name of the extension type. +std::ostream& operator<<(std::ostream& out, Extension i); + +// A unique vector of extensions +using Extensions = utils::UniqueVector; + +} // namespace tint::ast + +#endif // SRC_TINT_AST_EXTENSION_H_ diff --git a/src/tint/ast/extension_test.cc b/src/tint/ast/extension_test.cc new file mode 100644 index 0000000000..ed27674b9e --- /dev/null +++ b/src/tint/ast/extension_test.cc @@ -0,0 +1,36 @@ + +// Copyright 2021 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/tint/ast/extension.h" + +#include "gtest/gtest.h" + +namespace tint::ast { +namespace { + +TEST(ExtensionTest, NameToKind_InvalidName) { + EXPECT_EQ(ParseExtension("f16"), Extension::kF16); + EXPECT_EQ(ParseExtension(""), Extension::kNone); + EXPECT_EQ(ParseExtension("__ImpossibleExtensionName"), Extension::kNone); + EXPECT_EQ(ParseExtension("123"), Extension::kNone); +} + +TEST(ExtensionTest, KindToName) { + EXPECT_EQ(std::string(str(Extension::kF16)), "f16"); + EXPECT_EQ(std::string(str(Extension::kNone)), ""); +} + +} // namespace +} // namespace tint::ast diff --git a/src/tint/ast/module.cc b/src/tint/ast/module.cc index e163c19d99..40dff98599 100644 --- a/src/tint/ast/module.cc +++ b/src/tint/ast/module.cc @@ -68,18 +68,18 @@ void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id); global_variables_.push_back(var); }, - [&](const Enable* ext) { - TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, ext, program_id); - extensions_.insert(ext->kind); + [&](const Enable* enable) { + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id); + enables_.push_back(enable); }, [&](Default) { TINT_ICE(AST, diags) << "Unknown global declaration type"; }); } -void Module::AddEnable(const ast::Enable* ext) { - TINT_ASSERT(AST, ext); - TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, ext, program_id); - global_declarations_.push_back(ext); - extensions_.insert(ext->kind); +void Module::AddEnable(const ast::Enable* enable) { + TINT_ASSERT(AST, enable); + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id); + global_declarations_.push_back(enable); + enables_.push_back(enable); } void Module::AddGlobalVariable(const ast::Variable* var) { @@ -117,7 +117,7 @@ void Module::Copy(CloneContext* ctx, const Module* src) { type_decls_.clear(); functions_.clear(); global_variables_.clear(); - extensions_.clear(); + enables_.clear(); for (auto* decl : global_declarations_) { if (!decl) { diff --git a/src/tint/ast/module.h b/src/tint/ast/module.h index d8be2ed67b..45b1ec6ebe 100644 --- a/src/tint/ast/module.h +++ b/src/tint/ast/module.h @@ -78,7 +78,7 @@ class Module final : public Castable { VariableList& GlobalVariables() { return global_variables_; } /// @returns the extension set for the module - const ExtensionSet& Extensions() const { return extensions_; } + const EnableList& Enables() const { return enables_; } /// Adds a type declaration to the Builder. /// @param decl the type declaration to add @@ -120,7 +120,7 @@ class Module final : public Castable { std::vector type_decls_; FunctionList functions_; VariableList global_variables_; - ExtensionSet extensions_; + EnableList enables_; }; } // namespace tint::ast diff --git a/src/tint/inspector/inspector.cc b/src/tint/inspector/inspector.cc index 2bfe8157a5..9a2afb8eee 100644 --- a/src/tint/inspector/inspector.cc +++ b/src/tint/inspector/inspector.cc @@ -19,6 +19,7 @@ #include "src/tint/ast/bool_literal_expression.h" #include "src/tint/ast/call_expression.h" +#include "src/tint/ast/extension.h" #include "src/tint/ast/float_literal_expression.h" #include "src/tint/ast/id_attribute.h" #include "src/tint/ast/interpolate_attribute.h" @@ -32,6 +33,7 @@ #include "src/tint/sem/function.h" #include "src/tint/sem/i32.h" #include "src/tint/sem/matrix.h" +#include "src/tint/sem/module.h" #include "src/tint/sem/multisampled_texture.h" #include "src/tint/sem/sampled_texture.h" #include "src/tint/sem/statement.h" @@ -544,16 +546,13 @@ uint32_t Inspector::GetWorkgroupStorageSize(const std::string& entry_point) { } std::vector Inspector::GetUsedExtensionNames() { - std::vector result; - - ast::ExtensionSet set = program_->AST().Extensions(); - result.reserve(set.size()); - for (auto kind : set) { - std::string name = ast::Enable::KindToName(kind); - result.push_back(name); + auto& extensions = program_->Sem().Module()->Extensions(); + std::vector out; + out.reserve(extensions.size()); + for (auto ext : extensions) { + out.push_back(ast::str(ext)); } - - return result; + return out; } std::vector> Inspector::GetEnableDirectives() { @@ -563,7 +562,7 @@ std::vector> Inspector::GetEnableDirectives() { auto global_decls = program_->AST().GlobalDeclarations(); for (auto* node : global_decls) { if (auto* ext = node->As()) { - result.push_back({ext->name, ext->source}); + result.push_back({ast::str(ext->extension), ext->source}); } } diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc index 18a33b1afa..033f5b82b1 100644 --- a/src/tint/inspector/inspector_test.cc +++ b/src/tint/inspector/inspector_test.cc @@ -2849,7 +2849,7 @@ fn main() { // Test calling GetUsedExtensionNames on a shader with valid extension. TEST_F(InspectorGetUsedExtensionNamesTest, Simple) { std::string shader = R"( -enable InternalExtensionForTesting; +enable f16; @stage(fragment) fn main() { @@ -2859,15 +2859,15 @@ fn main() { auto result = inspector.GetUsedExtensionNames(); EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0], "InternalExtensionForTesting"); + EXPECT_EQ(result[0], "f16"); } // Test calling GetUsedExtensionNames on a shader with a extension enabled for // multiple times. TEST_F(InspectorGetUsedExtensionNamesTest, Duplicated) { std::string shader = R"( -enable InternalExtensionForTesting; -enable InternalExtensionForTesting; +enable f16; +enable f16; @stage(fragment) fn main() { @@ -2877,7 +2877,7 @@ fn main() { auto result = inspector.GetUsedExtensionNames(); EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0], "InternalExtensionForTesting"); + EXPECT_EQ(result[0], "f16"); } // Test calling GetEnableDirectives on a empty shader. @@ -2906,7 +2906,7 @@ fn main() { // Test calling GetEnableDirectives on a shader with valid extension. TEST_F(InspectorGetEnableDirectivesTest, Simple) { std::string shader = R"( -enable InternalExtensionForTesting; +enable f16; @stage(fragment) fn main() { @@ -2916,17 +2916,17 @@ fn main() { auto result = inspector.GetEnableDirectives(); EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0].first, "InternalExtensionForTesting"); - EXPECT_EQ(result[0].second.range, (Source::Range{{2, 8}, {2, 35}})); + EXPECT_EQ(result[0].first, "f16"); + EXPECT_EQ(result[0].second.range, (Source::Range{{2, 8}, {2, 11}})); } // Test calling GetEnableDirectives on a shader with a extension enabled for // multiple times. TEST_F(InspectorGetEnableDirectivesTest, Duplicated) { std::string shader = R"( -enable InternalExtensionForTesting; +enable f16; -enable InternalExtensionForTesting; +enable f16; @stage(fragment) fn main() { })"; @@ -2935,10 +2935,10 @@ fn main() { auto result = inspector.GetEnableDirectives(); EXPECT_EQ(result.size(), 2u); - EXPECT_EQ(result[0].first, "InternalExtensionForTesting"); - EXPECT_EQ(result[0].second.range, (Source::Range{{2, 8}, {2, 35}})); - EXPECT_EQ(result[1].first, "InternalExtensionForTesting"); - EXPECT_EQ(result[1].second.range, (Source::Range{{4, 8}, {4, 35}})); + EXPECT_EQ(result[0].first, "f16"); + EXPECT_EQ(result[0].second.range, (Source::Range{{2, 8}, {2, 11}})); + EXPECT_EQ(result[1].first, "f16"); + EXPECT_EQ(result[1].second.range, (Source::Range{{4, 8}, {4, 11}})); } // Crash was occuring in ::GenerateSamplerTargets, when diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index a91d87c82e..32c0e93382 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -39,6 +39,7 @@ #include "src/tint/ast/disable_validation_attribute.h" #include "src/tint/ast/discard_statement.h" #include "src/tint/ast/enable.h" +#include "src/tint/ast/extension.h" #include "src/tint/ast/external_texture.h" #include "src/tint/ast/f16.h" #include "src/tint/ast/f32.h" @@ -1307,6 +1308,15 @@ class ProgramBuilder { return Construct(ty.array(subtype, std::forward(n)), std::forward(args)...); } + /// Adds the extension to the list of enable directives at the top of the module. + /// @param ext the extension to enable + /// @return an `ast::Enable` enabling the given extension. + const ast::Enable* Enable(ast::Extension ext) { + auto* enable = create(ext); + AST().AddEnable(enable); + return enable; + } + /// @param name the variable name /// @param type the variable type /// @param optional the optional variable settings. diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc index abd97e50ca..4f0b152934 100644 --- a/src/tint/reader/wgsl/parser_impl.cc +++ b/src/tint/reader/wgsl/parser_impl.cc @@ -366,13 +366,11 @@ Maybe ParserImpl::enable_directive() { return Failure::kErrored; } - if (ast::Enable::NameToKind(name.value) != ast::Enable::ExtensionKind::kNoExtension) { - const ast::Enable* extension = create(name.source, name.value); - builder_.AST().AddEnable(extension); - } else { - // Error if an unknown extension is used + auto extension = ast::ParseExtension(name.value); + if (extension == ast::Extension::kNone) { return add_error(name.source, "unsupported extension: '" + name.value + "'"); } + builder_.AST().AddEnable(create(name.source, extension)); return true; }); diff --git a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc index 0fd6b802b3..bdf7eebd12 100644 --- a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc +++ b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc @@ -23,41 +23,36 @@ using EnableDirectiveTest = ParserImplTest; // Test a valid enable directive. TEST_F(EnableDirectiveTest, Valid) { - auto p = parser("enable InternalExtensionForTesting;"); + auto p = parser("enable f16;"); p->enable_directive(); EXPECT_FALSE(p->has_error()) << p->error(); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions(), - ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting}); - EXPECT_EQ(ast.GlobalDeclarations().size(), 1u); - auto* node = ast.GlobalDeclarations()[0]->As(); - EXPECT_TRUE(node != nullptr); - EXPECT_EQ(node->name, "InternalExtensionForTesting"); - EXPECT_EQ(node->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting); + ASSERT_EQ(ast.Enables().size(), 1u); + auto* enable = ast.Enables()[0]; + EXPECT_EQ(enable->extension, ast::Extension::kF16); + ASSERT_EQ(ast.GlobalDeclarations().size(), 1u); + EXPECT_EQ(ast.GlobalDeclarations()[0], enable); } // Test multiple enable directives for a same extension. TEST_F(EnableDirectiveTest, EnableMultipleTime) { auto p = parser(R"( -enable InternalExtensionForTesting; -enable InternalExtensionForTesting; +enable f16; +enable f16; )"); p->translation_unit(); EXPECT_FALSE(p->has_error()) << p->error(); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions(), - ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting}); - EXPECT_EQ(ast.GlobalDeclarations().size(), 2u); - auto* node1 = ast.GlobalDeclarations()[0]->As(); - EXPECT_TRUE(node1 != nullptr); - EXPECT_EQ(node1->name, "InternalExtensionForTesting"); - EXPECT_EQ(node1->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting); - auto* node2 = ast.GlobalDeclarations()[1]->As(); - EXPECT_TRUE(node2 != nullptr); - EXPECT_EQ(node2->name, "InternalExtensionForTesting"); - EXPECT_EQ(node2->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting); + ASSERT_EQ(ast.Enables().size(), 2u); + auto* enable_a = ast.Enables()[0]; + auto* enable_b = ast.Enables()[1]; + EXPECT_EQ(enable_a->extension, ast::Extension::kF16); + EXPECT_EQ(enable_b->extension, ast::Extension::kF16); + ASSERT_EQ(ast.GlobalDeclarations().size(), 2u); + EXPECT_EQ(ast.GlobalDeclarations()[0], enable_a); + EXPECT_EQ(ast.GlobalDeclarations()[1], enable_b); } // Test an unknown extension identifier. @@ -69,42 +64,42 @@ TEST_F(EnableDirectiveTest, InvalidIdentifier) { EXPECT_EQ(p->error(), "1:8: unsupported extension: 'NotAValidExtensionName'"); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions().size(), 0u); + EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); } -// Test an enable directive missing ending semiclon. -TEST_F(EnableDirectiveTest, MissingEndingSemiclon) { - auto p = parser("enable InternalExtensionForTesting"); +// Test an enable directive missing ending semicolon. +TEST_F(EnableDirectiveTest, MissingEndingSemicolon) { + auto p = parser("enable f16"); p->translation_unit(); EXPECT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:35: expected ';' for enable directive"); + EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive"); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions().size(), 0u); + EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); } // Test using invalid tokens in an enable directive. TEST_F(EnableDirectiveTest, InvalidTokens) { { - auto p = parser("enable InternalExtensionForTesting<;"); + auto p = parser("enable f16<;"); p->translation_unit(); EXPECT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:35: expected ';' for enable directive"); + EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive"); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions().size(), 0u); + EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); } { - auto p = parser("enable translation_unit(); EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: invalid extension name"); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions().size(), 0u); + EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); } { @@ -114,7 +109,7 @@ TEST_F(EnableDirectiveTest, InvalidTokens) { EXPECT_EQ(p->error(), "1:8: invalid extension name"); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions().size(), 0u); + EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); } { @@ -124,7 +119,7 @@ TEST_F(EnableDirectiveTest, InvalidTokens) { EXPECT_EQ(p->error(), "1:8: invalid extension name"); auto program = p->program(); auto& ast = program.AST(); - EXPECT_EQ(ast.Extensions().size(), 0u); + EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); } } @@ -133,35 +128,39 @@ TEST_F(EnableDirectiveTest, InvalidTokens) { TEST_F(EnableDirectiveTest, FollowingOtherGlobalDecl) { auto p = parser(R"( var t: f32 = 0f; -enable InternalExtensionForTesting; +enable f16; )"); p->translation_unit(); EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "3:1: enable directives must come before all global declarations"); auto program = p->program(); auto& ast = program.AST(); - // Accept the enable directive although it cause an error - EXPECT_EQ(ast.Extensions(), - ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting}); - EXPECT_EQ(ast.GlobalDeclarations().size(), 2u); + // Accept the enable directive although it caused an error + ASSERT_EQ(ast.Enables().size(), 1u); + auto* enable = ast.Enables()[0]; + EXPECT_EQ(enable->extension, ast::Extension::kF16); + ASSERT_EQ(ast.GlobalDeclarations().size(), 2u); + EXPECT_EQ(ast.GlobalDeclarations()[1], enable); } -// Test an enable directive go after an empty semiclon. -TEST_F(EnableDirectiveTest, FollowingEmptySemiclon) { +// Test an enable directive go after an empty semicolon. +TEST_F(EnableDirectiveTest, FollowingEmptySemicolon) { auto p = parser(R"( ; -enable InternalExtensionForTesting; +enable f16; )"); p->translation_unit(); - // An empty semiclon is treated as a global declaration + // An empty semicolon is treated as a global declaration EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "3:1: enable directives must come before all global declarations"); auto program = p->program(); auto& ast = program.AST(); // Accept the enable directive although it cause an error - EXPECT_EQ(ast.Extensions(), - ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting}); - EXPECT_EQ(ast.GlobalDeclarations().size(), 1u); + ASSERT_EQ(ast.Enables().size(), 1u); + auto* enable = ast.Enables()[0]; + EXPECT_EQ(enable->extension, ast::Extension::kF16); + ASSERT_EQ(ast.GlobalDeclarations().size(), 1u); + EXPECT_EQ(ast.GlobalDeclarations()[0], enable); } } // namespace diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc index 0e48b55048..770d8d0b4d 100644 --- a/src/tint/resolver/builtin_validation_test.cc +++ b/src/tint/resolver/builtin_validation_test.cc @@ -378,10 +378,7 @@ using ResolverDP4aExtensionValidationTest = ResolverTest; TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithExtension) { // enable chromium_experimental_dp4a; // fn func { return dot4I8Packed(1u, 2u); } - auto* ext = - create(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}}, - "chromium_experimental_dp4a"); - AST().AddEnable(ext); + Enable(ast::Extension::kChromiumExperimentalDP4a); Func("func", {}, ty.i32(), { @@ -409,10 +406,7 @@ TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithoutExtension) { TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithExtension) { // enable chromium_experimental_dp4a; // fn func { return dot4U8Packed(1u, 2u); } - auto* ext = - create(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}}, - "chromium_experimental_dp4a"); - AST().AddEnable(ext); + Enable(ast::Extension::kChromiumExperimentalDP4a); Func("func", {}, ty.u32(), { diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 4993cfef84..b9c0833c8e 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -101,9 +101,6 @@ bool Resolver::Resolve() { return false; } - // Create the semantic module - builder_->Sem().SetModule(builder_->create(dependencies_.ordered_globals)); - bool result = ResolveInternal(); if (!result && !diagnostics_.contains_errors()) { @@ -111,6 +108,10 @@ bool Resolver::Resolve() { return false; } + // Create the semantic module + builder_->Sem().SetModule(builder_->create( + std::move(dependencies_.ordered_globals), std::move(enabled_extensions_))); + return result; } @@ -120,19 +121,16 @@ bool Resolver::ResolveInternal() { // Process all module-scope declarations in dependency order. for (auto* decl : dependencies_.ordered_globals) { Mark(decl); - // Enable directives don't have sem node. - if (decl->Is()) { - continue; - } - if (!Switch( + if (!Switch( decl, // + [&](const ast::Enable* e) { return Enable(e); }, [&](const ast::TypeDecl* td) { return TypeDecl(td); }, [&](const ast::Function* func) { return Function(func); }, [&](const ast::Variable* var) { return GlobalVariable(var); }, [&](Default) { TINT_UNREACHABLE(Resolver, diagnostics_) << "unhandled global declaration: " << decl->TypeInfo().name; - return nullptr; + return false; })) { return false; } @@ -146,8 +144,10 @@ bool Resolver::ResolveInternal() { return false; } - if (!AnalyzeUniformity(builder_, dependencies_)) { - // TODO(jrprice): Reject programs that fail uniformity analysis. + if (!enabled_extensions_.contains(ast::Extension::kChromiumDisableUniformityAnalysis)) { + if (!AnalyzeUniformity(builder_, dependencies_)) { + // TODO(jrprice): Reject programs that fail uniformity analysis. + } } bool result = true; @@ -174,7 +174,7 @@ sem::Type* Resolver::Type(const ast::Type* ty) { [&](const ast::U32*) { return builder_->create(); }, [&](const ast::F16* t) -> sem::F16* { // Validate if f16 type is allowed. - if (builder_->AST().Extensions().count(ast::Enable::ExtensionKind::kF16) == 0) { + if (!enabled_extensions_.contains(ast::Extension::kF16)) { AddError("f16 used without 'f16' extension enabled", t->source); return nullptr; } @@ -1358,7 +1358,7 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr, current_function_->AddDirectlyCalledBuiltin(builtin); - if (!validator_.RequiredExtensionForBuiltinFunction(call, builder_->AST().Extensions())) { + if (!validator_.RequiredExtensionForBuiltinFunction(call, enabled_extensions_)) { return nullptr; } @@ -1750,6 +1750,11 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) { return sem; } +bool Resolver::Enable(const ast::Enable* enable) { + enabled_extensions_.add(enable->extension); + return true; +} + sem::Type* Resolver::TypeDecl(const ast::TypeDecl* named_type) { sem::Type* result = nullptr; if (auto* alias = named_type->As()) { diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h index 348c8e753a..865c243c00 100644 --- a/src/tint/resolver/resolver.h +++ b/src/tint/resolver/resolver.h @@ -228,6 +228,10 @@ class Resolver { /// @param ty the ast::Type sem::Type* Type(const ast::Type* ty); + /// @param enable the enable declaration + /// @returns the resolved extension + bool Enable(const ast::Enable* enable); + /// @param named_type the named type to resolve /// @returns the resolved semantic type sem::Type* TypeDecl(const ast::TypeDecl* named_type); @@ -351,6 +355,7 @@ class Resolver { DependencyGraph dependencies_; SemHelper sem_; Validator validator_; + ast::Extensions enabled_extensions_; std::vector entry_points_; std::unordered_map atomic_composite_info_; std::unordered_set marked_; diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc index 5f4617eb61..26b705f00a 100644 --- a/src/tint/resolver/type_validation_test.cc +++ b/src/tint/resolver/type_validation_test.cc @@ -665,8 +665,8 @@ TEST_F(ResolverTypeValidationTest, BuiltinAsType) { TEST_F(ResolverTypeValidationTest, F16TypeUsedWithExtension) { // enable f16; // var v : f16; - auto* ext = create("f16"); - AST().AddEnable(ext); + Enable(ast::Extension::kF16); + Global("v", ty.f16(), ast::StorageClass::kPrivate); EXPECT_TRUE(r()->Resolve()) << r()->error(); diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc index 350e93bd06..273a07e44e 100644 --- a/src/tint/resolver/uniformity.cc +++ b/src/tint/resolver/uniformity.cc @@ -1548,11 +1548,6 @@ class UniformityGraph { } // namespace bool AnalyzeUniformity(ProgramBuilder* builder, const DependencyGraph& dependency_graph) { - if (builder->AST().Extensions().count( - ast::Enable::ExtensionKind::kChromiumDisableUniformityAnalysis)) { - return true; - } - UniformityGraph graph(builder); return graph.Build(dependency_graph); } diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc index b278954389..9f698e6a86 100644 --- a/src/tint/resolver/validator.cc +++ b/src/tint/resolver/validator.cc @@ -1553,21 +1553,22 @@ bool Validator::TextureBuiltinFunction(const sem::Call* call) const { check_arg_is_constexpr(sem::ParameterUsage::kComponent, 0, 3); } -bool Validator::RequiredExtensionForBuiltinFunction(const sem::Call* call, - const ast::ExtensionSet& extensionSet) const { +bool Validator::RequiredExtensionForBuiltinFunction( + const sem::Call* call, + const ast::Extensions& enabled_extensions) const { const auto* builtin = call->Target()->As(); if (!builtin) { return true; } const auto extension = builtin->RequiredExtension(); - if (extension == ast::Enable::ExtensionKind::kNoExtension) { + if (extension == ast::Extension::kNone) { return true; } - if (extensionSet.find(extension) == extensionSet.cend()) { + if (!enabled_extensions.contains(extension)) { AddError("cannot call built-in function '" + std::string(builtin->str()) + - "' without extension " + ast::Enable::KindToName(extension), + "' without extension " + ast::str(extension), call->Declaration()->source); return false; } diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h index 6efb543fce..a8c18d5894 100644 --- a/src/tint/resolver/validator.h +++ b/src/tint/resolver/validator.h @@ -361,10 +361,10 @@ class Validator { /// Validates an optional builtin function and its required extension. /// @param call the builtin call to validate - /// @param extensionSet all the extensions declared in current module + /// @param enabled_extensions all the extensions declared in current module /// @returns true on success, false otherwise bool RequiredExtensionForBuiltinFunction(const sem::Call* call, - const ast::ExtensionSet& extensionSet) const; + const ast::Extensions& enabled_extensions) const; /// Validates there are no duplicate attributes /// @param attributes the list of attributes to validate diff --git a/src/tint/sem/builtin.cc b/src/tint/sem/builtin.cc index faf451e01a..bb2878be3a 100644 --- a/src/tint/sem/builtin.cc +++ b/src/tint/sem/builtin.cc @@ -153,11 +153,11 @@ bool Builtin::HasSideEffects() const { return false; } -ast::Enable::ExtensionKind Builtin::RequiredExtension() const { +ast::Extension Builtin::RequiredExtension() const { if (IsDP4a()) { - return ast::Enable::ExtensionKind::kChromiumExperimentalDP4a; + return ast::Extension::kChromiumExperimentalDP4a; } - return ast::Enable::ExtensionKind::kNoExtension; + return ast::Extension::kNone; } } // namespace tint::sem diff --git a/src/tint/sem/builtin.h b/src/tint/sem/builtin.h index 4752f1608d..1dc61ad9d5 100644 --- a/src/tint/sem/builtin.h +++ b/src/tint/sem/builtin.h @@ -18,6 +18,7 @@ #include #include +#include "src/tint/ast/extension.h" #include "src/tint/sem/builtin_type.h" #include "src/tint/sem/call_target.h" #include "src/tint/sem/pipeline_stage_set.h" @@ -144,8 +145,8 @@ class Builtin final : public Castable { bool HasSideEffects() const; /// @returns the required extension of this builtin function. Returns - /// ast::Enable::ExtensionKind::kNoExtension if no extension is required. - ast::Enable::ExtensionKind RequiredExtension() const; + /// ast::Extension::kNone if no extension is required. + ast::Extension RequiredExtension() const; private: const BuiltinType type_; diff --git a/src/tint/sem/module.cc b/src/tint/sem/module.cc index 83b71360a5..7c60650572 100644 --- a/src/tint/sem/module.cc +++ b/src/tint/sem/module.cc @@ -21,8 +21,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Module); namespace tint::sem { -Module::Module(std::vector dep_ordered_decls) - : dep_ordered_decls_(std::move(dep_ordered_decls)) {} +Module::Module(std::vector dep_ordered_decls, ast::Extensions extensions) + : dep_ordered_decls_(std::move(dep_ordered_decls)), extensions_(std::move(extensions)) {} Module::~Module() = default; diff --git a/src/tint/sem/module.h b/src/tint/sem/module.h index c265d4ea08..a7b3d452fd 100644 --- a/src/tint/sem/module.h +++ b/src/tint/sem/module.h @@ -17,6 +17,7 @@ #include +#include "src/tint/ast/extension.h" #include "src/tint/sem/node.h" // Forward declarations @@ -33,7 +34,8 @@ class Module final : public Castable { public: /// Constructor /// @param dep_ordered_decls the dependency-ordered module-scope declarations - explicit Module(std::vector dep_ordered_decls); + /// @param extensions the list of enabled extensions in the module + Module(std::vector dep_ordered_decls, ast::Extensions extensions); /// Destructor ~Module() override; @@ -43,8 +45,12 @@ class Module final : public Castable { return dep_ordered_decls_; } + /// @returns the list of enabled extensions in the module + const ast::Extensions& Extensions() const { return extensions_; } + private: const std::vector dep_ordered_decls_; + ast::Extensions extensions_; }; } // namespace tint::sem diff --git a/src/tint/transform/disable_uniformity_analysis.cc b/src/tint/transform/disable_uniformity_analysis.cc index c02503128c..7a3002377d 100644 --- a/src/tint/transform/disable_uniformity_analysis.cc +++ b/src/tint/transform/disable_uniformity_analysis.cc @@ -17,6 +17,7 @@ #include #include "src/tint/program_builder.h" +#include "src/tint/sem/module.h" TINT_INSTANTIATE_TYPEINFO(tint::transform::DisableUniformityAnalysis); @@ -27,13 +28,12 @@ DisableUniformityAnalysis::DisableUniformityAnalysis() = default; DisableUniformityAnalysis::~DisableUniformityAnalysis() = default; bool DisableUniformityAnalysis::ShouldRun(const Program* program, const DataMap&) const { - return !program->AST().Extensions().count( - ast::Enable::ExtensionKind::kChromiumDisableUniformityAnalysis); + return !program->Sem().Module()->Extensions().contains( + ast::Extension::kChromiumDisableUniformityAnalysis); } void DisableUniformityAnalysis::Run(CloneContext& ctx, const DataMap&, DataMap&) const { - ctx.dst->AST().AddEnable(ctx.dst->create( - ast::Enable::KindToName(ast::Enable::ExtensionKind::kChromiumDisableUniformityAnalysis))); + ctx.dst->Enable(ast::Extension::kChromiumDisableUniformityAnalysis); ctx.Clone(); } diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc index 6c573ffb15..f6e0d987ec 100644 --- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc +++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc @@ -727,10 +727,7 @@ void main() { } TEST_F(HlslGeneratorImplTest_Builtin, Dot4I8Packed) { - auto* ext = - create(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}}, - "chromium_experimental_dp4a"); - AST().AddEnable(ext); + Enable(ast::Extension::kChromiumExperimentalDP4a); auto* val1 = Var("val1", ty.u32()); auto* val2 = Var("val2", ty.u32()); @@ -756,10 +753,7 @@ void test_function() { } TEST_F(HlslGeneratorImplTest_Builtin, Dot4U8Packed) { - auto* ext = - create(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}}, - "chromium_experimental_dp4a"); - AST().AddEnable(ext); + Enable(ast::Extension::kChromiumExperimentalDP4a); auto* val1 = Var("val1", ty.u32()); auto* val2 = Var("val2", ty.u32()); diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc index aaa64cec57..0b3118a9c1 100644 --- a/src/tint/writer/spirv/builder.cc +++ b/src/tint/writer/spirv/builder.cc @@ -256,7 +256,7 @@ bool Builder::Build() { push_memory_model(spv::Op::OpMemoryModel, {U32Operand(SpvAddressingModelLogical), U32Operand(SpvMemoryModelGLSL450)}); - for (auto ext : builder_.AST().Extensions()) { + for (auto ext : builder_.Sem().Module()->Extensions()) { GenerateExtension(ext); } @@ -366,7 +366,7 @@ void Builder::push_capability(uint32_t cap) { } } -bool Builder::GenerateExtension(ast::Enable::ExtensionKind) { +bool Builder::GenerateExtension(ast::Extension) { /* For each supported extension, push corresponding capability into the builder. For example: diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h index 34cfd76292..1745ed568f 100644 --- a/src/tint/writer/spirv/builder.h +++ b/src/tint/writer/spirv/builder.h @@ -224,11 +224,11 @@ class Builder { ast::InterpolationType type, ast::InterpolationSampling sampling); - /// Generates a extension for the given extension kind. Emits an error and - /// returns false if the extension kind is not supported. - /// @param kind ExtensionKind of the extension to generate + /// Generates the enabling of an extension. Emits an error and returns false if the extension is + /// not supported. + /// @param ext the extension to generate /// @returns true on success. - bool GenerateExtension(ast::Enable::ExtensionKind kind); + bool GenerateExtension(ast::Extension ext); /// Generates a label for the given id. Emits an error and returns false if /// we're currently outside a function. /// @param id the id to use for the label diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc index 121d90425d..677421d070 100644 --- a/src/tint/writer/wgsl/generator_impl.cc +++ b/src/tint/writer/wgsl/generator_impl.cc @@ -62,12 +62,12 @@ GeneratorImpl::~GeneratorImpl() = default; bool GeneratorImpl::Generate() { // Generate enable directives before any other global declarations. - for (auto ext : program_->AST().Extensions()) { - if (!EmitEnableDirective(ext)) { + for (auto enable : program_->AST().Enables()) { + if (!EmitEnable(enable)) { return false; } } - if (!program_->AST().Extensions().empty()) { + if (!program_->AST().Enables().empty()) { line(); } // Generate global declarations in the order they appear in the module. @@ -94,13 +94,9 @@ bool GeneratorImpl::Generate() { return true; } -bool GeneratorImpl::EmitEnableDirective(const ast::Enable::ExtensionKind ext) { +bool GeneratorImpl::EmitEnable(const ast::Enable* enable) { auto out = line(); - auto extension = ast::Enable::KindToName(ext); - if (extension == "") { - return false; - } - out << "enable " << extension << ";"; + out << "enable " << enable->extension << ";"; return true; } diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h index 8473b4f6fe..a17e2da70f 100644 --- a/src/tint/writer/wgsl/generator_impl.h +++ b/src/tint/writer/wgsl/generator_impl.h @@ -53,9 +53,9 @@ class GeneratorImpl : public TextGenerator { bool Generate(); /// Handles generating a enable directive - /// @param ext the extension kind in the enable directive to generate + /// @param enable the enable node /// @returns true if the enable directive was emitted - bool EmitEnableDirective(const ast::Enable::ExtensionKind ext); + bool EmitEnable(const ast::Enable* enable); /// Handles generating a declared type /// @param ty the declared type to generate /// @returns true if the declared type was emitted diff --git a/src/tint/writer/wgsl/generator_impl_enable_test.cc b/src/tint/writer/wgsl/generator_impl_enable_test.cc index f9de37146b..503a9a0022 100644 --- a/src/tint/writer/wgsl/generator_impl_enable_test.cc +++ b/src/tint/writer/wgsl/generator_impl_enable_test.cc @@ -20,10 +20,12 @@ namespace { using WgslGeneratorImplTest = TestHelper; TEST_F(WgslGeneratorImplTest, Emit_Enable) { + auto* enable = Enable(ast::Extension::kF16); + GeneratorImpl& gen = Build(); - ASSERT_TRUE(gen.EmitEnableDirective(ast::Enable::ExtensionKind::kInternalExtensionForTesting)); - EXPECT_EQ(gen.result(), R"(enable InternalExtensionForTesting; + ASSERT_TRUE(gen.EmitEnable(enable)); + EXPECT_EQ(gen.result(), R"(enable f16; )"); } diff --git a/test/tint/BUILD.gn b/test/tint/BUILD.gn index a66428b540..c89e1b57b7 100644 --- a/test/tint/BUILD.gn +++ b/test/tint/BUILD.gn @@ -164,6 +164,7 @@ tint_unittests_source_set("tint_unittests_ast_src") { "../../src/tint/ast/depth_texture_test.cc", "../../src/tint/ast/discard_statement_test.cc", "../../src/tint/ast/enable_test.cc", + "../../src/tint/ast/extension_test.cc", "../../src/tint/ast/external_texture_test.cc", "../../src/tint/ast/f16_test.cc", "../../src/tint/ast/f32_test.cc", diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl deleted file mode 100644 index 9ed8f61592..0000000000 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2022 The Tint Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Enable a void internal extension -enable InternalExtensionForTesting; - -fn bar() { -} - -@stage(fragment) -fn main() -> @location(0) vec4 { - var a : vec2 = vec2(); - bar(); - return vec4(0.4, 0.4, 0.8, 1.0); -} diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.spvasm b/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.spvasm deleted file mode 100644 index f07e733007..0000000000 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.spvasm +++ /dev/null @@ -1,47 +0,0 @@ -; SPIR-V -; Version: 1.3 -; Generator: Google Tint Compiler; 0 -; Bound: 25 -; Schema: 0 - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %value - OpExecutionMode %main OriginUpperLeft - OpName %value "value" - OpName %bar "bar" - OpName %main_inner "main_inner" - OpName %a "a" - OpName %main "main" - OpDecorate %value Location 0 - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 -%_ptr_Output_v4float = OpTypePointer Output %v4float - %5 = OpConstantNull %v4float - %value = OpVariable %_ptr_Output_v4float Output %5 - %void = OpTypeVoid - %6 = OpTypeFunction %void - %10 = OpTypeFunction %v4float - %v2float = OpTypeVector %float 2 - %14 = OpConstantNull %v2float -%_ptr_Function_v2float = OpTypePointer Function %v2float -%float_0_400000006 = OpConstant %float 0.400000006 -%float_0_800000012 = OpConstant %float 0.800000012 - %float_1 = OpConstant %float 1 - %21 = OpConstantComposite %v4float %float_0_400000006 %float_0_400000006 %float_0_800000012 %float_1 - %bar = OpFunction %void None %6 - %9 = OpLabel - OpReturn - OpFunctionEnd - %main_inner = OpFunction %v4float None %10 - %12 = OpLabel - %a = OpVariable %_ptr_Function_v2float Function %14 - OpStore %a %14 - %17 = OpFunctionCall %void %bar - OpReturnValue %21 - OpFunctionEnd - %main = OpFunction %void None %6 - %23 = OpLabel - %24 = OpFunctionCall %v4float %main_inner - OpStore %value %24 - OpReturn - OpFunctionEnd diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.wgsl deleted file mode 100644 index 987fb57fa8..0000000000 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.wgsl +++ /dev/null @@ -1,11 +0,0 @@ -enable InternalExtensionForTesting; - -fn bar() { -} - -@stage(fragment) -fn main() -> @location(0) vec4 { - var a : vec2 = vec2(); - bar(); - return vec4(0.400000006, 0.400000006, 0.800000012, 1.0); -} diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl deleted file mode 100644 index c20b4535ba..0000000000 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 The Tint Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Enable a void internal extension for multiple times -enable InternalExtensionForTesting; -enable InternalExtensionForTesting; -enable InternalExtensionForTesting; - -fn bar() { -} - -@stage(fragment) -fn main() -> @location(0) vec4 { - var a : vec2 = vec2(); - bar(); - return vec4(0.4, 0.4, 0.8, 1.0); -} diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.spvasm b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.spvasm deleted file mode 100644 index f07e733007..0000000000 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.spvasm +++ /dev/null @@ -1,47 +0,0 @@ -; SPIR-V -; Version: 1.3 -; Generator: Google Tint Compiler; 0 -; Bound: 25 -; Schema: 0 - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %value - OpExecutionMode %main OriginUpperLeft - OpName %value "value" - OpName %bar "bar" - OpName %main_inner "main_inner" - OpName %a "a" - OpName %main "main" - OpDecorate %value Location 0 - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 -%_ptr_Output_v4float = OpTypePointer Output %v4float - %5 = OpConstantNull %v4float - %value = OpVariable %_ptr_Output_v4float Output %5 - %void = OpTypeVoid - %6 = OpTypeFunction %void - %10 = OpTypeFunction %v4float - %v2float = OpTypeVector %float 2 - %14 = OpConstantNull %v2float -%_ptr_Function_v2float = OpTypePointer Function %v2float -%float_0_400000006 = OpConstant %float 0.400000006 -%float_0_800000012 = OpConstant %float 0.800000012 - %float_1 = OpConstant %float 1 - %21 = OpConstantComposite %v4float %float_0_400000006 %float_0_400000006 %float_0_800000012 %float_1 - %bar = OpFunction %void None %6 - %9 = OpLabel - OpReturn - OpFunctionEnd - %main_inner = OpFunction %v4float None %10 - %12 = OpLabel - %a = OpVariable %_ptr_Function_v2float Function %14 - OpStore %a %14 - %17 = OpFunctionCall %void %bar - OpReturnValue %21 - OpFunctionEnd - %main = OpFunction %void None %6 - %23 = OpLabel - %24 = OpFunctionCall %v4float %main_inner - OpStore %value %24 - OpReturn - OpFunctionEnd diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.wgsl deleted file mode 100644 index 987fb57fa8..0000000000 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.wgsl +++ /dev/null @@ -1,11 +0,0 @@ -enable InternalExtensionForTesting; - -fn bar() { -} - -@stage(fragment) -fn main() -> @location(0) vec4 { - var a : vec2 = vec2(); - bar(); - return vec4(0.400000006, 0.400000006, 0.800000012, 1.0); -} diff --git a/test/tint/extensions/parsing/basic.wgsl b/test/tint/extensions/parsing/basic.wgsl new file mode 100644 index 0000000000..d1d3017ddd --- /dev/null +++ b/test/tint/extensions/parsing/basic.wgsl @@ -0,0 +1,7 @@ +// Enable a void internal extension +enable f16; + +@stage(fragment) +fn main() -> @location(0) vec4 { + return vec4(0.1, 0.2, 0.3, 0.4); +} diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl b/test/tint/extensions/parsing/basic.wgsl.expected.glsl similarity index 61% rename from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl rename to test/tint/extensions/parsing/basic.wgsl.expected.glsl index 995583f921..b094b6e4a7 100644 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl +++ b/test/tint/extensions/parsing/basic.wgsl.expected.glsl @@ -2,13 +2,8 @@ precision mediump float; layout(location = 0) out vec4 value; -void bar() { -} - vec4 tint_symbol() { - vec2 a = vec2(0.0f, 0.0f); - bar(); - return vec4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f); + return vec4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f); } void main() { diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.hlsl b/test/tint/extensions/parsing/basic.wgsl.expected.hlsl similarity index 67% rename from test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.hlsl rename to test/tint/extensions/parsing/basic.wgsl.expected.hlsl index 93c7fa7301..1af441af34 100644 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.hlsl +++ b/test/tint/extensions/parsing/basic.wgsl.expected.hlsl @@ -1,14 +1,9 @@ -void bar() { -} - struct tint_symbol { float4 value : SV_Target0; }; float4 main_inner() { - float2 a = float2(0.0f, 0.0f); - bar(); - return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f); + return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f); } tint_symbol main() { diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.msl b/test/tint/extensions/parsing/basic.wgsl.expected.msl similarity index 74% rename from test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.msl rename to test/tint/extensions/parsing/basic.wgsl.expected.msl index d7fde539d8..dc91926917 100644 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.msl +++ b/test/tint/extensions/parsing/basic.wgsl.expected.msl @@ -1,17 +1,12 @@ #include using namespace metal; -void bar() { -} - struct tint_symbol_1 { float4 value [[color(0)]]; }; float4 tint_symbol_inner() { - float2 a = float2(); - bar(); - return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f); + return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f); } fragment tint_symbol_1 tint_symbol() { diff --git a/test/tint/extensions/parsing/basic.wgsl.expected.spvasm b/test/tint/extensions/parsing/basic.wgsl.expected.spvasm new file mode 100644 index 0000000000..225da82e55 --- /dev/null +++ b/test/tint/extensions/parsing/basic.wgsl.expected.spvasm @@ -0,0 +1,36 @@ +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 19 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %value + OpExecutionMode %main OriginUpperLeft + OpName %value "value" + OpName %main_inner "main_inner" + OpName %main "main" + OpDecorate %value Location 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %5 = OpConstantNull %v4float + %value = OpVariable %_ptr_Output_v4float Output %5 + %6 = OpTypeFunction %v4float +%float_0_100000001 = OpConstant %float 0.100000001 +%float_0_200000003 = OpConstant %float 0.200000003 +%float_0_300000012 = OpConstant %float 0.300000012 +%float_0_400000006 = OpConstant %float 0.400000006 + %13 = OpConstantComposite %v4float %float_0_100000001 %float_0_200000003 %float_0_300000012 %float_0_400000006 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %main_inner = OpFunction %v4float None %6 + %8 = OpLabel + OpReturnValue %13 + OpFunctionEnd + %main = OpFunction %void None %14 + %17 = OpLabel + %18 = OpFunctionCall %v4float %main_inner + OpStore %value %18 + OpReturn + OpFunctionEnd diff --git a/test/tint/extensions/parsing/basic.wgsl.expected.wgsl b/test/tint/extensions/parsing/basic.wgsl.expected.wgsl new file mode 100644 index 0000000000..c084b23263 --- /dev/null +++ b/test/tint/extensions/parsing/basic.wgsl.expected.wgsl @@ -0,0 +1,6 @@ +enable f16; + +@stage(fragment) +fn main() -> @location(0) vec4 { + return vec4(0.100000001, 0.200000003, 0.300000012, 0.400000006); +} diff --git a/test/tint/extensions/parsing/duplicated_extensions.wgsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl new file mode 100644 index 0000000000..d72f18de62 --- /dev/null +++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl @@ -0,0 +1,9 @@ +// Enable a void internal extension for multiple times +enable f16; +enable f16; +enable f16; + +@stage(fragment) +fn main() -> @location(0) vec4 { + return vec4(0.1, 0.2, 0.3, 0.4); +} diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.glsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.glsl similarity index 61% rename from test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.glsl rename to test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.glsl index 995583f921..b094b6e4a7 100644 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.glsl +++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.glsl @@ -2,13 +2,8 @@ precision mediump float; layout(location = 0) out vec4 value; -void bar() { -} - vec4 tint_symbol() { - vec2 a = vec2(0.0f, 0.0f); - bar(); - return vec4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f); + return vec4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f); } void main() { diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.hlsl similarity index 67% rename from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl rename to test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.hlsl index 93c7fa7301..1af441af34 100644 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl +++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.hlsl @@ -1,14 +1,9 @@ -void bar() { -} - struct tint_symbol { float4 value : SV_Target0; }; float4 main_inner() { - float2 a = float2(0.0f, 0.0f); - bar(); - return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f); + return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f); } tint_symbol main() { diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.msl similarity index 74% rename from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl rename to test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.msl index d7fde539d8..dc91926917 100644 --- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl +++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.msl @@ -1,17 +1,12 @@ #include using namespace metal; -void bar() { -} - struct tint_symbol_1 { float4 value [[color(0)]]; }; float4 tint_symbol_inner() { - float2 a = float2(); - bar(); - return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f); + return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f); } fragment tint_symbol_1 tint_symbol() { diff --git a/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm new file mode 100644 index 0000000000..225da82e55 --- /dev/null +++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm @@ -0,0 +1,36 @@ +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 19 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %value + OpExecutionMode %main OriginUpperLeft + OpName %value "value" + OpName %main_inner "main_inner" + OpName %main "main" + OpDecorate %value Location 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %5 = OpConstantNull %v4float + %value = OpVariable %_ptr_Output_v4float Output %5 + %6 = OpTypeFunction %v4float +%float_0_100000001 = OpConstant %float 0.100000001 +%float_0_200000003 = OpConstant %float 0.200000003 +%float_0_300000012 = OpConstant %float 0.300000012 +%float_0_400000006 = OpConstant %float 0.400000006 + %13 = OpConstantComposite %v4float %float_0_100000001 %float_0_200000003 %float_0_300000012 %float_0_400000006 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %main_inner = OpFunction %v4float None %6 + %8 = OpLabel + OpReturnValue %13 + OpFunctionEnd + %main = OpFunction %void None %14 + %17 = OpLabel + %18 = OpFunctionCall %v4float %main_inner + OpStore %value %18 + OpReturn + OpFunctionEnd diff --git a/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.wgsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.wgsl new file mode 100644 index 0000000000..be5f381a0f --- /dev/null +++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.wgsl @@ -0,0 +1,8 @@ +enable f16; +enable f16; +enable f16; + +@stage(fragment) +fn main() -> @location(0) vec4 { + return vec4(0.100000001, 0.200000003, 0.300000012, 0.400000006); +}