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
12 changes: 12 additions & 0 deletions src/ir/constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,17 @@ std::optional<Constraint> approximateOrTermEqualPair(const Abstract::Op aOp,
if (aOp == Eq && bOp == GtS) {
return Constraint{GeS, term};
}
if (aOp == Eq && bOp == GtU) {
return Constraint{GeU, term};
}

// x > C || x >= C === x >= C
if (aOp == GtS && bOp == GeS) {
return Constraint{GeS, term};
}
if (aOp == GtU && bOp == GeU) {
return Constraint{GeU, term};
}

// TODO: all the rest

Expand All @@ -286,11 +292,17 @@ std::optional<Constraint> approximateOrAdjacentConstantPair(
if (aOp == Eq && bOp == GeS && !aConstant.isSignedMax()) {
return Constraint{GeS, {aConstant}};
}
if (aOp == Eq && bOp == GeU && !aConstant.isUnsignedMax()) {
return Constraint{GeU, {aConstant}};
}

// x > C || x >= C+1 === x > C, if C+1 does not overflow.
if (aOp == GtS && bOp == GeS && !aConstant.isSignedMax()) {
return Constraint{GtS, {aConstant}};
}
if (aOp == GtU && bOp == GeU && !aConstant.isUnsignedMax()) {
return Constraint{GtU, {aConstant}};
}

// TODO: all the rest

Expand Down
65 changes: 63 additions & 2 deletions test/gtest/constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,12 @@ TEST(ConstraintTest, TestOrLoop) {
checkOr(leftNe, right, empty);

// Change the GtS on the right to GtU:
// { x == 5 } || { x >U 5 && x <= 42 } ==> { x <= 42 }
// { x == 5 } || { x >U 5 && x <= 42 } ==> { x >=U 5 && x <= 42 }
AndedConstraintSet rightGtU(
{{GtU, {Literal(int32_t(5))}}, {LeS, {Literal(int32_t(42))}}});
checkOr(left, rightGtU, rightOnly42);
AndedConstraintSet resultMixed(
{{GeU, {Literal(int32_t(5))}}, {LeS, {Literal(int32_t(42))}}});
checkOr(left, rightGtU, resultMixed);

// Change the LeS on the right to LeU:
// { x == 5 } || { x > 5 && x <=U 42 } ==> { x >= 5 && x <=U 42 }
Expand All @@ -373,6 +375,65 @@ TEST(ConstraintTest, TestOrLoop) {
checkOr(left, rightAdded, resultAdded);
}

TEST(ConstraintTest, TestOrLoopUnsigned) {
// As above, but unsigned.

// { x == 5 } || { x > 5 && x <= 42 } ==> { x >= 5 && x <= 42 }
AndedConstraintSet left{{Eq, {Literal(int32_t(5))}}};
AndedConstraintSet right(
{{GtU, {Literal(int32_t(5))}}, {LeU, {Literal(int32_t(42))}}});
AndedConstraintSet result(
{{GeU, {Literal(int32_t(5))}}, {LeU, {Literal(int32_t(42))}}});
checkOr(left, right, result);

// Changes to constants:

// Change 5 on the left to 7:
// { x == 7 } || { x > 5 && x <= 42 } ==> { x > 5 && x <= 42}
AndedConstraintSet left7{{Eq, {Literal(int32_t(7))}}};
checkOr(left7, right, right);

// Change 5 on the left to 99:
// { x == 99 } || { x > 5 && x <= 42 } ==> { x > 5 }
// TODO: we could emit a range (5, 99]
AndedConstraintSet left99{{Eq, {Literal(int32_t(99))}}};
AndedConstraintSet rightOnly5{{GtU, {Literal(int32_t(5))}}};
checkOr(left99, right, rightOnly5);

// Change 5 on the left to 4:
// { x == 4 } || { x > 5 && x <= 42 } ==> { x <= 42 }
// TODO: we could emit a range [4, 42]
AndedConstraintSet left4{{Eq, {Literal(int32_t(4))}}};
AndedConstraintSet rightOnly42({{LeU, {Literal(int32_t(42))}}});
checkOr(left4, right, rightOnly42);

// Change 5 on the right to 6:
// { x == 5 } || { x > 6 && x <= 42 } ==> { x <= 42 }
AndedConstraintSet right6(
{{GtU, {Literal(int32_t(6))}}, {LeU, {Literal(int32_t(42))}}});
checkOr(left, right6, rightOnly42);

// Changes to operations:

// Change the Eq on the left to Ne. We fail to find anything for the OR.
// { x != 5 } || { x > 5 && x <= 42 } ==> {}
// TODO: we could emit x != 5
AndedConstraintSet leftNe{{Ne, {Literal(int32_t(5))}}};
auto empty = AndedConstraintSet::makeProvesNothing();
checkOr(leftNe, right, empty);

// Add an operation on the right, x != 21:
// { x == 5 } || { x > 5 && x <= 42 && x != 21 } ==>
// { x >= 5 && x <= 42 && x != 21 }
AndedConstraintSet rightAdded({{GtU, {Literal(int32_t(5))}},
{LeU, {Literal(int32_t(42))}},
{Ne, {Literal(int32_t(21))}}});
AndedConstraintSet resultAdded({{GeU, {Literal(int32_t(5))}},
{LeU, {Literal(int32_t(42))}},
{Ne, {Literal(int32_t(21))}}});
checkOr(left, rightAdded, resultAdded);
}

static void checkAnd(const AndedConstraintSet& a,
const AndedConstraintSet& b,
const AndedConstraintSet& result) {
Expand Down
Loading