-
Notifications
You must be signed in to change notification settings - Fork 12.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[InstCombine] Fold A == MIN_INT ? B != MIN_INT : A < B
to A < B
#120177
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-analysis Author: Veera (veera-sivarajan) ChangesThis PR simplifies: Proof: https://alive2.llvm.org/ce/z/bR6E2s This helps in optimizing comparison of optional unsigned non-zero types in rust-lang/rust#49892. Rust compiler's current output: https://rust.godbolt.org/z/9fxfq3Gn8 Full diff: https://github.com/llvm/llvm-project/pull/120177.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 3325cd972cf1eb..fcbaaafe69ec48 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4608,6 +4608,45 @@ static Value *simplifySelectWithEquivalence(Value *CmpLHS, Value *CmpRHS,
return nullptr;
}
+/// `A == MIN_INT ? B != MIN_INT : A < B` --> `A < B`
+/// `A == MAX_INT ? B != MAX_INT : A > B` --> `A > B`
+static Value *foldSelectWithExtremeEqCond(Value *CmpLHS, Value *CmpRHS,
+ Value *TrueVal, Value *FalseVal) {
+ CmpPredicate Pred;
+ Value *A, *B;
+
+ if (!match(FalseVal, m_ICmp(Pred, m_Value(A), m_Value(B))))
+ return nullptr;
+
+ // make sure `CmpLHS` is on the LHS of `FalseVal`.
+ if (match(CmpLHS, m_Specific(B))) {
+ std::swap(A, B);
+ Pred = CmpInst::getSwappedPredicate(Pred);
+ }
+
+ APInt C;
+ unsigned NumBits = A->getType()->getScalarSizeInBits();
+
+ if (ICmpInst::isLT(Pred)) {
+ C = CmpInst::isSigned(Pred) ? APInt::getSignedMinValue(NumBits)
+ : APInt::getMinValue(NumBits);
+ } else if (ICmpInst::isGT(Pred)) {
+ C = CmpInst::isSigned(Pred) ? APInt::getSignedMaxValue(NumBits)
+ : APInt::getMaxValue(NumBits);
+ } else {
+ return nullptr;
+ }
+
+ if (!match(CmpLHS, m_Specific(A)) || !match(CmpRHS, m_SpecificInt(C)))
+ return nullptr;
+
+ if (!match(TrueVal, m_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(B),
+ m_SpecificInt(C))))
+ return nullptr;
+
+ return FalseVal;
+}
+
/// Try to simplify a select instruction when its condition operand is an
/// integer comparison.
static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
@@ -4728,6 +4767,10 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
Q, MaxRecurse))
return V;
}
+
+ if (Value *V =
+ foldSelectWithExtremeEqCond(CmpLHS, CmpRHS, TrueVal, FalseVal))
+ return V;
}
return nullptr;
@@ -7141,7 +7184,6 @@ static Value *simplifyInstructionWithOperands(Instruction *I,
NewOps[1], I->getFastMathFlags(), Q, MaxRecurse);
case Instruction::Select:
return simplifySelectInst(NewOps[0], NewOps[1], NewOps[2], Q, MaxRecurse);
- break;
case Instruction::GetElementPtr: {
auto *GEPI = cast<GetElementPtrInst>(I);
return simplifyGEPInst(GEPI->getSourceElementType(), NewOps[0],
diff --git a/llvm/test/Transforms/InstSimplify/select-with-extreme-eq-cond.ll b/llvm/test/Transforms/InstSimplify/select-with-extreme-eq-cond.ll
new file mode 100644
index 00000000000000..3fa9468035cb7a
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/select-with-extreme-eq-cond.ll
@@ -0,0 +1,360 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @compare_unsigned_min(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_unsigned_min(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP2]]
+;
+start:
+ %2 = icmp eq i8 %0, 0
+ %3 = icmp ne i8 %1, 0
+ %4 = icmp ult i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_signed_min(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_signed_min(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp eq i8 %0, -128
+ %3 = icmp ne i8 %1, -128
+ %4 = icmp slt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_unsigned_max(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_unsigned_max(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp eq i8 %0, 255
+ %3 = icmp ne i8 %1, 255
+ %4 = icmp ugt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_signed_max(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_signed_max(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp eq i8 %0, 127
+ %3 = icmp ne i8 %1, 127
+ %4 = icmp sgt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @relational_cmp_unsigned_min(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @relational_cmp_unsigned_min(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp ule i8 %0, 0
+ %3 = icmp ugt i8 %1, 0
+ %4 = icmp ult i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @relational_cmp_signed_min(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @relational_cmp_signed_min(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp sle i8 %0, -128
+ %3 = icmp sgt i8 %1, -128
+ %4 = icmp slt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @relational_cmp_unsigned_max(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @relational_cmp_unsigned_max(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp uge i8 %0, 255
+ %3 = icmp ult i8 %1, 255
+ %4 = icmp ugt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @relational_cmp_signed_max(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @relational_cmp_signed_max(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp sge i8 %0, 127
+ %3 = icmp slt i8 %1, 127
+ %4 = icmp sgt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+declare void @use(i1)
+
+define i1 @compare_signed_max_multiuse(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_signed_max_multiuse(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: call void @use(i1 [[TMP4]])
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp eq i8 %0, 127
+ %3 = icmp ne i8 %1, 127
+ %4 = icmp sgt i8 %0, %1
+ call void @use(i1 %4)
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_signed_min_samesign(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_signed_min_samesign(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp samesign slt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp eq i8 %0, -128
+ %3 = icmp ne i8 %1, -128
+ %4 = icmp samesign slt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_flipped(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_flipped(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i8 [[TMP1]], [[TMP0]]
+; CHECK-NEXT: ret i1 [[TMP4]]
+;
+start:
+ %2 = icmp eq i8 %0, 0
+ %3 = icmp ne i8 %1, 0
+ %4 = icmp ugt i8 %1, %0
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_swapped(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_swapped(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = icmp ult i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ %2 = icmp ne i8 %0, 0
+ %3 = icmp ne i8 %1, 0
+ %4 = icmp ult i8 %0, %1
+ %result = select i1 %2, i1 %4, i1 %3
+ ret i1 %result
+}
+
+define i1 @compare_swapped_flipped_unsigned_max(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_swapped_flipped_unsigned_max(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[TMP0]]
+; CHECK-NEXT: ret i1 [[TMP2]]
+;
+start:
+ %2 = icmp ne i8 %0, 255
+ %3 = icmp ne i8 %1, 255
+ %4 = icmp ult i8 %1, %0
+ %result = select i1 %2, i1 %4, i1 %3
+ ret i1 %result
+}
+
+define i1 @compare_unsigned_min_illegal_type(i9 %0, i9 %1) {
+; CHECK-LABEL: define i1 @compare_unsigned_min_illegal_type(
+; CHECK-SAME: i9 [[TMP0:%.*]], i9 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i9 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[TMP2]]
+;
+start:
+ %2 = icmp eq i9 %0, 0
+ %3 = icmp ne i9 %1, 0
+ %4 = icmp ult i9 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define <2 x i1> @compare_vector(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: define <2 x i1> @compare_vector(
+; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult <2 x i8> [[X]], [[Y]]
+; CHECK-NEXT: ret <2 x i1> [[TMP1]]
+;
+ %2 = icmp eq <2 x i8> %x, <i8 0, i8 0>
+ %3 = icmp ne <2 x i8> %y, <i8 0, i8 0>
+ %4 = icmp ult <2 x i8> %x, %y
+ %result = select <2 x i1> %2, <2 x i1> %3, <2 x i1> %4
+ ret <2 x i1> %result
+}
+
+define i1 @compare_float_negative(half %0, half %1) {
+; CHECK-LABEL: define i1 @compare_float_negative(
+; CHECK-SAME: half [[TMP0:%.*]], half [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = fcmp oeq half [[TMP0]], 0xH0000
+; CHECK-NEXT: [[TMP3:%.*]] = fcmp one half [[TMP1]], 0xH0000
+; CHECK-NEXT: [[TMP4:%.*]] = fcmp ult half [[TMP0]], [[TMP1]]
+; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 [[TMP4]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ %2 = fcmp oeq half %0, 0.0
+ %3 = fcmp one half %1, 0.0
+ %4 = fcmp ult half %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_unsigned_max_swapped_lhs_rhs_negative(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_unsigned_max_swapped_lhs_rhs_negative(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP0]], -1
+; CHECK-NEXT: [[DOTNOT:%.*]] = icmp ne i8 [[TMP1]], -1
+; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[DOTNOT]], i1 [[TMP2]], i1 false
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ %2 = icmp eq i8 %0, 255
+ %3 = icmp ne i8 %1, 255
+ %4 = icmp ugt i8 %0, %1
+ %result = select i1 %3, i1 %2, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_signed_min_negative(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_signed_min_negative(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP0]], -127
+; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP1]], -127
+; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 [[TMP4]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ %2 = icmp eq i8 %0, -127
+ %3 = icmp ne i8 %1, -127
+ %4 = icmp slt i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_unsigned_max_negative(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_unsigned_max_negative(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP0]], -1
+; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP1]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 [[TMP4]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ %2 = icmp eq i8 %0, 255
+ %3 = icmp ne i8 %1, 255
+ %4 = icmp ult i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @non_strict_op_negative(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @non_strict_op_negative(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP1]], 0
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i8 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 [[TMP4]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ %2 = icmp eq i8 %0, 0
+ %3 = icmp ne i8 %1, 0
+ %4 = icmp ule i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_poison_negative(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_poison_negative(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: ret i1 poison
+;
+start:
+ %2 = icmp eq i8 %0, 0
+ %3 = icmp ne i8 poison, 0
+ %4 = icmp ult i8 %0, poison
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_cond_poison_negative(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_cond_poison_negative(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: ret i1 poison
+;
+start:
+ %2 = icmp eq i8 %0, poison
+ %3 = icmp ne i8 %1, 0
+ %4 = icmp ult i8 %0, %1
+ %result = select i1 %2, i1 %3, i1 %4
+ ret i1 %result
+}
+
+define i1 @compare_true_poison_negative(i8 %0, i8 %1) {
+; CHECK-LABEL: define i1 @compare_true_poison_negative(
+; CHECK-SAME: i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: ret i1 poison
+;
+start:
+ %2 = icmp eq i8 %0, poison
+ %3 = icmp ne i8 %1, 0
+ %4 = icmp ult i8 %0, %1
+ %result = select i1 %2, i1 poison, i1 %4
+ ret i1 %result
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is incorrect to preserve samesign
flag: https://alive2.llvm.org/ce/z/2NdTWW
You should either implement this fold and drop the flag in InstCombine or bail out on icmps with samesign
in InstSimplify.
The first option is preferred. |
A == MIN_INT ? B != MIN_INT : A < B
to A < B
A == MIN_INT ? B != MIN_INT : A < B
to A < B
92fb27e
to
c34b817
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
c34b817
to
8b0239b
Compare
8b0239b
to
122e3eb
Compare
llvm/test/Transforms/InstCombine/select-with-extreme-eq-cond.ll
Outdated
Show resolved
Hide resolved
llvm/test/Transforms/InstCombine/select-with-extreme-eq-cond.ll
Outdated
Show resolved
Hide resolved
llvm/test/Transforms/InstCombine/select-with-extreme-eq-cond.ll
Outdated
Show resolved
Hide resolved
A == MIN_INT ? B != MIN_INT : A < B
to A < B
A == MIN_INT ? B != MIN_INT : A < B
to A < B
122e3eb
to
2280f2f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you!
Please merge it for me. I don't have commit access yet. |
This PR folds:
A == MIN_INT ? B != MIN_INT : A < B
toA < B
A == MAX_INT ? B != MAX_INT : A > B
toA > B
Proof: https://alive2.llvm.org/ce/z/bR6E2s
This helps in optimizing comparison of optional unsigned non-zero types in rust-lang/rust#49892.
Rust compiler's current output: https://rust.godbolt.org/z/9fxfq3Gn8