Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1206,11 +1206,28 @@ ICmpInst::Predicate Pred1, Value *V1, const APInt &C1, ICmpInst::Predicate Pred2, Value *V2, const APInt &C2, IRBuilderBase &Builder, bool IsAnd) { + // Look through addition of a constant offset. This allows us to interpret + // the V + C' < C'' range idiom into a proper range. + const APInt *Offset1 = nullptr, *Offset2 = nullptr; + if (V1 != V2) { + Value *X; + if (match(V1, m_Add(m_Value(X), m_APInt(Offset1)))) + V1 = X; + if (match(V2, m_Add(m_Value(X), m_APInt(Offset2)))) + V2 = X; + } + if (V1 != V2) return nullptr; ConstantRange CR1 = ConstantRange::makeExactICmpRegion(Pred1, C1); + if (Offset1) + CR1 = CR1.subtract(*Offset1); + ConstantRange CR2 = ConstantRange::makeExactICmpRegion(Pred2, C2); + if (Offset2) + CR2 = CR2.subtract(*Offset2); + Optional CR = IsAnd ? CR1.exactIntersectWith(CR2) : CR1.exactUnionWith(CR2); if (!CR) @@ -2462,15 +2479,6 @@ if (!LHSC || !RHSC) return nullptr; - // (icmp ult (X + CA), C1) | (icmp eq X, C2) -> (icmp ule (X + CA), C1) - // iff C2 + CA == C1. - if (PredL == ICmpInst::ICMP_ULT && PredR == ICmpInst::ICMP_EQ) { - ConstantInt *AddC; - if (match(LHS0, m_Add(m_Specific(RHS0), m_ConstantInt(AddC)))) - if (RHSC->getValue() + AddC->getValue() == LHSC->getValue()) - return Builder.CreateICmpULE(LHS0, LHSC); - } - return foldAndOrOfICmpsUsingRanges(PredL, LHS0, LHSC->getValue(), PredR, RHS0, RHSC->getValue(), Builder, /* IsAnd */ false); Index: llvm/test/Transforms/InstCombine/and-or-icmps.ll =================================================================== --- llvm/test/Transforms/InstCombine/and-or-icmps.ll +++ llvm/test/Transforms/InstCombine/and-or-icmps.ll @@ -1047,11 +1047,8 @@ define i1 @or_ranges_overlap(i8 %x) { ; CHECK-LABEL: @or_ranges_overlap( ; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -5 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 6 -; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[X]], -10 -; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 11 -; CHECK-NEXT: [[C7:%.*]] = or i1 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i1 [[C7]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 16 +; CHECK-NEXT: ret i1 [[TMP2]] ; %c1 = icmp uge i8 %x, 5 %c2 = icmp ule i8 %x, 10 @@ -1066,11 +1063,8 @@ define i1 @or_ranges_adjacent(i8 %x) { ; CHECK-LABEL: @or_ranges_adjacent( ; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -5 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 6 -; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[X]], -11 -; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 10 -; CHECK-NEXT: [[C7:%.*]] = or i1 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i1 [[C7]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 16 +; CHECK-NEXT: ret i1 [[TMP2]] ; %c1 = icmp uge i8 %x, 5 %c2 = icmp ule i8 %x, 10 @@ -1117,11 +1111,9 @@ define i1 @or_ranges_single_elem_left(i8 %x) { ; CHECK-LABEL: @or_ranges_single_elem_left( -; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -5 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 6 -; CHECK-NEXT: [[C4:%.*]] = icmp eq i8 [[X]], 4 -; CHECK-NEXT: [[C6:%.*]] = or i1 [[TMP2]], [[C4]] -; CHECK-NEXT: ret i1 [[C6]] +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -4 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 7 +; CHECK-NEXT: ret i1 [[TMP2]] ; %c1 = icmp uge i8 %x, 5 %c2 = icmp ule i8 %x, 10 @@ -1133,12 +1125,9 @@ define i1 @and_ranges_overlap(i8 %x) { ; CHECK-LABEL: @and_ranges_overlap( -; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -5 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 6 -; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[X]], -7 -; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 14 -; CHECK-NEXT: [[C7:%.*]] = and i1 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i1 [[C7]] +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -7 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 4 +; CHECK-NEXT: ret i1 [[TMP2]] ; %c1 = icmp uge i8 %x, 5 %c2 = icmp ule i8 %x, 10 @@ -1152,12 +1141,8 @@ define i1 @and_ranges_overlap_single(i8 %x) { ; CHECK-LABEL: @and_ranges_overlap_single( -; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -5 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 6 -; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[X]], -10 -; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 11 -; CHECK-NEXT: [[C7:%.*]] = and i1 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i1 [[C7]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], 10 +; CHECK-NEXT: ret i1 [[TMP1]] ; %c1 = icmp uge i8 %x, 5 %c2 = icmp ule i8 %x, 10 @@ -1171,12 +1156,7 @@ define i1 @and_ranges_no_overlap(i8 %x) { ; CHECK-LABEL: @and_ranges_no_overlap( -; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -5 -; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 6 -; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[X]], -11 -; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 10 -; CHECK-NEXT: [[C7:%.*]] = and i1 [[TMP2]], [[TMP4]] -; CHECK-NEXT: ret i1 [[C7]] +; CHECK-NEXT: ret i1 false ; %c1 = icmp uge i8 %x, 5 %c2 = icmp ule i8 %x, 10 Index: llvm/test/Transforms/InstCombine/or.ll =================================================================== --- llvm/test/Transforms/InstCombine/or.ll +++ llvm/test/Transforms/InstCombine/or.ll @@ -537,11 +537,9 @@ define i1 @test38(i32 %x) { ; CHECK-LABEL: @test38( -; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[X:%.*]], 7 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X]], 23 -; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[ADD1]], 30 -; CHECK-NEXT: [[RET1:%.*]] = or i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[RET1]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 7 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 31 +; CHECK-NEXT: ret i1 [[TMP2]] ; %add1 = add i32 %x, 7 %cmp1 = icmp eq i32 %x, 23 @@ -552,11 +550,9 @@ define i1 @test38_logical(i32 %x) { ; CHECK-LABEL: @test38_logical( -; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[X:%.*]], 7 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X]], 23 -; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[ADD1]], 30 -; CHECK-NEXT: [[RET1:%.*]] = or i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[RET1]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 7 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 31 +; CHECK-NEXT: ret i1 [[TMP2]] ; %add1 = add i32 %x, 7 %cmp1 = icmp eq i32 %x, 23 Index: llvm/test/Transforms/InstCombine/signed-truncation-check.ll =================================================================== --- llvm/test/Transforms/InstCombine/signed-truncation-check.ll +++ llvm/test/Transforms/InstCombine/signed-truncation-check.ll @@ -909,11 +909,8 @@ define i1 @negative_not_power_of_two(i32 %arg) { ; CHECK-LABEL: @negative_not_power_of_two( -; CHECK-NEXT: [[T1:%.*]] = icmp sgt i32 [[ARG:%.*]], -1 -; CHECK-NEXT: [[T2:%.*]] = add i32 [[ARG]], 255 -; CHECK-NEXT: [[T3:%.*]] = icmp ult i32 [[T2]], 256 -; CHECK-NEXT: [[T4:%.*]] = and i1 [[T1]], [[T3]] -; CHECK-NEXT: ret i1 [[T4]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] ; %t1 = icmp sgt i32 %arg, -1 %t2 = add i32 %arg, 255 ; should be power of two @@ -924,11 +921,8 @@ define i1 @negative_not_power_of_two_logical(i32 %arg) { ; CHECK-LABEL: @negative_not_power_of_two_logical( -; CHECK-NEXT: [[T1:%.*]] = icmp sgt i32 [[ARG:%.*]], -1 -; CHECK-NEXT: [[T2:%.*]] = add i32 [[ARG]], 255 -; CHECK-NEXT: [[T3:%.*]] = icmp ult i32 [[T2]], 256 -; CHECK-NEXT: [[T4:%.*]] = and i1 [[T1]], [[T3]] -; CHECK-NEXT: ret i1 [[T4]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] ; %t1 = icmp sgt i32 %arg, -1 %t2 = add i32 %arg, 255 ; should be power of two @@ -939,11 +933,8 @@ define i1 @negative_not_next_power_of_two(i32 %arg) { ; CHECK-LABEL: @negative_not_next_power_of_two( -; CHECK-NEXT: [[T1:%.*]] = icmp sgt i32 [[ARG:%.*]], -1 -; CHECK-NEXT: [[T2:%.*]] = add i32 [[ARG]], 64 -; CHECK-NEXT: [[T3:%.*]] = icmp ult i32 [[T2]], 256 -; CHECK-NEXT: [[T4:%.*]] = and i1 [[T1]], [[T3]] -; CHECK-NEXT: ret i1 [[T4]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ARG:%.*]], 192 +; CHECK-NEXT: ret i1 [[TMP1]] ; %t1 = icmp sgt i32 %arg, -1 %t2 = add i32 %arg, 64 ; should be 256 >> 1 @@ -954,11 +945,8 @@ define i1 @negative_not_next_power_of_two_logical(i32 %arg) { ; CHECK-LABEL: @negative_not_next_power_of_two_logical( -; CHECK-NEXT: [[T1:%.*]] = icmp sgt i32 [[ARG:%.*]], -1 -; CHECK-NEXT: [[T2:%.*]] = add i32 [[ARG]], 64 -; CHECK-NEXT: [[T3:%.*]] = icmp ult i32 [[T2]], 256 -; CHECK-NEXT: [[T4:%.*]] = and i1 [[T1]], [[T3]] -; CHECK-NEXT: ret i1 [[T4]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ARG:%.*]], 192 +; CHECK-NEXT: ret i1 [[TMP1]] ; %t1 = icmp sgt i32 %arg, -1 %t2 = add i32 %arg, 64 ; should be 256 >> 1 @@ -970,12 +958,9 @@ ; I don't think this can be folded, at least not into single instruction. define i1 @two_signed_truncation_checks(i32 %arg) { ; CHECK-LABEL: @two_signed_truncation_checks( -; CHECK-NEXT: [[T1:%.*]] = add i32 [[ARG:%.*]], 512 -; CHECK-NEXT: [[T2:%.*]] = icmp ult i32 [[T1]], 1024 -; CHECK-NEXT: [[T3:%.*]] = add i32 [[ARG]], 128 -; CHECK-NEXT: [[T4:%.*]] = icmp ult i32 [[T3]], 256 -; CHECK-NEXT: [[T5:%.*]] = and i1 [[T2]], [[T4]] -; CHECK-NEXT: ret i1 [[T5]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[ARG:%.*]], 128 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 256 +; CHECK-NEXT: ret i1 [[TMP2]] ; %t1 = add i32 %arg, 512 %t2 = icmp ult i32 %t1, 1024 @@ -987,12 +972,9 @@ define i1 @two_signed_truncation_checks_logical(i32 %arg) { ; CHECK-LABEL: @two_signed_truncation_checks_logical( -; CHECK-NEXT: [[T1:%.*]] = add i32 [[ARG:%.*]], 512 -; CHECK-NEXT: [[T2:%.*]] = icmp ult i32 [[T1]], 1024 -; CHECK-NEXT: [[T3:%.*]] = add i32 [[ARG]], 128 -; CHECK-NEXT: [[T4:%.*]] = icmp ult i32 [[T3]], 256 -; CHECK-NEXT: [[T5:%.*]] = and i1 [[T2]], [[T4]] -; CHECK-NEXT: ret i1 [[T5]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[ARG:%.*]], 128 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 256 +; CHECK-NEXT: ret i1 [[TMP2]] ; %t1 = add i32 %arg, 512 %t2 = icmp ult i32 %t1, 1024