diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index aca760810ef..fa5c491554e 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3948,6 +3948,27 @@ static Optional isImpliedCondMatchingOperands(CmpInst::Predicate APred, return None; } +/// Return true if "icmp1 APred ALHS C1" implies "icmp2 BPred BLHS C2" is +/// true. Return false if "icmp1 APred ALHS C1" implies "icmp2 BPred BLHS +/// C2" is false. Otherwise, return None if we can't infer anything. +static Optional +isImpliedCondMatchingImmOperands(CmpInst::Predicate APred, Value *ALHS, + ConstantInt *C1, CmpInst::Predicate BPred, + Value *BLHS, ConstantInt *C2) { + assert(ALHS == BLHS && "LHS operands must match."); + ConstantRange DomCR = + ConstantRange::makeExactICmpRegion(APred, C1->getValue()); + ConstantRange CR = + ConstantRange::makeAllowedICmpRegion(BPred, C2->getValue()); + ConstantRange Intersection = DomCR.intersectWith(CR); + ConstantRange Difference = DomCR.difference(CR); + if (Intersection.isEmptySet()) + return false; + if (Difference.isEmptySet()) + return true; + return None; +} + Optional llvm::isImpliedCondition(Value *LHS, Value *RHS, const DataLayout &DL, bool InvertAPred, unsigned Depth, AssumptionCache *AC, @@ -3985,6 +4006,14 @@ Optional llvm::isImpliedCondition(Value *LHS, Value *RHS, if (Implication) return Implication; + if (ALHS == BLHS && isa(ARHS) && isa(BRHS)) { + Implication = + isImpliedCondMatchingImmOperands(APred, ALHS, cast(ARHS), + BPred, BLHS, cast(BRHS)); + if (Implication) + return Implication; + } + if (APred == BPred) return isImpliedCondOperands(APred, ALHS, ARHS, BLHS, BRHS, DL, Depth, AC, CxtI, DT); diff --git a/test/CodeGen/AArch64/addsub.ll b/test/CodeGen/AArch64/addsub.ll index d6350a6db0e..c0235cd5d9e 100644 --- a/test/CodeGen/AArch64/addsub.ll +++ b/test/CodeGen/AArch64/addsub.ll @@ -5,6 +5,7 @@ ; loads and stores. @var_i32 = global i32 42 +@var2_i32 = global i32 43 @var_i64 = global i64 0 ; Add pure 12-bit immediates: @@ -106,6 +107,7 @@ define void @sub_med() { define void @testing() { ; CHECK-LABEL: testing: %val = load i32, i32* @var_i32 + %val2 = load i32, i32* @var2_i32 ; CHECK: cmp {{w[0-9]+}}, #4095 ; CHECK: b.ne [[RET:.?LBB[0-9]+_[0-9]+]] @@ -117,7 +119,7 @@ test2: ; CHECK: b.lo [[RET]] %newval2 = add i32 %val, 1 store i32 %newval2, i32* @var_i32 - %cmp_pos_big = icmp ult i32 %val, 14610432 + %cmp_pos_big = icmp ult i32 %val2, 14610432 br i1 %cmp_pos_big, label %ret, label %test3 test3: @@ -133,7 +135,7 @@ test4: ; CHECK: b.gt [[RET]] %newval4 = add i32 %val, 3 store i32 %newval4, i32* @var_i32 - %cmp_pos_sgt = icmp sgt i32 %val, 321 + %cmp_pos_sgt = icmp sgt i32 %val2, 321 br i1 %cmp_pos_sgt, label %ret, label %test5 test5: @@ -141,7 +143,7 @@ test5: ; CHECK: b.gt [[RET]] %newval5 = add i32 %val, 4 store i32 %newval5, i32* @var_i32 - %cmp_neg_uge = icmp sgt i32 %val, -444 + %cmp_neg_uge = icmp sgt i32 %val2, -444 br i1 %cmp_neg_uge, label %ret, label %test6 test6: diff --git a/test/CodeGen/AArch64/combine-comparisons-by-cse.ll b/test/CodeGen/AArch64/combine-comparisons-by-cse.ll index 59b4c953ee9..1f8e0efa067 100644 --- a/test/CodeGen/AArch64/combine-comparisons-by-cse.ll +++ b/test/CodeGen/AArch64/combine-comparisons-by-cse.ll @@ -405,11 +405,11 @@ return: ; preds = %land.lhs.true, %con define void @cmp_shifted(i32 %in, i32 %lhs, i32 %rhs) { ; CHECK-LABEL: cmp_shifted: -; CHECK: cmp w0, #1 -; [...] ; CHECK: cmp w0, #2, lsl #12 +; [...] +; CHECK: cmp w0, #1 - %tst_low = icmp sgt i32 %in, 0 + %tst_low = icmp sgt i32 %in, 8191 br i1 %tst_low, label %true, label %false true: @@ -417,7 +417,7 @@ true: ret void false: - %tst = icmp sgt i32 %in, 8191 + %tst = icmp sgt i32 %in, 0 br i1 %tst, label %truer, label %falser truer: diff --git a/test/Transforms/InstCombine/select-implied.ll b/test/Transforms/InstCombine/select-implied.ll index 0616bd97fd3..2100e3eae00 100644 --- a/test/Transforms/InstCombine/select-implied.ll +++ b/test/Transforms/InstCombine/select-implied.ll @@ -40,7 +40,7 @@ end: ; CHECK-LABEL: @test3 ; CHECK-NOT: select ; CHECK: call void @foo(i32 30) -define void @test3(i32 %a, i32 %b) { +define void @test3(i32 %a) { %cmp1 = icmp ugt i32 %a, 10 br i1 %cmp1, label %taken, label %end @@ -101,5 +101,23 @@ ret: ret void } +; A >u 10 implies A >u 9 is true. +; CHECK-LABEL: @test5 +; CHECK-NOT: select +; CHECK: call void @foo(i32 30) +define void @test5(i32 %a) { + %cmp1 = icmp ugt i32 %a, 10 + br i1 %cmp1, label %taken, label %end + +taken: + %cmp2 = icmp ugt i32 %a, 9 + %c = select i1 %cmp2, i32 30, i32 0 + call void @foo(i32 %c) + br label %end + +end: + ret void +} + declare void @foo(i32) declare i32 @bar(i32) diff --git a/test/Transforms/SimplifyCFG/implied-cond-matching-imm.ll b/test/Transforms/SimplifyCFG/implied-cond-matching-imm.ll new file mode 100644 index 00000000000..60ef8136598 --- /dev/null +++ b/test/Transforms/SimplifyCFG/implied-cond-matching-imm.ll @@ -0,0 +1,123 @@ +; RUN: opt %s -S -simplifycfg | FileCheck %s + +; cmp1 implies cmp2 is false +; CHECK-LABEL: @test1 +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test1(i32 %a) { + %cmp1 = icmp eq i32 %a, 0 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp eq i32 %a, 1 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is false +; CHECK-LABEL: @test2 +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test2(i32 %a) { + %cmp1 = icmp ugt i32 %a, 5 + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ugt i32 %a, 6 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is false +; CHECK-LABEL: @test3 +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test3(i32 %a) { + %cmp1 = icmp ugt i32 %a, 1 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp eq i32 %a, 0 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is true +; CHECK-LABEL: @test4 +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test4(i32 %a) { + %cmp1 = icmp sgt i32 %a, 1 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, 0 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is true +; CHECK-LABEL: @test5 +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test5(i32 %a) { + %cmp1 = icmp sgt i32 %a, 5 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, -1 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +declare void @is(i1)