Skip to content

Commit

Permalink
[InstCombine] Teach foldSelectICmpAndOr to recognize (select (icmp sl…
Browse files Browse the repository at this point in the history
…t (trunc (X)), 0), Y, (or Y, C2))

Summary:
InstCombine likes to turn (icmp eq (and X, C1), 0) into (icmp slt (trunc (X)), 0) sometimes. This breaks foldSelectICmpAndOr's ability to recognize (select (icmp eq (and X, C1), 0), Y, (or Y, C2))->(or (shl (and X, C1), C3), y).

This patch tries to recover this. I had to flip around some of the early out checks so that I could create a new And instruction during the compare processing without it possibly never getting used.

Reviewers: spatel, majnemer, davide

Reviewed By: spatel

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D34184

llvm-svn: 306029
  • Loading branch information
topperc committed Jun 22, 2017
1 parent a690e3c commit dffbbcb
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 21 deletions.
49 changes: 38 additions & 11 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,19 +317,44 @@ static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal,
Value *FalseVal,
InstCombiner::BuilderTy *Builder) {
const ICmpInst *IC = dyn_cast<ICmpInst>(SI.getCondition());
if (!IC || !IC->isEquality() || !SI.getType()->isIntegerTy())
if (!IC || !SI.getType()->isIntegerTy())
return nullptr;

Value *CmpLHS = IC->getOperand(0);
Value *CmpRHS = IC->getOperand(1);

if (!match(CmpRHS, m_Zero()))
return nullptr;
Value *V;
unsigned C1Log;
bool IsEqualZero;
bool NeedAnd = false;
if (IC->isEquality()) {
if (!match(CmpRHS, m_Zero()))
return nullptr;

const APInt *C1;
if (!match(CmpLHS, m_And(m_Value(), m_Power2(C1))))
return nullptr;

V = CmpLHS;
C1Log = C1->logBase2();
IsEqualZero = IC->getPredicate() == ICmpInst::ICMP_EQ;
} else if (IC->getPredicate() == ICmpInst::ICMP_SLT ||
IC->getPredicate() == ICmpInst::ICMP_SGT) {
// We also need to recognize (icmp slt (trunc (X)), 0) and
// (icmp sgt (trunc (X)), -1).
IsEqualZero = IC->getPredicate() == ICmpInst::ICMP_SGT;
if ((IsEqualZero && !match(CmpRHS, m_AllOnes())) ||
(!IsEqualZero && !match(CmpRHS, m_Zero())))
return nullptr;

Value *X;
const APInt *C1;
if (!match(CmpLHS, m_And(m_Value(X), m_Power2(C1))))
if (!match(CmpLHS, m_OneUse(m_Trunc(m_Value(V)))))
return nullptr;

C1Log = CmpLHS->getType()->getScalarSizeInBits() - 1;
NeedAnd = true;
} else {
return nullptr;
}

const APInt *C2;
bool OrOnTrueVal = false;
Expand All @@ -340,15 +365,11 @@ static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal,
if (!OrOnFalseVal && !OrOnTrueVal)
return nullptr;

Value *V = CmpLHS;
Value *Y = OrOnFalseVal ? TrueVal : FalseVal;

unsigned C1Log = C1->logBase2();
unsigned C2Log = C2->logBase2();

ICmpInst::Predicate Pred = IC->getPredicate();
bool NeedXor = (Pred == ICmpInst::ICMP_NE && OrOnFalseVal) ||
(Pred == ICmpInst::ICMP_EQ && OrOnTrueVal);
bool NeedXor = (!IsEqualZero && OrOnFalseVal) || (IsEqualZero && OrOnTrueVal);
bool NeedShift = C1Log != C2Log;
bool NeedZExtTrunc = Y->getType()->getIntegerBitWidth() !=
V->getType()->getIntegerBitWidth();
Expand All @@ -359,6 +380,12 @@ static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal,
(IC->hasOneUse() + Or->hasOneUse()))
return nullptr;

if (NeedAnd) {
// Insert the AND instruction on the input to the truncate.
APInt C1 = APInt::getOneBitSet(V->getType()->getScalarSizeInBits(), C1Log);
V = Builder->CreateAnd(V, ConstantInt::get(V->getType(), C1));
}

if (C2Log > C1Log) {
V = Builder->CreateZExtOrTrunc(V, Y->getType());
V = Builder->CreateShl(V, C2Log - C1Log);
Expand Down
19 changes: 9 additions & 10 deletions llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,10 @@ define i32 @test67(i16 %x) {

define i32 @test68(i32 %x, i32 %y) {
; CHECK-LABEL: @test68(
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TMP1]], -1
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[OR]]
; CHECK-NEXT: ret i32 [[SELECT]]
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 6
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 2
; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[TMP3]]
;
%and = and i32 %x, 128
%cmp = icmp eq i32 %and, 0
Expand All @@ -312,11 +311,11 @@ define i32 @test68(i32 %x, i32 %y) {

define i32 @test69(i32 %x, i32 %y) {
; CHECK-LABEL: @test69(
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TMP1]], 0
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[OR]]
; CHECK-NEXT: ret i32 [[SELECT]]
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 6
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 2
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2]], 2
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP3]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[TMP4]]
;
%and = and i32 %x, 128
%cmp = icmp ne i32 %and, 0
Expand Down

0 comments on commit dffbbcb

Please sign in to comment.