Remove special case type determination
* Affects any, all, derivatives, dot and select * Add validation for those builtins Change-Id: I029b5acf92ddb2239c4f50d2e179bdb63d09aafd Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/39801 Reviewed-by: dan sinclair <dsinclair@chromium.org> Commit-Queue: Alan Baker <alanbaker@google.com>
This commit is contained in:
parent
e809fb3ae5
commit
2e6a1bb396
|
@ -119,5 +119,13 @@ bool Type::is_integer_scalar_or_vector() const {
|
||||||
return is_unsigned_scalar_or_vector() || is_signed_scalar_or_vector();
|
return is_unsigned_scalar_or_vector() || is_signed_scalar_or_vector();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Type::is_bool_vector() const {
|
||||||
|
return Is<Vector>() && As<Vector>()->type()->Is<Bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::is_bool_scalar_or_vector() const {
|
||||||
|
return Is<Bool>() || is_bool_vector();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type
|
} // namespace type
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -95,6 +95,10 @@ class Type : public Castable<Type> {
|
||||||
bool is_signed_scalar_or_vector() const;
|
bool is_signed_scalar_or_vector() const;
|
||||||
/// @returns true if this type is an integer scalar or vector
|
/// @returns true if this type is an integer scalar or vector
|
||||||
bool is_integer_scalar_or_vector() const;
|
bool is_integer_scalar_or_vector() const;
|
||||||
|
/// @returns true if this type is a boolean vector
|
||||||
|
bool is_bool_vector() const;
|
||||||
|
/// @returns true if this type is boolean scalar or vector
|
||||||
|
bool is_bool_scalar_or_vector() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type();
|
Type();
|
||||||
|
|
|
@ -452,6 +452,7 @@ enum class IntrinsicDataType {
|
||||||
kSignedInteger,
|
kSignedInteger,
|
||||||
kUnsignedInteger,
|
kUnsignedInteger,
|
||||||
kFloat,
|
kFloat,
|
||||||
|
kBool,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IntrinsicData {
|
struct IntrinsicData {
|
||||||
|
@ -466,6 +467,9 @@ struct IntrinsicData {
|
||||||
constexpr const IntrinsicData kIntrinsicData[] = {
|
constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
{ast::Intrinsic::kAbs, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kAbs, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kAcos, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kAcos, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kAll, IntrinsicDataType::kBool, 1, 0},
|
||||||
|
{ast::Intrinsic::kAny, IntrinsicDataType::kBool, 1, 0},
|
||||||
|
{ast::Intrinsic::kArrayLength, IntrinsicDataType::kUnsignedInteger, 1, 0},
|
||||||
{ast::Intrinsic::kAsin, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kAsin, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kAtan, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kAtan, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kAtan2, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kAtan2, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
@ -477,10 +481,20 @@ constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
{ast::Intrinsic::kCross, IntrinsicDataType::kFloat, 3, 0},
|
{ast::Intrinsic::kCross, IntrinsicDataType::kFloat, 3, 0},
|
||||||
{ast::Intrinsic::kDeterminant, IntrinsicDataType::kFloat, 1, 0},
|
{ast::Intrinsic::kDeterminant, IntrinsicDataType::kFloat, 1, 0},
|
||||||
{ast::Intrinsic::kDistance, IntrinsicDataType::kFloat, 1, 0},
|
{ast::Intrinsic::kDistance, IntrinsicDataType::kFloat, 1, 0},
|
||||||
|
{ast::Intrinsic::kDpdx, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kDpdxCoarse, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kDpdxFine, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kDpdy, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kDpdyCoarse, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kDpdyFine, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kDot, IntrinsicDataType::kFloat, 1, 0},
|
||||||
{ast::Intrinsic::kExp, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kExp, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kExp2, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kExp2, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kFaceForward, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kFaceForward, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kFloor, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kFloor, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kFwidth, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kFwidthCoarse, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kFwidthFine, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kFma, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kFma, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kFract, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kFract, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kFrexp, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kFrexp, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
@ -498,6 +512,7 @@ constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
{ast::Intrinsic::kReflect, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kReflect, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kReverseBits, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kReverseBits, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kRound, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kRound, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
{ast::Intrinsic::kSelect, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kSign, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kSign, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kSin, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kSin, IntrinsicDataType::kDependent, 0, 0},
|
||||||
{ast::Intrinsic::kSinh, IntrinsicDataType::kDependent, 0, 0},
|
{ast::Intrinsic::kSinh, IntrinsicDataType::kDependent, 0, 0},
|
||||||
|
@ -516,28 +531,6 @@ constexpr const uint32_t kIntrinsicDataCount =
|
||||||
|
|
||||||
bool TypeDeterminer::DetermineIntrinsic(ast::IdentifierExpression* ident,
|
bool TypeDeterminer::DetermineIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::CallExpression* expr) {
|
ast::CallExpression* expr) {
|
||||||
if (ast::intrinsic::IsDerivative(ident->intrinsic())) {
|
|
||||||
if (expr->params().size() != 1) {
|
|
||||||
set_error(expr->source(),
|
|
||||||
"incorrect number of parameters for " +
|
|
||||||
builder_->Symbols().NameFor(ident->symbol()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The result type must be the same as the type of the parameter.
|
|
||||||
auto* param_type = TypeOf(expr->params()[0])->UnwrapPtrIfNeeded();
|
|
||||||
SetType(expr->func(), param_type);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (ident->intrinsic() == ast::Intrinsic::kAny ||
|
|
||||||
ident->intrinsic() == ast::Intrinsic::kAll) {
|
|
||||||
SetType(expr->func(), builder_->create<type::Bool>());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (ident->intrinsic() == ast::Intrinsic::kArrayLength) {
|
|
||||||
SetType(expr->func(), builder_->create<type::U32>());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (ast::intrinsic::IsFloatClassificationIntrinsic(ident->intrinsic())) {
|
if (ast::intrinsic::IsFloatClassificationIntrinsic(ident->intrinsic())) {
|
||||||
if (expr->params().size() != 1) {
|
if (expr->params().size() != 1) {
|
||||||
set_error(expr->source(),
|
set_error(expr->source(),
|
||||||
|
@ -743,24 +736,6 @@ bool TypeDeterminer::DetermineIntrinsic(ast::IdentifierExpression* ident,
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (ident->intrinsic() == ast::Intrinsic::kDot) {
|
|
||||||
SetType(expr->func(), builder_->create<type::F32>());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (ident->intrinsic() == ast::Intrinsic::kSelect) {
|
|
||||||
if (expr->params().size() != 3) {
|
|
||||||
set_error(expr->source(),
|
|
||||||
"incorrect number of parameters for " +
|
|
||||||
builder_->Symbols().NameFor(ident->symbol()) +
|
|
||||||
" expected 3 got " + std::to_string(expr->params().size()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The result type must be the same as the type of the parameter.
|
|
||||||
auto* param_type = TypeOf(expr->params()[0])->UnwrapPtrIfNeeded();
|
|
||||||
SetType(expr->func(), param_type);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IntrinsicData* data = nullptr;
|
const IntrinsicData* data = nullptr;
|
||||||
for (uint32_t i = 0; i < kIntrinsicDataCount; ++i) {
|
for (uint32_t i = 0; i < kIntrinsicDataCount; ++i) {
|
||||||
|
@ -799,6 +774,9 @@ bool TypeDeterminer::DetermineIntrinsic(ast::IdentifierExpression* ident,
|
||||||
case IntrinsicDataType::kFloat:
|
case IntrinsicDataType::kFloat:
|
||||||
type = builder_->create<type::F32>();
|
type = builder_->create<type::F32>();
|
||||||
break;
|
break;
|
||||||
|
case IntrinsicDataType::kBool:
|
||||||
|
type = builder_->create<type::Bool>();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error_ = "unhandled intrinsic data type for " +
|
error_ = "unhandled intrinsic data type for " +
|
||||||
builder_->Symbols().NameFor(ident->symbol());
|
builder_->Symbols().NameFor(ident->symbol());
|
||||||
|
|
|
@ -1196,23 +1196,11 @@ TEST_P(IntrinsicDerivativeTest, MissingParam) {
|
||||||
|
|
||||||
auto* expr = Call(name);
|
auto* expr = Call(name);
|
||||||
EXPECT_FALSE(td()->DetermineResultType(expr));
|
EXPECT_FALSE(td()->DetermineResultType(expr));
|
||||||
EXPECT_EQ(td()->error(), "incorrect number of parameters for " + name);
|
EXPECT_EQ(td()->error(),
|
||||||
|
"missing parameter 0 required for type determination in builtin " +
|
||||||
|
std::string(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(IntrinsicDerivativeTest, ToomManyParams) {
|
|
||||||
auto name = GetParam();
|
|
||||||
|
|
||||||
auto* var1 = Var("ident1", ast::StorageClass::kNone, ty.vec4<f32>());
|
|
||||||
auto* var2 = Var("ident2", ast::StorageClass::kNone, ty.vec4<f32>());
|
|
||||||
AST().AddGlobalVariable(var1);
|
|
||||||
AST().AddGlobalVariable(var2);
|
|
||||||
|
|
||||||
EXPECT_TRUE(td()->Determine());
|
|
||||||
|
|
||||||
auto* expr = Call(name, "ident1", "ident2");
|
|
||||||
EXPECT_FALSE(td()->DetermineResultType(expr));
|
|
||||||
EXPECT_EQ(td()->error(), "incorrect number of parameters for " + name);
|
|
||||||
}
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TypeDeterminerTest,
|
INSTANTIATE_TEST_SUITE_P(TypeDeterminerTest,
|
||||||
IntrinsicDerivativeTest,
|
IntrinsicDerivativeTest,
|
||||||
testing::Values("dpdx",
|
testing::Values("dpdx",
|
||||||
|
@ -1520,32 +1508,15 @@ TEST_F(TypeDeterminerTest, Intrinsic_Select) {
|
||||||
EXPECT_TRUE(TypeOf(expr)->As<type::Vector>()->type()->Is<type::F32>());
|
EXPECT_TRUE(TypeOf(expr)->As<type::Vector>()->type()->Is<type::F32>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TypeDeterminerTest, Intrinsic_Select_TooFewParams) {
|
TEST_F(TypeDeterminerTest, Intrinsic_Select_NoParams) {
|
||||||
auto* var = Var("v", ast::StorageClass::kNone, ty.vec3<f32>());
|
auto* expr = Call("select");
|
||||||
|
|
||||||
AST().AddGlobalVariable(var);
|
|
||||||
|
|
||||||
auto* expr = Call("select", "v");
|
|
||||||
|
|
||||||
// Register the variable
|
// Register the variable
|
||||||
EXPECT_TRUE(td()->Determine());
|
EXPECT_TRUE(td()->Determine());
|
||||||
EXPECT_FALSE(td()->DetermineResultType(expr));
|
EXPECT_FALSE(td()->DetermineResultType(expr));
|
||||||
EXPECT_EQ(td()->error(),
|
EXPECT_EQ(
|
||||||
"incorrect number of parameters for select expected 3 got 1");
|
td()->error(),
|
||||||
}
|
"missing parameter 0 required for type determination in builtin select");
|
||||||
|
|
||||||
TEST_F(TypeDeterminerTest, Intrinsic_Select_TooManyParams) {
|
|
||||||
auto* var = Var("v", ast::StorageClass::kNone, ty.vec3<f32>());
|
|
||||||
|
|
||||||
AST().AddGlobalVariable(var);
|
|
||||||
|
|
||||||
auto* expr = Call("select", "v", "v", "v", "v");
|
|
||||||
|
|
||||||
// Register the variable
|
|
||||||
EXPECT_TRUE(td()->Determine());
|
|
||||||
EXPECT_FALSE(td()->DetermineResultType(expr));
|
|
||||||
EXPECT_EQ(td()->error(),
|
|
||||||
"incorrect number of parameters for select expected 3 got 4");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using UnaryOpExpressionTest = TypeDeterminerTestWithParam<ast::UnaryOp>;
|
using UnaryOpExpressionTest = TypeDeterminerTestWithParam<ast::UnaryOp>;
|
||||||
|
|
|
@ -656,6 +656,237 @@ TEST_F(ValidatorBuiltinsTest, Cross_TooFewParams) {
|
||||||
"incorrect number of parameters for cross expected 2 got 1");
|
"incorrect number of parameters for cross expected 2 got 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_Float_Scalar) {
|
||||||
|
auto* builtin = Call("dot", Expr(1.0f), Expr(1.0f));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(), "incorrect type for dot. Requires float vector value");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_Integer_Scalar) {
|
||||||
|
auto* builtin = Call("dot", Expr(1), Expr(1));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(), "incorrect type for dot. Requires float vector value");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_Float_Vec2) {
|
||||||
|
auto* builtin = Call("dot", vec2<float>(1.0f, 1.0f), vec2<float>(1.0f, 1.0f));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_Float_Vec3) {
|
||||||
|
auto* builtin =
|
||||||
|
Call("dot", vec3<float>(1.0f, 1.0f, 1.0f), vec3<float>(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_Float_Vec4) {
|
||||||
|
auto* builtin = Call("dot", vec4<float>(1.0f, 1.0f, 1.0f, 1.0f),
|
||||||
|
vec4<float>(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_Integer_Vector) {
|
||||||
|
auto* builtin = Call("dot", vec2<int>(1, 1), vec2<int>(1, 1));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(), "incorrect type for dot. Requires float vector value");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_TooFewParams) {
|
||||||
|
auto* builtin = Call("dot", vec2<float>(1.0f, 1.0f));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect number of parameters for dot expected 2 got 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Dot_TooManyParams) {
|
||||||
|
auto* builtin = Call("dot", vec2<float>(1.0f, 1.0f), vec2<float>(1.0f, 1.0f),
|
||||||
|
vec2<float>(1.0f, 1.0f));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect number of parameters for dot expected 2 got 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Float_Scalar) {
|
||||||
|
auto* builtin = Call("select", Expr(1.0f), Expr(1.0f), Expr(true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Integer_Scalar) {
|
||||||
|
auto* builtin = Call("select", Expr(1), Expr(1), Expr(true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Boolean_Scalar) {
|
||||||
|
auto* builtin = Call("select", Expr(true), Expr(true), Expr(true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Float_Vec2) {
|
||||||
|
auto* builtin = Call("select", vec2<float>(1.0f, 1.0f),
|
||||||
|
vec2<float>(1.0f, 1.0f), vec2<bool>(true, true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Integer_Vec2) {
|
||||||
|
auto* builtin =
|
||||||
|
Call("select", vec2<int>(1, 1), vec2<int>(1, 1), vec2<bool>(true, true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Boolean_Vec2) {
|
||||||
|
auto* builtin = Call("select", vec2<bool>(true, true), vec2<bool>(true, true),
|
||||||
|
vec2<bool>(true, true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_BadSelector) {
|
||||||
|
auto* builtin = Call("select", Expr(1), Expr(1), Expr(1));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Selector must be a bool scalar or "
|
||||||
|
"vector value");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Matrix) {
|
||||||
|
auto* mat = mat2x2<float>(vec2<float>(1.0f, 1.0f), vec2<float>(1.0f, 1.0f));
|
||||||
|
auto* builtin = Call("select", mat, mat, Expr(true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Requires bool, int or float scalar or "
|
||||||
|
"vector");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Mismatch_Scalar) {
|
||||||
|
auto* builtin = Call("select", Expr(1.0f), Expr(1), Expr(true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Value parameter types must match "
|
||||||
|
"result type");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Mismatched_Vector) {
|
||||||
|
auto* builtin =
|
||||||
|
Call("select", Expr(1.0f), vec2<float>(1.0f, 1.0f), Expr(true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Value parameter types must match "
|
||||||
|
"result type");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Mismatched_VectorSize) {
|
||||||
|
auto* builtin = Call("select", vec3<float>(1.0f, 1.0f, 1.0f),
|
||||||
|
vec2<float>(1.0f, 1.0f), vec3<bool>(true, true, true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Value parameter types must match "
|
||||||
|
"result type");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Mismatch_Selector_Vector) {
|
||||||
|
auto* builtin =
|
||||||
|
Call("select", Expr(1.0f), Expr(1.0f), vec2<bool>(true, true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Selector must be a bool scalar to "
|
||||||
|
"match scalar result type");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Mismatch_Selector_Scalar) {
|
||||||
|
auto* builtin = Call("select", vec2<float>(1.0f, 1.0f),
|
||||||
|
vec2<float>(1.0f, 1.0f), Expr(true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Selector must be a vector with the "
|
||||||
|
"same number of elements as the result type");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, Select_Mismatch_Selector_VectorSize) {
|
||||||
|
auto* builtin = Call("select", vec2<float>(1.0f, 1.0f),
|
||||||
|
vec2<float>(1.0f, 1.0f), vec3<bool>(true, true, true));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for select. Selector must be a vector with the "
|
||||||
|
"same number of elements as the result type");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidatorBuiltinsTest, ArrayLength_Sized) {
|
||||||
|
auto* var = Var("a", ast::StorageClass::kWorkgroup, ty.array<int, 4>());
|
||||||
|
RegisterVariable(var);
|
||||||
|
auto* builtin = Call("arrayLength", Expr("a"));
|
||||||
|
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for arrayLength. Input must be a runtime array");
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ValidatorBuiltinsTestWithParams : public ValidatorTestHelper,
|
class ValidatorBuiltinsTestWithParams : public ValidatorTestHelper,
|
||||||
public testing::TestWithParam<T> {};
|
public testing::TestWithParam<T> {};
|
||||||
|
@ -840,12 +1071,21 @@ INSTANTIATE_TEST_SUITE_P(ValidatorBuiltinsTest,
|
||||||
std::make_tuple("clamp", 3),
|
std::make_tuple("clamp", 3),
|
||||||
std::make_tuple("cos", 1),
|
std::make_tuple("cos", 1),
|
||||||
std::make_tuple("cosh", 1),
|
std::make_tuple("cosh", 1),
|
||||||
|
std::make_tuple("dpdx", 1),
|
||||||
|
std::make_tuple("dpdxCoarse", 1),
|
||||||
|
std::make_tuple("dpdxFine", 1),
|
||||||
|
std::make_tuple("dpdy", 1),
|
||||||
|
std::make_tuple("dpdyCoarse", 1),
|
||||||
|
std::make_tuple("dpdyFine", 1),
|
||||||
std::make_tuple("exp", 1),
|
std::make_tuple("exp", 1),
|
||||||
std::make_tuple("exp2", 1),
|
std::make_tuple("exp2", 1),
|
||||||
std::make_tuple("faceForward", 3),
|
std::make_tuple("faceForward", 3),
|
||||||
std::make_tuple("floor", 1),
|
std::make_tuple("floor", 1),
|
||||||
std::make_tuple("fma", 3),
|
std::make_tuple("fma", 3),
|
||||||
std::make_tuple("fract", 1),
|
std::make_tuple("fract", 1),
|
||||||
|
std::make_tuple("fwidth", 1),
|
||||||
|
std::make_tuple("fwidthCoarse", 1),
|
||||||
|
std::make_tuple("fwidthFine", 1),
|
||||||
std::make_tuple("inverseSqrt", 1),
|
std::make_tuple("inverseSqrt", 1),
|
||||||
std::make_tuple("ldexp", 2),
|
std::make_tuple("ldexp", 2),
|
||||||
std::make_tuple("log", 1),
|
std::make_tuple("log", 1),
|
||||||
|
@ -1125,4 +1365,133 @@ INSTANTIATE_TEST_SUITE_P(ValidatorBuiltinsTest,
|
||||||
std::make_tuple("max", 2),
|
std::make_tuple("max", 2),
|
||||||
std::make_tuple("min", 2),
|
std::make_tuple("min", 2),
|
||||||
std::make_tuple("reverseBits", 1)));
|
std::make_tuple("reverseBits", 1)));
|
||||||
|
|
||||||
|
using BooleanVectorInput =
|
||||||
|
ValidatorBuiltinsTestWithParams<std::tuple<std::string, uint32_t>>;
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, Scalar) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
ast::ExpressionList params;
|
||||||
|
for (uint32_t i = 0; i < num_params; ++i) {
|
||||||
|
params.push_back(Expr(true));
|
||||||
|
}
|
||||||
|
auto* builtin = Call(name, params);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for " + name + ". Requires bool vector value");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, Vec2) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
ast::ExpressionList params;
|
||||||
|
for (uint32_t i = 0; i < num_params; ++i) {
|
||||||
|
params.push_back(vec2<bool>(true, true));
|
||||||
|
}
|
||||||
|
auto* builtin = Call(name, params);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, Vec3) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
ast::ExpressionList params;
|
||||||
|
for (uint32_t i = 0; i < num_params; ++i) {
|
||||||
|
params.push_back(vec3<bool>(true, true, true));
|
||||||
|
}
|
||||||
|
auto* builtin = Call(name, params);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, Vec4) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
ast::ExpressionList params;
|
||||||
|
for (uint32_t i = 0; i < num_params; ++i) {
|
||||||
|
params.push_back(vec4<bool>(true, true, true, true));
|
||||||
|
}
|
||||||
|
auto* builtin = Call(name, params);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_TRUE(v.ValidateCallExpr(builtin)) << v.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, NoParams) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
auto* builtin = Call(name);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(), "incorrect number of parameters for " + name +
|
||||||
|
" expected " + std::to_string(num_params) +
|
||||||
|
" got 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, TooManyParams) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
ast::ExpressionList params;
|
||||||
|
for (uint32_t i = 0; i < num_params + 1; ++i) {
|
||||||
|
params.push_back(vec2<bool>(true, true));
|
||||||
|
}
|
||||||
|
auto* builtin = Call(name, params);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(), "incorrect number of parameters for " + name +
|
||||||
|
" expected " + std::to_string(num_params) + " got " +
|
||||||
|
std::to_string(num_params + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, Integer) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
ast::ExpressionList params;
|
||||||
|
for (uint32_t i = 0; i < num_params; ++i) {
|
||||||
|
params.push_back(vec2<uint32_t>(1, 1));
|
||||||
|
}
|
||||||
|
auto* builtin = Call(name, params);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for " + name + ". Requires bool vector value");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BooleanVectorInput, Float) {
|
||||||
|
std::string name = std::get<0>(GetParam());
|
||||||
|
uint32_t num_params = std::get<1>(GetParam());
|
||||||
|
|
||||||
|
ast::ExpressionList params;
|
||||||
|
for (uint32_t i = 0; i < num_params; ++i) {
|
||||||
|
params.push_back(vec2<float>(1.0f, 1.0f));
|
||||||
|
}
|
||||||
|
auto* builtin = Call(name, params);
|
||||||
|
EXPECT_TRUE(td()->DetermineResultType(builtin)) << td()->error();
|
||||||
|
ValidatorImpl& v = Build();
|
||||||
|
EXPECT_FALSE(v.ValidateCallExpr(builtin));
|
||||||
|
EXPECT_EQ(v.error(),
|
||||||
|
"incorrect type for " + name + ". Requires bool vector value");
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(ValidatorBuiltinsTest,
|
||||||
|
BooleanVectorInput,
|
||||||
|
::testing::Values(std::make_tuple("all", 1),
|
||||||
|
std::make_tuple("any", 1)));
|
||||||
|
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "src/semantic/expression.h"
|
#include "src/semantic/expression.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/f32_type.h"
|
#include "src/type/f32_type.h"
|
||||||
#include "src/type/i32_type.h"
|
#include "src/type/i32_type.h"
|
||||||
#include "src/type/matrix_type.h"
|
#include "src/type/matrix_type.h"
|
||||||
|
@ -54,6 +55,9 @@ enum class IntrinsicDataType {
|
||||||
kFloatVector,
|
kFloatVector,
|
||||||
kFloatScalar,
|
kFloatScalar,
|
||||||
kMatrix,
|
kMatrix,
|
||||||
|
kBoolVector,
|
||||||
|
kBoolScalar,
|
||||||
|
kBoolScalarOrVector,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IntrinsicData {
|
struct IntrinsicData {
|
||||||
|
@ -71,6 +75,9 @@ constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
true},
|
true},
|
||||||
{ast::Intrinsic::kAcos, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kAcos, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
true},
|
true},
|
||||||
|
{ast::Intrinsic::kAll, 1, IntrinsicDataType::kBoolVector, 0, false},
|
||||||
|
{ast::Intrinsic::kAny, 1, IntrinsicDataType::kBoolVector, 0, false},
|
||||||
|
{ast::Intrinsic::kArrayLength, 1, IntrinsicDataType::kMixed, 0, false},
|
||||||
{ast::Intrinsic::kAsin, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kAsin, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
true},
|
true},
|
||||||
{ast::Intrinsic::kAtan, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kAtan, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
@ -90,6 +97,19 @@ constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
{ast::Intrinsic::kDeterminant, 1, IntrinsicDataType::kMatrix, 0, false},
|
{ast::Intrinsic::kDeterminant, 1, IntrinsicDataType::kMatrix, 0, false},
|
||||||
{ast::Intrinsic::kDistance, 2, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kDistance, 2, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
false},
|
false},
|
||||||
|
{ast::Intrinsic::kDot, 2, IntrinsicDataType::kFloatVector, 0, false},
|
||||||
|
{ast::Intrinsic::kDpdx, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
|
{ast::Intrinsic::kDpdxCoarse, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
|
{ast::Intrinsic::kDpdxFine, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
|
{ast::Intrinsic::kDpdy, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
|
{ast::Intrinsic::kDpdyCoarse, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
|
{ast::Intrinsic::kDpdyFine, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
{ast::Intrinsic::kExp, 1, IntrinsicDataType::kFloatScalarOrVector, 0, true},
|
{ast::Intrinsic::kExp, 1, IntrinsicDataType::kFloatScalarOrVector, 0, true},
|
||||||
{ast::Intrinsic::kExp2, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kExp2, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
true},
|
true},
|
||||||
|
@ -101,6 +121,12 @@ constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
{ast::Intrinsic::kFract, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kFract, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
true},
|
true},
|
||||||
{ast::Intrinsic::kFrexp, 2, IntrinsicDataType::kMixed, 0, false},
|
{ast::Intrinsic::kFrexp, 2, IntrinsicDataType::kMixed, 0, false},
|
||||||
|
{ast::Intrinsic::kFwidth, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
|
{ast::Intrinsic::kFwidthCoarse, 1, IntrinsicDataType::kFloatScalarOrVector,
|
||||||
|
0, true},
|
||||||
|
{ast::Intrinsic::kFwidthFine, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
true},
|
||||||
{ast::Intrinsic::kInverseSqrt, 1, IntrinsicDataType::kFloatScalarOrVector,
|
{ast::Intrinsic::kInverseSqrt, 1, IntrinsicDataType::kFloatScalarOrVector,
|
||||||
0, true},
|
0, true},
|
||||||
{ast::Intrinsic::kLdexp, 2, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kLdexp, 2, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
|
@ -125,6 +151,7 @@ constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
true},
|
true},
|
||||||
{ast::Intrinsic::kRound, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kRound, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
true},
|
true},
|
||||||
|
{ast::Intrinsic::kSelect, 3, IntrinsicDataType::kMixed, 0, false},
|
||||||
{ast::Intrinsic::kSign, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
{ast::Intrinsic::kSign, 1, IntrinsicDataType::kFloatScalarOrVector, 0,
|
||||||
true},
|
true},
|
||||||
{ast::Intrinsic::kSin, 1, IntrinsicDataType::kFloatScalarOrVector, 0, true},
|
{ast::Intrinsic::kSin, 1, IntrinsicDataType::kFloatScalarOrVector, 0, true},
|
||||||
|
@ -204,6 +231,33 @@ bool IsValidType(type::Type* type,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case IntrinsicDataType::kBoolVector:
|
||||||
|
if (!type->is_bool_vector()) {
|
||||||
|
impl->add_error(source, "incorrect type for " + name +
|
||||||
|
". Requires bool vector value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (vector_size > 0 && vector_size != type->As<type::Vector>()->size()) {
|
||||||
|
impl->add_error(source, "incorrect vector size for " + name +
|
||||||
|
". Requires " +
|
||||||
|
std::to_string(vector_size) + " elements");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IntrinsicDataType::kBoolScalar:
|
||||||
|
if (!type->Is<type::Bool>()) {
|
||||||
|
impl->add_error(source, "incorrect type for " + name +
|
||||||
|
". Requires bool scalar value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IntrinsicDataType::kBoolScalarOrVector:
|
||||||
|
if (!type->is_bool_scalar_or_vector()) {
|
||||||
|
impl->add_error(source, "incorrect type for " + name +
|
||||||
|
". Requires bool scalar or vector value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -677,9 +731,98 @@ bool ValidatorImpl::ValidateCallExpr(const ast::CallExpression* expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->intrinsic == ast::Intrinsic::kSelect) {
|
||||||
|
auto* type = program_->TypeOf(expr->func());
|
||||||
|
auto* t0 =
|
||||||
|
program_->TypeOf(expr->params()[0])->UnwrapPtrIfNeeded();
|
||||||
|
auto* t1 =
|
||||||
|
program_->TypeOf(expr->params()[1])->UnwrapPtrIfNeeded();
|
||||||
|
auto* t2 =
|
||||||
|
program_->TypeOf(expr->params()[2])->UnwrapPtrIfNeeded();
|
||||||
|
if (!type->is_scalar() && !type->Is<type::Vector>()) {
|
||||||
|
add_error(expr->source(),
|
||||||
|
"incorrect type for " + builtin +
|
||||||
|
". Requires bool, int or float scalar or vector");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != t0 || type != t1) {
|
||||||
|
add_error(expr->source(),
|
||||||
|
"incorrect type for " + builtin +
|
||||||
|
". Value parameter types must match result type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!t2->is_bool_scalar_or_vector()) {
|
||||||
|
add_error(
|
||||||
|
expr->params()[2]->source(),
|
||||||
|
"incorrect type for " + builtin +
|
||||||
|
". Selector must be a bool scalar or vector value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->Is<type::Vector>()) {
|
||||||
|
auto size = type->As<type::Vector>()->size();
|
||||||
|
if (t2->is_scalar() || size != t2->As<type::Vector>()->size()) {
|
||||||
|
add_error(expr->params()[2]->source(),
|
||||||
|
"incorrect type for " + builtin +
|
||||||
|
". Selector must be a vector with the same "
|
||||||
|
"number of elements as the result type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!t2->is_scalar()) {
|
||||||
|
add_error(expr->params()[2]->source(),
|
||||||
|
"incorrect type for " + builtin +
|
||||||
|
". Selector must be a bool scalar to match "
|
||||||
|
"scalar result type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->intrinsic == ast::Intrinsic::kArrayLength) {
|
||||||
|
if (!program_->TypeOf(expr->func())
|
||||||
|
->UnwrapPtrIfNeeded()
|
||||||
|
->Is<type::U32>()) {
|
||||||
|
add_error(
|
||||||
|
expr->source(),
|
||||||
|
"incorrect type for " + builtin +
|
||||||
|
". Result type must be an unsigned int scalar value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* p0 =
|
||||||
|
program_->TypeOf(expr->params()[0])->UnwrapPtrIfNeeded();
|
||||||
|
if (!p0->Is<type::Array>() ||
|
||||||
|
!p0->As<type::Array>()->IsRuntimeArray()) {
|
||||||
|
add_error(expr->params()[0]->source(),
|
||||||
|
"incorrect type for " + builtin +
|
||||||
|
". Input must be a runtime array");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result types don't match parameter types.
|
// Result types don't match parameter types.
|
||||||
|
if (data->intrinsic == ast::Intrinsic::kAll ||
|
||||||
|
data->intrinsic == ast::Intrinsic::kAny) {
|
||||||
|
if (!IsValidType(program_->TypeOf(expr->func()), expr->source(),
|
||||||
|
builtin, IntrinsicDataType::kBoolScalar, 0,
|
||||||
|
this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->intrinsic == ast::Intrinsic::kDot) {
|
||||||
|
if (!IsValidType(program_->TypeOf(expr->func()), expr->source(),
|
||||||
|
builtin, IntrinsicDataType::kFloatScalar, 0,
|
||||||
|
this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (data->intrinsic == ast::Intrinsic::kLength ||
|
if (data->intrinsic == ast::Intrinsic::kLength ||
|
||||||
data->intrinsic == ast::Intrinsic::kDistance ||
|
data->intrinsic == ast::Intrinsic::kDistance ||
|
||||||
data->intrinsic == ast::Intrinsic::kDeterminant) {
|
data->intrinsic == ast::Intrinsic::kDeterminant) {
|
||||||
|
|
Loading…
Reference in New Issue