// (icmp eq X, 0) | (icmp ult Other, X) -> (icmp ule Other, X-1)
// (icmp ne X, 0) & (icmp uge Other, X) -> (icmp ugt Other, X-1)
-Value *foldAndOrOfICmpEqZeroAndICmp(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
- IRBuilderBase &Builder) {
+static Value *foldAndOrOfICmpEqZeroAndICmp(ICmpInst *LHS, ICmpInst *RHS,
+ bool IsAnd, bool IsLogical,
+ IRBuilderBase &Builder) {
ICmpInst::Predicate LPred =
IsAnd ? LHS->getInversePredicate() : LHS->getPredicate();
ICmpInst::Predicate RPred =
else
return nullptr;
+ if (IsLogical)
+ Other = Builder.CreateFreeze(Other);
return Builder.CreateICmp(
IsAnd ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE,
Builder.CreateAdd(LHS0, Constant::getAllOnesValue(LHS0->getType())),
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, IsLogical, Builder))
return V;
- // TODO: One of these directions is fine with logical and/or, the other could
- // be supported by inserting freeze.
- if (!IsLogical) {
- if (Value *V = foldAndOrOfICmpEqZeroAndICmp(LHS, RHS, IsAnd, Builder))
- return V;
- if (Value *V = foldAndOrOfICmpEqZeroAndICmp(RHS, LHS, IsAnd, Builder))
- return V;
- }
+ if (Value *V =
+ foldAndOrOfICmpEqZeroAndICmp(LHS, RHS, IsAnd, IsLogical, Builder))
+ return V;
+ // We can treat logical like bitwise here, because both operands are used on
+ // the LHS, and as such poison from both will propagate.
+ if (Value *V = foldAndOrOfICmpEqZeroAndICmp(RHS, LHS, IsAnd,
+ /*IsLogical*/ false, Builder))
+ return V;
// TODO: Verify whether this is safe for logical and/or.
if (!IsLogical) {
define i1 @or_icmp_eq_B_0_icmp_ult_A_B_logical(i64 %a, i64 %b) {
; CHECK-LABEL: @or_icmp_eq_B_0_icmp_ult_A_B_logical(
-; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[B:%.*]], 0
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 [[A:%.*]], [[B]]
-; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i1 true, i1 [[TMP2]]
+; CHECK-NEXT: [[TMP1:%.*]] = freeze i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[B:%.*]], -1
+; CHECK-NEXT: [[TMP3:%.*]] = icmp uge i64 [[TMP2]], [[TMP1]]
; CHECK-NEXT: ret i1 [[TMP3]]
;
%1 = icmp eq i64 %b, 0
define i1 @and_icmp_ne_B_0_icmp_uge_A_B_commuted2_logical(i64 %a, i64 %b) {
; CHECK-LABEL: @and_icmp_ne_B_0_icmp_uge_A_B_commuted2_logical(
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[B:%.*]], 0
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ule i64 [[B]], [[A:%.*]]
-; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i1 [[TMP2]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = freeze i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[B:%.*]], -1
+; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i64 [[TMP2]], [[TMP1]]
; CHECK-NEXT: ret i1 [[TMP3]]
;
%1 = icmp ne i64 %b, 0
define i1 @and_icmp_ne_B_0_icmp_uge_A_B_logical(i64 %a, i64 %b) {
; CHECK-LABEL: @and_icmp_ne_B_0_icmp_uge_A_B_logical(
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[B:%.*]], 0
-; CHECK-NEXT: [[TMP2:%.*]] = icmp uge i64 [[A:%.*]], [[B]]
-; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i1 [[TMP2]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = freeze i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[B:%.*]], -1
+; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i64 [[TMP2]], [[TMP1]]
; CHECK-NEXT: ret i1 [[TMP3]]
;
%1 = icmp ne i64 %b, 0