Add const-eval for min and max

This CL adds const-eval for `min` and `max`.

Bug: tint:1581
Change-Id: Ica68ba312f21767c46d57d83570ddc72ee857231
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/110166
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
dan sinclair
2022-11-15 18:39:38 +00:00
committed by Dawn LUCI CQ
parent 6924d6e903
commit acce83d109
382 changed files with 13549 additions and 4810 deletions

View File

@@ -2119,6 +2119,30 @@ ConstEval::Result ConstEval::insertBits(const sem::Type* ty,
return TransformElements(builder, ty, transform, args[0], args[1]);
}
ConstEval::Result ConstEval::max(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source&) {
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
auto create = [&](auto e0, auto e1) {
return CreateElement(builder, c0->Type(), decltype(e0)(std::max(e0, e1)));
};
return Dispatch_fia_fiu32_f16(create, c0, c1);
};
return TransformElements(builder, ty, transform, args[0], args[1]);
}
ConstEval::Result ConstEval::min(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source&) {
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
auto create = [&](auto e0, auto e1) {
return CreateElement(builder, c0->Type(), decltype(e0)(std::min(e0, e1)));
};
return Dispatch_fia_fiu32_f16(create, c0, c1);
};
return TransformElements(builder, ty, transform, args[0], args[1]);
}
ConstEval::Result ConstEval::pack2x16float(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source& source) {

View File

@@ -584,6 +584,24 @@ class ConstEval {
utils::VectorRef<const sem::Constant*> args,
const Source& source);
/// max builtin
/// @param ty the expression type
/// @param args the input arguments
/// @param source the source location of the conversion
/// @return the result value, or null if the value cannot be calculated
Result max(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source& source);
/// min builtin
/// @param ty the expression type
/// @param args the input arguments
/// @param source the source location of the conversion
/// @return the result value, or null if the value cannot be calculated
Result min(const sem::Type* ty, // NOLINT(build/include_what_you_use) -- confused by min
utils::VectorRef<const sem::Constant*> args,
const Source& source);
/// pack2x16float builtin
/// @param ty the expression type
/// @param args the input arguments

View File

@@ -1291,6 +1291,60 @@ INSTANTIATE_TEST_SUITE_P(ExtractBits,
std::make_tuple(1, u32::Highest()), //
std::make_tuple(u32::Highest(), u32::Highest())));
template <typename T>
std::vector<Case> MaxCases() {
return {
C({T(0), T(0)}, T(0)),
C({T(0), T::Highest()}, T::Highest()),
C({T::Lowest(), T(0)}, T(0)),
C({T::Highest(), T::Lowest()}, T::Highest()),
C({T::Highest(), T::Highest()}, T::Highest()),
C({T::Lowest(), T::Lowest()}, T::Lowest()),
// Vector tests
C({Vec(T(0), T(0)), Vec(T(0), T(42))}, Vec(T(0), T(42))),
C({Vec(T::Lowest(), T(0)), Vec(T(0), T::Lowest())}, Vec(T(0), T(0))),
C({Vec(T::Lowest(), T::Highest()), Vec(T::Highest(), T::Lowest())},
Vec(T::Highest(), T::Highest())),
};
}
INSTANTIATE_TEST_SUITE_P( //
Max,
ResolverConstEvalBuiltinTest,
testing::Combine(testing::Values(sem::BuiltinType::kMax),
testing::ValuesIn(Concat(MaxCases<AInt>(), //
MaxCases<i32>(),
MaxCases<u32>(),
MaxCases<AFloat>(),
MaxCases<f32>(),
MaxCases<f16>()))));
template <typename T>
std::vector<Case> MinCases() {
return {C({T(0), T(0)}, T(0)), //
C({T(0), T(42)}, T(0)), //
C({T::Lowest(), T(0)}, T::Lowest()), //
C({T(0), T::Highest()}, T(0)), //
C({T::Highest(), T::Lowest()}, T::Lowest()),
C({T::Highest(), T::Highest()}, T::Highest()),
C({T::Lowest(), T::Lowest()}, T::Lowest()),
// Vector tests
C({Vec(T(0), T(0)), Vec(T(0), T(42))}, Vec(T(0), T(0))),
C({Vec(T::Lowest(), T(0), T(1)), Vec(T(0), T(42), T::Highest())},
Vec(T::Lowest(), T(0), T(1)))};
}
INSTANTIATE_TEST_SUITE_P( //
Min,
ResolverConstEvalBuiltinTest,
testing::Combine(testing::Values(sem::BuiltinType::kMin),
testing::ValuesIn(Concat(MinCases<AInt>(), //
MinCases<i32>(),
MinCases<u32>(),
MinCases<AFloat>(),
MinCases<f32>(),
MinCases<f16>()))));
std::vector<Case> Pack4x8snormCases() {
return {
C({Vec(f32(0), f32(0), f32(0), f32(0))}, Val(u32(0x0000'0000))),

File diff suppressed because it is too large Load Diff

View File

@@ -472,8 +472,13 @@ constexpr Method kSwitchMethods[] = {
constexpr Method kNoMaterializeMethods[] = {
Method::kPhonyAssign, //
Method::kBinaryOp,
// TODO(crbug.com/tint/1504): Enable once "min" supports const evaluation
// Method::kBuiltinArg,
};
/// Methods that do not materialize
constexpr Method kNoMaterializeScalarVectorMethods[] = {
Method::kPhonyAssign, //
Method::kBinaryOp,
Method::kBuiltinArg,
};
INSTANTIATE_TEST_SUITE_P(
MaterializeScalar,
@@ -697,6 +702,17 @@ INSTANTIATE_TEST_SUITE_P(NoMaterialize,
Types<AFloatM, AFloatM>(1.0_a, 1.0_a), //
})));
INSTANTIATE_TEST_SUITE_P(NoMaterializeScalarVector,
MaterializeAbstractNumericToConcreteType,
testing::Combine(testing::Values(Expectation::kNoMaterialize),
testing::ValuesIn(kNoMaterializeScalarVectorMethods),
testing::ValuesIn(std::vector<Data>{
Types<AInt, AInt>(1_a, 1_a), //
Types<AIntV, AIntV>(1_a, 1_a), //
Types<AFloat, AFloat>(1.0_a, 1.0_a), //
Types<AFloatV, AFloatV>(1.0_a, 1.0_a), //
})));
INSTANTIATE_TEST_SUITE_P(InvalidConversion,
MaterializeAbstractNumericToConcreteType,
testing::Combine(testing::Values(Expectation::kInvalidConversion),
@@ -771,9 +787,6 @@ enum class Method {
// let a = abstract_expr;
kLet,
// min(abstract_expr, abstract_expr)
kBuiltinArg,
// bitcast<f32>(abstract_expr)
kBitcastF32Arg,
@@ -810,8 +823,6 @@ static std::ostream& operator<<(std::ostream& o, Method m) {
return o << "var";
case Method::kLet:
return o << "let";
case Method::kBuiltinArg:
return o << "builtin-arg";
case Method::kBitcastF32Arg:
return o << "bitcast-f32-arg";
case Method::kBitcastVec3F32Arg:
@@ -890,10 +901,6 @@ TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
WrapInFunction(Decl(Let("a", abstract_expr())));
break;
}
case Method::kBuiltinArg: {
WrapInFunction(CallStmt(Call("min", abstract_expr(), abstract_expr())));
break;
}
case Method::kBitcastF32Arg: {
WrapInFunction(Bitcast<f32>(abstract_expr()));
break;
@@ -949,17 +956,8 @@ TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
}
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;
}
std::string expect = "error: cannot convert value of type '" + data.abstract_type_name +
"' to type '" + data.expected_type_name + "'";
EXPECT_THAT(r()->error(), testing::StartsWith(expect));
break;
}
@@ -977,16 +975,17 @@ TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
constexpr Method kScalarMethods[] = {
Method::kLet,
Method::kVar,
Method::kBuiltinArg,
Method::kBitcastF32Arg,
Method::kTintMaterializeBuiltin,
};
/// Methods that support vector materialization
constexpr Method kVectorMethods[] = {
Method::kLet, Method::kVar,
Method::kBuiltinArg, Method::kBitcastVec3F32Arg,
Method::kRuntimeIndex, Method::kTintMaterializeBuiltin,
Method::kLet,
Method::kVar,
Method::kBitcastVec3F32Arg,
Method::kRuntimeIndex,
Method::kTintMaterializeBuiltin,
};
/// Methods that support matrix materialization