tint/resolver: Add tests for implicit type materialization
These are tests for when there's no explicit target type for a materialization. In this case we expect an abstract-int to materialize to an i32 and an abstract-float to materialize to a f32. Fix a bug uncovered where we were creating a transposed matrix. Bug: tint:1504 Change-Id: Ie69dd7ec47174d3d7bef20315fd3780dade3a325 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/91845 Reviewed-by: David Neto <dneto@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
81b97656bc
commit
3a236c6c51
|
@ -34,10 +34,44 @@ using i32V = builder::vec<3, i32>;
|
||||||
using u32V = builder::vec<3, u32>;
|
using u32V = builder::vec<3, u32>;
|
||||||
using f32M = builder::mat<3, 2, f32>;
|
using f32M = builder::mat<3, 2, f32>;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
constexpr double kHighestU32 = static_cast<double>(u32::kHighest);
|
||||||
// MaterializeTests
|
constexpr double kLowestU32 = static_cast<double>(u32::kLowest);
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
constexpr double kHighestI32 = static_cast<double>(i32::kHighest);
|
||||||
namespace MaterializeTests {
|
constexpr double kLowestI32 = static_cast<double>(i32::kLowest);
|
||||||
|
constexpr double kHighestF32 = static_cast<double>(f32::kHighest);
|
||||||
|
constexpr double kLowestF32 = static_cast<double>(f32::kLowest);
|
||||||
|
constexpr double kTooBigF32 = static_cast<double>(3.5e+38);
|
||||||
|
constexpr double kPiF64 = 3.141592653589793;
|
||||||
|
constexpr double kPiF32 = 3.1415927410125732; // kPiF64 quantized to f32
|
||||||
|
|
||||||
|
constexpr double kSubnormalF32 = 0x1.0p-128;
|
||||||
|
|
||||||
|
enum class Expectation {
|
||||||
|
kMaterialize,
|
||||||
|
kNoMaterialize,
|
||||||
|
kInvalidConversion,
|
||||||
|
kValueCannotBeRepresented,
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::ostream& operator<<(std::ostream& o, Expectation m) {
|
||||||
|
switch (m) {
|
||||||
|
case Expectation::kMaterialize:
|
||||||
|
return o << "materialize";
|
||||||
|
case Expectation::kNoMaterialize:
|
||||||
|
return o << "no-materialize";
|
||||||
|
case Expectation::kInvalidConversion:
|
||||||
|
return o << "invalid-conversion";
|
||||||
|
case Expectation::kValueCannotBeRepresented:
|
||||||
|
return o << "value cannot be represented";
|
||||||
|
}
|
||||||
|
return o << "<unknown>";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MaterializeAbstractNumericToConcreteType
|
||||||
|
// Tests that an abstract-numeric will materialize to the expected concrete type
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
namespace materialize_abstract_numeric_to_concrete_type {
|
||||||
|
|
||||||
// How should the materialization occur?
|
// How should the materialization occur?
|
||||||
enum class Method {
|
enum class Method {
|
||||||
|
@ -188,31 +222,10 @@ static std::ostream& operator<<(std::ostream& o, const Data& c) {
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Expectation {
|
using MaterializeAbstractNumericToConcreteType =
|
||||||
kMaterialize,
|
|
||||||
kNoMaterialize,
|
|
||||||
kInvalidCast,
|
|
||||||
kValueCannotBeRepresented,
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::ostream& operator<<(std::ostream& o, Expectation m) {
|
|
||||||
switch (m) {
|
|
||||||
case Expectation::kMaterialize:
|
|
||||||
return o << "pass";
|
|
||||||
case Expectation::kNoMaterialize:
|
|
||||||
return o << "no-materialize";
|
|
||||||
case Expectation::kInvalidCast:
|
|
||||||
return o << "invalid-cast";
|
|
||||||
case Expectation::kValueCannotBeRepresented:
|
|
||||||
return o << "value too low or high";
|
|
||||||
}
|
|
||||||
return o << "<unknown>";
|
|
||||||
}
|
|
||||||
|
|
||||||
using MaterializeAbstractNumeric =
|
|
||||||
resolver::ResolverTestWithParam<std::tuple<Expectation, Method, Data>>;
|
resolver::ResolverTestWithParam<std::tuple<Expectation, Method, Data>>;
|
||||||
|
|
||||||
TEST_P(MaterializeAbstractNumeric, Test) {
|
TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
|
||||||
// Once F16 is properly supported, we'll need to enable this:
|
// Once F16 is properly supported, we'll need to enable this:
|
||||||
// Enable(ast::Extension::kF16);
|
// Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
@ -309,7 +322,7 @@ TEST_P(MaterializeAbstractNumeric, Test) {
|
||||||
check_types_and_values(sem);
|
check_types_and_values(sem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Expectation::kInvalidCast: {
|
case Expectation::kInvalidConversion: {
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
std::string expect;
|
std::string expect;
|
||||||
switch (method) {
|
switch (method) {
|
||||||
|
@ -338,170 +351,484 @@ TEST_P(MaterializeAbstractNumeric, Test) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Methods that support scalar materialization
|
/// Methods that support scalar materialization
|
||||||
constexpr Method kScalarMethods[] = {Method::kLet, //
|
constexpr Method kScalarMethods[] = {
|
||||||
Method::kVar, //
|
Method::kLet, Method::kVar, Method::kFnArg, Method::kBuiltinArg,
|
||||||
Method::kFnArg, //
|
Method::kReturn, Method::kArray, Method::kStruct, Method::kBinaryOp,
|
||||||
Method::kBuiltinArg, //
|
};
|
||||||
Method::kReturn, //
|
|
||||||
Method::kArray, //
|
|
||||||
Method::kStruct, //
|
|
||||||
Method::kBinaryOp};
|
|
||||||
|
|
||||||
/// Methods that support vector materialization
|
/// Methods that support vector materialization
|
||||||
constexpr Method kVectorMethods[] = {Method::kLet, //
|
constexpr Method kVectorMethods[] = {
|
||||||
Method::kVar, //
|
Method::kLet, Method::kVar, Method::kFnArg, Method::kBuiltinArg,
|
||||||
Method::kFnArg, //
|
Method::kReturn, Method::kArray, Method::kStruct, Method::kBinaryOp,
|
||||||
Method::kBuiltinArg, //
|
};
|
||||||
Method::kReturn, //
|
|
||||||
Method::kArray, //
|
|
||||||
Method::kStruct, //
|
|
||||||
Method::kBinaryOp};
|
|
||||||
|
|
||||||
/// Methods that support matrix materialization
|
/// Methods that support matrix materialization
|
||||||
constexpr Method kMatrixMethods[] = {Method::kLet, //
|
constexpr Method kMatrixMethods[] = {
|
||||||
Method::kVar, //
|
Method::kLet, Method::kVar, Method::kFnArg, Method::kReturn,
|
||||||
Method::kFnArg, //
|
Method::kArray, Method::kStruct, Method::kBinaryOp,
|
||||||
Method::kReturn, //
|
};
|
||||||
Method::kArray, //
|
|
||||||
Method::kStruct, //
|
|
||||||
Method::kBinaryOp};
|
|
||||||
|
|
||||||
/// Methods that support materialization for switch cases
|
/// Methods that support materialization for switch cases
|
||||||
constexpr Method kSwitchMethods[] = {Method::kSwitchCond, //
|
constexpr Method kSwitchMethods[] = {
|
||||||
Method::kSwitchCase, //
|
Method::kSwitchCond,
|
||||||
Method::kSwitchCondWithAbstractCase, //
|
Method::kSwitchCase,
|
||||||
Method::kSwitchCaseWithAbstractCase};
|
Method::kSwitchCondWithAbstractCase,
|
||||||
|
Method::kSwitchCaseWithAbstractCase,
|
||||||
constexpr double kMaxF32 = static_cast<double>(f32::kHighest);
|
};
|
||||||
constexpr double kPiF64 = 3.141592653589793;
|
|
||||||
constexpr double kPiF32 = 3.1415927410125732; // kPiF64 quantized to f32
|
|
||||||
|
|
||||||
constexpr double kSubnormalF32 = 0x1.0p-128;
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
MaterializeScalar,
|
MaterializeScalar,
|
||||||
MaterializeAbstractNumeric, //
|
MaterializeAbstractNumericToConcreteType,
|
||||||
testing::Combine(testing::Values(Expectation::kMaterialize), //
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
testing::ValuesIn(kScalarMethods), //
|
testing::ValuesIn(kScalarMethods),
|
||||||
testing::Values(Types<i32, AInt>(0_a, 0.0), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
Types<i32, AInt>(2147483647_a, 2147483647.0), //
|
Types<i32, AInt>(0_a, 0.0), //
|
||||||
Types<i32, AInt>(-2147483648_a, -2147483648.0), //
|
Types<i32, AInt>(1_a, 1.0), //
|
||||||
|
Types<i32, AInt>(-1_a, -1.0), //
|
||||||
|
Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
|
||||||
|
Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
|
||||||
Types<u32, AInt>(0_a, 0.0), //
|
Types<u32, AInt>(0_a, 0.0), //
|
||||||
Types<u32, AInt>(4294967295_a, 4294967295.0), //
|
Types<u32, AInt>(1_a, 1.0), //
|
||||||
|
Types<u32, AInt>(AInt(kHighestU32), kHighestU32), //
|
||||||
|
Types<u32, AInt>(AInt(kLowestU32), kLowestU32), //
|
||||||
Types<f32, AFloat>(0.0_a, 0.0), //
|
Types<f32, AFloat>(0.0_a, 0.0), //
|
||||||
Types<f32, AFloat>(AFloat(kMaxF32), kMaxF32), //
|
Types<f32, AFloat>(AFloat(kHighestF32), kHighestF32), //
|
||||||
Types<f32, AFloat>(AFloat(-kMaxF32), -kMaxF32), //
|
Types<f32, AFloat>(AFloat(kLowestF32), kLowestF32), //
|
||||||
Types<f32, AFloat>(AFloat(kPiF32), kPiF64), //
|
Types<f32, AFloat>(AFloat(kPiF32), kPiF64), //
|
||||||
Types<f32, AFloat>(AFloat(kSubnormalF32), kSubnormalF32), //
|
Types<f32, AFloat>(AFloat(kSubnormalF32), kSubnormalF32), //
|
||||||
Types<f32, AFloat>(AFloat(-kSubnormalF32), -kSubnormalF32) //
|
Types<f32, AFloat>(AFloat(-kSubnormalF32), -kSubnormalF32), //
|
||||||
/* Types<f16, AFloat>(1.0_a), */ //
|
/* Types<f16, AFloat>(1.0_a), */ //
|
||||||
/* Types<f16, AFloat>(1.0_a), */)));
|
/* Types<f16, AFloat>(1.0_a), */ //
|
||||||
|
})));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
MaterializeVector,
|
MaterializeVector,
|
||||||
MaterializeAbstractNumeric, //
|
MaterializeAbstractNumericToConcreteType,
|
||||||
testing::Combine(testing::Values(Expectation::kMaterialize), //
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
testing::ValuesIn(kVectorMethods), //
|
testing::ValuesIn(kVectorMethods),
|
||||||
testing::Values(Types<i32V, AIntV>(0_a, 0.0), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
Types<i32V, AIntV>(2147483647_a, 2147483647.0), //
|
Types<i32V, AIntV>(0_a, 0.0), //
|
||||||
Types<i32V, AIntV>(-2147483648_a, -2147483648.0), //
|
Types<i32V, AIntV>(1_a, 1.0), //
|
||||||
|
Types<i32V, AIntV>(-1_a, -1.0), //
|
||||||
|
Types<i32V, AIntV>(AInt(kHighestI32), kHighestI32), //
|
||||||
|
Types<i32V, AIntV>(AInt(kLowestI32), kLowestI32), //
|
||||||
Types<u32V, AIntV>(0_a, 0.0), //
|
Types<u32V, AIntV>(0_a, 0.0), //
|
||||||
Types<u32V, AIntV>(4294967295_a, 4294967295.0), //
|
Types<u32V, AIntV>(1_a, 1.0), //
|
||||||
|
Types<u32V, AIntV>(AInt(kHighestU32), kHighestU32), //
|
||||||
|
Types<u32V, AIntV>(AInt(kLowestU32), kLowestU32), //
|
||||||
Types<f32V, AFloatV>(0.0_a, 0.0), //
|
Types<f32V, AFloatV>(0.0_a, 0.0), //
|
||||||
Types<f32V, AFloatV>(AFloat(kMaxF32), kMaxF32), //
|
Types<f32V, AFloatV>(1.0_a, 1.0), //
|
||||||
Types<f32V, AFloatV>(AFloat(-kMaxF32), -kMaxF32), //
|
Types<f32V, AFloatV>(-1.0_a, -1.0), //
|
||||||
|
Types<f32V, AFloatV>(AFloat(kHighestF32), kHighestF32), //
|
||||||
|
Types<f32V, AFloatV>(AFloat(kLowestF32), kLowestF32), //
|
||||||
Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
|
Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
|
||||||
Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
|
Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
|
||||||
Types<f32V, AFloatV>(AFloat(-kSubnormalF32),
|
Types<f32V, AFloatV>(AFloat(-kSubnormalF32), -kSubnormalF32), //
|
||||||
-kSubnormalF32) //
|
|
||||||
/* Types<f16V, AFloatV>(1.0_a), */ //
|
/* Types<f16V, AFloatV>(1.0_a), */ //
|
||||||
/* Types<f16V, AFloatV>(1.0_a), */)));
|
/* Types<f16V, AFloatV>(1.0_a), */ //
|
||||||
|
})));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
MaterializeMatrix,
|
MaterializeMatrix,
|
||||||
MaterializeAbstractNumeric, //
|
MaterializeAbstractNumericToConcreteType,
|
||||||
testing::Combine(testing::Values(Expectation::kMaterialize), //
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
testing::ValuesIn(kMatrixMethods), //
|
testing::ValuesIn(kMatrixMethods),
|
||||||
testing::Values(Types<f32M, AFloatM>(0.0_a, 0.0), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
Types<f32M, AFloatM>(AFloat(kMaxF32), kMaxF32), //
|
Types<f32M, AFloatM>(0.0_a, 0.0), //
|
||||||
Types<f32M, AFloatM>(AFloat(-kMaxF32), -kMaxF32), //
|
Types<f32M, AFloatM>(1.0_a, 1.0), //
|
||||||
|
Types<f32M, AFloatM>(-1.0_a, -1.0), //
|
||||||
|
Types<f32M, AFloatM>(AFloat(kHighestF32), kHighestF32), //
|
||||||
|
Types<f32M, AFloatM>(AFloat(kLowestF32), kLowestF32), //
|
||||||
Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
|
Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
|
||||||
Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
|
Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
|
||||||
Types<f32M, AFloatM>(AFloat(-kSubnormalF32),
|
Types<f32M, AFloatM>(AFloat(-kSubnormalF32), -kSubnormalF32), //
|
||||||
-kSubnormalF32) //
|
|
||||||
/* Types<f16V, AFloatM>(1.0_a), */ //
|
/* Types<f16V, AFloatM>(1.0_a), */ //
|
||||||
)));
|
})));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(MaterializeSwitch,
|
||||||
MaterializeSwitch,
|
MaterializeAbstractNumericToConcreteType,
|
||||||
MaterializeAbstractNumeric, //
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
testing::Combine(testing::Values(Expectation::kMaterialize), //
|
testing::ValuesIn(kSwitchMethods),
|
||||||
testing::ValuesIn(kSwitchMethods), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
testing::Values(Types<i32, AInt>(0_a, 0.0), //
|
Types<i32, AInt>(0_a, 0.0), //
|
||||||
Types<i32, AInt>(2147483647_a, 2147483647.0), //
|
Types<i32, AInt>(1_a, 1.0), //
|
||||||
Types<i32, AInt>(-2147483648_a, -2147483648.0), //
|
Types<i32, AInt>(-1_a, -1.0), //
|
||||||
|
Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
|
||||||
|
Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
|
||||||
Types<u32, AInt>(0_a, 0.0), //
|
Types<u32, AInt>(0_a, 0.0), //
|
||||||
Types<u32, AInt>(4294967295_a, 4294967295.0))));
|
Types<u32, AInt>(1_a, 1.0), //
|
||||||
|
Types<u32, AInt>(AInt(kHighestU32), kHighestU32), //
|
||||||
|
Types<u32, AInt>(AInt(kLowestU32), kLowestU32), //
|
||||||
|
})));
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1504): Enable once we have abstract overloads of builtins / binary ops.
|
// TODO(crbug.com/tint/1504): Enable once we have abstract overloads of builtins / binary ops.
|
||||||
INSTANTIATE_TEST_SUITE_P(DISABLED_NoMaterialize,
|
INSTANTIATE_TEST_SUITE_P(DISABLED_NoMaterialize,
|
||||||
MaterializeAbstractNumeric, //
|
MaterializeAbstractNumericToConcreteType,
|
||||||
testing::Combine(testing::Values(Expectation::kNoMaterialize), //
|
testing::Combine(testing::Values(Expectation::kNoMaterialize),
|
||||||
testing::Values(Method::kBuiltinArg, //
|
testing::Values(Method::kBuiltinArg, Method::kBinaryOp),
|
||||||
Method::kBinaryOp), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
testing::Values(Types<AInt, AInt>(), //
|
Types<AInt, AInt>(), //
|
||||||
Types<AFloat, AFloat>(), //
|
Types<AFloat, AFloat>(), //
|
||||||
Types<AIntV, AIntV>(), //
|
Types<AIntV, AIntV>(), //
|
||||||
Types<AFloatV, AFloatV>(), //
|
Types<AFloatV, AFloatV>(), //
|
||||||
Types<AFloatM, AFloatM>())));
|
Types<AFloatM, AFloatM>(), //
|
||||||
INSTANTIATE_TEST_SUITE_P(InvalidCast,
|
})));
|
||||||
MaterializeAbstractNumeric, //
|
INSTANTIATE_TEST_SUITE_P(InvalidConversion,
|
||||||
testing::Combine(testing::Values(Expectation::kInvalidCast), //
|
MaterializeAbstractNumericToConcreteType,
|
||||||
testing::ValuesIn(kScalarMethods), //
|
testing::Combine(testing::Values(Expectation::kInvalidConversion),
|
||||||
testing::Values(Types<i32, AFloat>(), //
|
testing::ValuesIn(kScalarMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<i32, AFloat>(), //
|
||||||
Types<u32, AFloat>(), //
|
Types<u32, AFloat>(), //
|
||||||
Types<i32V, AFloatV>(), //
|
Types<i32V, AFloatV>(), //
|
||||||
Types<u32V, AFloatV>())));
|
Types<u32V, AFloatV>(), //
|
||||||
|
})));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(ScalarValueCannotBeRepresented,
|
||||||
ScalarValueCannotBeRepresented,
|
MaterializeAbstractNumericToConcreteType,
|
||||||
MaterializeAbstractNumeric, //
|
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
|
||||||
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented), //
|
testing::ValuesIn(kScalarMethods),
|
||||||
testing::ValuesIn(kScalarMethods), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
testing::Values(Types<i32, AInt>(0_a, 2147483648.0), //
|
Types<i32, AInt>(0_a, kHighestI32 + 1), //
|
||||||
Types<i32, AInt>(0_a, -2147483649.0), //
|
Types<i32, AInt>(0_a, kLowestI32 - 1), //
|
||||||
Types<u32, AInt>(0_a, 4294967296), //
|
Types<u32, AInt>(0_a, kHighestU32 + 1), //
|
||||||
Types<u32, AInt>(0_a, -1.0), //
|
Types<u32, AInt>(0_a, kLowestU32 - 1), //
|
||||||
Types<f32, AFloat>(0.0_a, 3.5e+38), //
|
Types<f32, AFloat>(0.0_a, kTooBigF32), //
|
||||||
Types<f32, AFloat>(0.0_a, -3.5e+38) //
|
Types<f32, AFloat>(0.0_a, -kTooBigF32), //
|
||||||
/* Types<f16, AFloat>(), */ //
|
/* Types<f16, AFloat>(), */ //
|
||||||
/* Types<f16, AFloat>(), */)));
|
/* Types<f16, AFloat>(), */ //
|
||||||
|
})));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(VectorValueCannotBeRepresented,
|
||||||
VectorValueCannotBeRepresented,
|
MaterializeAbstractNumericToConcreteType,
|
||||||
MaterializeAbstractNumeric, //
|
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
|
||||||
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented), //
|
testing::ValuesIn(kVectorMethods),
|
||||||
testing::ValuesIn(kVectorMethods), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
testing::Values(Types<i32V, AIntV>(0_a, 2147483648.0), //
|
Types<i32V, AIntV>(0_a, kHighestI32 + 1), //
|
||||||
Types<i32V, AIntV>(0_a, -2147483649.0), //
|
Types<i32V, AIntV>(0_a, kLowestI32 - 1), //
|
||||||
Types<u32V, AIntV>(0_a, 4294967296), //
|
Types<u32V, AIntV>(0_a, kHighestU32 + 1), //
|
||||||
Types<u32V, AIntV>(0_a, -1.0), //
|
Types<u32V, AIntV>(0_a, kLowestU32 - 1), //
|
||||||
Types<f32V, AFloatV>(0.0_a, 3.5e+38), //
|
Types<f32V, AFloatV>(0.0_a, kTooBigF32), //
|
||||||
Types<f32V, AFloatV>(0.0_a, -3.5e+38) //
|
Types<f32V, AFloatV>(0.0_a, -kTooBigF32), //
|
||||||
/* Types<f16V, AFloatV>(), */ //
|
/* Types<f16V, AFloatV>(), */ //
|
||||||
/* Types<f16V, AFloatV>(), */)));
|
/* Types<f16V, AFloatV>(), */ //
|
||||||
|
})));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(MatrixValueCannotBeRepresented,
|
||||||
|
MaterializeAbstractNumericToConcreteType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
|
||||||
|
testing::ValuesIn(kMatrixMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<f32M, AFloatM>(0.0_a, kTooBigF32), //
|
||||||
|
Types<f32M, AFloatM>(0.0_a, -kTooBigF32), //
|
||||||
|
/* Types<f16M, AFloatM>(), */ //
|
||||||
|
/* Types<f16M, AFloatM>(), */ //
|
||||||
|
})));
|
||||||
|
|
||||||
|
} // namespace materialize_abstract_numeric_to_concrete_type
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tests that in the absence of a 'target type' an abstract-int will materialize to i32, and an
|
||||||
|
// abstract-float will materialize to f32.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
namespace materialize_abstract_numeric_to_default_type {
|
||||||
|
|
||||||
|
// How should the materialization occur?
|
||||||
|
enum class Method {
|
||||||
|
// var a = abstract_expr;
|
||||||
|
kVar,
|
||||||
|
|
||||||
|
// let a = abstract_expr;
|
||||||
|
kLet,
|
||||||
|
|
||||||
|
// min(abstract_expr, abstract_expr);
|
||||||
|
kBuiltinArg,
|
||||||
|
|
||||||
|
// array<i32, abstract_expr>();
|
||||||
|
kArrayLength,
|
||||||
|
|
||||||
|
// switch (abstract_expr) {
|
||||||
|
// case abstract_expr: {}
|
||||||
|
// default: {}
|
||||||
|
// }
|
||||||
|
kSwitch,
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::ostream& operator<<(std::ostream& o, Method m) {
|
||||||
|
switch (m) {
|
||||||
|
case Method::kVar:
|
||||||
|
return o << "var";
|
||||||
|
case Method::kLet:
|
||||||
|
return o << "let";
|
||||||
|
case Method::kBuiltinArg:
|
||||||
|
return o << "builtin-arg";
|
||||||
|
case Method::kArrayLength:
|
||||||
|
return o << "array-length";
|
||||||
|
case Method::kSwitch:
|
||||||
|
return o << "switch";
|
||||||
|
}
|
||||||
|
return o << "<unknown>";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
std::string expected_type_name;
|
||||||
|
std::string expected_element_type_name;
|
||||||
|
builder::sem_type_func_ptr expected_sem_ty;
|
||||||
|
std::string abstract_type_name;
|
||||||
|
builder::ast_expr_func_ptr abstract_expr;
|
||||||
|
std::variant<AInt, AFloat> materialized_value;
|
||||||
|
double literal_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename EXPECTED_TYPE, typename ABSTRACT_TYPE, typename MATERIALIZED_TYPE>
|
||||||
|
Data Types(MATERIALIZED_TYPE materialized_value, double literal_value) {
|
||||||
|
using ExpectedDataType = builder::DataType<EXPECTED_TYPE>;
|
||||||
|
using AbstractDataType = builder::DataType<ABSTRACT_TYPE>;
|
||||||
|
using TargetElementDataType = builder::DataType<typename ExpectedDataType::ElementType>;
|
||||||
|
return {
|
||||||
|
ExpectedDataType::Name(), // expected_type_name
|
||||||
|
TargetElementDataType::Name(), // expected_element_type_name
|
||||||
|
ExpectedDataType::Sem, // expected_sem_ty
|
||||||
|
AbstractDataType::Name(), // abstract_type_name
|
||||||
|
AbstractDataType::Expr, // abstract_expr
|
||||||
|
materialized_value,
|
||||||
|
literal_value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::ostream& operator<<(std::ostream& o, const Data& c) {
|
||||||
|
auto print_value = [&](auto&& v) { o << v; };
|
||||||
|
o << "[" << c.expected_type_name << " <- " << c.abstract_type_name << "] [";
|
||||||
|
std::visit(print_value, c.materialized_value);
|
||||||
|
o << " <- " << c.literal_value << "]";
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
using MaterializeAbstractNumericToDefaultType =
|
||||||
|
resolver::ResolverTestWithParam<std::tuple<Expectation, Method, Data>>;
|
||||||
|
|
||||||
|
TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
|
||||||
|
// Once F16 is properly supported, we'll need to enable this:
|
||||||
|
// Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
const auto& param = GetParam();
|
||||||
|
const auto& expectation = std::get<0>(param);
|
||||||
|
const auto& method = std::get<1>(param);
|
||||||
|
const auto& data = std::get<2>(param);
|
||||||
|
|
||||||
|
ast::ExpressionList abstract_exprs;
|
||||||
|
auto abstract_expr = [&] {
|
||||||
|
auto* expr = data.abstract_expr(*this, data.literal_value);
|
||||||
|
abstract_exprs.emplace_back(expr);
|
||||||
|
return expr;
|
||||||
|
};
|
||||||
|
switch (method) {
|
||||||
|
case Method::kVar:
|
||||||
|
WrapInFunction(Decl(Var("a", nullptr, abstract_expr())));
|
||||||
|
break;
|
||||||
|
case Method::kLet:
|
||||||
|
WrapInFunction(Decl(Let("a", nullptr, abstract_expr())));
|
||||||
|
break;
|
||||||
|
case Method::kBuiltinArg:
|
||||||
|
WrapInFunction(CallStmt(Call("min", abstract_expr(), abstract_expr())));
|
||||||
|
break;
|
||||||
|
case Method::kArrayLength:
|
||||||
|
WrapInFunction(Construct(ty.array(ty.i32(), abstract_expr())));
|
||||||
|
break;
|
||||||
|
case Method::kSwitch:
|
||||||
|
WrapInFunction(Switch(abstract_expr(),
|
||||||
|
Case(abstract_expr()->As<ast::IntLiteralExpression>()),
|
||||||
|
DefaultCase()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto check_types_and_values = [&](const sem::Expression* expr) {
|
||||||
|
auto* expected_sem_ty = data.expected_sem_ty(*this);
|
||||||
|
|
||||||
|
EXPECT_TYPE(expr->Type(), expected_sem_ty);
|
||||||
|
EXPECT_TYPE(expr->ConstantValue().Type(), expected_sem_ty);
|
||||||
|
|
||||||
|
uint32_t num_elems = 0;
|
||||||
|
const sem::Type* expected_sem_el_ty = sem::Type::ElementOf(expected_sem_ty, &num_elems);
|
||||||
|
EXPECT_TYPE(expr->ConstantValue().ElementType(), expected_sem_el_ty);
|
||||||
|
expr->ConstantValue().WithElements([&](auto&& vec) {
|
||||||
|
using VEC_TY = std::decay_t<decltype(vec)>;
|
||||||
|
using EL_TY = typename VEC_TY::value_type;
|
||||||
|
ASSERT_TRUE(std::holds_alternative<EL_TY>(data.materialized_value));
|
||||||
|
VEC_TY expected(num_elems, std::get<EL_TY>(data.materialized_value));
|
||||||
|
EXPECT_EQ(vec, expected);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (expectation) {
|
||||||
|
case Expectation::kMaterialize: {
|
||||||
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
for (auto* expr : abstract_exprs) {
|
||||||
|
auto* materialize = Sem().Get<sem::Materialize>(expr);
|
||||||
|
ASSERT_NE(materialize, nullptr);
|
||||||
|
check_types_and_values(materialize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expectation::kInvalidConversion: {
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
std::string expect;
|
||||||
|
switch (method) {
|
||||||
|
case Method::kBuiltinArg:
|
||||||
|
expect = "error: no matching call to min(" + data.abstract_type_name + ", " +
|
||||||
|
data.abstract_type_name + ")";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expect = "error: cannot convert value of type '" + data.abstract_type_name +
|
||||||
|
"' to type '" + data.expected_type_name + "'";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
EXPECT_THAT(r()->error(), testing::StartsWith(expect));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expectation::kValueCannotBeRepresented:
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_THAT(r()->error(), testing::HasSubstr("cannot be represented as '" +
|
||||||
|
data.expected_element_type_name + "'"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FAIL() << "unhandled expectation: " << expectation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Methods that support scalar materialization
|
||||||
|
constexpr Method kScalarMethods[] = {
|
||||||
|
Method::kLet,
|
||||||
|
Method::kVar,
|
||||||
|
Method::kBuiltinArg,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Methods that support vector materialization
|
||||||
|
constexpr Method kVectorMethods[] = {
|
||||||
|
Method::kLet,
|
||||||
|
Method::kVar,
|
||||||
|
Method::kBuiltinArg,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Methods that support matrix materialization
|
||||||
|
constexpr Method kMatrixMethods[] = {
|
||||||
|
Method::kLet,
|
||||||
|
Method::kVar,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Methods that support materialization for switch cases
|
||||||
|
constexpr Method kSwitchMethods[] = {
|
||||||
|
Method::kSwitch,
|
||||||
|
};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
MatrixValueCannotBeRepresented,
|
MaterializeScalar,
|
||||||
MaterializeAbstractNumeric, //
|
MaterializeAbstractNumericToDefaultType,
|
||||||
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented), //
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
testing::ValuesIn(kMatrixMethods), //
|
testing::ValuesIn(kScalarMethods),
|
||||||
testing::Values(Types<f32M, AFloatM>(0.0_a, 3.5e+38), //
|
testing::ValuesIn(std::vector<Data>{
|
||||||
Types<f32M, AFloatM>(0.0_a, -3.5e+38) //
|
Types<i32, AInt>(0_a, 0.0), //
|
||||||
/* Types<f16M, AFloatM>(), */ //
|
Types<i32, AInt>(1_a, 1.0), //
|
||||||
/* Types<f16M, AFloatM>(), */)));
|
Types<i32, AInt>(-1_a, -1.0), //
|
||||||
|
Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
|
||||||
|
Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
|
||||||
|
Types<f32, AFloat>(0.0_a, 0.0), //
|
||||||
|
Types<f32, AFloat>(AFloat(kHighestF32), kHighestF32), //
|
||||||
|
Types<f32, AFloat>(AFloat(kLowestF32), kLowestF32), //
|
||||||
|
Types<f32, AFloat>(AFloat(kPiF32), kPiF64), //
|
||||||
|
Types<f32, AFloat>(AFloat(kSubnormalF32), kSubnormalF32), //
|
||||||
|
Types<f32, AFloat>(AFloat(-kSubnormalF32), -kSubnormalF32), //
|
||||||
|
})));
|
||||||
|
|
||||||
} // namespace MaterializeTests
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
MaterializeVector,
|
||||||
|
MaterializeAbstractNumericToDefaultType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
|
testing::ValuesIn(kVectorMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<i32V, AIntV>(0_a, 0.0), //
|
||||||
|
Types<i32V, AIntV>(1_a, 1.0), //
|
||||||
|
Types<i32V, AIntV>(-1_a, -1.0), //
|
||||||
|
Types<i32V, AIntV>(AInt(kHighestI32), kHighestI32), //
|
||||||
|
Types<i32V, AIntV>(AInt(kLowestI32), kLowestI32), //
|
||||||
|
Types<f32V, AFloatV>(0.0_a, 0.0), //
|
||||||
|
Types<f32V, AFloatV>(1.0_a, 1.0), //
|
||||||
|
Types<f32V, AFloatV>(-1.0_a, -1.0), //
|
||||||
|
Types<f32V, AFloatV>(AFloat(kHighestF32), kHighestF32), //
|
||||||
|
Types<f32V, AFloatV>(AFloat(kLowestF32), kLowestF32), //
|
||||||
|
Types<f32V, AFloatV>(AFloat(kPiF32), kPiF64), //
|
||||||
|
Types<f32V, AFloatV>(AFloat(kSubnormalF32), kSubnormalF32), //
|
||||||
|
Types<f32V, AFloatV>(AFloat(-kSubnormalF32), -kSubnormalF32), //
|
||||||
|
})));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
MaterializeMatrix,
|
||||||
|
MaterializeAbstractNumericToDefaultType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
|
testing::ValuesIn(kMatrixMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<f32M, AFloatM>(0.0_a, 0.0), //
|
||||||
|
Types<f32M, AFloatM>(1.0_a, 1.0), //
|
||||||
|
Types<f32M, AFloatM>(-1.0_a, -1.0), //
|
||||||
|
Types<f32M, AFloatM>(AFloat(kHighestF32), kHighestF32), //
|
||||||
|
Types<f32M, AFloatM>(AFloat(kLowestF32), kLowestF32), //
|
||||||
|
Types<f32M, AFloatM>(AFloat(kPiF32), kPiF64), //
|
||||||
|
Types<f32M, AFloatM>(AFloat(kSubnormalF32), kSubnormalF32), //
|
||||||
|
Types<f32M, AFloatM>(AFloat(-kSubnormalF32), -kSubnormalF32), //
|
||||||
|
})));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(MaterializeSwitch,
|
||||||
|
MaterializeAbstractNumericToDefaultType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kMaterialize),
|
||||||
|
testing::ValuesIn(kSwitchMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<i32, AInt>(0_a, 0.0), //
|
||||||
|
Types<i32, AInt>(AInt(kHighestI32), kHighestI32), //
|
||||||
|
Types<i32, AInt>(AInt(kLowestI32), kLowestI32), //
|
||||||
|
})));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(ScalarValueCannotBeRepresented,
|
||||||
|
MaterializeAbstractNumericToDefaultType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
|
||||||
|
testing::ValuesIn(kScalarMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<i32, AInt>(0_a, kHighestI32 + 1), //
|
||||||
|
Types<i32, AInt>(0_a, kLowestI32 - 1), //
|
||||||
|
Types<f32, AFloat>(0.0_a, kTooBigF32), //
|
||||||
|
Types<f32, AFloat>(0.0_a, -kTooBigF32), //
|
||||||
|
})));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(VectorValueCannotBeRepresented,
|
||||||
|
MaterializeAbstractNumericToDefaultType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
|
||||||
|
testing::ValuesIn(kVectorMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<i32V, AIntV>(0_a, kHighestI32 + 1), //
|
||||||
|
Types<i32V, AIntV>(0_a, kLowestI32 - 1), //
|
||||||
|
Types<i32V, AIntV>(0_a, kHighestU32 + 1), //
|
||||||
|
Types<f32V, AFloatV>(0.0_a, kTooBigF32), //
|
||||||
|
Types<f32V, AFloatV>(0.0_a, -kTooBigF32), //
|
||||||
|
})));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(MatrixValueCannotBeRepresented,
|
||||||
|
MaterializeAbstractNumericToDefaultType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
|
||||||
|
testing::ValuesIn(kMatrixMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<f32M, AFloatM>(0.0_a, kTooBigF32), //
|
||||||
|
Types<f32M, AFloatM>(0.0_a, -kTooBigF32), //
|
||||||
|
})));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(SwitchValueCannotBeRepresented,
|
||||||
|
MaterializeAbstractNumericToDefaultType,
|
||||||
|
testing::Combine(testing::Values(Expectation::kValueCannotBeRepresented),
|
||||||
|
testing::ValuesIn(kSwitchMethods),
|
||||||
|
testing::ValuesIn(std::vector<Data>{
|
||||||
|
Types<i32, AInt>(0_a, kHighestI32 + 1), //
|
||||||
|
Types<i32, AInt>(0_a, kLowestI32 - 1), //
|
||||||
|
})));
|
||||||
|
|
||||||
|
} // namespace materialize_abstract_numeric_to_default_type
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
|
|
@ -1145,7 +1145,7 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
|
||||||
auto i32v = [&](uint32_t width) { return builder_->create<sem::Vector>(i32(), width); };
|
auto i32v = [&](uint32_t width) { return builder_->create<sem::Vector>(i32(), width); };
|
||||||
auto f32v = [&](uint32_t width) { return builder_->create<sem::Vector>(f32(), width); };
|
auto f32v = [&](uint32_t width) { return builder_->create<sem::Vector>(f32(), width); };
|
||||||
auto f32m = [&](uint32_t columns, uint32_t rows) {
|
auto f32m = [&](uint32_t columns, uint32_t rows) {
|
||||||
return builder_->create<sem::Matrix>(f32v(columns), rows);
|
return builder_->create<sem::Matrix>(f32v(rows), columns);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type dispatch based on the expression type
|
// Type dispatch based on the expression type
|
||||||
|
|
Loading…
Reference in New Issue