[InstCombine] Avoid modifying instructions in-place

As discussed on D73919, this replaces a few cases where we were
modifying multiple operands of instructions in-place with the
creation of a new instruction, which we generally prefer nowadays.

This tends to be more readable and less prone to worklist management
bugs.

Test changes are only superficial (instruction naming and order).
This commit is contained in:
Nikita Popov 2020-02-08 17:02:10 +01:00
parent ed54f1ad37
commit add593f8b5
5 changed files with 32 additions and 48 deletions

View File

@ -2742,33 +2742,24 @@ static Instruction *foldXorToXor(BinaryOperator &I,
// (A | B) ^ (A & B) -> A ^ B
// (A | B) ^ (B & A) -> A ^ B
if (match(&I, m_c_Xor(m_And(m_Value(A), m_Value(B)),
m_c_Or(m_Deferred(A), m_Deferred(B))))) {
I.setOperand(0, A);
I.setOperand(1, B);
return &I;
}
m_c_Or(m_Deferred(A), m_Deferred(B)))))
return BinaryOperator::CreateXor(A, B);
// (A | ~B) ^ (~A | B) -> A ^ B
// (~B | A) ^ (~A | B) -> A ^ B
// (~A | B) ^ (A | ~B) -> A ^ B
// (B | ~A) ^ (A | ~B) -> A ^ B
if (match(&I, m_Xor(m_c_Or(m_Value(A), m_Not(m_Value(B))),
m_c_Or(m_Not(m_Deferred(A)), m_Deferred(B))))) {
I.setOperand(0, A);
I.setOperand(1, B);
return &I;
}
m_c_Or(m_Not(m_Deferred(A)), m_Deferred(B)))))
return BinaryOperator::CreateXor(A, B);
// (A & ~B) ^ (~A & B) -> A ^ B
// (~B & A) ^ (~A & B) -> A ^ B
// (~A & B) ^ (A & ~B) -> A ^ B
// (B & ~A) ^ (A & ~B) -> A ^ B
if (match(&I, m_Xor(m_c_And(m_Value(A), m_Not(m_Value(B))),
m_c_And(m_Not(m_Deferred(A)), m_Deferred(B))))) {
I.setOperand(0, A);
I.setOperand(1, B);
return &I;
}
m_c_And(m_Not(m_Deferred(A)), m_Deferred(B)))))
return BinaryOperator::CreateXor(A, B);
// For the remaining cases we need to get rid of one of the operands.
if (!Op0->hasOneUse() && !Op1->hasOneUse())
@ -3109,9 +3100,7 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
MaskedValueIsZero(X, *C, 0, &I)) {
Constant *NewC = ConstantInt::get(I.getType(), *C ^ *RHSC);
Worklist.push(cast<Instruction>(Op0));
I.setOperand(0, X);
I.setOperand(1, NewC);
return &I;
return BinaryOperator::CreateXor(X, NewC);
}
}
}

View File

@ -1680,12 +1680,11 @@ Instruction *InstCombiner::foldICmpAndShift(ICmpInst &Cmp, BinaryOperator *And,
if (Cmp.getPredicate() == ICmpInst::ICMP_NE)
return replaceInstUsesWith(Cmp, ConstantInt::getTrue(Cmp.getType()));
} else {
Cmp.setOperand(1, ConstantInt::get(And->getType(), NewCst));
APInt NewAndCst = IsShl ? C2.lshr(*C3) : C2.shl(*C3);
And->setOperand(1, ConstantInt::get(And->getType(), NewAndCst));
And->setOperand(0, Shift->getOperand(0));
Worklist.push(Shift); // Shift is dead.
return &Cmp;
Value *NewAnd = Builder.CreateAnd(
Shift->getOperand(0), ConstantInt::get(And->getType(), NewAndCst));
return new ICmpInst(Cmp.getPredicate(),
NewAnd, ConstantInt::get(And->getType(), NewCst));
}
}
}
@ -4154,9 +4153,7 @@ Instruction *InstCombiner::foldICmpEquality(ICmpInst &I) {
if (X) { // Build (X^Y) & Z
Op1 = Builder.CreateXor(X, Y);
Op1 = Builder.CreateAnd(Op1, Z);
I.setOperand(0, Op1);
I.setOperand(1, Constant::getNullValue(Op1->getType()));
return &I;
return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
}
}

View File

@ -1917,10 +1917,8 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
else
Elts.push_back(ConstantInt::get(Int32Ty, Mask[i] % LHSWidth));
}
SVI.setOperand(0, SVI.getOperand(1));
SVI.setOperand(1, UndefValue::get(RHS->getType()));
SVI.setOperand(2, ConstantVector::get(Elts));
return &SVI;
return new ShuffleVectorInst(LHS, UndefValue::get(RHS->getType()),
ConstantVector::get(Elts));
}
// shuffle undef, x, mask --> shuffle x, undef, mask'

View File

@ -183,10 +183,10 @@ define i1 @test62_as1(i8 addrspace(1)* %a) {
; Variation of the above with an ashr
define i1 @icmp_and_ashr_multiuse(i32 %X) {
; CHECK-LABEL: @icmp_and_ashr_multiuse(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[X]], 496
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[AND]], 224
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i32 [[AND2]], 432
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 224
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[X]], 496
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i32 [[TMP2]], 432
; CHECK-NEXT: [[AND3:%.*]] = and i1 [[TOBOOL]], [[TOBOOL2]]
; CHECK-NEXT: ret i1 [[AND3]]
;

View File

@ -98,8 +98,8 @@ define <2 x i1> @test5_zero() {
define i32 @test6(i32 %a, i32 %b) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: [[E:%.*]] = ashr i32 [[A:%.*]], 31
; CHECK-NEXT: [[F:%.*]] = and i32 [[E]], [[B:%.*]]
; CHECK-NEXT: [[A_LOBIT_NEG:%.*]] = ashr i32 [[A:%.*]], 31
; CHECK-NEXT: [[F:%.*]] = and i32 [[A_LOBIT_NEG]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[F]]
;
%c = icmp sle i32 %a, -1
@ -1775,8 +1775,8 @@ define i1 @icmp_and_shl_neg_eq_0(i32 %A, i32 %B) {
define i1 @icmp_add_and_shr_ne_0(i32 %X) {
; CHECK-LABEL: @icmp_add_and_shr_ne_0(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[AND]], 224
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 224
; CHECK-NEXT: ret i1 [[TOBOOL]]
;
%shr = lshr i32 %X, 4
@ -1788,8 +1788,8 @@ define i1 @icmp_add_and_shr_ne_0(i32 %X) {
define <2 x i1> @icmp_add_and_shr_ne_0_vec(<2 x i32> %X) {
; CHECK-LABEL: @icmp_add_and_shr_ne_0_vec(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 240, i32 240>
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne <2 x i32> [[AND]], <i32 224, i32 224>
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 240, i32 240>
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 224, i32 224>
; CHECK-NEXT: ret <2 x i1> [[TOBOOL]]
;
%shr = lshr <2 x i32> %X, <i32 4, i32 4>
@ -1802,10 +1802,10 @@ define <2 x i1> @icmp_add_and_shr_ne_0_vec(<2 x i32> %X) {
; Variation of the above with an extra use of the shift
define i1 @icmp_and_shr_multiuse(i32 %X) {
; CHECK-LABEL: @icmp_and_shr_multiuse(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[X]], 496
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[AND]], 224
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i32 [[AND2]], 432
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 224
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[X]], 496
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i32 [[TMP2]], 432
; CHECK-NEXT: [[AND3:%.*]] = and i1 [[TOBOOL]], [[TOBOOL2]]
; CHECK-NEXT: ret i1 [[AND3]]
;
@ -1821,10 +1821,10 @@ define i1 @icmp_and_shr_multiuse(i32 %X) {
; Variation of the above with an ashr
define i1 @icmp_and_ashr_multiuse(i32 %X) {
; CHECK-LABEL: @icmp_and_ashr_multiuse(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[X]], 496
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[AND]], 224
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i32 [[AND2]], 432
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 224
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[X]], 496
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i32 [[TMP2]], 432
; CHECK-NEXT: [[AND3:%.*]] = and i1 [[TOBOOL]], [[TOBOOL2]]
; CHECK-NEXT: ret i1 [[AND3]]
;