tint: implement short-circuiting of const eval bitcast

Bug: tint:1581
Change-Id: I6058dee593bf97f9dee202a80ced7b2551da0ba9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/115220
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
Antonio Maiorano 2022-12-21 21:15:03 +00:00
parent bf9c34642a
commit bc44620d68
5 changed files with 42 additions and 39 deletions

View File

@ -1330,13 +1330,10 @@ ConstEval::Result ConstEval::Swizzle(const type::Type* ty,
return builder.create<constant::Composite>(ty, std::move(values)); return builder.create<constant::Composite>(ty, std::move(values));
} }
ConstEval::Result ConstEval::Bitcast(const type::Type* ty, const sem::Expression* expr) { ConstEval::Result ConstEval::Bitcast(const type::Type* ty,
auto* value = expr->ConstantValue(); const constant::Value* value,
if (!value) { const Source& source) {
return nullptr;
}
auto* el_ty = type::Type::DeepestElementOf(ty); auto* el_ty = type::Type::DeepestElementOf(ty);
auto& source = expr->Declaration()->source;
auto transform = [&](const constant::Value* c0) { auto transform = [&](const constant::Value* c0) {
auto create = [&](auto e) { auto create = [&](auto e) {
return Switch( return Switch(

View File

@ -80,10 +80,11 @@ class ConstEval {
Result ArrayOrStructInit(const type::Type* ty, utils::VectorRef<const sem::Expression*> args); Result ArrayOrStructInit(const type::Type* ty, utils::VectorRef<const sem::Expression*> args);
/// @param ty the target type /// @param ty the target type
/// @param expr the input expression /// @param value the value being converted
/// @param source the source location
/// @return the bit-cast of the given expression to the given type, or null if the value cannot /// @return the bit-cast of the given expression to the given type, or null if the value cannot
/// be calculated /// be calculated
Result Bitcast(const type::Type* ty, const sem::Expression* expr); Result Bitcast(const type::Type* ty, const constant::Value* value, const Source& source);
/// @param obj the object being indexed /// @param obj the object being indexed
/// @param idx the index expression /// @param idx the index expression

View File

@ -1775,8 +1775,7 @@ TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Error_Index) {
// Short-Circuit Bitcast // Short-Circuit Bitcast
//////////////////////////////////////////////// ////////////////////////////////////////////////
// @TODO(crbug.com/tint/1581): Enable once const eval of bitcast is implemented TEST_F(ResolverConstEvalTest, ShortCircuit_And_Invalid_Bitcast) {
TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_And_Invalid_Bitcast) {
// const one = 1; // const one = 1;
// const a = 0x7F800000; // const a = 0x7F800000;
// const result = (one == 0) && (bitcast<f32>(a) == 0.0); // const result = (one == 0) && (bitcast<f32>(a) == 0.0);
@ -1791,8 +1790,7 @@ TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_And_Invalid_Bitcast) {
ValidateAnd(Sem(), binary); ValidateAnd(Sem(), binary);
} }
// @TODO(crbug.com/tint/1581): Enable once const eval of bitcast is implemented TEST_F(ResolverConstEvalTest, NonShortCircuit_And_Invalid_Bitcast) {
TEST_F(ResolverConstEvalTest, DISABLED_NonShortCircuit_And_Invalid_Bitcast) {
// const one = 1; // const one = 1;
// const a = 0x7F800000; // const a = 0x7F800000;
// const result = (one == 1) && (bitcast<f32>(a) == 0.0); // const result = (one == 1) && (bitcast<f32>(a) == 0.0);
@ -1804,11 +1802,10 @@ TEST_F(ResolverConstEvalTest, DISABLED_NonShortCircuit_And_Invalid_Bitcast) {
GlobalConst("result", binary); GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: value not representable as f32 message here"); EXPECT_EQ(r()->error(), "12:34 error: value inf cannot be represented as 'f32'");
} }
// @TODO(crbug.com/tint/1581): Enable once const eval of bitcast is implemented TEST_F(ResolverConstEvalTest, ShortCircuit_And_Error_Bitcast) {
TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_And_Error_Bitcast) {
// const one = 1; // const one = 1;
// const a = 0x7F800000; // const a = 0x7F800000;
// const result = (one == 0) && (bitcast<f32>(a) == 0i); // const result = (one == 0) && (bitcast<f32>(a) == 0i);
@ -1820,11 +1817,15 @@ TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_And_Error_Bitcast) {
GlobalConst("result", binary); GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload message here)"); EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for operator == (f32, i32)
2 candidate operators:
operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
)");
} }
// @TODO(crbug.com/tint/1581): Enable once const eval of bitcast is implemented TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Invalid_Bitcast) {
TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_Or_Invalid_Bitcast) {
// const one = 1; // const one = 1;
// const a = 0x7F800000; // const a = 0x7F800000;
// const result = (one == 1) || (bitcast<f32>(a) == 0.0); // const result = (one == 1) || (bitcast<f32>(a) == 0.0);
@ -1839,8 +1840,7 @@ TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_Or_Invalid_Bitcast) {
ValidateOr(Sem(), binary); ValidateOr(Sem(), binary);
} }
// @TODO(crbug.com/tint/1581): Enable once const eval of bitcast is implemented TEST_F(ResolverConstEvalTest, NonShortCircuit_Or_Invalid_Bitcast) {
TEST_F(ResolverConstEvalTest, DISABLED_NonShortCircuit_Or_Invalid_Bitcast) {
// const one = 1; // const one = 1;
// const a = 0x7F800000; // const a = 0x7F800000;
// const result = (one == 0) || (bitcast<f32>(a) == 0.0); // const result = (one == 0) || (bitcast<f32>(a) == 0.0);
@ -1852,11 +1852,10 @@ TEST_F(ResolverConstEvalTest, DISABLED_NonShortCircuit_Or_Invalid_Bitcast) {
GlobalConst("result", binary); GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: value not representable as f32 message here"); EXPECT_EQ(r()->error(), "12:34 error: value inf cannot be represented as 'f32'");
} }
// @TODO(crbug.com/tint/1581): Enable once const eval of bitcast is implemented TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Error_Bitcast) {
TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_Or_Error_Bitcast) {
// const one = 1; // const one = 1;
// const a = 0x7F800000; // const a = 0x7F800000;
// const result = (one == 1) || (bitcast<f32>(a) == 0i); // const result = (one == 1) || (bitcast<f32>(a) == 0i);
@ -1868,7 +1867,12 @@ TEST_F(ResolverConstEvalTest, DISABLED_ShortCircuit_Or_Error_Bitcast) {
GlobalConst("result", binary); GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload message here)"); EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for operator == (f32, i32)
2 candidate operators:
operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
)");
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////

