IntrinsicTable: Fix a number of TODOs
And add tests for IntrinsicTable. Drop all the type unwrapping - be precise: * Display the actual argument types in the signature mismatch message * Only dereference pointer arguments if the parameter does not expect a pointer Correctly match access control on storage types Note that I was mistaken in tint:486 - the TypeDeterminer is resolving identifiers to variables correctly as pointer types. The confustion here was probably due to all the UnwrapAll() calls, which have now all gone. Fixed: tint:486 Change-Id: I239eabd1fedfc082566c4af616ccfc58786cae25 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/41280 Commit-Queue: Ben Clayton <bclayton@google.com> Auto-Submit: Ben Clayton <bclayton@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
2101c35f3b
commit
faca02d438
1
BUILD.gn
1
BUILD.gn
|
@ -835,6 +835,7 @@ source_set("tint_unittests_core_src") {
|
||||||
"src/diagnostic/formatter_test.cc",
|
"src/diagnostic/formatter_test.cc",
|
||||||
"src/diagnostic/printer_test.cc",
|
"src/diagnostic/printer_test.cc",
|
||||||
"src/inspector/inspector_test.cc",
|
"src/inspector/inspector_test.cc",
|
||||||
|
"src/intrinsic_table_test.cc",
|
||||||
"src/namer_test.cc",
|
"src/namer_test.cc",
|
||||||
"src/program_builder_test.cc",
|
"src/program_builder_test.cc",
|
||||||
"src/program_test.cc",
|
"src/program_test.cc",
|
||||||
|
|
|
@ -465,6 +465,7 @@ if(${TINT_BUILD_TESTS})
|
||||||
diagnostic/formatter_test.cc
|
diagnostic/formatter_test.cc
|
||||||
diagnostic/printer_test.cc
|
diagnostic/printer_test.cc
|
||||||
inspector/inspector_test.cc
|
inspector/inspector_test.cc
|
||||||
|
intrinsic_table_test.cc
|
||||||
namer_test.cc
|
namer_test.cc
|
||||||
program_test.cc
|
program_test.cc
|
||||||
scope_stack_test.cc
|
scope_stack_test.cc
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "src/block_allocator.h"
|
#include "src/block_allocator.h"
|
||||||
#include "src/program_builder.h"
|
#include "src/program_builder.h"
|
||||||
#include "src/semantic/intrinsic.h"
|
#include "src/semantic/intrinsic.h"
|
||||||
|
#include "src/type/access_control_type.h"
|
||||||
#include "src/type/depth_texture_type.h"
|
#include "src/type/depth_texture_type.h"
|
||||||
#include "src/type/f32_type.h"
|
#include "src/type/f32_type.h"
|
||||||
#include "src/type/multisampled_texture_type.h"
|
#include "src/type/multisampled_texture_type.h"
|
||||||
|
@ -91,15 +92,33 @@ class Matcher {
|
||||||
virtual ~Matcher() = default;
|
virtual ~Matcher() = default;
|
||||||
|
|
||||||
/// Checks whether the given argument type matches.
|
/// Checks whether the given argument type matches.
|
||||||
|
/// Aliases are automatically unwrapped before matching.
|
||||||
/// Match may add to, or compare against the open types and numbers in state.
|
/// Match may add to, or compare against the open types and numbers in state.
|
||||||
/// @returns true if the argument type is as expected.
|
/// @returns true if the argument type is as expected.
|
||||||
virtual bool Match(MatchState& state, type::Type* argument_type) const = 0;
|
bool Match(MatchState& state, type::Type* argument_type) const {
|
||||||
|
auto* unwrapped = argument_type;
|
||||||
|
while (auto* alias = unwrapped->As<type::Alias>()) {
|
||||||
|
unwrapped = alias->type();
|
||||||
|
}
|
||||||
|
return MatchUnwrapped(state, unwrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @return true if the matcher is expecting a pointer. If this method returns
|
||||||
|
/// false and the argument is a pointer type, then the argument should be
|
||||||
|
/// dereferenced before calling.
|
||||||
|
virtual bool ExpectsPointer() const { return false; }
|
||||||
|
|
||||||
/// @return a string representation of the matcher. Used for printing error
|
/// @return a string representation of the matcher. Used for printing error
|
||||||
/// messages when no overload is found.
|
/// messages when no overload is found.
|
||||||
virtual std::string str() const = 0;
|
virtual std::string str() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// Checks whether the given alias-unwrapped argument type matches.
|
||||||
|
/// Match may add to, or compare against the open types and numbers in state.
|
||||||
|
/// @returns true if the argument type is as expected.
|
||||||
|
virtual bool MatchUnwrapped(MatchState& state,
|
||||||
|
type::Type* argument_type) const = 0;
|
||||||
|
|
||||||
/// Checks `state.open_type` to see if the OpenType `t` is equal to the type
|
/// Checks `state.open_type` to see if the OpenType `t` is equal to the type
|
||||||
/// `ty`. If `state.open_type` does not contain an entry for `t`, then `ty`
|
/// `ty`. If `state.open_type` does not contain an entry for `t`, then `ty`
|
||||||
/// is added and returns true.
|
/// is added and returns true.
|
||||||
|
@ -154,7 +173,7 @@ class OpenTypeBuilder : public Builder {
|
||||||
public:
|
public:
|
||||||
explicit OpenTypeBuilder(OpenType open_type) : open_type_(open_type) {}
|
explicit OpenTypeBuilder(OpenType open_type) : open_type_(open_type) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
return MatchOpenType(state, open_type_, ty);
|
return MatchOpenType(state, open_type_, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +190,7 @@ class OpenTypeBuilder : public Builder {
|
||||||
/// VoidBuilder is a Matcher / Builder for void types.
|
/// VoidBuilder is a Matcher / Builder for void types.
|
||||||
class VoidBuilder : public Builder {
|
class VoidBuilder : public Builder {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->Is<type::Void>();
|
return ty->Is<type::Void>();
|
||||||
}
|
}
|
||||||
type::Type* Build(BuildState& state) const override {
|
type::Type* Build(BuildState& state) const override {
|
||||||
|
@ -183,7 +202,7 @@ class VoidBuilder : public Builder {
|
||||||
/// BoolBuilder is a Matcher / Builder for boolean types.
|
/// BoolBuilder is a Matcher / Builder for boolean types.
|
||||||
class BoolBuilder : public Builder {
|
class BoolBuilder : public Builder {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->Is<type::Bool>();
|
return ty->Is<type::Bool>();
|
||||||
}
|
}
|
||||||
type::Type* Build(BuildState& state) const override {
|
type::Type* Build(BuildState& state) const override {
|
||||||
|
@ -195,7 +214,7 @@ class BoolBuilder : public Builder {
|
||||||
/// F32Builder is a Matcher / Builder for f32 types.
|
/// F32Builder is a Matcher / Builder for f32 types.
|
||||||
class F32Builder : public Builder {
|
class F32Builder : public Builder {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->Is<type::F32>();
|
return ty->Is<type::F32>();
|
||||||
}
|
}
|
||||||
type::Type* Build(BuildState& state) const override {
|
type::Type* Build(BuildState& state) const override {
|
||||||
|
@ -207,7 +226,7 @@ class F32Builder : public Builder {
|
||||||
/// U32Builder is a Matcher / Builder for u32 types.
|
/// U32Builder is a Matcher / Builder for u32 types.
|
||||||
class U32Builder : public Builder {
|
class U32Builder : public Builder {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->Is<type::U32>();
|
return ty->Is<type::U32>();
|
||||||
}
|
}
|
||||||
type::Type* Build(BuildState& state) const override {
|
type::Type* Build(BuildState& state) const override {
|
||||||
|
@ -219,7 +238,7 @@ class U32Builder : public Builder {
|
||||||
/// I32Builder is a Matcher / Builder for i32 types.
|
/// I32Builder is a Matcher / Builder for i32 types.
|
||||||
class I32Builder : public Builder {
|
class I32Builder : public Builder {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->Is<type::I32>();
|
return ty->Is<type::I32>();
|
||||||
}
|
}
|
||||||
type::Type* Build(BuildState& state) const override {
|
type::Type* Build(BuildState& state) const override {
|
||||||
|
@ -231,7 +250,7 @@ class I32Builder : public Builder {
|
||||||
/// IU32Matcher is a Matcher for i32 or u32 types.
|
/// IU32Matcher is a Matcher for i32 or u32 types.
|
||||||
class IU32Matcher : public Matcher {
|
class IU32Matcher : public Matcher {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->Is<type::I32>() || ty->Is<type::U32>();
|
return ty->Is<type::I32>() || ty->Is<type::U32>();
|
||||||
}
|
}
|
||||||
std::string str() const override { return "i32 or u32"; }
|
std::string str() const override { return "i32 or u32"; }
|
||||||
|
@ -240,7 +259,7 @@ class IU32Matcher : public Matcher {
|
||||||
/// FIU32Matcher is a Matcher for f32, i32 or u32 types.
|
/// FIU32Matcher is a Matcher for f32, i32 or u32 types.
|
||||||
class FIU32Matcher : public Matcher {
|
class FIU32Matcher : public Matcher {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->Is<type::F32>() || ty->Is<type::I32>() || ty->Is<type::U32>();
|
return ty->Is<type::F32>() || ty->Is<type::I32>() || ty->Is<type::U32>();
|
||||||
}
|
}
|
||||||
std::string str() const override { return "f32, i32 or u32"; }
|
std::string str() const override { return "f32, i32 or u32"; }
|
||||||
|
@ -249,7 +268,7 @@ class FIU32Matcher : public Matcher {
|
||||||
/// ScalarMatcher is a Matcher for f32, i32, u32 or boolean types.
|
/// ScalarMatcher is a Matcher for f32, i32, u32 or boolean types.
|
||||||
class ScalarMatcher : public Matcher {
|
class ScalarMatcher : public Matcher {
|
||||||
public:
|
public:
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
return ty->is_scalar();
|
return ty->is_scalar();
|
||||||
}
|
}
|
||||||
std::string str() const override { return "scalar"; }
|
std::string str() const override { return "scalar"; }
|
||||||
|
@ -262,8 +281,8 @@ class OpenSizeVecBuilder : public Builder {
|
||||||
OpenSizeVecBuilder(OpenNumber size, Builder* element_builder)
|
OpenSizeVecBuilder(OpenNumber size, Builder* element_builder)
|
||||||
: size_(size), element_builder_(element_builder) {}
|
: size_(size), element_builder_(element_builder) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
if (auto* vec = ty->UnwrapAll()->As<type::Vector>()) {
|
if (auto* vec = ty->As<type::Vector>()) {
|
||||||
if (!MatchOpenNumber(state, size_, vec->size())) {
|
if (!MatchOpenNumber(state, size_, vec->size())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -294,8 +313,8 @@ class VecBuilder : public Builder {
|
||||||
VecBuilder(uint32_t size, Builder* element_builder)
|
VecBuilder(uint32_t size, Builder* element_builder)
|
||||||
: size_(size), element_builder_(element_builder) {}
|
: size_(size), element_builder_(element_builder) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
if (auto* vec = ty->UnwrapAll()->As<type::Vector>()) {
|
if (auto* vec = ty->As<type::Vector>()) {
|
||||||
if (vec->size() == size_) {
|
if (vec->size() == size_) {
|
||||||
return element_builder_->Match(state, vec->type());
|
return element_builder_->Match(state, vec->type());
|
||||||
}
|
}
|
||||||
|
@ -326,8 +345,8 @@ class OpenSizeMatBuilder : public Builder {
|
||||||
Builder* element_builder)
|
Builder* element_builder)
|
||||||
: columns_(columns), rows_(rows), element_builder_(element_builder) {}
|
: columns_(columns), rows_(rows), element_builder_(element_builder) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
if (auto* mat = ty->UnwrapAll()->As<type::Matrix>()) {
|
if (auto* mat = ty->As<type::Matrix>()) {
|
||||||
if (!MatchOpenNumber(state, columns_, mat->columns())) {
|
if (!MatchOpenNumber(state, columns_, mat->columns())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +366,7 @@ class OpenSizeMatBuilder : public Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string str() const override {
|
std::string str() const override {
|
||||||
return "max" + std::string(tint::str(columns_)) + "x" +
|
return "mat" + std::string(tint::str(columns_)) + "x" +
|
||||||
std::string(tint::str(rows_)) + "<" + element_builder_->str() + ">";
|
std::string(tint::str(rows_)) + "<" + element_builder_->str() + ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,15 +382,11 @@ class PtrBuilder : public Builder {
|
||||||
explicit PtrBuilder(Builder* element_builder)
|
explicit PtrBuilder(Builder* element_builder)
|
||||||
: element_builder_(element_builder) {}
|
: element_builder_(element_builder) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
if (auto* ptr = ty->As<type::Pointer>()) {
|
if (auto* ptr = ty->As<type::Pointer>()) {
|
||||||
return element_builder_->Match(state, ptr->type());
|
return element_builder_->Match(state, ptr->type());
|
||||||
}
|
}
|
||||||
// TODO(bclayton): https://crbug.com/tint/486
|
return false;
|
||||||
// TypeDeterminer currently folds away the pointers on expressions.
|
|
||||||
// We'll need to fix this to ensure that pointer parameters are not fed
|
|
||||||
// non-pointer arguments, but for now just accept them.
|
|
||||||
return element_builder_->Match(state, ty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type::Type* Build(BuildState& state) const override {
|
type::Type* Build(BuildState& state) const override {
|
||||||
|
@ -379,6 +394,8 @@ class PtrBuilder : public Builder {
|
||||||
return state.ty_mgr.Get<type::Pointer>(el, ast::StorageClass::kNone);
|
return state.ty_mgr.Get<type::Pointer>(el, ast::StorageClass::kNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExpectsPointer() const override { return true; }
|
||||||
|
|
||||||
std::string str() const override {
|
std::string str() const override {
|
||||||
return "ptr<" + element_builder_->str() + ">";
|
return "ptr<" + element_builder_->str() + ">";
|
||||||
}
|
}
|
||||||
|
@ -393,7 +410,7 @@ class ArrayBuilder : public Builder {
|
||||||
explicit ArrayBuilder(Builder* element_builder)
|
explicit ArrayBuilder(Builder* element_builder)
|
||||||
: element_builder_(element_builder) {}
|
: element_builder_(element_builder) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
if (auto* arr = ty->As<type::Array>()) {
|
if (auto* arr = ty->As<type::Array>()) {
|
||||||
if (arr->size() == 0) {
|
if (arr->size() == 0) {
|
||||||
return element_builder_->Match(state, arr->type());
|
return element_builder_->Match(state, arr->type());
|
||||||
|
@ -422,7 +439,7 @@ class SampledTextureBuilder : public Builder {
|
||||||
Builder* type_builder)
|
Builder* type_builder)
|
||||||
: dimensions_(dimensions), type_builder_(type_builder) {}
|
: dimensions_(dimensions), type_builder_(type_builder) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
if (auto* tex = ty->As<type::SampledTexture>()) {
|
if (auto* tex = ty->As<type::SampledTexture>()) {
|
||||||
if (tex->dim() == dimensions_) {
|
if (tex->dim() == dimensions_) {
|
||||||
return type_builder_->Match(state, tex->type());
|
return type_builder_->Match(state, tex->type());
|
||||||
|
@ -455,7 +472,7 @@ class MultisampledTextureBuilder : public Builder {
|
||||||
Builder* type_builder)
|
Builder* type_builder)
|
||||||
: dimensions_(dimensions), type_builder_(type_builder) {}
|
: dimensions_(dimensions), type_builder_(type_builder) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
if (auto* tex = ty->As<type::MultisampledTexture>()) {
|
if (auto* tex = ty->As<type::MultisampledTexture>()) {
|
||||||
if (tex->dim() == dimensions_) {
|
if (tex->dim() == dimensions_) {
|
||||||
return type_builder_->Match(state, tex->type());
|
return type_builder_->Match(state, tex->type());
|
||||||
|
@ -487,7 +504,7 @@ class DepthTextureBuilder : public Builder {
|
||||||
explicit DepthTextureBuilder(type::TextureDimension dimensions)
|
explicit DepthTextureBuilder(type::TextureDimension dimensions)
|
||||||
: dimensions_(dimensions) {}
|
: dimensions_(dimensions) {}
|
||||||
|
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
if (auto* tex = ty->As<type::DepthTexture>()) {
|
if (auto* tex = ty->As<type::DepthTexture>()) {
|
||||||
return tex->dim() == dimensions_;
|
return tex->dim() == dimensions_;
|
||||||
}
|
}
|
||||||
|
@ -520,7 +537,15 @@ class StorageTextureBuilder : public Builder {
|
||||||
texel_format_(texel_format),
|
texel_format_(texel_format),
|
||||||
channel_format_(channel_format) {}
|
channel_format_(channel_format) {}
|
||||||
|
|
||||||
bool Match(MatchState& state, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
|
if (auto* ac = ty->As<type::AccessControl>()) {
|
||||||
|
// If we have an storage texture argument that's got an access control
|
||||||
|
// type wrapped around it, accept it. Signatures that don't include an
|
||||||
|
// access control imply any access. Example:
|
||||||
|
// textureDimensions(t : texture_storage_1d<F>) -> i32
|
||||||
|
ty = ac->type();
|
||||||
|
}
|
||||||
|
|
||||||
if (auto* tex = ty->As<type::StorageTexture>()) {
|
if (auto* tex = ty->As<type::StorageTexture>()) {
|
||||||
if (MatchOpenNumber(state, texel_format_,
|
if (MatchOpenNumber(state, texel_format_,
|
||||||
static_cast<uint32_t>(tex->image_format()))) {
|
static_cast<uint32_t>(tex->image_format()))) {
|
||||||
|
@ -557,7 +582,7 @@ class SamplerBuilder : public Builder {
|
||||||
public:
|
public:
|
||||||
explicit SamplerBuilder(type::SamplerKind kind) : kind_(kind) {}
|
explicit SamplerBuilder(type::SamplerKind kind) : kind_(kind) {}
|
||||||
|
|
||||||
bool Match(MatchState&, type::Type* ty) const override {
|
bool MatchUnwrapped(MatchState&, type::Type* ty) const override {
|
||||||
if (auto* sampler = ty->As<type::Sampler>()) {
|
if (auto* sampler = ty->As<type::Sampler>()) {
|
||||||
return sampler->kind() == kind_;
|
return sampler->kind() == kind_;
|
||||||
}
|
}
|
||||||
|
@ -582,6 +607,38 @@ class SamplerBuilder : public Builder {
|
||||||
type::SamplerKind const kind_;
|
type::SamplerKind const kind_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// AccessControlBuilder is a Matcher / Builder for AccessControl types
|
||||||
|
class AccessControlBuilder : public Builder {
|
||||||
|
public:
|
||||||
|
explicit AccessControlBuilder(ast::AccessControl access_control,
|
||||||
|
Builder* type)
|
||||||
|
: access_control_(access_control), type_(type) {}
|
||||||
|
|
||||||
|
bool MatchUnwrapped(MatchState& state, type::Type* ty) const override {
|
||||||
|
if (auto* ac = ty->As<type::AccessControl>()) {
|
||||||
|
if (ac->access_control() == access_control_) {
|
||||||
|
return type_->Match(state, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
type::Type* Build(BuildState& state) const override {
|
||||||
|
auto* ty = type_->Build(state);
|
||||||
|
return state.ty_mgr.Get<type::AccessControl>(access_control_, ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str() const override {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "[[access(" << access_control_ << ")]] " << type_->str();
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ast::AccessControl const access_control_;
|
||||||
|
Builder* const type_;
|
||||||
|
};
|
||||||
|
|
||||||
/// Impl is the private implementation of the IntrinsicTable interface.
|
/// Impl is the private implementation of the IntrinsicTable interface.
|
||||||
class Impl : public IntrinsicTable {
|
class Impl : public IntrinsicTable {
|
||||||
public:
|
public:
|
||||||
|
@ -717,6 +774,12 @@ class Impl : public IntrinsicTable {
|
||||||
return matcher_allocator_.Create<SamplerBuilder>(kind);
|
return matcher_allocator_.Create<SamplerBuilder>(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @returns a Matcher / Builder that matches an access control type
|
||||||
|
Builder* access_control(ast::AccessControl access_control, Builder* type) {
|
||||||
|
return matcher_allocator_.Create<AccessControlBuilder>(access_control,
|
||||||
|
type);
|
||||||
|
}
|
||||||
|
|
||||||
/// Registers an overload with the given intrinsic type, return type Matcher /
|
/// Registers an overload with the given intrinsic type, return type Matcher /
|
||||||
/// Builder, and parameter Matcher / Builders.
|
/// Builder, and parameter Matcher / Builders.
|
||||||
/// This overload of Register does not constrain any OpenTypes.
|
/// This overload of Register does not constrain any OpenTypes.
|
||||||
|
@ -1044,6 +1107,26 @@ Impl::Impl() {
|
||||||
storage_texture(Dim::k2dArray, OpenNumber::F, OpenType::T);
|
storage_texture(Dim::k2dArray, OpenNumber::F, OpenType::T);
|
||||||
auto* tex_storage_3d_FT =
|
auto* tex_storage_3d_FT =
|
||||||
storage_texture(Dim::k3d, OpenNumber::F, OpenType::T);
|
storage_texture(Dim::k3d, OpenNumber::F, OpenType::T);
|
||||||
|
auto* tex_storage_ro_1d_FT =
|
||||||
|
access_control(ast::AccessControl::kReadOnly, tex_storage_1d_FT);
|
||||||
|
auto* tex_storage_ro_1d_array_FT =
|
||||||
|
access_control(ast::AccessControl::kReadOnly, tex_storage_1d_array_FT);
|
||||||
|
auto* tex_storage_ro_2d_FT =
|
||||||
|
access_control(ast::AccessControl::kReadOnly, tex_storage_2d_FT);
|
||||||
|
auto* tex_storage_ro_2d_array_FT =
|
||||||
|
access_control(ast::AccessControl::kReadOnly, tex_storage_2d_array_FT);
|
||||||
|
auto* tex_storage_ro_3d_FT =
|
||||||
|
access_control(ast::AccessControl::kReadOnly, tex_storage_3d_FT);
|
||||||
|
auto* tex_storage_wo_1d_FT =
|
||||||
|
access_control(ast::AccessControl::kWriteOnly, tex_storage_1d_FT);
|
||||||
|
auto* tex_storage_wo_1d_array_FT =
|
||||||
|
access_control(ast::AccessControl::kWriteOnly, tex_storage_1d_array_FT);
|
||||||
|
auto* tex_storage_wo_2d_FT =
|
||||||
|
access_control(ast::AccessControl::kWriteOnly, tex_storage_2d_FT);
|
||||||
|
auto* tex_storage_wo_2d_array_FT =
|
||||||
|
access_control(ast::AccessControl::kWriteOnly, tex_storage_2d_array_FT);
|
||||||
|
auto* tex_storage_wo_3d_FT =
|
||||||
|
access_control(ast::AccessControl::kWriteOnly, tex_storage_3d_FT);
|
||||||
auto* sampler = this->sampler(type::SamplerKind::kSampler);
|
auto* sampler = this->sampler(type::SamplerKind::kSampler);
|
||||||
auto* sampler_comparison =
|
auto* sampler_comparison =
|
||||||
this->sampler(type::SamplerKind::kComparisonSampler);
|
this->sampler(type::SamplerKind::kComparisonSampler);
|
||||||
|
@ -1170,14 +1253,12 @@ Impl::Impl() {
|
||||||
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_cube}, {s, sampler}, {coords, vec3_f32}, {level, i32}, }); // NOLINT
|
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_cube}, {s, sampler}, {coords, vec3_f32}, {level, i32}, }); // NOLINT
|
||||||
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_cube_array},{s, sampler}, {coords, vec3_f32}, {array_index, i32}, {level, i32}, }); // NOLINT
|
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_cube_array},{s, sampler}, {coords, vec3_f32}, {array_index, i32}, {level, i32}, }); // NOLINT
|
||||||
|
|
||||||
// TODO(bclayton): Check for [[access(write)]]
|
Register(I::kTextureStore, void_, {{t, tex_storage_wo_1d_FT}, {coords, i32}, {value, vec4_T}, }); // NOLINT
|
||||||
Register(I::kTextureStore, void_, {{t, tex_storage_1d_FT}, {coords, i32}, {value, vec4_T}, }); // NOLINT
|
Register(I::kTextureStore, void_, {{t, tex_storage_wo_1d_array_FT},{coords, i32}, {array_index, i32}, {value, vec4_T}, }); // NOLINT
|
||||||
Register(I::kTextureStore, void_, {{t, tex_storage_1d_array_FT},{coords, i32}, {array_index, i32}, {value, vec4_T}, }); // NOLINT
|
Register(I::kTextureStore, void_, {{t, tex_storage_wo_2d_FT}, {coords, vec2_i32}, {value, vec4_T}, }); // NOLINT
|
||||||
Register(I::kTextureStore, void_, {{t, tex_storage_2d_FT}, {coords, vec2_i32}, {value, vec4_T}, }); // NOLINT
|
Register(I::kTextureStore, void_, {{t, tex_storage_wo_2d_array_FT},{coords, vec2_i32}, {array_index, i32}, {value, vec4_T}, }); // NOLINT
|
||||||
Register(I::kTextureStore, void_, {{t, tex_storage_2d_array_FT},{coords, vec2_i32}, {array_index, i32}, {value, vec4_T}, }); // NOLINT
|
Register(I::kTextureStore, void_, {{t, tex_storage_wo_3d_FT}, {coords, vec3_i32}, {value, vec4_T}, }); // NOLINT
|
||||||
Register(I::kTextureStore, void_, {{t, tex_storage_3d_FT}, {coords, vec3_i32}, {value, vec4_T}, }); // NOLINT
|
|
||||||
|
|
||||||
// TODO(bclayton): Check for [[access(read)]]
|
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_T}, {coords, vec2_i32}, {level, i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_T}, {coords, vec2_i32}, {level, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_array_T}, {coords, vec2_i32}, {array_index, i32}, {level, i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_array_T}, {coords, vec2_i32}, {array_index, i32}, {level, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_3d_T}, {coords, vec3_i32}, {level, i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_3d_T}, {coords, vec3_i32}, {level, i32}, }); // NOLINT
|
||||||
|
@ -1185,11 +1266,11 @@ Impl::Impl() {
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_ms_2d_array_T}, {coords, vec2_i32}, {array_index, i32}, {sample_index, i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_ms_2d_array_T}, {coords, vec2_i32}, {array_index, i32}, {sample_index, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, f32, {{t, tex_depth_2d}, {coords, vec2_i32}, {level, i32}, }); // NOLINT
|
Register(I::kTextureLoad, f32, {{t, tex_depth_2d}, {coords, vec2_i32}, {level, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, f32, {{t, tex_depth_2d_array}, {coords, vec2_i32}, {array_index, i32}, {level, i32}, }); // NOLINT
|
Register(I::kTextureLoad, f32, {{t, tex_depth_2d_array}, {coords, vec2_i32}, {array_index, i32}, {level, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_1d_FT}, {coords, i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_ro_1d_FT}, {coords, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_1d_array_FT},{coords, i32}, {array_index, i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_ro_1d_array_FT},{coords, i32}, {array_index, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_2d_FT}, {coords, vec2_i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_ro_2d_FT}, {coords, vec2_i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_2d_array_FT},{coords, vec2_i32}, {array_index, i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_ro_2d_array_FT},{coords, vec2_i32}, {array_index, i32}, }); // NOLINT
|
||||||
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_3d_FT}, {coords, vec3_i32}, }); // NOLINT
|
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_ro_3d_FT}, {coords, vec3_i32}, }); // NOLINT
|
||||||
|
|
||||||
// TODO(bclayton): Update the rest of tint to reflect the spec changes made in
|
// TODO(bclayton): Update the rest of tint to reflect the spec changes made in
|
||||||
// https://github.com/gpuweb/gpuweb/pull/1301:
|
// https://github.com/gpuweb/gpuweb/pull/1301:
|
||||||
|
@ -1287,7 +1368,7 @@ IntrinsicTable::Result Impl::Lookup(
|
||||||
ss << ", ";
|
ss << ", ";
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
ss << arg->UnwrapAll()->FriendlyName(builder.Symbols());
|
ss << arg->FriendlyName(builder.Symbols());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ss << ")" << std::endl;
|
ss << ")" << std::endl;
|
||||||
|
@ -1327,13 +1408,21 @@ semantic::Intrinsic* Impl::Overload::Match(ProgramBuilder& builder,
|
||||||
auto count = std::min(parameters.size(), args.size());
|
auto count = std::min(parameters.size(), args.size());
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
assert(args[i]);
|
assert(args[i]);
|
||||||
auto* arg_ty = args[i]->UnwrapAll();
|
auto* arg_ty = args[i];
|
||||||
if (!parameters[i].matcher->Match(matcher_state, arg_ty)) {
|
if (auto* ptr = arg_ty->As<type::Pointer>()) {
|
||||||
matched = false;
|
if (!parameters[i].matcher->ExpectsPointer()) {
|
||||||
continue;
|
// Argument is a pointer, but the matcher isn't expecting one.
|
||||||
|
// Perform an implicit dereference.
|
||||||
|
arg_ty = ptr->type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parameters[i].matcher->Match(matcher_state, arg_ty)) {
|
||||||
|
// A correct parameter match is scored higher than number of parameters to
|
||||||
|
// arguments.
|
||||||
|
match_score += 2;
|
||||||
|
} else {
|
||||||
|
matched = false;
|
||||||
}
|
}
|
||||||
// Weight correct parameter matches more than exact number of arguments
|
|
||||||
match_score += 2;
|
|
||||||
}
|
}
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -0,0 +1,488 @@
|
||||||
|
// Copyright 2021 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "src/intrinsic_table.h"
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "src/program_builder.h"
|
||||||
|
#include "src/type/access_control_type.h"
|
||||||
|
#include "src/type/depth_texture_type.h"
|
||||||
|
#include "src/type/multisampled_texture_type.h"
|
||||||
|
#include "src/type/sampled_texture_type.h"
|
||||||
|
#include "src/type/storage_texture_type.h"
|
||||||
|
|
||||||
|
namespace tint {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
using ::testing::HasSubstr;
|
||||||
|
|
||||||
|
using IntrinsicType = semantic::IntrinsicType;
|
||||||
|
using Parameter = semantic::Parameter;
|
||||||
|
|
||||||
|
class IntrinsicTableTest : public testing::Test, public ProgramBuilder {
|
||||||
|
public:
|
||||||
|
std::unique_ptr<IntrinsicTable> table = IntrinsicTable::Create();
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchF32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kCos, {ty.f32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCos);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.f32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchF32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kCos, {ty.i32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchU32) {
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kUnpack2x16Float, {ty.u32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kUnpack2x16Float);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec2<f32>());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.u32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchU32) {
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kUnpack2x16Float, {ty.f32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchI32) {
|
||||||
|
auto* tex =
|
||||||
|
create<type::SampledTexture>(type::TextureDimension::k1d, ty.f32());
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kTextureLoad, {tex, ty.i32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
|
||||||
|
Parameter{ty.i32(), Parameter::Usage::kCoords}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchI32) {
|
||||||
|
auto* tex =
|
||||||
|
create<type::SampledTexture>(type::TextureDimension::k1d, ty.f32());
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kTextureLoad, {tex, ty.f32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kCountOneBits, {ty.i32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCountOneBits);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.i32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.i32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kCountOneBits, {ty.u32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCountOneBits);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.u32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.u32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchIU32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kCountOneBits, {ty.f32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.i32(), ty.i32(), ty.i32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.i32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.i32()}, Parameter{ty.i32()},
|
||||||
|
Parameter{ty.i32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.u32(), ty.u32(), ty.u32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.u32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.u32()}, Parameter{ty.u32()},
|
||||||
|
Parameter{ty.u32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.f32(), ty.f32(), ty.f32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.f32()}, Parameter{ty.f32()},
|
||||||
|
Parameter{ty.f32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchFIU32) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.bool_(), ty.bool_(), ty.bool_()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchBool) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kSelect,
|
||||||
|
{ty.f32(), ty.f32(), ty.bool_()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kSelect);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.f32()}, Parameter{ty.f32()},
|
||||||
|
Parameter{ty.bool_()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchBool) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kSelect,
|
||||||
|
{ty.f32(), ty.f32(), ty.f32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchPointer) {
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kModf,
|
||||||
|
{ty.f32(), ty.pointer<f32>(ast::StorageClass::kNone)});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kModf);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(
|
||||||
|
result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.f32()},
|
||||||
|
Parameter{ty.pointer<f32>(ast::StorageClass::kNone)}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchPointer) {
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kModf, {ty.f32(), ty.f32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchArray) {
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kArrayLength, {ty.array<f32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kArrayLength);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.u32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.array<f32>()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchArray) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kArrayLength, {ty.f32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchSampler) {
|
||||||
|
auto* tex =
|
||||||
|
create<type::SampledTexture>(type::TextureDimension::k2d, ty.f32());
|
||||||
|
auto* sampler = create<type::Sampler>(type::SamplerKind::kSampler);
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureSample,
|
||||||
|
{tex, sampler, ty.vec2<f32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureSample);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
|
||||||
|
EXPECT_THAT(
|
||||||
|
result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
|
||||||
|
Parameter{sampler, Parameter::Usage::kSampler},
|
||||||
|
Parameter{ty.vec2<f32>(), Parameter::Usage::kCoords}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchSampler) {
|
||||||
|
auto* tex =
|
||||||
|
create<type::SampledTexture>(type::TextureDimension::k2d, ty.f32());
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureSample,
|
||||||
|
{tex, ty.f32(), ty.vec2<f32>()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchSampledTexture) {
|
||||||
|
auto* tex =
|
||||||
|
create<type::SampledTexture>(type::TextureDimension::k2d, ty.f32());
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kTextureLoad, {tex, ty.vec2<i32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
|
||||||
|
EXPECT_THAT(
|
||||||
|
result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
|
||||||
|
Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
|
||||||
|
auto* tex =
|
||||||
|
create<type::MultisampledTexture>(type::TextureDimension::k2d, ty.f32());
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
|
||||||
|
{tex, ty.vec2<i32>(), ty.i32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
|
||||||
|
Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords},
|
||||||
|
Parameter{ty.i32(), Parameter::Usage::kSampleIndex}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchDepthTexture) {
|
||||||
|
auto* tex = create<type::DepthTexture>(type::TextureDimension::k2d);
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kTextureLoad, {tex, ty.vec2<i32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(
|
||||||
|
result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
|
||||||
|
Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchROStorageTexture) {
|
||||||
|
auto* tex = create<type::StorageTexture>(
|
||||||
|
type::TextureDimension::k2d, type::ImageFormat::kR16Float,
|
||||||
|
type::StorageTexture::SubtypeFor(type::ImageFormat::kR16Float, Types()));
|
||||||
|
auto* tex_ac =
|
||||||
|
create<type::AccessControl>(ast::AccessControl::kReadOnly, tex);
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
|
||||||
|
{tex_ac, ty.vec2<i32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
|
||||||
|
EXPECT_THAT(
|
||||||
|
result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{tex_ac, Parameter::Usage::kTexture},
|
||||||
|
Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
|
||||||
|
auto* tex = create<type::StorageTexture>(
|
||||||
|
type::TextureDimension::k2d, type::ImageFormat::kR16Float,
|
||||||
|
type::StorageTexture::SubtypeFor(type::ImageFormat::kR16Float, Types()));
|
||||||
|
auto* tex_ac =
|
||||||
|
create<type::AccessControl>(ast::AccessControl::kWriteOnly, tex);
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureStore,
|
||||||
|
{tex_ac, ty.vec2<i32>(), ty.vec4<f32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureStore);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.void_());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{tex_ac, Parameter::Usage::kTexture},
|
||||||
|
Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords},
|
||||||
|
Parameter{ty.vec4<f32>(), Parameter::Usage::kValue}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchTexture) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
|
||||||
|
{ty.f32(), ty.vec2<i32>()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchAutoPointerDereference) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kCos,
|
||||||
|
{ty.pointer<f32>(ast::StorageClass::kNone)});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCos);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.f32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchWithAliasUnwrapping) {
|
||||||
|
auto* alias_a = ty.alias("alias_a", ty.f32());
|
||||||
|
auto* alias_b = ty.alias("alias_b", alias_a);
|
||||||
|
auto* alias_c = ty.alias("alias_c", alias_b);
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kCos, {alias_c});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCos);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.f32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchOpenType) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.f32(), ty.f32(), ty.f32()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.f32()}, Parameter{ty.f32()},
|
||||||
|
Parameter{ty.f32()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchOpenType) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.f32(), ty.u32(), ty.f32()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchOpenSizeVector) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.vec2<f32>(), ty.vec2<f32>(), ty.vec2<f32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec2<f32>());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.vec2<f32>()}, Parameter{ty.vec2<f32>()},
|
||||||
|
Parameter{ty.vec2<f32>()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchOpenSizeVector) {
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kClamp,
|
||||||
|
{ty.vec2<f32>(), ty.vec2<u32>(), ty.vec2<f32>()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchOpenSizeMatrix) {
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kDeterminant, {ty.mat3x3<f32>()});
|
||||||
|
ASSERT_NE(result.intrinsic, nullptr);
|
||||||
|
ASSERT_EQ(result.error, "");
|
||||||
|
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kDeterminant);
|
||||||
|
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
|
||||||
|
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||||
|
ElementsAre(Parameter{ty.mat3x3<f32>()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) {
|
||||||
|
auto result =
|
||||||
|
table->Lookup(*this, IntrinsicType::kDeterminant, {ty.mat3x2<f32>()});
|
||||||
|
ASSERT_EQ(result.intrinsic, nullptr);
|
||||||
|
ASSERT_THAT(result.error, HasSubstr("no matching call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
|
||||||
|
// None of the arguments match, so expect the overloads with 2 parameters to
|
||||||
|
// come first
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureDimensions,
|
||||||
|
{ty.bool_(), ty.bool_()});
|
||||||
|
ASSERT_EQ(result.error,
|
||||||
|
R"(no matching call to textureDimensions(bool, bool)
|
||||||
|
|
||||||
|
27 candidate functions:
|
||||||
|
textureDimensions(texture : texture_2d<T>, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_2d_array<T>, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_3d<T>, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube<T>, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube_array<T>, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_depth_2d, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_2d_array, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube_array, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_1d<T>) -> i32
|
||||||
|
textureDimensions(texture : texture_1d_array<T>) -> i32
|
||||||
|
textureDimensions(texture : texture_2d<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_2d_array<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_3d<T>) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube<T>) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube_array<T>) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_multisampled_2d<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_multisampled_2d_array<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_2d) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_2d_array) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube_array) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_storage_1d<F>) -> i32
|
||||||
|
textureDimensions(texture : texture_storage_1d_array<F>) -> i32
|
||||||
|
textureDimensions(texture : texture_storage_2d<F>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_storage_2d_array<F>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_storage_3d<F>) -> vec3<i32>
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
|
||||||
|
auto* tex = create<type::DepthTexture>(type::TextureDimension::k2d);
|
||||||
|
auto result = table->Lookup(*this, IntrinsicType::kTextureDimensions,
|
||||||
|
{tex, ty.bool_()});
|
||||||
|
ASSERT_EQ(result.error,
|
||||||
|
R"(no matching call to textureDimensions(texture_depth_2d, bool)
|
||||||
|
|
||||||
|
27 candidate functions:
|
||||||
|
textureDimensions(texture : texture_depth_2d, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_2d) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_2d<T>, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_2d_array<T>, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_3d<T>, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube<T>, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube_array<T>, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_depth_2d_array, level : i32) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube_array, level : i32) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_1d<T>) -> i32
|
||||||
|
textureDimensions(texture : texture_1d_array<T>) -> i32
|
||||||
|
textureDimensions(texture : texture_2d<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_2d_array<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_3d<T>) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube<T>) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_cube_array<T>) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_multisampled_2d<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_multisampled_2d_array<T>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_2d_array) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_depth_cube_array) -> vec3<i32>
|
||||||
|
textureDimensions(texture : texture_storage_1d<F>) -> i32
|
||||||
|
textureDimensions(texture : texture_storage_1d_array<F>) -> i32
|
||||||
|
textureDimensions(texture : texture_storage_2d<F>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_storage_2d_array<F>) -> vec2<i32>
|
||||||
|
textureDimensions(texture : texture_storage_3d<F>) -> vec3<i32>
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint
|
|
@ -56,6 +56,13 @@ struct Parameter {
|
||||||
Usage const usage = Usage::kNone;
|
Usage const usage = Usage::kNone;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Parameter parameter);
|
||||||
|
|
||||||
|
/// Comparison operator for Parameters
|
||||||
|
static inline bool operator==(const Parameter& a, const Parameter& b) {
|
||||||
|
return a.type == b.type && a.usage == b.usage;
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns a string representation of the given parameter usage.
|
/// @returns a string representation of the given parameter usage.
|
||||||
const char* str(Parameter::Usage usage);
|
const char* str(Parameter::Usage usage);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/semantic/call_target.h"
|
#include "src/semantic/call_target.h"
|
||||||
|
|
||||||
|
#include "src/symbol_table.h"
|
||||||
#include "src/type/type.h"
|
#include "src/type/type.h"
|
||||||
|
|
||||||
TINT_INSTANTIATE_CLASS_ID(tint::semantic::CallTarget);
|
TINT_INSTANTIATE_CLASS_ID(tint::semantic::CallTarget);
|
||||||
|
@ -65,5 +66,12 @@ const char* str(Parameter::Usage usage) {
|
||||||
return "<unknown>";
|
return "<unknown>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Parameter parameter) {
|
||||||
|
out << "[type: " << parameter.type->FriendlyName(SymbolTable{})
|
||||||
|
<< ", usage: " << str(parameter.usage) << "]";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace semantic
|
} // namespace semantic
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "src/semantic/expression.h"
|
#include "src/semantic/expression.h"
|
||||||
#include "src/semantic/function.h"
|
#include "src/semantic/function.h"
|
||||||
#include "src/semantic/variable.h"
|
#include "src/semantic/variable.h"
|
||||||
|
#include "src/type/access_control_type.h"
|
||||||
#include "src/type/alias_type.h"
|
#include "src/type/alias_type.h"
|
||||||
#include "src/type/array_type.h"
|
#include "src/type/array_type.h"
|
||||||
#include "src/type/bool_type.h"
|
#include "src/type/bool_type.h"
|
||||||
|
@ -1379,13 +1380,13 @@ TEST_P(Intrinsic_FloatMethod, TooManyParams) {
|
||||||
|
|
||||||
Global("my_var", ast::StorageClass::kNone, ty.f32());
|
Global("my_var", ast::StorageClass::kNone, ty.f32());
|
||||||
|
|
||||||
auto* expr = Call(name, "my_var", "my_var");
|
auto* expr = Call(name, "my_var", 1.23f);
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
EXPECT_FALSE(td()->Determine());
|
EXPECT_FALSE(td()->Determine());
|
||||||
|
|
||||||
EXPECT_EQ(td()->error(), "no matching call to " + name +
|
EXPECT_EQ(td()->error(), "no matching call to " + name +
|
||||||
"(f32, f32)\n\n"
|
"(ptr<f32>, f32)\n\n"
|
||||||
"2 candidate functions:\n " +
|
"2 candidate functions:\n " +
|
||||||
name + "(f32) -> bool\n " + name +
|
name + "(f32) -> bool\n " + name +
|
||||||
"(vecN<f32>) -> vecN<bool>\n");
|
"(vecN<f32>) -> vecN<bool>\n");
|
||||||
|
@ -1469,11 +1470,13 @@ TEST_P(Intrinsic_StorageTextureOperation, TextureLoadRo) {
|
||||||
auto* coords_type = GetCoordsType(dim, ty.i32());
|
auto* coords_type = GetCoordsType(dim, ty.i32());
|
||||||
|
|
||||||
auto* subtype = type::StorageTexture::SubtypeFor(format, Types());
|
auto* subtype = type::StorageTexture::SubtypeFor(format, Types());
|
||||||
type::Type* texture_type = create<type::StorageTexture>(dim, format, subtype);
|
auto* texture_type = create<type::StorageTexture>(dim, format, subtype);
|
||||||
|
auto* ro_texture_type =
|
||||||
|
create<type::AccessControl>(ast::AccessControl::kReadOnly, texture_type);
|
||||||
|
|
||||||
ast::ExpressionList call_params;
|
ast::ExpressionList call_params;
|
||||||
|
|
||||||
add_call_param("texture", texture_type, &call_params);
|
add_call_param("texture", ro_texture_type, &call_params);
|
||||||
add_call_param("coords", coords_type, &call_params);
|
add_call_param("coords", coords_type, &call_params);
|
||||||
|
|
||||||
if (type::IsTextureArray(dim)) {
|
if (type::IsTextureArray(dim)) {
|
||||||
|
@ -2504,7 +2507,7 @@ TEST_P(ImportData_Matrix_OneParam_Test, NoParams) {
|
||||||
"no matching call to " + std::string(param.name) + R"(()
|
"no matching call to " + std::string(param.name) + R"(()
|
||||||
|
|
||||||
1 candidate function:
|
1 candidate function:
|
||||||
determinant(maxNxN<f32>) -> f32
|
determinant(matNxN<f32>) -> f32
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue