forked from OSchip/llvm-project
[InstCombine]: foldSelectICmpAndAnd(): and is commutative
Summary: The fold added in D45108 did not account for the fact that the and instruction is commutative, and if the mask is a variable, the mask variable and the fold variable may be swapped. I have noticed this by accident when looking into [[ https://bugs.llvm.org/show_bug.cgi?id=6773 | PR6773 ]] This extends/generalizes that fold, so it is handled too. Reviewers: spatel, craig.topper Reviewed By: spatel Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D45539 llvm-svn: 330001
This commit is contained in:
parent
ea626e37ba
commit
c00659328a
|
@ -402,39 +402,35 @@ Instruction *InstCombiner::foldSelectIntoOp(SelectInst &SI, Value *TrueVal,
|
|||
/// zext (icmp ne i32 (and X, (or Y, (shl 1, Z))), 0)
|
||||
/// Note:
|
||||
/// Z may be 0 if lshr is missing.
|
||||
/// Worst case scenario is that we will replace 5 instructions with 5 different
|
||||
/// Worst-case scenario is that we will replace 5 instructions with 5 different
|
||||
/// instructions, but we got rid of select.
|
||||
static Instruction *foldSelectICmpAndAnd(Type *SelType, const ICmpInst *IC,
|
||||
Value *TrueVal, Value *FalseVal,
|
||||
static Instruction *foldSelectICmpAndAnd(Type *SelType, const ICmpInst *Cmp,
|
||||
Value *TVal, Value *FVal,
|
||||
InstCombiner::BuilderTy &Builder) {
|
||||
if (!(IC->hasOneUse() && IC->getOperand(0)->hasOneUse()))
|
||||
if (!(Cmp->hasOneUse() && Cmp->getOperand(0)->hasOneUse() &&
|
||||
Cmp->getPredicate() == ICmpInst::ICMP_EQ &&
|
||||
match(Cmp->getOperand(1), m_Zero()) && match(FVal, m_One())))
|
||||
return nullptr;
|
||||
|
||||
Value *X, *Y;
|
||||
ICmpInst::Predicate EqPred;
|
||||
if (!(match(IC, m_ICmp(EqPred, m_And(m_Value(X), m_Value(Y)), m_Zero())) &&
|
||||
ICmpInst::Predicate::ICMP_EQ == EqPred && match(FalseVal, m_One())))
|
||||
return nullptr;
|
||||
|
||||
// The TrueVal has general form of:
|
||||
// and %B, 1
|
||||
// The TrueVal has general form of: and %B, 1
|
||||
Value *B;
|
||||
if (!match(TrueVal, m_OneUse(m_And(m_Value(B), m_One()))))
|
||||
if (!match(TVal, m_OneUse(m_And(m_Value(B), m_One()))))
|
||||
return nullptr;
|
||||
|
||||
// Where %B can be one of:
|
||||
// %X
|
||||
// or
|
||||
// lshr %X, %Z
|
||||
// Where %Z may or may not be a constant.
|
||||
Value *MaskB, *Z;
|
||||
if (match(B, m_Specific(X))) {
|
||||
MaskB = ConstantInt::get(SelType, 1);
|
||||
} else if (match(B, m_OneUse(m_LShr(m_Specific(X), m_Value(Z))))) {
|
||||
MaskB = Builder.CreateShl(ConstantInt::get(SelType, 1), Z);
|
||||
} else
|
||||
// Where %B may be optionally shifted: lshr %X, %Z.
|
||||
Value *X, *Z;
|
||||
const bool HasShift = match(B, m_OneUse(m_LShr(m_Value(X), m_Value(Z))));
|
||||
if (!HasShift)
|
||||
X = B;
|
||||
|
||||
Value *Y;
|
||||
if (!match(Cmp->getOperand(0), m_c_And(m_Specific(X), m_Value(Y))))
|
||||
return nullptr;
|
||||
|
||||
// ((X & Y) == 0) ? ((X >> Z) & 1) : 1 --> (X & (Y | (1 << Z))) != 0
|
||||
// ((X & Y) == 0) ? (X & 1) : 1 --> (X & (Y | 1)) != 0
|
||||
Constant *One = ConstantInt::get(SelType, 1);
|
||||
Value *MaskB = HasShift ? Builder.CreateShl(One, Z) : One;
|
||||
Value *FullMask = Builder.CreateOr(Y, MaskB);
|
||||
Value *MaskedX = Builder.CreateAnd(X, FullMask);
|
||||
Value *ICmpNeZero = Builder.CreateIsNotNull(MaskedX);
|
||||
|
|
|
@ -177,11 +177,10 @@ define i32 @f_var0(i32 %arg, i32 %arg1) {
|
|||
; Should be exactly as the previous one
|
||||
define i32 @f_var0_commutative_and(i32 %arg, i32 %arg1) {
|
||||
; CHECK-LABEL: @f_var0_commutative_and(
|
||||
; CHECK-NEXT: [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP]], 0
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[ARG]], 1
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP3]], 1
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32 [[TMP4]], i32 1
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 2
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP3]] to i32
|
||||
; CHECK-NEXT: ret i32 [[TMP5]]
|
||||
;
|
||||
%tmp = and i32 %arg1, %arg ; in different order
|
||||
|
@ -259,10 +258,10 @@ define i32 @f_var1(i32 %arg, i32 %arg1) {
|
|||
; Should be exactly as the previous one
|
||||
define i32 @f_var1_commutative_and(i32 %arg, i32 %arg1) {
|
||||
; CHECK-LABEL: @f_var1_commutative_and(
|
||||
; CHECK-NEXT: [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP]], 0
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[ARG]], 1
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 1
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 1
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32
|
||||
; CHECK-NEXT: ret i32 [[TMP4]]
|
||||
;
|
||||
%tmp = and i32 %arg1, %arg ; in different order
|
||||
|
@ -398,11 +397,11 @@ define i32 @f_var3(i32 %arg, i32 %arg1, i32 %arg2) {
|
|||
; Should be exactly as the previous one
|
||||
define i32 @f_var3_commutative_and(i32 %arg, i32 %arg1, i32 %arg2) {
|
||||
; CHECK-LABEL: @f_var3_commutative_and(
|
||||
; CHECK-NEXT: [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP]], 0
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 [[ARG]], [[ARG2:%.*]]
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 1
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = select i1 [[TMP3]], i32 [[TMP5]], i32 1
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 1, [[ARG2:%.*]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[ARG1:%.*]]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[ARG:%.*]]
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP4]] to i32
|
||||
; CHECK-NEXT: ret i32 [[TMP6]]
|
||||
;
|
||||
%tmp = and i32 %arg1, %arg ; in different order
|
||||
|
|
Loading…
Reference in New Issue