tint: Improve the output of DependencyGraph
Add ResolvedIdentifier to hold the resolved AST node, sem::BuiltinType or type::Builtin. Reduces duplicate builtin symbol lookups in Resolver. Bug: tint:1810 Change-Id: Idde2b5f6fa22804b5019adc14c717bebd8342475 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119041 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
9e36723497
commit
cf0e9301b2
|
@ -879,8 +879,7 @@ class ProgramBuilder {
|
||||||
/// @returns the type name
|
/// @returns the type name
|
||||||
template <typename NAME, typename... ARGS, typename _ = DisableIfSource<NAME>>
|
template <typename NAME, typename... ARGS, typename _ = DisableIfSource<NAME>>
|
||||||
const ast::TypeName* operator()(NAME&& name, ARGS&&... args) const {
|
const ast::TypeName* operator()(NAME&& name, ARGS&&... args) const {
|
||||||
return builder->create<ast::TypeName>(
|
return (*this)(builder->source_, std::forward<NAME>(name), std::forward<ARGS>(args)...);
|
||||||
builder->Ident(std::forward<NAME>(name), std::forward<ARGS>(args)...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a type name
|
/// Creates a type name
|
||||||
|
@ -891,7 +890,8 @@ class ProgramBuilder {
|
||||||
template <typename NAME, typename... ARGS>
|
template <typename NAME, typename... ARGS>
|
||||||
const ast::TypeName* operator()(const Source& source, NAME&& name, ARGS&&... args) const {
|
const ast::TypeName* operator()(const Source& source, NAME&& name, ARGS&&... args) const {
|
||||||
return builder->create<ast::TypeName>(
|
return builder->create<ast::TypeName>(
|
||||||
source, builder->Ident(std::forward<NAME>(name), std::forward<ARGS>(args)...));
|
source,
|
||||||
|
builder->Ident(source, std::forward<NAME>(name), std::forward<ARGS>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an alias type
|
/// Creates an alias type
|
||||||
|
|
|
@ -210,7 +210,7 @@ TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsAliasUsedAsVariable) {
|
||||||
WrapInFunction(Decl(Var("v", Expr(Source{{56, 78}}, "mix"))));
|
WrapInFunction(Decl(Var("v", Expr(Source{{56, 78}}, "mix"))));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), R"(56:78 error: missing '(' for builtin call)");
|
EXPECT_EQ(r()->error(), R"(56:78 error: missing '(' for type initializer or cast)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsAliasUsedAsType) {
|
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsAliasUsedAsType) {
|
||||||
|
@ -242,7 +242,7 @@ TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsStructUsedAsVariable) {
|
||||||
WrapInFunction(Decl(Var("v", Expr(Source{{12, 34}}, "mix"))));
|
WrapInFunction(Decl(Var("v", Expr(Source{{12, 34}}, "mix"))));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), R"(12:34 error: missing '(' for builtin call)");
|
EXPECT_EQ(r()->error(), R"(12:34 error: missing '(' for type initializer or cast)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsStructUsedAsType) {
|
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsStructUsedAsType) {
|
||||||
|
|
|
@ -354,7 +354,8 @@ class DependencyScanner {
|
||||||
Switch(
|
Switch(
|
||||||
expr,
|
expr,
|
||||||
[&](const ast::IdentifierExpression* ident) {
|
[&](const ast::IdentifierExpression* ident) {
|
||||||
AddDependency(ident, ident->identifier->symbol, "identifier", "references");
|
AddDependency(ident->identifier, ident->identifier->symbol, "identifier",
|
||||||
|
"references");
|
||||||
},
|
},
|
||||||
[&](const ast::CallExpression* call) {
|
[&](const ast::CallExpression* call) {
|
||||||
if (call->target.name) {
|
if (call->target.name) {
|
||||||
|
@ -392,7 +393,7 @@ class DependencyScanner {
|
||||||
TraverseType(ptr->type);
|
TraverseType(ptr->type);
|
||||||
},
|
},
|
||||||
[&](const ast::TypeName* tn) { //
|
[&](const ast::TypeName* tn) { //
|
||||||
AddDependency(tn, tn->name->symbol, "type", "references");
|
AddDependency(tn->name, tn->name->symbol, "type", "references");
|
||||||
},
|
},
|
||||||
[&](const ast::Vector* vec) { //
|
[&](const ast::Vector* vec) { //
|
||||||
TraverseType(vec->type);
|
TraverseType(vec->type);
|
||||||
|
@ -468,15 +469,25 @@ class DependencyScanner {
|
||||||
UnhandledNode(diagnostics_, attr);
|
UnhandledNode(diagnostics_, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the dependency from `from` to `to`, erroring if `to` cannot be
|
/// Adds the dependency from @p from to @p to, erroring if @p to cannot be resolved.
|
||||||
/// resolved.
|
void AddDependency(const ast::Identifier* from,
|
||||||
void AddDependency(const ast::Node* from, Symbol to, const char* use, const char* action) {
|
Symbol to,
|
||||||
|
const char* use,
|
||||||
|
const char* action) {
|
||||||
auto* resolved = scope_stack_.Get(to);
|
auto* resolved = scope_stack_.Get(to);
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
if (!IsBuiltin(to)) {
|
auto s = symbols_.NameFor(to);
|
||||||
UnknownSymbol(to, from->source, use);
|
if (auto builtin_fn = sem::ParseBuiltinType(s); builtin_fn != sem::BuiltinType::kNone) {
|
||||||
|
graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_fn));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (auto builtin_ty = type::ParseBuiltin(s); builtin_ty != type::Builtin::kUndefined) {
|
||||||
|
graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_ty));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnknownSymbol(to, from->source, use);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto global = globals_.Find(to); global && (*global)->node == resolved) {
|
if (auto global = globals_.Find(to); global && (*global)->node == resolved) {
|
||||||
|
@ -486,17 +497,7 @@ class DependencyScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graph_.resolved_symbols.Add(from, resolved);
|
graph_.resolved_identifiers.Add(from, ResolvedIdentifier(resolved));
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns true if `name` is the name of a builtin function, or builtin type alias
|
|
||||||
bool IsBuiltin(Symbol name) const {
|
|
||||||
auto s = symbols_.NameFor(name);
|
|
||||||
if (sem::ParseBuiltinType(s) != sem::BuiltinType::kNone ||
|
|
||||||
type::ParseBuiltin(s) != type::Builtin::kUndefined) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends an error to the diagnostics that the given symbol cannot be
|
/// Appends an error to the diagnostics that the given symbol cannot be
|
||||||
|
@ -529,7 +530,7 @@ struct DependencyAnalysis {
|
||||||
/// @returns true if analysis found no errors, otherwise false.
|
/// @returns true if analysis found no errors, otherwise false.
|
||||||
bool Run(const ast::Module& module) {
|
bool Run(const ast::Module& module) {
|
||||||
// Reserve container memory
|
// Reserve container memory
|
||||||
graph_.resolved_symbols.Reserve(module.GlobalDeclarations().Length());
|
graph_.resolved_identifiers.Reserve(module.GlobalDeclarations().Length());
|
||||||
sorted_.Reserve(module.GlobalDeclarations().Length());
|
sorted_.Reserve(module.GlobalDeclarations().Length());
|
||||||
|
|
||||||
// Collect all the named globals from the AST module
|
// Collect all the named globals from the AST module
|
||||||
|
@ -821,4 +822,20 @@ bool DependencyGraph::Build(const ast::Module& module,
|
||||||
return da.Run(module);
|
return da.Run(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const ResolvedIdentifier& ri) {
|
||||||
|
if (!ri) {
|
||||||
|
return out << "<unresolved symbol>";
|
||||||
|
}
|
||||||
|
if (auto* node = ri.Node()) {
|
||||||
|
return out << "'" << node->TypeInfo().name << "' at " << node->source;
|
||||||
|
}
|
||||||
|
if (auto builtin_fn = ri.BuiltinFunction(); builtin_fn != sem::BuiltinType::kNone) {
|
||||||
|
return out << "builtin function '" << builtin_fn << "'";
|
||||||
|
}
|
||||||
|
if (auto builtin_ty = ri.BuiltinType(); builtin_ty != type::Builtin::kUndefined) {
|
||||||
|
return out << "builtin function '" << builtin_ty << "'";
|
||||||
|
}
|
||||||
|
return out << "<unhandled ResolvedIdentifier value>";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
|
|
@ -19,10 +19,83 @@
|
||||||
|
|
||||||
#include "src/tint/ast/module.h"
|
#include "src/tint/ast/module.h"
|
||||||
#include "src/tint/diagnostic/diagnostic.h"
|
#include "src/tint/diagnostic/diagnostic.h"
|
||||||
|
#include "src/tint/sem/builtin_type.h"
|
||||||
|
#include "src/tint/type/builtin.h"
|
||||||
#include "src/tint/utils/hashmap.h"
|
#include "src/tint/utils/hashmap.h"
|
||||||
|
|
||||||
namespace tint::resolver {
|
namespace tint::resolver {
|
||||||
|
|
||||||
|
/// ResolvedIdentifier holds the resolution of an ast::Identifier.
|
||||||
|
/// Can hold one of:
|
||||||
|
/// - const ast::TypeDecl* (as const ast::Node*)
|
||||||
|
/// - const ast::Variable* (as const ast::Node*)
|
||||||
|
/// - const ast::Function* (as const ast::Node*)
|
||||||
|
/// - sem::BuiltinType
|
||||||
|
/// - type::Builtin
|
||||||
|
class ResolvedIdentifier {
|
||||||
|
public:
|
||||||
|
ResolvedIdentifier() = default;
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// @param value the resolved identifier value
|
||||||
|
template <typename T>
|
||||||
|
ResolvedIdentifier(T value) : value_(value) {} // NOLINT(runtime/explicit)
|
||||||
|
|
||||||
|
/// @return true if the ResolvedIdentifier holds a value (successfully resolved)
|
||||||
|
operator bool() const { return !std::holds_alternative<std::monostate>(value_); }
|
||||||
|
|
||||||
|
/// @return the node pointer if the ResolvedIdentifier holds an AST node, otherwise nullptr
|
||||||
|
const ast::Node* Node() const {
|
||||||
|
if (auto n = std::get_if<const ast::Node*>(&value_)) {
|
||||||
|
return *n;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @return the builtin function if the ResolvedIdentifier holds sem::BuiltinType, otherwise
|
||||||
|
/// sem::BuiltinType::kNone
|
||||||
|
sem::BuiltinType BuiltinFunction() const {
|
||||||
|
if (auto n = std::get_if<sem::BuiltinType>(&value_)) {
|
||||||
|
return *n;
|
||||||
|
}
|
||||||
|
return sem::BuiltinType::kNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @return the builtin type if the ResolvedIdentifier holds type::Builtin, otherwise
|
||||||
|
/// type::Builtin::kUndefined
|
||||||
|
type::Builtin BuiltinType() const {
|
||||||
|
if (auto n = std::get_if<type::Builtin>(&value_)) {
|
||||||
|
return *n;
|
||||||
|
}
|
||||||
|
return type::Builtin::kUndefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @param value the value to compare the ResolvedIdentifier to
|
||||||
|
/// @return true if the ResolvedIdentifier is equal to @p value
|
||||||
|
template <typename T>
|
||||||
|
bool operator==(const T& value) const {
|
||||||
|
if (auto n = std::get_if<T>(&value_)) {
|
||||||
|
return *n == value;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @param other the other value to compare to this
|
||||||
|
/// @return true if this ResolvedIdentifier and @p other are not equal
|
||||||
|
template <typename T>
|
||||||
|
bool operator!=(const T& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<std::monostate, const ast::Node*, sem::BuiltinType, type::Builtin> value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @param out the std::ostream to write to
|
||||||
|
/// @param ri the ResolvedIdentifier
|
||||||
|
/// @returns `out` so calls can be chained
|
||||||
|
std::ostream& operator<<(std::ostream& out, const ResolvedIdentifier& ri);
|
||||||
|
|
||||||
/// DependencyGraph holds information about module-scope declaration dependency
|
/// DependencyGraph holds information about module-scope declaration dependency
|
||||||
/// analysis and symbol resolutions.
|
/// analysis and symbol resolutions.
|
||||||
struct DependencyGraph {
|
struct DependencyGraph {
|
||||||
|
@ -48,9 +121,8 @@ struct DependencyGraph {
|
||||||
/// All globals in dependency-sorted order.
|
/// All globals in dependency-sorted order.
|
||||||
utils::Vector<const ast::Node*, 32> ordered_globals;
|
utils::Vector<const ast::Node*, 32> ordered_globals;
|
||||||
|
|
||||||
/// Map of ast::IdentifierExpression or ast::TypeName to a type, function, or
|
/// Map of ast::Identifier to a ResolvedIdentifier
|
||||||
/// variable that declares the symbol.
|
utils::Hashmap<const ast::Identifier*, ResolvedIdentifier, 64> resolved_identifiers;
|
||||||
utils::Hashmap<const ast::Node*, const ast::Node*, 64> resolved_symbols;
|
|
||||||
|
|
||||||
/// Map of ast::Variable to a type, function, or variable that is shadowed by
|
/// Map of ast::Variable to a type, function, or variable that is shadowed by
|
||||||
/// the variable key. A declaration (X) shadows another (Y) if X and Y use
|
/// the variable key. A declaration (X) shadows another (Y) if X and Y use
|
||||||
|
|
|
@ -103,8 +103,7 @@ static constexpr SymbolDeclKind kFuncDeclKinds[] = {
|
||||||
SymbolDeclKind::Function,
|
SymbolDeclKind::Function,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// SymbolUseKind is used by parameterized tests to enumerate the different
|
/// SymbolUseKind is used by parameterized tests to enumerate the different kinds of symbol uses.
|
||||||
/// kinds of symbol uses.
|
|
||||||
enum class SymbolUseKind {
|
enum class SymbolUseKind {
|
||||||
GlobalVarType,
|
GlobalVarType,
|
||||||
GlobalVarArrayElemType,
|
GlobalVarArrayElemType,
|
||||||
|
@ -400,19 +399,19 @@ struct SymbolTestHelper {
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
~SymbolTestHelper();
|
~SymbolTestHelper();
|
||||||
|
|
||||||
/// Declares a symbol with the given kind
|
/// Declares an identifier with the given kind
|
||||||
/// @param kind the kind of symbol declaration
|
/// @param kind the kind of identifier declaration
|
||||||
/// @param symbol the symbol to use for the declaration
|
/// @param symbol the symbol to use for the declaration
|
||||||
/// @param source the source of the declaration
|
/// @param source the source of the declaration
|
||||||
/// @returns the declaration node
|
/// @returns the identifier node
|
||||||
const ast::Node* Add(SymbolDeclKind kind, Symbol symbol, Source source);
|
const ast::Node* Add(SymbolDeclKind kind, Symbol symbol, Source source);
|
||||||
|
|
||||||
/// Declares a use of a symbol with the given kind
|
/// Declares a use of an identifier with the given kind
|
||||||
/// @param kind the kind of symbol use
|
/// @param kind the kind of symbol use
|
||||||
/// @param symbol the declaration symbol to use
|
/// @param symbol the declaration symbol to use
|
||||||
/// @param source the source of the use
|
/// @param source the source of the use
|
||||||
/// @returns the use node
|
/// @returns the use node
|
||||||
const ast::Node* Add(SymbolUseKind kind, Symbol symbol, Source source);
|
const ast::Identifier* Add(SymbolUseKind kind, Symbol symbol, Source source);
|
||||||
|
|
||||||
/// Builds a function, if any parameter or local declarations have been added
|
/// Builds a function, if any parameter or local declarations have been added
|
||||||
void Build();
|
void Build();
|
||||||
|
@ -422,7 +421,7 @@ SymbolTestHelper::SymbolTestHelper(ProgramBuilder* b) : builder(b) {}
|
||||||
|
|
||||||
SymbolTestHelper::~SymbolTestHelper() {}
|
SymbolTestHelper::~SymbolTestHelper() {}
|
||||||
|
|
||||||
const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind, Symbol symbol, Source source) {
|
const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind, Symbol symbol, Source source = {}) {
|
||||||
auto& b = *builder;
|
auto& b = *builder;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolDeclKind::GlobalVar:
|
case SymbolDeclKind::GlobalVar:
|
||||||
|
@ -464,88 +463,90 @@ const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind, Symbol symbol, Sourc
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source source) {
|
const ast::Identifier* SymbolTestHelper::Add(SymbolUseKind kind,
|
||||||
|
Symbol symbol,
|
||||||
|
Source source = {}) {
|
||||||
auto& b = *builder;
|
auto& b = *builder;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolUseKind::GlobalVarType: {
|
case SymbolUseKind::GlobalVarType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), node, type::AddressSpace::kPrivate);
|
b.GlobalVar(b.Sym(), node, type::AddressSpace::kPrivate);
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarArrayElemType: {
|
case SymbolUseKind::GlobalVarArrayElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.array(node, 4_i), type::AddressSpace::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.array(node, 4_i), type::AddressSpace::kPrivate);
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarArraySizeValue: {
|
case SymbolUseKind::GlobalVarArraySizeValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.array(b.ty.i32(), node), type::AddressSpace::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.array(b.ty.i32(), node), type::AddressSpace::kPrivate);
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarVectorElemType: {
|
case SymbolUseKind::GlobalVarVectorElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.vec3(node), type::AddressSpace::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.vec3(node), type::AddressSpace::kPrivate);
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarMatrixElemType: {
|
case SymbolUseKind::GlobalVarMatrixElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.mat3x4(node), type::AddressSpace::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.mat3x4(node), type::AddressSpace::kPrivate);
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarSampledTexElemType: {
|
case SymbolUseKind::GlobalVarSampledTexElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.sampled_texture(type::TextureDimension::k2d, node));
|
b.GlobalVar(b.Sym(), b.ty.sampled_texture(type::TextureDimension::k2d, node));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarMultisampledTexElemType: {
|
case SymbolUseKind::GlobalVarMultisampledTexElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.multisampled_texture(type::TextureDimension::k2d, node));
|
b.GlobalVar(b.Sym(), b.ty.multisampled_texture(type::TextureDimension::k2d, node));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarValue: {
|
case SymbolUseKind::GlobalVarValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.i32(), type::AddressSpace::kPrivate, node);
|
b.GlobalVar(b.Sym(), b.ty.i32(), type::AddressSpace::kPrivate, node);
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalConstType: {
|
case SymbolUseKind::GlobalConstType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalConst(b.Sym(), node, b.Expr(1_i));
|
b.GlobalConst(b.Sym(), node, b.Expr(1_i));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalConstArrayElemType: {
|
case SymbolUseKind::GlobalConstArrayElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalConst(b.Sym(), b.ty.array(node, 4_i), b.Expr(1_i));
|
b.GlobalConst(b.Sym(), b.ty.array(node, 4_i), b.Expr(1_i));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalConstArraySizeValue: {
|
case SymbolUseKind::GlobalConstArraySizeValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
b.GlobalConst(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i));
|
b.GlobalConst(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i));
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalConstVectorElemType: {
|
case SymbolUseKind::GlobalConstVectorElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalConst(b.Sym(), b.ty.vec3(node), b.Expr(1_i));
|
b.GlobalConst(b.Sym(), b.ty.vec3(node), b.Expr(1_i));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalConstMatrixElemType: {
|
case SymbolUseKind::GlobalConstMatrixElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.GlobalConst(b.Sym(), b.ty.mat3x4(node), b.Expr(1_i));
|
b.GlobalConst(b.Sym(), b.ty.mat3x4(node), b.Expr(1_i));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalConstValue: {
|
case SymbolUseKind::GlobalConstValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
b.GlobalConst(b.Sym(), b.ty.i32(), node);
|
b.GlobalConst(b.Sym(), b.ty.i32(), node);
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::AliasType: {
|
case SymbolUseKind::AliasType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.Alias(b.Sym(), node);
|
b.Alias(b.Sym(), node);
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::StructMemberType: {
|
case SymbolUseKind::StructMemberType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
b.Structure(b.Sym(), utils::Vector{b.Member("m", node)});
|
b.Structure(b.Sym(), utils::Vector{b.Member("m", node)});
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::CallFunction: {
|
case SymbolUseKind::CallFunction: {
|
||||||
auto* node = b.Ident(source, symbol);
|
auto* node = b.Ident(source, symbol);
|
||||||
|
@ -555,72 +556,72 @@ const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source
|
||||||
case SymbolUseKind::ParameterType: {
|
case SymbolUseKind::ParameterType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
parameters.Push(b.Param(b.Sym(), node));
|
parameters.Push(b.Param(b.Sym(), node));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalVarType: {
|
case SymbolUseKind::LocalVarType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
statements.Push(b.Decl(b.Var(b.Sym(), node)));
|
statements.Push(b.Decl(b.Var(b.Sym(), node)));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalVarArrayElemType: {
|
case SymbolUseKind::LocalVarArrayElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.array(node, 4_u), b.Expr(1_i))));
|
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.array(node, 4_u), b.Expr(1_i))));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalVarArraySizeValue: {
|
case SymbolUseKind::LocalVarArraySizeValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i))));
|
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i))));
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalVarVectorElemType: {
|
case SymbolUseKind::LocalVarVectorElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.vec3(node))));
|
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.vec3(node))));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalVarMatrixElemType: {
|
case SymbolUseKind::LocalVarMatrixElemType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.mat3x4(node))));
|
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.mat3x4(node))));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalVarValue: {
|
case SymbolUseKind::LocalVarValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
|
statements.Push(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalLetType: {
|
case SymbolUseKind::LocalLetType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
statements.Push(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
|
statements.Push(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::LocalLetValue: {
|
case SymbolUseKind::LocalLetValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
statements.Push(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
|
statements.Push(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::NestedLocalVarType: {
|
case SymbolUseKind::NestedLocalVarType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
nested_statements.Push(b.Decl(b.Var(b.Sym(), node)));
|
nested_statements.Push(b.Decl(b.Var(b.Sym(), node)));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::NestedLocalVarValue: {
|
case SymbolUseKind::NestedLocalVarValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
nested_statements.Push(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
|
nested_statements.Push(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::NestedLocalLetType: {
|
case SymbolUseKind::NestedLocalLetType: {
|
||||||
auto* node = b.ty(source, symbol);
|
auto* node = b.ty(source, symbol);
|
||||||
nested_statements.Push(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
|
nested_statements.Push(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
|
||||||
return node;
|
return node->name;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::NestedLocalLetValue: {
|
case SymbolUseKind::NestedLocalLetValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
nested_statements.Push(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
|
nested_statements.Push(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::WorkgroupSizeValue: {
|
case SymbolUseKind::WorkgroupSizeValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
func_attrs.Push(b.WorkgroupSize(1_i, node, 2_i));
|
func_attrs.Push(b.WorkgroupSize(1_i, node, 2_i));
|
||||||
return node;
|
return node->identifier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -641,7 +642,7 @@ void SymbolTestHelper::Build() {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Used-before-declarated tests
|
// Used-before-declared tests
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
namespace used_before_decl_tests {
|
namespace used_before_decl_tests {
|
||||||
|
|
||||||
|
@ -1103,14 +1104,14 @@ TEST_F(ResolverDependencyGraphOrderedGlobalsTest, DirectiveFirst) {
|
||||||
} // namespace ordered_globals
|
} // namespace ordered_globals
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Resolved symbols tests
|
// Resolve to user-declaration tests
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
namespace resolved_symbols {
|
namespace resolve_to_user_decl {
|
||||||
|
|
||||||
using ResolverDependencyGraphResolvedSymbolTest =
|
using ResolverDependencyGraphResolveToUserDeclTest =
|
||||||
ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolUseKind>>;
|
ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolUseKind>>;
|
||||||
|
|
||||||
TEST_P(ResolverDependencyGraphResolvedSymbolTest, Test) {
|
TEST_P(ResolverDependencyGraphResolveToUserDeclTest, Test) {
|
||||||
const Symbol symbol = Sym("SYMBOL");
|
const Symbol symbol = Sym("SYMBOL");
|
||||||
const auto decl_kind = std::get<0>(GetParam());
|
const auto decl_kind = std::get<0>(GetParam());
|
||||||
const auto use_kind = std::get<1>(GetParam());
|
const auto use_kind = std::get<1>(GetParam());
|
||||||
|
@ -1128,41 +1129,209 @@ TEST_P(ResolverDependencyGraphResolvedSymbolTest, Test) {
|
||||||
|
|
||||||
if (expect_pass) {
|
if (expect_pass) {
|
||||||
// Check that the use resolves to the declaration
|
// Check that the use resolves to the declaration
|
||||||
auto resolved_symbol = graph.resolved_symbols.Find(use);
|
auto resolved_identifier = graph.resolved_identifiers.Find(use);
|
||||||
ASSERT_TRUE(resolved_symbol);
|
ASSERT_TRUE(resolved_identifier);
|
||||||
EXPECT_EQ(*resolved_symbol, decl)
|
auto* resolved_node = resolved_identifier->Node();
|
||||||
<< "resolved: " << (*resolved_symbol ? (*resolved_symbol)->TypeInfo().name : "<null>")
|
EXPECT_EQ(resolved_node, decl)
|
||||||
<< "\n"
|
<< "resolved: " << (resolved_node ? resolved_node->TypeInfo().name : "<null>") << "\n"
|
||||||
<< "decl: " << decl->TypeInfo().name;
|
<< "decl: " << decl->TypeInfo().name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(Types,
|
INSTANTIATE_TEST_SUITE_P(Types,
|
||||||
ResolverDependencyGraphResolvedSymbolTest,
|
ResolverDependencyGraphResolveToUserDeclTest,
|
||||||
testing::Combine(testing::ValuesIn(kTypeDeclKinds),
|
testing::Combine(testing::ValuesIn(kTypeDeclKinds),
|
||||||
testing::ValuesIn(kTypeUseKinds)));
|
testing::ValuesIn(kTypeUseKinds)));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(Values,
|
INSTANTIATE_TEST_SUITE_P(Values,
|
||||||
ResolverDependencyGraphResolvedSymbolTest,
|
ResolverDependencyGraphResolveToUserDeclTest,
|
||||||
testing::Combine(testing::ValuesIn(kValueDeclKinds),
|
testing::Combine(testing::ValuesIn(kValueDeclKinds),
|
||||||
testing::ValuesIn(kValueUseKinds)));
|
testing::ValuesIn(kValueUseKinds)));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(Functions,
|
INSTANTIATE_TEST_SUITE_P(Functions,
|
||||||
ResolverDependencyGraphResolvedSymbolTest,
|
ResolverDependencyGraphResolveToUserDeclTest,
|
||||||
testing::Combine(testing::ValuesIn(kFuncDeclKinds),
|
testing::Combine(testing::ValuesIn(kFuncDeclKinds),
|
||||||
testing::ValuesIn(kFuncUseKinds)));
|
testing::ValuesIn(kFuncUseKinds)));
|
||||||
|
|
||||||
} // namespace resolved_symbols
|
} // namespace resolve_to_user_decl
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Resolve to builtin func tests
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
namespace resolve_to_builtin_func {
|
||||||
|
|
||||||
|
using ResolverDependencyGraphResolveToBuiltinFunc =
|
||||||
|
ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, sem::BuiltinType>>;
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, Resolve) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto builtin = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(utils::ToString(builtin));
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->BuiltinFunction(), builtin) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, ShadowedByGlobalVar) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto builtin = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(utils::ToString(builtin));
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* decl = helper.Add(SymbolDeclKind::GlobalVar, symbol);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->Node(), decl) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, ShadowedByStruct) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto builtin = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(utils::ToString(builtin));
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* decl = helper.Add(SymbolDeclKind::Struct, symbol);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->Node(), decl) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, ShadowedByFunc) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto builtin = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(utils::ToString(builtin));
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->Node(), decl) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Types,
|
||||||
|
ResolverDependencyGraphResolveToBuiltinFunc,
|
||||||
|
testing::Combine(testing::ValuesIn(kTypeUseKinds),
|
||||||
|
testing::ValuesIn(sem::kBuiltinTypes)));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Values,
|
||||||
|
ResolverDependencyGraphResolveToBuiltinFunc,
|
||||||
|
testing::Combine(testing::ValuesIn(kValueUseKinds),
|
||||||
|
testing::ValuesIn(sem::kBuiltinTypes)));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Functions,
|
||||||
|
ResolverDependencyGraphResolveToBuiltinFunc,
|
||||||
|
testing::Combine(testing::ValuesIn(kFuncUseKinds),
|
||||||
|
testing::ValuesIn(sem::kBuiltinTypes)));
|
||||||
|
|
||||||
|
} // namespace resolve_to_builtin_func
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Resolve to builtin type tests
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
namespace resolve_to_builtin_type {
|
||||||
|
|
||||||
|
using ResolverDependencyGraphResolveToBuiltinType =
|
||||||
|
ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, const char*>>;
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinType, Resolve) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto name = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(name);
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->BuiltinType(), type::ParseBuiltin(name)) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinType, ShadowedByGlobalVar) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto name = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(name);
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* decl = helper.Add(SymbolDeclKind::GlobalVar, symbol);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->Node(), decl) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinType, ShadowedByStruct) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto name = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(name);
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* decl = helper.Add(SymbolDeclKind::Struct, symbol);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->Node(), decl) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ResolverDependencyGraphResolveToBuiltinType, ShadowedByFunc) {
|
||||||
|
const auto use = std::get<0>(GetParam());
|
||||||
|
const auto name = std::get<1>(GetParam());
|
||||||
|
const auto symbol = Symbols().New(name);
|
||||||
|
|
||||||
|
SymbolTestHelper helper(this);
|
||||||
|
auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
|
||||||
|
auto* ident = helper.Add(use, symbol);
|
||||||
|
helper.Build();
|
||||||
|
|
||||||
|
auto resolved = Build().resolved_identifiers.Get(ident);
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
EXPECT_EQ(resolved->Node(), decl) << *resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Types,
|
||||||
|
ResolverDependencyGraphResolveToBuiltinType,
|
||||||
|
testing::Combine(testing::ValuesIn(kTypeUseKinds),
|
||||||
|
testing::ValuesIn(type::kBuiltinStrings)));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Values,
|
||||||
|
ResolverDependencyGraphResolveToBuiltinType,
|
||||||
|
testing::Combine(testing::ValuesIn(kValueUseKinds),
|
||||||
|
testing::ValuesIn(type::kBuiltinStrings)));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Functions,
|
||||||
|
ResolverDependencyGraphResolveToBuiltinType,
|
||||||
|
testing::Combine(testing::ValuesIn(kFuncUseKinds),
|
||||||
|
testing::ValuesIn(type::kBuiltinStrings)));
|
||||||
|
|
||||||
|
} // namespace resolve_to_builtin_type
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Shadowing tests
|
// Shadowing tests
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
namespace shadowing {
|
namespace shadowing {
|
||||||
|
|
||||||
using ResolverDependencyShadowTest =
|
using ResolverDependencyGraphShadowTest =
|
||||||
ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolDeclKind>>;
|
ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolDeclKind>>;
|
||||||
|
|
||||||
TEST_P(ResolverDependencyShadowTest, Test) {
|
TEST_P(ResolverDependencyGraphShadowTest, Test) {
|
||||||
const Symbol symbol = Sym("SYMBOL");
|
const Symbol symbol = Sym("SYMBOL");
|
||||||
const auto outer_kind = std::get<0>(GetParam());
|
const auto outer_kind = std::get<0>(GetParam());
|
||||||
const auto inner_kind = std::get<1>(GetParam());
|
const auto inner_kind = std::get<1>(GetParam());
|
||||||
|
@ -1185,12 +1354,12 @@ TEST_P(ResolverDependencyShadowTest, Test) {
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(LocalShadowGlobal,
|
INSTANTIATE_TEST_SUITE_P(LocalShadowGlobal,
|
||||||
ResolverDependencyShadowTest,
|
ResolverDependencyGraphShadowTest,
|
||||||
testing::Combine(testing::ValuesIn(kGlobalDeclKinds),
|
testing::Combine(testing::ValuesIn(kGlobalDeclKinds),
|
||||||
testing::ValuesIn(kLocalDeclKinds)));
|
testing::ValuesIn(kLocalDeclKinds)));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(NestedLocalShadowLocal,
|
INSTANTIATE_TEST_SUITE_P(NestedLocalShadowLocal,
|
||||||
ResolverDependencyShadowTest,
|
ResolverDependencyGraphShadowTest,
|
||||||
testing::Combine(testing::Values(SymbolDeclKind::Parameter,
|
testing::Combine(testing::Values(SymbolDeclKind::Parameter,
|
||||||
SymbolDeclKind::LocalVar,
|
SymbolDeclKind::LocalVar,
|
||||||
SymbolDeclKind::LocalLet),
|
SymbolDeclKind::LocalLet),
|
||||||
|
@ -1204,6 +1373,18 @@ INSTANTIATE_TEST_SUITE_P(NestedLocalShadowLocal,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
namespace ast_traversal {
|
namespace ast_traversal {
|
||||||
|
|
||||||
|
static const ast::Identifier* IdentifierOf(const ast::IdentifierExpression* expr) {
|
||||||
|
return expr->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ast::Identifier* IdentifierOf(const ast::TypeName* ty) {
|
||||||
|
return ty->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ast::Identifier* IdentifierOf(const ast::Identifier* ident) {
|
||||||
|
return ident;
|
||||||
|
}
|
||||||
|
|
||||||
using ResolverDependencyGraphTraversalTest = ResolverDependencyGraphTest;
|
using ResolverDependencyGraphTraversalTest = ResolverDependencyGraphTest;
|
||||||
|
|
||||||
TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
||||||
|
@ -1217,7 +1398,7 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
||||||
|
|
||||||
struct SymbolUse {
|
struct SymbolUse {
|
||||||
const ast::Node* decl = nullptr;
|
const ast::Node* decl = nullptr;
|
||||||
const ast::Node* use = nullptr;
|
const ast::Identifier* use = nullptr;
|
||||||
std::string where;
|
std::string where;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1225,7 +1406,8 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
||||||
|
|
||||||
auto add_use = [&](const ast::Node* decl, auto* use, int line, const char* kind) {
|
auto add_use = [&](const ast::Node* decl, auto* use, int line, const char* kind) {
|
||||||
symbol_uses.Push(
|
symbol_uses.Push(
|
||||||
SymbolUse{decl, use, std::string(__FILE__) + ":" + std::to_string(line) + ": " + kind});
|
SymbolUse{decl, IdentifierOf(use),
|
||||||
|
std::string(__FILE__) + ":" + std::to_string(line) + ": " + kind});
|
||||||
return use;
|
return use;
|
||||||
};
|
};
|
||||||
#define V add_use(value_decl, Expr(value_sym), __LINE__, "V()")
|
#define V add_use(value_decl, Expr(value_sym), __LINE__, "V()")
|
||||||
|
@ -1310,9 +1492,9 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
||||||
|
|
||||||
auto graph = Build();
|
auto graph = Build();
|
||||||
for (auto use : symbol_uses) {
|
for (auto use : symbol_uses) {
|
||||||
auto resolved_symbol = graph.resolved_symbols.Find(use.use);
|
auto resolved_identifier = graph.resolved_identifiers.Find(use.use);
|
||||||
ASSERT_TRUE(resolved_symbol) << use.where;
|
ASSERT_TRUE(resolved_identifier) << use.where;
|
||||||
EXPECT_EQ(*resolved_symbol, use.decl) << use.where;
|
EXPECT_EQ(*resolved_identifier, use.decl) << use.where;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ Resolver::Resolver(ProgramBuilder* builder)
|
||||||
diagnostics_(builder->Diagnostics()),
|
diagnostics_(builder->Diagnostics()),
|
||||||
const_eval_(*builder),
|
const_eval_(*builder),
|
||||||
intrinsic_table_(IntrinsicTable::Create(*builder)),
|
intrinsic_table_(IntrinsicTable::Create(*builder)),
|
||||||
sem_(builder, dependencies_),
|
sem_(builder),
|
||||||
validator_(builder,
|
validator_(builder,
|
||||||
sem_,
|
sem_,
|
||||||
enabled_extensions_,
|
enabled_extensions_,
|
||||||
|
@ -332,41 +332,45 @@ type::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
TINT_UNREACHABLE(Resolver, builder_->Diagnostics()) << "TODO(crbug.com/tint/1810)";
|
TINT_UNREACHABLE(Resolver, builder_->Diagnostics()) << "TODO(crbug.com/tint/1810)";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* resolved = sem_.ResolvedSymbol(t);
|
auto resolved = dependencies_.resolved_identifiers.Get(t->name);
|
||||||
if (resolved == nullptr) {
|
if (!resolved) {
|
||||||
if (IsBuiltin(t->name->symbol)) {
|
TINT_ICE(Resolver, builder_->Diagnostics()) << "identifier was not resolved";
|
||||||
auto name = builder_->Symbols().NameFor(t->name->symbol);
|
return nullptr;
|
||||||
AddError("cannot use builtin '" + name + "' as type", ty->source);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return BuiltinType(t->name->symbol, t->source);
|
|
||||||
}
|
}
|
||||||
return Switch(
|
|
||||||
resolved, //
|
if (auto* ast_node = resolved->Node()) {
|
||||||
[&](type::Type* type) { return type; },
|
auto* resolved_node = sem_.Get(ast_node);
|
||||||
[&](sem::Variable* var) {
|
return Switch(
|
||||||
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
resolved_node, //
|
||||||
AddError("cannot use variable '" + name + "' as type", ty->source);
|
[&](type::Type* type) { return type; },
|
||||||
AddNote("'" + name + "' declared here", var->Declaration()->source);
|
[&](sem::Variable* variable) {
|
||||||
return nullptr;
|
auto name = builder_->Symbols().NameFor(variable->Declaration()->symbol);
|
||||||
},
|
AddError("cannot use variable '" + name + "' as type", ty->source);
|
||||||
[&](sem::Function* func) {
|
AddNote("'" + name + "' declared here", variable->Declaration()->source);
|
||||||
auto name = builder_->Symbols().NameFor(func->Declaration()->symbol);
|
return nullptr;
|
||||||
AddError("cannot use function '" + name + "' as type", ty->source);
|
},
|
||||||
AddNote("'" + name + "' declared here", func->Declaration()->source);
|
[&](sem::Function* func) {
|
||||||
return nullptr;
|
auto name = builder_->Symbols().NameFor(func->Declaration()->symbol);
|
||||||
},
|
AddError("cannot use function '" + name + "' as type", ty->source);
|
||||||
[&](Default) -> type::Type* {
|
AddNote("'" + name + "' declared here", func->Declaration()->source);
|
||||||
TINT_UNREACHABLE(Resolver, diagnostics_)
|
return nullptr;
|
||||||
<< "Unhandled resolved type '"
|
});
|
||||||
<< (resolved ? resolved->TypeInfo().name : "<null>")
|
}
|
||||||
<< "' resolved from ast::Type '" << ty->TypeInfo().name << "'";
|
|
||||||
return nullptr;
|
if (auto builtin_ty = resolved->BuiltinType();
|
||||||
});
|
builtin_ty != type::Builtin::kUndefined) {
|
||||||
},
|
return BuiltinType(builtin_ty, t->name);
|
||||||
[&](Default) {
|
}
|
||||||
|
|
||||||
|
if (auto builtin_fn = resolved->BuiltinFunction();
|
||||||
|
builtin_fn != sem::BuiltinType::kNone) {
|
||||||
|
auto name = builder_->Symbols().NameFor(t->name->symbol);
|
||||||
|
AddError("cannot use builtin '" + name + "' as type", ty->source);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
TINT_UNREACHABLE(Resolver, diagnostics_)
|
TINT_UNREACHABLE(Resolver, diagnostics_)
|
||||||
<< "Unhandled type: '" << ty->TypeInfo().name << "'";
|
<< "unhandled resolved identifier: " << *resolved;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -947,7 +951,8 @@ sem::GlobalVariable* Resolver::GlobalVariable(const ast::Variable* v) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track the pipeline-overridable constants that are transitively referenced by this variable.
|
// Track the pipeline-overridable constants that are transitively referenced by this
|
||||||
|
// variable.
|
||||||
for (auto* var : transitively_referenced_overrides) {
|
for (auto* var : transitively_referenced_overrides) {
|
||||||
builder_->Sem().AddTransitivelyReferencedOverride(sem, var);
|
builder_->Sem().AddTransitivelyReferencedOverride(sem, var);
|
||||||
}
|
}
|
||||||
|
@ -1176,8 +1181,8 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
|
||||||
"abstract-integer, i32 or u32";
|
"abstract-integer, i32 or u32";
|
||||||
|
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (size_t i = 0; i < 3; i++) {
|
||||||
// Each argument to this attribute can either be a literal, an identifier for a module-scope
|
// Each argument to this attribute can either be a literal, an identifier for a
|
||||||
// constants, a const-expression, or nullptr if not specified.
|
// module-scope constants, a const-expression, or nullptr if not specified.
|
||||||
auto* value = values[i];
|
auto* value = values[i];
|
||||||
if (!value) {
|
if (!value) {
|
||||||
break;
|
break;
|
||||||
|
@ -1604,8 +1609,8 @@ sem::ValueExpression* Resolver::Expression(const ast::Expression* root) {
|
||||||
return sem_expr;
|
return sem_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we just processed the lhs of a constexpr logical binary expression, mark the rhs for
|
// If we just processed the lhs of a constexpr logical binary expression, mark the rhs
|
||||||
// short-circuiting.
|
// for short-circuiting.
|
||||||
if (sem_expr->ConstantValue()) {
|
if (sem_expr->ConstantValue()) {
|
||||||
if (auto binary = logical_binary_lhs_to_parent_.Find(expr)) {
|
if (auto binary = logical_binary_lhs_to_parent_.Find(expr)) {
|
||||||
const bool lhs_is_true = sem_expr->ConstantValue()->ValueAs<bool>();
|
const bool lhs_is_true = sem_expr->ConstantValue()->ValueAs<bool>();
|
||||||
|
@ -1678,7 +1683,8 @@ bool Resolver::AliasAnalysis(const sem::Call* call) {
|
||||||
auto& target_info = alias_analysis_infos_[target];
|
auto& target_info = alias_analysis_infos_[target];
|
||||||
auto& caller_info = alias_analysis_infos_[current_function_];
|
auto& caller_info = alias_analysis_infos_[current_function_];
|
||||||
|
|
||||||
// Track the set of root identifiers that are read and written by arguments passed in this call.
|
// Track the set of root identifiers that are read and written by arguments passed in this
|
||||||
|
// call.
|
||||||
std::unordered_map<const sem::Variable*, const sem::ValueExpression*> arg_reads;
|
std::unordered_map<const sem::Variable*, const sem::ValueExpression*> arg_reads;
|
||||||
std::unordered_map<const sem::Variable*, const sem::ValueExpression*> arg_writes;
|
std::unordered_map<const sem::Variable*, const sem::ValueExpression*> arg_writes;
|
||||||
for (size_t i = 0; i < args.Length(); i++) {
|
for (size_t i = 0; i < args.Length(); i++) {
|
||||||
|
@ -1715,8 +1721,8 @@ bool Resolver::AliasAnalysis(const sem::Call* call) {
|
||||||
},
|
},
|
||||||
[&](const sem::Parameter* param) { caller_info.parameter_writes.insert(param); });
|
[&](const sem::Parameter* param) { caller_info.parameter_writes.insert(param); });
|
||||||
} else if (target_info.parameter_reads.count(target->Parameters()[i])) {
|
} else if (target_info.parameter_reads.count(target->Parameters()[i])) {
|
||||||
// Arguments that are read from can alias with arguments or module-scope variables that
|
// Arguments that are read from can alias with arguments or module-scope variables
|
||||||
// are written to.
|
// that are written to.
|
||||||
if (arg_writes.count(root)) {
|
if (arg_writes.count(root)) {
|
||||||
return make_error(arg, {arg_writes.at(root), Alias::Argument, "write"});
|
return make_error(arg, {arg_writes.at(root), Alias::Argument, "write"});
|
||||||
}
|
}
|
||||||
|
@ -2101,8 +2107,8 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
||||||
// Constant evaluation failed.
|
// Constant evaluation failed.
|
||||||
// Can happen for expressions that will fail validation (later).
|
// Can happen for expressions that will fail validation (later).
|
||||||
// Use the kRuntime EvaluationStage, as kConstant will trigger an assertion in
|
// Use the kRuntime EvaluationStage, as kConstant will trigger an assertion in
|
||||||
// the sem::ValueExpression initializer, which checks that kConstant is paired with
|
// the sem::ValueExpression initializer, which checks that kConstant is paired
|
||||||
// a constant value.
|
// with a constant value.
|
||||||
stage = sem::EvaluationStage::kRuntime;
|
stage = sem::EvaluationStage::kRuntime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2310,35 +2316,44 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
||||||
// conversion.
|
// conversion.
|
||||||
auto* ident = expr->target.name;
|
auto* ident = expr->target.name;
|
||||||
Mark(ident);
|
Mark(ident);
|
||||||
if (auto* resolved = sem_.ResolvedSymbol<type::Type>(ident)) {
|
|
||||||
// A type initializer or conversions.
|
auto resolved = dependencies_.resolved_identifiers.Get(ident);
|
||||||
// Note: Unlike the code path where we're resolving the call target from an
|
if (!resolved) {
|
||||||
// ast::Type, all types must already have the element type explicitly specified,
|
TINT_ICE(Resolver, builder_->Diagnostics()) << "identifier was not resolved";
|
||||||
// so there's no need to infer element types.
|
return nullptr;
|
||||||
return ty_init_or_conv(resolved);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* resolved = sem_.ResolvedSymbol<sem::Node>(ident);
|
if (auto* ast_node = resolved->Node()) {
|
||||||
call = Switch<sem::Call*>(
|
auto* resolved_node = sem_.Get(ast_node);
|
||||||
resolved, //
|
return Switch(
|
||||||
[&](sem::Function* func) { return FunctionCall(expr, func, args, arg_behaviors); },
|
resolved_node, //
|
||||||
[&](sem::Variable* var) {
|
[&](const type::Type* ty) {
|
||||||
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
// A type initializer or conversions.
|
||||||
AddError("cannot call variable '" + name + "'", ident->source);
|
// Note: Unlike the code path where we're resolving the call target from an
|
||||||
AddNote("'" + name + "' declared here", var->Declaration()->source);
|
// ast::Type, all types must already have the element type explicitly
|
||||||
return nullptr;
|
// specified, so there's no need to infer element types.
|
||||||
},
|
return ty_init_or_conv(ty);
|
||||||
[&](Default) -> sem::Call* {
|
},
|
||||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
[&](sem::Function* func) { return FunctionCall(expr, func, args, arg_behaviors); },
|
||||||
if (auto builtin_type = sem::ParseBuiltinType(name);
|
[&](sem::Variable* var) {
|
||||||
builtin_type != sem::BuiltinType::kNone) {
|
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
||||||
return BuiltinCall(expr, builtin_type, args);
|
AddError("cannot call variable '" + name + "'", ident->source);
|
||||||
}
|
AddNote("'" + name + "' declared here", var->Declaration()->source);
|
||||||
if (auto* alias = BuiltinType(ident->symbol, ident->source)) {
|
return nullptr;
|
||||||
return ty_init_or_conv(alias);
|
});
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
});
|
if (auto builtin_fn = resolved->BuiltinFunction(); builtin_fn != sem::BuiltinType::kNone) {
|
||||||
|
return BuiltinCall(expr, builtin_fn, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto builtin_ty = resolved->BuiltinType(); builtin_ty != type::Builtin::kUndefined) {
|
||||||
|
auto* ty = BuiltinType(builtin_ty, expr->target.name);
|
||||||
|
return ty ? ty_init_or_conv(ty) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TINT_UNREACHABLE(Resolver, diagnostics_) << "unhandled resolved identifier: " << *resolved;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!call) {
|
if (!call) {
|
||||||
|
@ -2438,13 +2453,12 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
type::Type* Resolver::BuiltinType(Symbol sym, const Source& source) const {
|
type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) const {
|
||||||
auto name = builder_->Symbols().NameFor(sym);
|
|
||||||
auto& b = *builder_;
|
auto& b = *builder_;
|
||||||
auto vec_f32 = [&](uint32_t n) { return b.create<type::Vector>(b.create<type::F32>(), n); };
|
auto vec_f32 = [&](uint32_t n) { return b.create<type::Vector>(b.create<type::F32>(), n); };
|
||||||
auto vec_f16 = [&](uint32_t n) { return b.create<type::Vector>(b.create<type::F16>(), n); };
|
auto vec_f16 = [&](uint32_t n) { return b.create<type::Vector>(b.create<type::F16>(), n); };
|
||||||
|
|
||||||
switch (type::ParseBuiltin(name)) {
|
switch (builtin_ty) {
|
||||||
case type::Builtin::kMat2X2F:
|
case type::Builtin::kMat2X2F:
|
||||||
return b.create<type::Matrix>(vec_f32(2u), 2u);
|
return b.create<type::Matrix>(vec_f32(2u), 2u);
|
||||||
case type::Builtin::kMat2X3F:
|
case type::Builtin::kMat2X3F:
|
||||||
|
@ -2464,32 +2478,41 @@ type::Type* Resolver::BuiltinType(Symbol sym, const Source& source) const {
|
||||||
case type::Builtin::kMat4X4F:
|
case type::Builtin::kMat4X4F:
|
||||||
return b.create<type::Matrix>(vec_f32(4u), 4u);
|
return b.create<type::Matrix>(vec_f32(4u), 4u);
|
||||||
case type::Builtin::kMat2X2H:
|
case type::Builtin::kMat2X2H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(2u), 2u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(2u), 2u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat2X3H:
|
case type::Builtin::kMat2X3H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(3u), 2u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(3u), 2u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat2X4H:
|
case type::Builtin::kMat2X4H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(4u), 2u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(4u), 2u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat3X2H:
|
case type::Builtin::kMat3X2H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(2u), 3u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(2u), 3u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat3X3H:
|
case type::Builtin::kMat3X3H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(3u), 3u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(3u), 3u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat3X4H:
|
case type::Builtin::kMat3X4H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(4u), 3u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(4u), 3u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat4X2H:
|
case type::Builtin::kMat4X2H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(2u), 4u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(2u), 4u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat4X3H:
|
case type::Builtin::kMat4X3H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(3u), 4u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(3u), 4u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kMat4X4H:
|
case type::Builtin::kMat4X4H:
|
||||||
return validator_.CheckF16Enabled(source) ? b.create<type::Matrix>(vec_f16(4u), 4u)
|
return validator_.CheckF16Enabled(ident->source)
|
||||||
: nullptr;
|
? b.create<type::Matrix>(vec_f16(4u), 4u)
|
||||||
|
: nullptr;
|
||||||
case type::Builtin::kVec2F:
|
case type::Builtin::kVec2F:
|
||||||
return vec_f32(2u);
|
return vec_f32(2u);
|
||||||
case type::Builtin::kVec3F:
|
case type::Builtin::kVec3F:
|
||||||
|
@ -2497,11 +2520,11 @@ type::Type* Resolver::BuiltinType(Symbol sym, const Source& source) const {
|
||||||
case type::Builtin::kVec4F:
|
case type::Builtin::kVec4F:
|
||||||
return vec_f32(4u);
|
return vec_f32(4u);
|
||||||
case type::Builtin::kVec2H:
|
case type::Builtin::kVec2H:
|
||||||
return validator_.CheckF16Enabled(source) ? vec_f16(2u) : nullptr;
|
return validator_.CheckF16Enabled(ident->source) ? vec_f16(2u) : nullptr;
|
||||||
case type::Builtin::kVec3H:
|
case type::Builtin::kVec3H:
|
||||||
return validator_.CheckF16Enabled(source) ? vec_f16(3u) : nullptr;
|
return validator_.CheckF16Enabled(ident->source) ? vec_f16(3u) : nullptr;
|
||||||
case type::Builtin::kVec4H:
|
case type::Builtin::kVec4H:
|
||||||
return validator_.CheckF16Enabled(source) ? vec_f16(4u) : nullptr;
|
return validator_.CheckF16Enabled(ident->source) ? vec_f16(4u) : nullptr;
|
||||||
case type::Builtin::kVec2I:
|
case type::Builtin::kVec2I:
|
||||||
return b.create<type::Vector>(b.create<type::I32>(), 2u);
|
return b.create<type::Vector>(b.create<type::I32>(), 2u);
|
||||||
case type::Builtin::kVec3I:
|
case type::Builtin::kVec3I:
|
||||||
|
@ -2518,7 +2541,8 @@ type::Type* Resolver::BuiltinType(Symbol sym, const Source& source) const {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINT_ICE(Resolver, diagnostics_) << source << " unhandled builtin type '" << name << "'";
|
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||||
|
TINT_ICE(Resolver, diagnostics_) << ident->source << " unhandled builtin type '" << name << "'";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2685,97 +2709,110 @@ sem::ValueExpression* Resolver::Literal(const ast::LiteralExpression* literal) {
|
||||||
|
|
||||||
sem::ValueExpression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
|
sem::ValueExpression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
|
||||||
Mark(expr->identifier);
|
Mark(expr->identifier);
|
||||||
auto symbol = expr->identifier->symbol;
|
|
||||||
auto* sem_resolved = sem_.ResolvedSymbol<sem::Node>(expr);
|
|
||||||
if (auto* variable = As<sem::Variable>(sem_resolved)) {
|
|
||||||
auto* user = builder_->create<sem::VariableUser>(expr, current_statement_, variable);
|
|
||||||
|
|
||||||
if (current_statement_) {
|
auto resolved = dependencies_.resolved_identifiers.Get(expr->identifier);
|
||||||
// If identifier is part of a loop continuing block, make sure it
|
if (!resolved) {
|
||||||
// doesn't refer to a variable that is bypassed by a continue statement
|
TINT_ICE(Resolver, builder_->Diagnostics()) << "identifier was not resolved";
|
||||||
// in the loop's body block.
|
return nullptr;
|
||||||
if (auto* continuing_block =
|
}
|
||||||
current_statement_->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
|
|
||||||
auto* loop_block = continuing_block->FindFirstParent<sem::LoopBlockStatement>();
|
if (auto* ast_node = resolved->Node()) {
|
||||||
if (loop_block->FirstContinue()) {
|
auto* resolved_node = sem_.Get(ast_node);
|
||||||
// If our identifier is in loop_block->decls, make sure its index is
|
return Switch(
|
||||||
// less than first_continue
|
resolved_node, //
|
||||||
if (auto decl = loop_block->Decls().Find(symbol)) {
|
[&](sem::Variable* variable) -> sem::VariableUser* {
|
||||||
if (decl->order >= loop_block->NumDeclsAtFirstContinue()) {
|
auto symbol = expr->identifier->symbol;
|
||||||
AddError("continue statement bypasses declaration of '" +
|
auto* user =
|
||||||
builder_->Symbols().NameFor(symbol) + "'",
|
builder_->create<sem::VariableUser>(expr, current_statement_, variable);
|
||||||
loop_block->FirstContinue()->source);
|
|
||||||
AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
|
if (current_statement_) {
|
||||||
"' declared here",
|
// If identifier is part of a loop continuing block, make sure it
|
||||||
decl->variable->Declaration()->source);
|
// doesn't refer to a variable that is bypassed by a continue statement
|
||||||
AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
|
// in the loop's body block.
|
||||||
"' referenced in continuing block here",
|
if (auto* continuing_block =
|
||||||
expr->source);
|
current_statement_
|
||||||
return nullptr;
|
->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
|
||||||
|
auto* loop_block =
|
||||||
|
continuing_block->FindFirstParent<sem::LoopBlockStatement>();
|
||||||
|
if (loop_block->FirstContinue()) {
|
||||||
|
// If our identifier is in loop_block->decls, make sure its index is
|
||||||
|
// less than first_continue
|
||||||
|
if (auto decl = loop_block->Decls().Find(symbol)) {
|
||||||
|
if (decl->order >= loop_block->NumDeclsAtFirstContinue()) {
|
||||||
|
AddError("continue statement bypasses declaration of '" +
|
||||||
|
builder_->Symbols().NameFor(symbol) + "'",
|
||||||
|
loop_block->FirstContinue()->source);
|
||||||
|
AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
|
||||||
|
"' declared here",
|
||||||
|
decl->variable->Declaration()->source);
|
||||||
|
AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
|
||||||
|
"' referenced in continuing block here",
|
||||||
|
expr->source);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* global = variable->As<sem::GlobalVariable>();
|
auto* global = variable->As<sem::GlobalVariable>();
|
||||||
if (current_function_) {
|
if (current_function_) {
|
||||||
if (global) {
|
if (global) {
|
||||||
current_function_->AddDirectlyReferencedGlobal(global);
|
current_function_->AddDirectlyReferencedGlobal(global);
|
||||||
auto* refs = builder_->Sem().TransitivelyReferencedOverrides(global);
|
auto* refs = builder_->Sem().TransitivelyReferencedOverrides(global);
|
||||||
if (refs) {
|
if (refs) {
|
||||||
for (auto* var : *refs) {
|
for (auto* var : *refs) {
|
||||||
current_function_->AddTransitivelyReferencedGlobal(var);
|
current_function_->AddTransitivelyReferencedGlobal(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (variable->Declaration()->Is<ast::Override>()) {
|
||||||
}
|
if (resolved_overrides_) {
|
||||||
} else if (variable->Declaration()->Is<ast::Override>()) {
|
// Track the reference to this pipeline-overridable constant and any other
|
||||||
if (resolved_overrides_) {
|
// pipeline-overridable constants that it references.
|
||||||
// Track the reference to this pipeline-overridable constant and any other
|
resolved_overrides_->Add(global);
|
||||||
// pipeline-overridable constants that it references.
|
auto* refs = builder_->Sem().TransitivelyReferencedOverrides(global);
|
||||||
resolved_overrides_->Add(global);
|
if (refs) {
|
||||||
auto* refs = builder_->Sem().TransitivelyReferencedOverrides(global);
|
for (auto* var : *refs) {
|
||||||
if (refs) {
|
resolved_overrides_->Add(var);
|
||||||
for (auto* var : *refs) {
|
}
|
||||||
resolved_overrides_->Add(var);
|
}
|
||||||
}
|
}
|
||||||
|
} else if (variable->Declaration()->Is<ast::Var>()) {
|
||||||
|
// Use of a module-scope 'var' outside of a function.
|
||||||
|
// Note: The spec is currently vague around the rules here. See
|
||||||
|
// https://github.com/gpuweb/gpuweb/issues/3081. Remove this comment when
|
||||||
|
// resolved.
|
||||||
|
std::string desc = "var '" + builder_->Symbols().NameFor(symbol) + "' ";
|
||||||
|
AddError(desc + "cannot be referenced at module-scope", expr->source);
|
||||||
|
AddNote(desc + "declared here", variable->Declaration()->source);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (variable->Declaration()->Is<ast::Var>()) {
|
|
||||||
// Use of a module-scope 'var' outside of a function.
|
|
||||||
// Note: The spec is currently vague around the rules here. See
|
|
||||||
// https://github.com/gpuweb/gpuweb/issues/3081. Remove this comment when resolved.
|
|
||||||
std::string desc = "var '" + builder_->Symbols().NameFor(symbol) + "' ";
|
|
||||||
AddError(desc + "cannot be referenced at module-scope", expr->source);
|
|
||||||
AddNote(desc + "declared here", variable->Declaration()->source);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
variable->AddUser(user);
|
variable->AddUser(user);
|
||||||
return user;
|
return user;
|
||||||
|
},
|
||||||
|
[&](const type::Type*) {
|
||||||
|
AddError("missing '(' for type initializer or cast", expr->source.End());
|
||||||
|
return nullptr;
|
||||||
|
},
|
||||||
|
[&](const sem::Function*) {
|
||||||
|
AddError("missing '(' for function call", expr->source.End());
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Is<sem::Function>(sem_resolved)) {
|
if (resolved->BuiltinType() != type::Builtin::kUndefined) {
|
||||||
AddError("missing '(' for function call", expr->source.End());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsBuiltin(symbol)) {
|
|
||||||
AddError("missing '(' for builtin call", expr->source.End());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sem_.ResolvedSymbol<type::Type>(expr) ||
|
|
||||||
type::ParseBuiltin(builder_->Symbols().NameFor(symbol)) != type::Builtin::kUndefined) {
|
|
||||||
AddError("missing '(' for type initializer or cast", expr->source.End());
|
AddError("missing '(' for type initializer or cast", expr->source.End());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The dependency graph should have errored on this unresolved identifier before reaching here.
|
if (resolved->BuiltinFunction() != sem::BuiltinType::kNone) {
|
||||||
TINT_ICE(Resolver, diagnostics_)
|
AddError("missing '(' for builtin call", expr->source.End());
|
||||||
<< expr->source << " unresolved identifier:\n"
|
return nullptr;
|
||||||
<< "resolved: " << (sem_resolved ? sem_resolved->TypeInfo().name : "<null>") << "\n"
|
}
|
||||||
<< "name: " << builder_->Symbols().NameFor(symbol);
|
|
||||||
|
TINT_UNREACHABLE(Resolver, diagnostics_) << "unhandled resolved identifier: " << *resolved;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2977,8 +3014,8 @@ sem::ValueExpression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The arguments have constant values, but the operator cannot be const-evaluated. This
|
// The arguments have constant values, but the operator cannot be const-evaluated.
|
||||||
// can only be evaluated at runtime.
|
// This can only be evaluated at runtime.
|
||||||
stage = sem::EvaluationStage::kRuntime;
|
stage = sem::EvaluationStage::kRuntime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3966,9 +4003,4 @@ void Resolver::AddNote(const std::string& msg, const Source& source) const {
|
||||||
diagnostics_.add_note(diag::System::Resolver, msg, source);
|
diagnostics_.add_note(diag::System::Resolver, msg, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::IsBuiltin(Symbol symbol) const {
|
|
||||||
std::string name = builder_->Symbols().NameFor(symbol);
|
|
||||||
return sem::ParseBuiltinType(name) != sem::BuiltinType::kNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
|
|
@ -428,12 +428,9 @@ class Resolver {
|
||||||
/// Adds the given note message to the diagnostics
|
/// Adds the given note message to the diagnostics
|
||||||
void AddNote(const std::string& msg, const Source& source) const;
|
void AddNote(const std::string& msg, const Source& source) const;
|
||||||
|
|
||||||
/// @returns true if the symbol is the name of a builtin function.
|
/// @returns the type::Type for the builtin type @p builtin_ty with the identifier @p ident
|
||||||
bool IsBuiltin(Symbol) const;
|
|
||||||
|
|
||||||
/// @returns the builtin type for the symbol @p symbol at @p source
|
|
||||||
/// @note: Will raise an ICE if @p symbol is not a builtin type.
|
/// @note: Will raise an ICE if @p symbol is not a builtin type.
|
||||||
type::Type* BuiltinType(Symbol symbol, const Source& source) const;
|
type::Type* BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) const;
|
||||||
|
|
||||||
// ArrayInitializerSig represents a unique array initializer signature.
|
// ArrayInitializerSig represents a unique array initializer signature.
|
||||||
// It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
|
// It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
|
|
||||||
namespace tint::resolver {
|
namespace tint::resolver {
|
||||||
|
|
||||||
SemHelper::SemHelper(ProgramBuilder* builder, DependencyGraph& dependencies)
|
SemHelper::SemHelper(ProgramBuilder* builder) : builder_(builder) {}
|
||||||
: builder_(builder), dependencies_(dependencies) {}
|
|
||||||
|
|
||||||
SemHelper::~SemHelper() = default;
|
SemHelper::~SemHelper() = default;
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,7 @@ class SemHelper {
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param builder the program builder
|
/// @param builder the program builder
|
||||||
/// @param dependencies the program dependency graph
|
explicit SemHelper(ProgramBuilder* builder);
|
||||||
explicit SemHelper(ProgramBuilder* builder, DependencyGraph& dependencies);
|
|
||||||
~SemHelper();
|
~SemHelper();
|
||||||
|
|
||||||
/// Get is a helper for obtaining the semantic node for the given AST node.
|
/// Get is a helper for obtaining the semantic node for the given AST node.
|
||||||
|
@ -76,18 +75,6 @@ class SemHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the resolved symbol (function, type or variable) for the given ast::Identifier or
|
|
||||||
/// ast::TypeName cast to the given semantic type.
|
|
||||||
/// @param node the node to retrieve
|
|
||||||
template <typename SEM = sem::Info::InferFromAST>
|
|
||||||
sem::Info::GetResultType<SEM, ast::Node>* ResolvedSymbol(const ast::Node* node) const {
|
|
||||||
if (auto resolved = dependencies_.resolved_symbols.Find(node)) {
|
|
||||||
auto* sem = builder_->Sem().Get<SEM>(*resolved);
|
|
||||||
return const_cast<sem::Info::GetResultType<SEM, ast::Node>*>(sem);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns the resolved type of the ast::Expression `expr`
|
/// @returns the resolved type of the ast::Expression `expr`
|
||||||
/// @param expr the expression
|
/// @param expr the expression
|
||||||
type::Type* TypeOf(const ast::Expression* expr) const;
|
type::Type* TypeOf(const ast::Expression* expr) const;
|
||||||
|
@ -104,7 +91,6 @@ class SemHelper {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProgramBuilder* builder_;
|
ProgramBuilder* builder_;
|
||||||
DependencyGraph& dependencies_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
|
|
@ -2344,8 +2344,8 @@ bool Validator::Assignment(const ast::Statement* a, const type::Type* rhs_ty) co
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
|
// https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
|
||||||
auto const* lhs_ty = sem_.TypeOf(lhs);
|
auto const* lhs_ty = sem_.TypeOf(lhs);
|
||||||
|
|
||||||
if (auto* variable = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
|
if (auto* var_user = sem_.Get<sem::VariableUser>(lhs)) {
|
||||||
auto* v = variable->Declaration();
|
auto* v = var_user->Variable()->Declaration();
|
||||||
const char* err = Switch(
|
const char* err = Switch(
|
||||||
v, //
|
v, //
|
||||||
[&](const ast::Parameter*) { return "cannot assign to function parameter"; },
|
[&](const ast::Parameter*) { return "cannot assign to function parameter"; },
|
||||||
|
@ -2392,8 +2392,8 @@ bool Validator::IncrementDecrementStatement(const ast::IncrementDecrementStateme
|
||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#increment-decrement
|
// https://gpuweb.github.io/gpuweb/wgsl/#increment-decrement
|
||||||
|
|
||||||
if (auto* variable = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
|
if (auto* var_user = sem_.Get<sem::VariableUser>(lhs)) {
|
||||||
auto* v = variable->Declaration();
|
auto* v = var_user->Variable()->Declaration();
|
||||||
const char* err = Switch(
|
const char* err = Switch(
|
||||||
v, //
|
v, //
|
||||||
[&](const ast::Parameter*) { return "cannot modify function parameter"; },
|
[&](const ast::Parameter*) { return "cannot modify function parameter"; },
|
||||||
|
|
|
@ -161,6 +161,124 @@ const char* str(BuiltinType i);
|
||||||
/// matches the name in the WGSL spec.
|
/// matches the name in the WGSL spec.
|
||||||
std::ostream& operator<<(std::ostream& out, BuiltinType i);
|
std::ostream& operator<<(std::ostream& out, BuiltinType i);
|
||||||
|
|
||||||
|
/// All builtin types
|
||||||
|
constexpr BuiltinType kBuiltinTypes[] = {
|
||||||
|
BuiltinType::kAbs,
|
||||||
|
BuiltinType::kAcos,
|
||||||
|
BuiltinType::kAcosh,
|
||||||
|
BuiltinType::kAll,
|
||||||
|
BuiltinType::kAny,
|
||||||
|
BuiltinType::kArrayLength,
|
||||||
|
BuiltinType::kAsin,
|
||||||
|
BuiltinType::kAsinh,
|
||||||
|
BuiltinType::kAtan,
|
||||||
|
BuiltinType::kAtan2,
|
||||||
|
BuiltinType::kAtanh,
|
||||||
|
BuiltinType::kCeil,
|
||||||
|
BuiltinType::kClamp,
|
||||||
|
BuiltinType::kCos,
|
||||||
|
BuiltinType::kCosh,
|
||||||
|
BuiltinType::kCountLeadingZeros,
|
||||||
|
BuiltinType::kCountOneBits,
|
||||||
|
BuiltinType::kCountTrailingZeros,
|
||||||
|
BuiltinType::kCross,
|
||||||
|
BuiltinType::kDegrees,
|
||||||
|
BuiltinType::kDeterminant,
|
||||||
|
BuiltinType::kDistance,
|
||||||
|
BuiltinType::kDot,
|
||||||
|
BuiltinType::kDot4I8Packed,
|
||||||
|
BuiltinType::kDot4U8Packed,
|
||||||
|
BuiltinType::kDpdx,
|
||||||
|
BuiltinType::kDpdxCoarse,
|
||||||
|
BuiltinType::kDpdxFine,
|
||||||
|
BuiltinType::kDpdy,
|
||||||
|
BuiltinType::kDpdyCoarse,
|
||||||
|
BuiltinType::kDpdyFine,
|
||||||
|
BuiltinType::kExp,
|
||||||
|
BuiltinType::kExp2,
|
||||||
|
BuiltinType::kExtractBits,
|
||||||
|
BuiltinType::kFaceForward,
|
||||||
|
BuiltinType::kFirstLeadingBit,
|
||||||
|
BuiltinType::kFirstTrailingBit,
|
||||||
|
BuiltinType::kFloor,
|
||||||
|
BuiltinType::kFma,
|
||||||
|
BuiltinType::kFract,
|
||||||
|
BuiltinType::kFrexp,
|
||||||
|
BuiltinType::kFwidth,
|
||||||
|
BuiltinType::kFwidthCoarse,
|
||||||
|
BuiltinType::kFwidthFine,
|
||||||
|
BuiltinType::kInsertBits,
|
||||||
|
BuiltinType::kInverseSqrt,
|
||||||
|
BuiltinType::kLdexp,
|
||||||
|
BuiltinType::kLength,
|
||||||
|
BuiltinType::kLog,
|
||||||
|
BuiltinType::kLog2,
|
||||||
|
BuiltinType::kMax,
|
||||||
|
BuiltinType::kMin,
|
||||||
|
BuiltinType::kMix,
|
||||||
|
BuiltinType::kModf,
|
||||||
|
BuiltinType::kNormalize,
|
||||||
|
BuiltinType::kPack2X16Float,
|
||||||
|
BuiltinType::kPack2X16Snorm,
|
||||||
|
BuiltinType::kPack2X16Unorm,
|
||||||
|
BuiltinType::kPack4X8Snorm,
|
||||||
|
BuiltinType::kPack4X8Unorm,
|
||||||
|
BuiltinType::kPow,
|
||||||
|
BuiltinType::kQuantizeToF16,
|
||||||
|
BuiltinType::kRadians,
|
||||||
|
BuiltinType::kReflect,
|
||||||
|
BuiltinType::kRefract,
|
||||||
|
BuiltinType::kReverseBits,
|
||||||
|
BuiltinType::kRound,
|
||||||
|
BuiltinType::kSaturate,
|
||||||
|
BuiltinType::kSelect,
|
||||||
|
BuiltinType::kSign,
|
||||||
|
BuiltinType::kSin,
|
||||||
|
BuiltinType::kSinh,
|
||||||
|
BuiltinType::kSmoothstep,
|
||||||
|
BuiltinType::kSqrt,
|
||||||
|
BuiltinType::kStep,
|
||||||
|
BuiltinType::kStorageBarrier,
|
||||||
|
BuiltinType::kTan,
|
||||||
|
BuiltinType::kTanh,
|
||||||
|
BuiltinType::kTranspose,
|
||||||
|
BuiltinType::kTrunc,
|
||||||
|
BuiltinType::kUnpack2X16Float,
|
||||||
|
BuiltinType::kUnpack2X16Snorm,
|
||||||
|
BuiltinType::kUnpack2X16Unorm,
|
||||||
|
BuiltinType::kUnpack4X8Snorm,
|
||||||
|
BuiltinType::kUnpack4X8Unorm,
|
||||||
|
BuiltinType::kWorkgroupBarrier,
|
||||||
|
BuiltinType::kWorkgroupUniformLoad,
|
||||||
|
BuiltinType::kTextureDimensions,
|
||||||
|
BuiltinType::kTextureGather,
|
||||||
|
BuiltinType::kTextureGatherCompare,
|
||||||
|
BuiltinType::kTextureNumLayers,
|
||||||
|
BuiltinType::kTextureNumLevels,
|
||||||
|
BuiltinType::kTextureNumSamples,
|
||||||
|
BuiltinType::kTextureSample,
|
||||||
|
BuiltinType::kTextureSampleBias,
|
||||||
|
BuiltinType::kTextureSampleCompare,
|
||||||
|
BuiltinType::kTextureSampleCompareLevel,
|
||||||
|
BuiltinType::kTextureSampleGrad,
|
||||||
|
BuiltinType::kTextureSampleLevel,
|
||||||
|
BuiltinType::kTextureSampleBaseClampToEdge,
|
||||||
|
BuiltinType::kTextureStore,
|
||||||
|
BuiltinType::kTextureLoad,
|
||||||
|
BuiltinType::kAtomicLoad,
|
||||||
|
BuiltinType::kAtomicStore,
|
||||||
|
BuiltinType::kAtomicAdd,
|
||||||
|
BuiltinType::kAtomicSub,
|
||||||
|
BuiltinType::kAtomicMax,
|
||||||
|
BuiltinType::kAtomicMin,
|
||||||
|
BuiltinType::kAtomicAnd,
|
||||||
|
BuiltinType::kAtomicOr,
|
||||||
|
BuiltinType::kAtomicXor,
|
||||||
|
BuiltinType::kAtomicExchange,
|
||||||
|
BuiltinType::kAtomicCompareExchangeWeak,
|
||||||
|
BuiltinType::kTintMaterialize,
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
|
||||||
#endif // SRC_TINT_SEM_BUILTIN_TYPE_H_
|
#endif // SRC_TINT_SEM_BUILTIN_TYPE_H_
|
||||||
|
|
|
@ -41,6 +41,13 @@ const char* str(BuiltinType i);
|
||||||
/// matches the name in the WGSL spec.
|
/// matches the name in the WGSL spec.
|
||||||
std::ostream& operator<<(std::ostream& out, BuiltinType i);
|
std::ostream& operator<<(std::ostream& out, BuiltinType i);
|
||||||
|
|
||||||
|
/// All builtin types
|
||||||
|
constexpr BuiltinType kBuiltinTypes[] = {
|
||||||
|
{{- range Sem.Builtins }}
|
||||||
|
BuiltinType::k{{PascalCase .Name}},
|
||||||
|
{{- end }}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
|
||||||
#endif // SRC_TINT_SEM_BUILTIN_TYPE_H_
|
#endif // SRC_TINT_SEM_BUILTIN_TYPE_H_
|
||||||
|
|
Loading…
Reference in New Issue