From 68bc5fb0ad4fb5fc2bee89bc1c969470213636b3 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Wed, 6 Feb 2019 16:43:54 +0000 Subject: [PATCH] [InstCombine] X | C == C --> (X & ~C) == 0 We should canonicalize to one of these forms, and compare-with-zero could be more conducive to follow-on transforms. This also leads to generally better codegen as shown in PR40611: https://bugs.llvm.org/show_bug.cgi?id=40611 llvm-svn: 353313 --- .../InstCombine/InstCombineCompares.cpp | 27 ++++++++++++------- llvm/test/Transforms/InstCombine/icmp.ll | 16 +++++------ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index ba03dcb74a38..399aa2d8d2ea 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1771,13 +1771,22 @@ Instruction *InstCombiner::foldICmpOrConstant(ICmpInst &Cmp, BinaryOperator *Or, ConstantInt::get(V->getType(), 1)); } - // X | C == C --> X <=u C - // X | C != C --> X >u C - // iff C+1 is a power of 2 (C is a bitmask of the low bits) - if (Cmp.isEquality() && Cmp.getOperand(1) == Or->getOperand(1) && - (C + 1).isPowerOf2()) { - Pred = (Pred == CmpInst::ICMP_EQ) ? CmpInst::ICMP_ULE : CmpInst::ICMP_UGT; - return new ICmpInst(Pred, Or->getOperand(0), Or->getOperand(1)); + Value *OrOp0 = Or->getOperand(0), *OrOp1 = Or->getOperand(1); + if (Cmp.isEquality() && Cmp.getOperand(1) == OrOp1) { + // X | C == C --> X <=u C + // X | C != C --> X >u C + // iff C+1 is a power of 2 (C is a bitmask of the low bits) + if ((C + 1).isPowerOf2()) { + Pred = (Pred == CmpInst::ICMP_EQ) ? CmpInst::ICMP_ULE : CmpInst::ICMP_UGT; + return new ICmpInst(Pred, OrOp0, OrOp1); + } + // More general: are all bits outside of a mask constant set or not set? + // X | C == C --> (X & ~C) == 0 + // X | C != C --> (X & ~C) != 0 + if (Or->hasOneUse()) { + Value *A = Builder.CreateAnd(OrOp0, ~C); + return new ICmpInst(Pred, A, ConstantInt::getNullValue(OrOp0->getType())); + } } if (!Cmp.isEquality() || !C.isNullValue() || !Or->hasOneUse()) @@ -1798,8 +1807,8 @@ Instruction *InstCombiner::foldICmpOrConstant(ICmpInst &Cmp, BinaryOperator *Or, // Are we using xors to bitwise check for a pair of (in)equalities? Convert to // a shorter form that has more potential to be folded even further. Value *X1, *X2, *X3, *X4; - if (match(Or->getOperand(0), m_OneUse(m_Xor(m_Value(X1), m_Value(X2)))) && - match(Or->getOperand(1), m_OneUse(m_Xor(m_Value(X3), m_Value(X4))))) { + if (match(OrOp0, m_OneUse(m_Xor(m_Value(X1), m_Value(X2)))) && + match(OrOp1, m_OneUse(m_Xor(m_Value(X3), m_Value(X4))))) { // ((X1 ^ X2) || (X3 ^ X4)) == 0 --> (X1 == X2) && (X3 == X4) // ((X1 ^ X2) || (X3 ^ X4)) != 0 --> (X1 != X2) || (X3 != X4) Value *Cmp12 = Builder.CreateICmp(Pred, X1, X2); diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll index 490471fdf4e2..7f8c6a3819db 100644 --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -2169,8 +2169,8 @@ define <2 x i1> @or63_ne63_vec(<2 x i8> %x) { define i1 @orC_eqC(i32 %x) { ; CHECK-LABEL: @orC_eqC( -; CHECK-NEXT: [[T0:%.*]] = or i32 [[X:%.*]], 42 -; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[T0]], 42 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -43 +; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[T1]] ; %t0 = or i32 %x, 42 @@ -2182,8 +2182,8 @@ define i1 @orC_eqC(i32 %x) { define <2 x i1> @orC_eqC_vec(<2 x i8> %x) { ; CHECK-LABEL: @orC_eqC_vec( -; CHECK-NEXT: [[T0:%.*]] = or <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[T1:%.*]] = icmp eq <2 x i8> [[T0]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[T1:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[T1]] ; %t0 = or <2 x i8> %x, @@ -2195,8 +2195,8 @@ define <2 x i1> @orC_eqC_vec(<2 x i8> %x) { define i1 @orC_neC(i32 %x) { ; CHECK-LABEL: @orC_neC( -; CHECK-NEXT: [[T0:%.*]] = or i32 [[X:%.*]], -42 -; CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], -42 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 41 +; CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[T1]] ; %t0 = or i32 %x, -42 @@ -2208,8 +2208,8 @@ define i1 @orC_neC(i32 %x) { define <2 x i1> @orC_neC_vec(<2 x i8> %x) { ; CHECK-LABEL: @orC_neC_vec( -; CHECK-NEXT: [[T0:%.*]] = or <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[T1:%.*]] = icmp ne <2 x i8> [[T0]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[T1:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[T1]] ; %t0 = or <2 x i8> %x,