tint: Support multiple extensions per 'enable'
Fixed: tint:1865 Change-Id: I245bd36b12ff23977c2e69deee27f976db820849 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/123900 Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Commit-Queue: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
0089d47887
commit
8f80d999c4
|
@ -495,6 +495,7 @@ libtint_source_set("libtint_ast_hdrs") {
|
|||
"ast/discard_statement.h",
|
||||
"ast/enable.h",
|
||||
"ast/expression.h",
|
||||
"ast/extension.h",
|
||||
"ast/float_literal_expression.h",
|
||||
"ast/for_loop_statement.h",
|
||||
"ast/function.h",
|
||||
|
@ -581,6 +582,7 @@ libtint_source_set("libtint_ast_src") {
|
|||
"ast/discard_statement.cc",
|
||||
"ast/enable.cc",
|
||||
"ast/expression.cc",
|
||||
"ast/extension.cc",
|
||||
"ast/float_literal_expression.cc",
|
||||
"ast/for_loop_statement.cc",
|
||||
"ast/function.cc",
|
||||
|
|
|
@ -134,6 +134,8 @@ list(APPEND TINT_LIB_SRCS
|
|||
ast/enable.h
|
||||
ast/expression.cc
|
||||
ast/expression.h
|
||||
ast/extension.cc
|
||||
ast/extension.h
|
||||
ast/float_literal_expression.cc
|
||||
ast/float_literal_expression.h
|
||||
ast/for_loop_statement.cc
|
||||
|
|
|
@ -20,15 +20,29 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Enable);
|
|||
|
||||
namespace tint::ast {
|
||||
|
||||
Enable::Enable(ProgramID pid, NodeID nid, const Source& src, builtin::Extension ext)
|
||||
: Base(pid, nid, src), extension(ext) {}
|
||||
Enable::Enable(ProgramID pid,
|
||||
NodeID nid,
|
||||
const Source& src,
|
||||
utils::VectorRef<const Extension*> exts)
|
||||
: Base(pid, nid, src), extensions(std::move(exts)) {}
|
||||
|
||||
Enable::Enable(Enable&&) = default;
|
||||
|
||||
Enable::~Enable() = default;
|
||||
|
||||
bool Enable::HasExtension(builtin::Extension ext) const {
|
||||
for (auto* e : extensions) {
|
||||
if (e->name == ext) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const Enable* Enable::Clone(CloneContext* ctx) const {
|
||||
auto src = ctx->Clone(source);
|
||||
return ctx->dst->create<Enable>(src, extension);
|
||||
auto exts = ctx->Clone(extensions);
|
||||
return ctx->dst->create<Enable>(src, std::move(exts));
|
||||
}
|
||||
|
||||
} // namespace tint::ast
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "src/tint/ast/node.h"
|
||||
#include "src/tint/builtin/extension.h"
|
||||
#include "src/tint/ast/extension.h"
|
||||
|
||||
namespace tint::ast {
|
||||
|
||||
|
@ -35,21 +34,24 @@ class Enable final : public Castable<Enable, Node> {
|
|||
/// @param pid the identifier of the program that owns this node
|
||||
/// @param nid the unique node identifier
|
||||
/// @param src the source of this node
|
||||
/// @param ext the extension
|
||||
Enable(ProgramID pid, NodeID nid, const Source& src, builtin::Extension ext);
|
||||
/// @param exts the extensions being enabled by this directive
|
||||
Enable(ProgramID pid, NodeID nid, const Source& src, utils::VectorRef<const Extension*> exts);
|
||||
/// Move constructor
|
||||
Enable(Enable&&);
|
||||
|
||||
~Enable() override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @param ext the extension to search for
|
||||
/// @returns true if this Enable lists the given extension
|
||||
bool HasExtension(builtin::Extension ext) const;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
const Enable* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// The extension name
|
||||
const builtin::Extension extension;
|
||||
/// The extensions being enabled by this directive
|
||||
const utils::Vector<const Extension*, 4> extensions;
|
||||
};
|
||||
|
||||
} // namespace tint::ast
|
||||
|
|
|
@ -27,7 +27,14 @@ TEST_F(EnableTest, Creation) {
|
|||
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->extension, builtin::Extension::kF16);
|
||||
ASSERT_EQ(ext->extensions.Length(), 1u);
|
||||
EXPECT_EQ(ext->extensions[0]->name, builtin::Extension::kF16);
|
||||
}
|
||||
|
||||
TEST_F(EnableTest, HasExtension) {
|
||||
auto* ext = Enable(Source{{{20, 2}, {20, 5}}}, builtin::Extension::kF16);
|
||||
EXPECT_TRUE(ext->HasExtension(builtin::Extension::kF16));
|
||||
EXPECT_FALSE(ext->HasExtension(builtin::Extension::kChromiumDisableUniformityAnalysis));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2023 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 "src/tint/program_builder.h"
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
// Doxygen gets confused with tint::ast::Extension and tint::builtin::Extension
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::ast::Extension);
|
||||
|
||||
namespace tint::ast {
|
||||
|
||||
Extension::Extension(ProgramID pid, NodeID nid, const Source& src, builtin::Extension ext)
|
||||
: Base(pid, nid, src), name(ext) {}
|
||||
|
||||
Extension::Extension(Extension&&) = default;
|
||||
|
||||
Extension::~Extension() = default;
|
||||
|
||||
const Extension* Extension::Clone(CloneContext* ctx) const {
|
||||
auto src = ctx->Clone(source);
|
||||
return ctx->dst->create<Extension>(src, name);
|
||||
}
|
||||
|
||||
} // namespace tint::ast
|
||||
|
||||
//! @endcond
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2023 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 "src/tint/ast/node.h"
|
||||
#include "src/tint/builtin/extension.h"
|
||||
|
||||
namespace tint::ast {
|
||||
|
||||
/// An extension used in an "enable" directive. Example:
|
||||
/// ```
|
||||
/// enable f16;
|
||||
/// ```
|
||||
class Extension final : public Castable<Extension, Node> {
|
||||
public:
|
||||
/// Create a extension
|
||||
/// @param pid the identifier of the program that owns this node
|
||||
/// @param nid the unique node identifier
|
||||
/// @param src the source of this node
|
||||
/// @param ext the extension
|
||||
Extension(ProgramID pid, NodeID nid, const Source& src, builtin::Extension ext);
|
||||
/// Move constructor
|
||||
Extension(Extension&&);
|
||||
|
||||
~Extension() override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
const Extension* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// The extension name
|
||||
const builtin::Extension name;
|
||||
};
|
||||
|
||||
} // namespace tint::ast
|
||||
|
||||
#endif // SRC_TINT_AST_EXTENSION_H_
|
|
@ -755,8 +755,8 @@ bool GenerateHlsl(const tint::Program* program, const Options& options) {
|
|||
|
||||
auto enable_list = program->AST().Enables();
|
||||
bool dxc_require_16bit_types = false;
|
||||
for (auto enable : enable_list) {
|
||||
if (enable->extension == tint::builtin::Extension::kF16) {
|
||||
for (auto* enable : enable_list) {
|
||||
if (enable->HasExtension(tint::builtin::Extension::kF16)) {
|
||||
dxc_require_16bit_types = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -571,8 +571,10 @@ std::vector<std::pair<std::string, Source>> Inspector::GetEnableDirectives() {
|
|||
// Ast nodes for enable directive are stored within global declarations list
|
||||
auto global_decls = program_->AST().GlobalDeclarations();
|
||||
for (auto* node : global_decls) {
|
||||
if (auto* ext = node->As<ast::Enable>()) {
|
||||
result.push_back({utils::ToString(ext->extension), ext->source});
|
||||
if (auto* enable = node->As<ast::Enable>()) {
|
||||
for (auto* ext : enable->extensions) {
|
||||
result.push_back({utils::ToString(ext->name), ext->source});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2048,20 +2048,22 @@ class ProgramBuilder {
|
|||
}
|
||||
|
||||
/// Adds the extension to the list of enable directives at the top of the module.
|
||||
/// @param ext the extension to enable
|
||||
/// @param extension the extension to enable
|
||||
/// @return an `ast::Enable` enabling the given extension.
|
||||
const ast::Enable* Enable(builtin::Extension ext) {
|
||||
auto* enable = create<ast::Enable>(ext);
|
||||
const ast::Enable* Enable(builtin::Extension extension) {
|
||||
auto* ext = create<ast::Extension>(extension);
|
||||
auto* enable = create<ast::Enable>(utils::Vector{ext});
|
||||
AST().AddEnable(enable);
|
||||
return enable;
|
||||
}
|
||||
|
||||
/// Adds the extension to the list of enable directives at the top of the module.
|
||||
/// @param source the enable source
|
||||
/// @param ext the extension to enable
|
||||
/// @param extension the extension to enable
|
||||
/// @return an `ast::Enable` enabling the given extension.
|
||||
const ast::Enable* Enable(const Source& source, builtin::Extension ext) {
|
||||
auto* enable = create<ast::Enable>(source, ext);
|
||||
const ast::Enable* Enable(const Source& source, builtin::Extension extension) {
|
||||
auto* ext = create<ast::Extension>(source, extension);
|
||||
auto* enable = create<ast::Enable>(source, utils::Vector{ext});
|
||||
AST().AddEnable(enable);
|
||||
return enable;
|
||||
}
|
||||
|
|
|
@ -390,53 +390,52 @@ Maybe<Void> ParserImpl::diagnostic_directive() {
|
|||
return decl;
|
||||
}
|
||||
|
||||
// enable_directive
|
||||
// : enable name SEMICLON
|
||||
// enable_directive :
|
||||
// | 'enable' identifier (COMMA identifier)* COMMA? SEMICOLON
|
||||
Maybe<Void> ParserImpl::enable_directive() {
|
||||
auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<Void> {
|
||||
return sync(Token::Type::kSemicolon, [&]() -> Maybe<Void> {
|
||||
MultiTokenSource decl_source(this);
|
||||
if (!match(Token::Type::kEnable)) {
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
||||
// Match the extension name.
|
||||
auto& t = peek();
|
||||
if (handle_error(t)) {
|
||||
// The token might itself be an error.
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
if (t.Is(Token::Type::kParenLeft)) {
|
||||
if (peek_is(Token::Type::kParenLeft)) {
|
||||
// A common error case is writing `enable(foo);` instead of `enable foo;`.
|
||||
synchronized_ = false;
|
||||
return add_error(t.source(), "enable directives don't take parenthesis");
|
||||
return add_error(peek().source(), "enable directives don't take parenthesis");
|
||||
}
|
||||
|
||||
auto ext = expect_enum("extension", builtin::ParseExtension, builtin::kExtensionStrings);
|
||||
if (ext.errored) {
|
||||
return Failure::kErrored;
|
||||
utils::Vector<const ast::Extension*, 4> extensions;
|
||||
while (continue_parsing()) {
|
||||
Source ext_src = peek().source();
|
||||
auto ext =
|
||||
expect_enum("extension", builtin::ParseExtension, builtin::kExtensionStrings);
|
||||
if (ext.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
extensions.Push(create<ast::Extension>(ext_src, ext.value));
|
||||
|
||||
if (!match(Token::Type::kComma)) {
|
||||
break;
|
||||
}
|
||||
if (peek_is(Token::Type::kSemicolon)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!expect("enable directive", Token::Type::kSemicolon)) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
builder_.AST().AddEnable(create<ast::Enable>(t.source(), ext.value));
|
||||
|
||||
builder_.AST().AddEnable(create<ast::Enable>(decl_source.Source(), std::move(extensions)));
|
||||
return kSuccess;
|
||||
});
|
||||
|
||||
if (decl.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (decl.matched) {
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
||||
// requires_directive
|
||||
// : require identifier (COMMA identifier)? SEMICLON
|
||||
// : require identifier (COMMA identifier)* COMMA? SEMICOLON
|
||||
Maybe<Void> ParserImpl::requires_directive() {
|
||||
auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<Void> {
|
||||
return sync(Token::Type::kSemicolon, [&]() -> Maybe<Void> {
|
||||
if (!match(Token::Type::kRequires)) {
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
@ -483,15 +482,6 @@ Maybe<Void> ParserImpl::requires_directive() {
|
|||
// conditional.
|
||||
return add_error(t.source(), "missing feature names in requires directive");
|
||||
});
|
||||
|
||||
if (decl.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (decl.matched) {
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
||||
// global_decl
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace {
|
|||
using EnableDirectiveTest = ParserImplTest;
|
||||
|
||||
// Test a valid enable directive.
|
||||
TEST_F(EnableDirectiveTest, Valid) {
|
||||
TEST_F(EnableDirectiveTest, Single) {
|
||||
auto p = parser("enable f16;");
|
||||
p->enable_directive();
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
|
@ -30,13 +30,105 @@ TEST_F(EnableDirectiveTest, Valid) {
|
|||
auto& ast = program.AST();
|
||||
ASSERT_EQ(ast.Enables().Length(), 1u);
|
||||
auto* enable = ast.Enables()[0];
|
||||
EXPECT_EQ(enable->extension, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->source.range.begin.column, 1u);
|
||||
EXPECT_EQ(enable->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->source.range.end.column, 12u);
|
||||
ASSERT_EQ(enable->extensions.Length(), 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.column, 11u);
|
||||
ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
|
||||
}
|
||||
|
||||
// Test a valid enable directive.
|
||||
TEST_F(EnableDirectiveTest, SingleTrailingComma) {
|
||||
auto p = parser("enable f16, ;");
|
||||
p->enable_directive();
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
auto program = p->program();
|
||||
auto& ast = program.AST();
|
||||
ASSERT_EQ(ast.Enables().Length(), 1u);
|
||||
auto* enable = ast.Enables()[0];
|
||||
EXPECT_EQ(enable->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->source.range.begin.column, 1u);
|
||||
EXPECT_EQ(enable->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->source.range.end.column, 14u);
|
||||
ASSERT_EQ(enable->extensions.Length(), 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.column, 11u);
|
||||
ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
|
||||
}
|
||||
|
||||
// Test a valid enable directive with multiple extensions.
|
||||
TEST_F(EnableDirectiveTest, Multiple) {
|
||||
auto p =
|
||||
parser("enable f16, chromium_disable_uniformity_analysis, chromium_experimental_dp4a;");
|
||||
p->enable_directive();
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
auto program = p->program();
|
||||
auto& ast = program.AST();
|
||||
ASSERT_EQ(ast.Enables().Length(), 1u);
|
||||
auto* enable = ast.Enables()[0];
|
||||
ASSERT_EQ(enable->extensions.Length(), 3u);
|
||||
EXPECT_EQ(enable->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.column, 11u);
|
||||
EXPECT_EQ(enable->extensions[1]->name, builtin::Extension::kChromiumDisableUniformityAnalysis);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.begin.column, 13u);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.end.column, 49u);
|
||||
EXPECT_EQ(enable->extensions[2]->name, builtin::Extension::kChromiumExperimentalDp4A);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.begin.column, 51u);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.end.column, 77u);
|
||||
ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
|
||||
}
|
||||
|
||||
// Test a valid enable directive with multiple extensions.
|
||||
TEST_F(EnableDirectiveTest, MultipleTrailingComma) {
|
||||
auto p =
|
||||
parser("enable f16, chromium_disable_uniformity_analysis, chromium_experimental_dp4a,;");
|
||||
p->enable_directive();
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
auto program = p->program();
|
||||
auto& ast = program.AST();
|
||||
ASSERT_EQ(ast.Enables().Length(), 1u);
|
||||
auto* enable = ast.Enables()[0];
|
||||
ASSERT_EQ(enable->extensions.Length(), 3u);
|
||||
EXPECT_EQ(enable->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.column, 11u);
|
||||
EXPECT_EQ(enable->extensions[1]->name, builtin::Extension::kChromiumDisableUniformityAnalysis);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.begin.column, 13u);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[1]->source.range.end.column, 49u);
|
||||
EXPECT_EQ(enable->extensions[2]->name, builtin::Extension::kChromiumExperimentalDp4A);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.begin.column, 51u);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.end.line, 1u);
|
||||
EXPECT_EQ(enable->extensions[2]->source.range.end.column, 77u);
|
||||
ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
|
||||
}
|
||||
|
||||
// Test multiple enable directives for a same extension.
|
||||
TEST_F(EnableDirectiveTest, EnableMultipleTime) {
|
||||
TEST_F(EnableDirectiveTest, EnableSameLine) {
|
||||
auto p = parser(R"(
|
||||
enable f16;
|
||||
enable f16;
|
||||
|
@ -48,8 +140,18 @@ enable f16;
|
|||
ASSERT_EQ(ast.Enables().Length(), 2u);
|
||||
auto* enable_a = ast.Enables()[0];
|
||||
auto* enable_b = ast.Enables()[1];
|
||||
EXPECT_EQ(enable_a->extension, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable_b->extension, builtin::Extension::kF16);
|
||||
ASSERT_EQ(enable_a->extensions.Length(), 1u);
|
||||
EXPECT_EQ(enable_a->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable_a->extensions[0]->source.range.begin.line, 2u);
|
||||
EXPECT_EQ(enable_a->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable_a->extensions[0]->source.range.end.line, 2u);
|
||||
EXPECT_EQ(enable_a->extensions[0]->source.range.end.column, 11u);
|
||||
ASSERT_EQ(enable_b->extensions.Length(), 1u);
|
||||
EXPECT_EQ(enable_b->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable_b->extensions[0]->source.range.begin.line, 3u);
|
||||
EXPECT_EQ(enable_b->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable_b->extensions[0]->source.range.end.line, 3u);
|
||||
EXPECT_EQ(enable_b->extensions[0]->source.range.end.column, 11u);
|
||||
ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[0], enable_a);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[1], enable_b);
|
||||
|
@ -169,7 +271,12 @@ enable f16;
|
|||
// Accept the enable directive although it caused an error
|
||||
ASSERT_EQ(ast.Enables().Length(), 1u);
|
||||
auto* enable = ast.Enables()[0];
|
||||
EXPECT_EQ(enable->extension, builtin::Extension::kF16);
|
||||
ASSERT_EQ(enable->extensions.Length(), 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.line, 3u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.line, 3u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.column, 11u);
|
||||
ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[1], enable);
|
||||
}
|
||||
|
@ -189,7 +296,12 @@ enable f16;
|
|||
// Accept the enable directive although it cause an error
|
||||
ASSERT_EQ(ast.Enables().Length(), 1u);
|
||||
auto* enable = ast.Enables()[0];
|
||||
EXPECT_EQ(enable->extension, builtin::Extension::kF16);
|
||||
ASSERT_EQ(enable->extensions.Length(), 1u);
|
||||
EXPECT_EQ(enable->extensions[0]->name, builtin::Extension::kF16);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.line, 3u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.begin.column, 8u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.line, 3u);
|
||||
EXPECT_EQ(enable->extensions[0]->source.range.end.column, 11u);
|
||||
ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
|
||||
EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
|
||||
}
|
||||
|
|
|
@ -3476,7 +3476,10 @@ bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) {
|
|||
}
|
||||
|
||||
bool Resolver::Enable(const ast::Enable* enable) {
|
||||
enabled_extensions_.Add(enable->extension);
|
||||
for (auto* ext : enable->extensions) {
|
||||
Mark(ext);
|
||||
enabled_extensions_.Add(ext->name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,8 +47,9 @@ struct BuiltinPolyfill::State {
|
|||
State(const Program* program, const Config& config) : src(program), cfg(config) {
|
||||
has_full_ptr_params = false;
|
||||
for (auto* enable : src->AST().Enables()) {
|
||||
if (enable->extension == builtin::Extension::kChromiumExperimentalFullPtrParameters) {
|
||||
if (enable->HasExtension(builtin::Extension::kChromiumExperimentalFullPtrParameters)) {
|
||||
has_full_ptr_params = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,8 +67,8 @@ struct PreservePadding::State {
|
|||
},
|
||||
[&](const ast::Enable* enable) {
|
||||
// Check if the full pointer parameters extension is already enabled.
|
||||
if (enable->extension ==
|
||||
builtin::Extension::kChromiumExperimentalFullPtrParameters) {
|
||||
if (enable->HasExtension(
|
||||
builtin::Extension::kChromiumExperimentalFullPtrParameters)) {
|
||||
ext_enabled = true;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -33,13 +33,14 @@ bool CheckSupportedExtensions(std::string_view writer_name,
|
|||
}
|
||||
|
||||
for (auto* enable : module.Enables()) {
|
||||
auto ext = enable->extension;
|
||||
if (!set.Contains(ext)) {
|
||||
diags.add_error(diag::System::Writer,
|
||||
std::string(writer_name) + " backend does not support extension '" +
|
||||
utils::ToString(ext) + "'",
|
||||
enable->source);
|
||||
return false;
|
||||
for (auto* ext : enable->extensions) {
|
||||
if (!set.Contains(ext->name)) {
|
||||
diags.add_error(diag::System::Writer,
|
||||
std::string(writer_name) + " backend does not support extension '" +
|
||||
utils::ToString(ext->name) + "'",
|
||||
ext->source);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -347,10 +347,10 @@ bool GeneratorImpl::Generate() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GeneratorImpl::RecordExtension(const ast::Enable* ext) {
|
||||
bool GeneratorImpl::RecordExtension(const ast::Enable* enable) {
|
||||
// Deal with extension node here, recording it within the generator for later emition.
|
||||
|
||||
if (ext->extension == builtin::Extension::kF16) {
|
||||
if (enable->HasExtension(builtin::Extension::kF16)) {
|
||||
requires_f16_extension_ = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -4154,10 +4154,7 @@ OpReturn
|
|||
namespace DP4A_builtin_tests {
|
||||
|
||||
TEST_F(BuiltinBuilderTest, Call_Dot4I8Packed) {
|
||||
auto* ext =
|
||||
create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
|
||||
builtin::Extension::kChromiumExperimentalDp4A);
|
||||
AST().AddEnable(ext);
|
||||
Enable(builtin::Extension::kChromiumExperimentalDp4A);
|
||||
|
||||
auto* val1 = Var("val1", ty.u32());
|
||||
auto* val2 = Var("val2", ty.u32());
|
||||
|
@ -4194,10 +4191,7 @@ OpFunctionEnd
|
|||
}
|
||||
|
||||
TEST_F(BuiltinBuilderTest, Call_Dot4U8Packed) {
|
||||
auto* ext =
|
||||
create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
|
||||
builtin::Extension::kChromiumExperimentalDp4A);
|
||||
AST().AddEnable(ext);
|
||||
Enable(builtin::Extension::kChromiumExperimentalDp4A);
|
||||
|
||||
auto* val1 = Var("val1", ty.u32());
|
||||
auto* val2 = Var("val2", ty.u32());
|
||||
|
|
|
@ -79,7 +79,15 @@ bool GeneratorImpl::EmitDiagnosticControl(const ast::DiagnosticControl& diagnost
|
|||
}
|
||||
|
||||
bool GeneratorImpl::EmitEnable(const ast::Enable* enable) {
|
||||
line() << "Enable [" << enable->extension << "]";
|
||||
auto l = line();
|
||||
l << "Enable [";
|
||||
for (auto* ext : enable->extensions) {
|
||||
if (ext != enable->extensions.Front()) {
|
||||
l << ", ";
|
||||
}
|
||||
l << ext->name;
|
||||
}
|
||||
l << "]";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,14 @@ bool GeneratorImpl::EmitDiagnosticControl(utils::StringStream& out,
|
|||
|
||||
bool GeneratorImpl::EmitEnable(const ast::Enable* enable) {
|
||||
auto out = line();
|
||||
out << "enable " << enable->extension << ";";
|
||||
out << "enable ";
|
||||
for (auto* ext : enable->extensions) {
|
||||
if (ext != enable->extensions.Front()) {
|
||||
out << ", ";
|
||||
}
|
||||
out << ext->name;
|
||||
}
|
||||
out << ";";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
enable chromium_experimental_push_constant, f16;
|
||||
|
||||
@fragment
|
||||
fn main() -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(0.1, 0.2, 0.3, 0.4);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
struct tint_symbol {
|
||||
float4 value : SV_Target0;
|
||||
};
|
||||
|
||||
float4 main_inner() {
|
||||
return float4(0.10000000149011611938f, 0.20000000298023223877f, 0.30000001192092895508f, 0.40000000596046447754f);
|
||||
}
|
||||
|
||||
tint_symbol main() {
|
||||
const float4 inner_result = main_inner();
|
||||
tint_symbol wrapper_result = (tint_symbol)0;
|
||||
wrapper_result.value = inner_result;
|
||||
return wrapper_result;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
struct tint_symbol {
|
||||
float4 value : SV_Target0;
|
||||
};
|
||||
|
||||
float4 main_inner() {
|
||||
return float4(0.10000000149011611938f, 0.20000000298023223877f, 0.30000001192092895508f, 0.40000000596046447754f);
|
||||
}
|
||||
|
||||
tint_symbol main() {
|
||||
const float4 inner_result = main_inner();
|
||||
tint_symbol wrapper_result = (tint_symbol)0;
|
||||
wrapper_result.value = inner_result;
|
||||
return wrapper_result;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#version 310 es
|
||||
#extension GL_AMD_gpu_shader_half_float : require
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 value;
|
||||
vec4 tint_symbol() {
|
||||
return vec4(0.10000000149011611938f, 0.20000000298023223877f, 0.30000001192092895508f, 0.40000000596046447754f);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 inner_result = tint_symbol();
|
||||
value = inner_result;
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
struct tint_symbol_1 {
|
||||
float4 value [[color(0)]];
|
||||
};
|
||||
|
||||
float4 tint_symbol_inner() {
|
||||
return float4(0.10000000149011611938f, 0.20000000298023223877f, 0.30000001192092895508f, 0.40000000596046447754f);
|
||||
}
|
||||
|
||||
fragment tint_symbol_1 tint_symbol() {
|
||||
float4 const inner_result = tint_symbol_inner();
|
||||
tint_symbol_1 wrapper_result = {};
|
||||
wrapper_result.value = inner_result;
|
||||
return wrapper_result;
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
; SPIR-V
|
||||
; Version: 1.3
|
||||
; Generator: Google Tint Compiler; 0
|
||||
; Bound: 19
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
OpCapability Float16
|
||||
OpCapability UniformAndStorageBuffer16BitAccess
|
||||
OpCapability StorageBuffer16BitAccess
|
||||
OpCapability StorageInputOutput16
|
||||
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
|
|
@ -0,0 +1,6 @@
|
|||
enable chromium_experimental_push_constant, f16;
|
||||
|
||||
@fragment
|
||||
fn main() -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(0.10000000000000000555, 0.2000000000000000111, 0.2999999999999999889, 0.4000000000000000222);
|
||||
}
|
Loading…
Reference in New Issue