From c6219bad2e6df66a8eb7aca8edcc56bc47101f39 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Sat, 30 Aug 2014 06:18:20 +0000 Subject: [PATCH] InstCombine: Try harder to combine icmp instructions consider: (and (icmp X, Y), (and Z, (icmp A, B))) It may be possible to combine (icmp X, Y) with (icmp A, B). If we successfully combine, create an 'and' instruction with Z. This fixes PR20814. N.B. There is room for improvement after this change but I'm not convinced it's worth chasing yet. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216814 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineAndOrXor.cpp | 28 +++++++++++++++++-- test/Transforms/InstCombine/and2.ll | 14 +++++++++- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 2920c8816ac..b19e8b4d72d 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1101,7 +1101,6 @@ Value *InstCombiner::FoldAndOfFCmps(FCmpInst *LHS, FCmpInst *RHS) { return nullptr; } - Instruction *InstCombiner::visitAnd(BinaryOperator &I) { bool Changed = SimplifyAssociativeOrCommutative(I); Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); @@ -1307,11 +1306,34 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { return BinaryOperator::CreateAnd(A, B); } - if (ICmpInst *RHS = dyn_cast(Op1)) - if (ICmpInst *LHS = dyn_cast(Op0)) + { + ICmpInst *LHS = dyn_cast(Op0); + ICmpInst *RHS = dyn_cast(Op1); + if (LHS && RHS) if (Value *Res = FoldAndOfICmps(LHS, RHS)) return ReplaceInstUsesWith(I, Res); + // TODO: Make this recursive; it's a little tricky because an arbitrary + // number of 'and' instructions might have to be created. + Value *X, *Y; + if (LHS && match(Op1, m_OneUse(m_And(m_Value(X), m_Value(Y))))) { + if (auto *Cmp = dyn_cast(X)) + if (Value *Res = FoldAndOfICmps(LHS, Cmp)) + return ReplaceInstUsesWith(I, Builder->CreateAnd(Res, Y)); + if (auto *Cmp = dyn_cast(Y)) + if (Value *Res = FoldAndOfICmps(LHS, Cmp)) + return ReplaceInstUsesWith(I, Builder->CreateAnd(Res, X)); + } + if (RHS && match(Op0, m_OneUse(m_And(m_Value(X), m_Value(Y))))) { + if (auto *Cmp = dyn_cast(X)) + if (Value *Res = FoldAndOfICmps(Cmp, RHS)) + return ReplaceInstUsesWith(I, Builder->CreateAnd(Res, Y)); + if (auto *Cmp = dyn_cast(Y)) + if (Value *Res = FoldAndOfICmps(Cmp, RHS)) + return ReplaceInstUsesWith(I, Builder->CreateAnd(Res, X)); + } + } + // If and'ing two fcmp, try combine them into one. if (FCmpInst *LHS = dyn_cast(I.getOperand(0))) if (FCmpInst *RHS = dyn_cast(I.getOperand(1))) diff --git a/test/Transforms/InstCombine/and2.ll b/test/Transforms/InstCombine/and2.ll index e88fd598300..c76bb4499e8 100644 --- a/test/Transforms/InstCombine/and2.ll +++ b/test/Transforms/InstCombine/and2.ll @@ -45,7 +45,7 @@ define <4 x i32> @test5(<4 x i32> %A) { ; Check that we combine "if x!=0 && x!=-1" into "if x+1u>1" define i32 @test6(i64 %x) nounwind { -; CHECK: @test6 +; CHECK-LABEL: @test6( ; CHECK-NEXT: add i64 %x, 1 ; CHECK-NEXT: icmp ugt i64 %x.off, 1 %cmp1 = icmp ne i64 %x, -1 @@ -54,3 +54,15 @@ define i32 @test6(i64 %x) nounwind { %land.ext = zext i1 %.cmp1 to i32 ret i32 %land.ext } + +define i1 @test7(i32 %i, i1 %b) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 %i, 0 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], %b +; CHECK-NEXT: ret i1 [[AND]] + %cmp1 = icmp slt i32 %i, 1 + %cmp2 = icmp sgt i32 %i, -1 + %and1 = and i1 %cmp1, %b + %and2 = and i1 %and1, %cmp2 + ret i1 %and2 +}