View File

@ -67,7 +67,7 @@ TEST_P(ResolverConstEvalBitcastTest, Test) {
auto* target_ty = target_create_ptrs.ast(*this); auto* target_ty = target_create_ptrs.ast(*this);
ASSERT_NE(target_ty, nullptr); ASSERT_NE(target_ty, nullptr);
auto* input_val = input.Expr(*this); auto* input_val = input.Expr(*this);
const ast::Expression* expr = Bitcast(target_ty, input_val); const ast::Expression* expr = Bitcast(Source{{12, 34}}, target_ty, input_val);
WrapInFunction(expr); WrapInFunction(expr);
@ -87,6 +87,7 @@ TEST_P(ResolverConstEvalBitcastTest, Test) {
EXPECT_EQ(expected_values, got_values); EXPECT_EQ(expected_values, got_values);
} else { } else {
ASSERT_FALSE(r()->Resolve()); ASSERT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), testing::StartsWith("12:34 error:"));
EXPECT_THAT(r()->error(), testing::HasSubstr("cannot be represented as")); EXPECT_THAT(r()->error(), testing::HasSubstr("cannot be represented as"));
} }
} }

View File

@ -1960,24 +1960,24 @@ sem::Expression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
if (!validator_.Bitcast(expr, ty)) { if (!validator_.Bitcast(expr, ty)) {
return nullptr; return nullptr;
} }
//
const constant::Value* val = nullptr; auto stage = inner->Stage();
sem::EvaluationStage stage = sem::EvaluationStage::kRuntime; if (stage == sem::EvaluationStage::kConstant && skip_const_eval_.Contains(expr)) {
// TODO(crbug.com/tint/1582): short circuit 'expr' once const eval of Bitcast is implemented. stage = sem::EvaluationStage::kNotEvaluated;
if (auto r = const_eval_.Bitcast(ty, inner)) {
val = r.Get();
if (val) {
stage = sem::EvaluationStage::kConstant;
} }
const constant::Value* value = nullptr;
if (stage == sem::EvaluationStage::kConstant) {
if (auto r = const_eval_.Bitcast(ty, inner->ConstantValue(), expr->source)) {
value = r.Get();
} else { } else {
return nullptr; return nullptr;
} }
}
auto* sem = builder_->create<sem::Expression>(expr, ty, stage, current_statement_, auto* sem = builder_->create<sem::Expression>(expr, ty, stage, current_statement_,
std::move(val), inner->HasSideEffects()); std::move(value), inner->HasSideEffects());
sem->Behaviors() = inner->Behaviors(); sem->Behaviors() = inner->Behaviors();
return sem; return sem;
} }