Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/IROperator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ bool is_const(const Expr &e, int64_t value) {
} else if (const FloatImm *i = e.as<FloatImm>()) {
return i->value == value;
} else if (const Cast *c = e.as<Cast>()) {
return is_const(c->value, value);
return c->type.can_represent(value) &&
is_const(c->value, value);
} else if (const Broadcast *b = e.as<Broadcast>()) {
return is_const(b->value, value);
} else {
Expand Down
23 changes: 23 additions & 0 deletions test/correctness/solve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,28 @@ void test_positive_const_multiplier_still_rewritten() {
(x != 2) || (Mod::make(seven, three) != 0));
}

// IROperator::is_const(e, -1) used to ignore signedness in casts. When `c`
// was a cast from `-1` to uint8, Solve.cpp's `f(x) * c cmp b` rewrite for
// `c == -1` treated `c` as -1 rather than the correct value (255).
void test_cast_signedness_respected() {
// int32(uint8(-1_i8)) == 255, not -1.
Expr fake_negative_one = Cast::make(Int(32), Cast::make(UInt(8), -1));

// Let N = fake_negative_one.
// Broken: y < N * x ~> x < -y ~> 1 < -100 ~> false
// Fixed: y < N * x ~> x * N > y ~> 1 * 255 > 100 ~> true
std::map<std::string, Expr> vars{
{"x", Expr(1)},
{"y", Expr(100)},
};
check_solve_equivalent(y < fake_negative_one * x, vars);
check_solve_equivalent(y <= fake_negative_one * x, vars);
check_solve_equivalent(y > fake_negative_one * x, vars);
check_solve_equivalent(y >= fake_negative_one * x, vars);
check_solve_equivalent(y == fake_negative_one * x, vars);
check_solve_equivalent(y != fake_negative_one * x, vars);
}

// Solver used to rewrite `f(x) + f(x) -> f(x) * 2` via `operator*(Expr, int)`,
// which rejects constants that don't fit in the expression type. For UInt(1),
// the literal 2 isn't representable, aborting the whole solve. Use Mul::make
Expand Down Expand Up @@ -610,6 +632,7 @@ int main(int argc, char **argv) {
test_unsigned_equality_still_rearranged();
test_nonconstant_multiplier_not_rewritten();
test_positive_const_multiplier_still_rewritten();
test_cast_signedness_respected();
test_solve_does_not_abort_on_narrow_self_add();
test_narrow_div_add_equivalence();
test_simplify_preserves_float_to_uint_cast_chain();
Expand Down
Loading