Generalize the reassociation transform in SimplifyCommutative (now renamed to

SimplifyAssociativeOrCommutative) "(A op C1) op C2" -> "A op (C1 op C2)",
which previously was only done if C1 and C2 were constants, to occur whenever
"C1 op C2" simplifies (a la InstructionSimplify).  Since the simplifying operand
combination can no longer be assumed to be the right-hand terms, consider all of
the possible permutations.  When compiling "gcc as one big file", transform 2
(i.e. using right-hand operands) fires about 4000 times but it has to be said
that most of the time the simplifying operands are both constants.  Transforms
3, 4 and 5 each fired once.  Transform 6, which is an existing transform that
I didn't change, never fired.  With this change, the testcase is now optimized
perfectly with one run of instcombine (previously it required instcombine +
reassociate + instcombine, and it may just have been luck that this worked).

llvm-svn: 119002
This commit is contained in:
Duncan Sands 2010-11-13 15:10:37 +00:00
parent e5ac78e16e
commit 641baf1646
6 changed files with 139 additions and 47 deletions

View File

@ -286,9 +286,9 @@ public:
private:
/// SimplifyCommutative - This performs a few simplifications for
/// commutative operators.
bool SimplifyCommutative(BinaryOperator &I);
/// SimplifyAssociativeOrCommutative - This performs a few simplifications for
/// operators which are associative or commutative.
bool SimplifyAssociativeOrCommutative(BinaryOperator &I);
/// SimplifyDemandedUseBits - Attempts to replace V with a simpler value
/// based on the demanded bits.

View File

@ -84,7 +84,7 @@ bool InstCombiner::WillNotOverflowSignedAdd(Value *LHS, Value *RHS) {
}
Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
bool Changed = SimplifyCommutative(I);
bool Changed = SimplifyAssociativeOrCommutative(I);
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
if (Value *V = SimplifyAddInst(LHS, RHS, I.hasNoSignedWrap(),
@ -342,7 +342,7 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
}
Instruction *InstCombiner::visitFAdd(BinaryOperator &I) {
bool Changed = SimplifyCommutative(I);
bool Changed = SimplifyAssociativeOrCommutative(I);
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
if (Constant *RHSC = dyn_cast<Constant>(RHS)) {

View File

@ -978,7 +978,7 @@ Value *InstCombiner::FoldAndOfFCmps(FCmpInst *LHS, FCmpInst *RHS) {
Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
bool Changed = SimplifyCommutative(I);
bool Changed = SimplifyAssociativeOrCommutative(I);
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (Value *V = SimplifyAndInst(Op0, Op1, TD))
@ -1686,7 +1686,7 @@ Instruction *InstCombiner::FoldOrWithConstants(BinaryOperator &I, Value *Op,
}
Instruction *InstCombiner::visitOr(BinaryOperator &I) {
bool Changed = SimplifyCommutative(I);
bool Changed = SimplifyAssociativeOrCommutative(I);
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (Value *V = SimplifyOrInst(Op0, Op1, TD))
@ -1973,7 +1973,7 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
}
Instruction *InstCombiner::visitXor(BinaryOperator &I) {
bool Changed = SimplifyCommutative(I);
bool Changed = SimplifyAssociativeOrCommutative(I);
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (isa<UndefValue>(Op1)) {

View File

@ -47,7 +47,7 @@ static bool MultiplyOverflows(ConstantInt *C1, ConstantInt *C2, bool sign) {
}
Instruction *InstCombiner::visitMul(BinaryOperator &I) {
bool Changed = SimplifyCommutative(I);
bool Changed = SimplifyAssociativeOrCommutative(I);
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (isa<UndefValue>(Op1)) // undef * X -> 0
@ -194,7 +194,7 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) {
}
Instruction *InstCombiner::visitFMul(BinaryOperator &I) {
bool Changed = SimplifyCommutative(I);
bool Changed = SimplifyAssociativeOrCommutative(I);
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
// Simplify mul instructions with a constant RHS...

View File

@ -106,53 +106,135 @@ bool InstCombiner::ShouldChangeType(const Type *From, const Type *To) const {
}
// SimplifyCommutative - This performs a few simplifications for commutative
// operators:
/// SimplifyAssociativeOrCommutative - This performs a few simplifications for
/// operators which are associative or commutative:
//
// Commutative operators:
//
// 1. Order operands such that they are listed from right (least complex) to
// left (most complex). This puts constants before unary operators before
// binary operators.
//
// 2. Transform: (op (op V, C1), C2) ==> (op V, (op C1, C2))
// 3. Transform: (op (op V1, C1), (op V2, C2)) ==> (op (op V1, V2), (op C1,C2))
// Associative operators:
//
bool InstCombiner::SimplifyCommutative(BinaryOperator &I) {
// 2. Transform: "(A op B) op C" ==> "A op (B op C)" if "B op C" simplifies.
// 3. Transform: "A op (B op C)" ==> "(A op B) op C" if "A op B" simplifies.
//
// Associative and commutative operators:
//
// 4. Transform: "(A op B) op C" ==> "(C op A) op B" if "C op A" simplifies.
// 5. Transform: "A op (B op C)" ==> "B op (C op A)" if "C op A" simplifies.
// 6. Transform: "(A op C1) op (B op C2)" ==> "(A op B) op (C1 op C2)"
// if C1 and C2 are constants.
//
bool InstCombiner::SimplifyAssociativeOrCommutative(BinaryOperator &I) {
Instruction::BinaryOps Opcode = I.getOpcode();
bool Changed = false;
if (getComplexity(I.getOperand(0)) < getComplexity(I.getOperand(1)))
do {
// Order operands such that they are listed from right (least complex) to
// left (most complex). This puts constants before unary operators before
// binary operators.
if (I.isCommutative() && getComplexity(I.getOperand(0)) <
getComplexity(I.getOperand(1)))
Changed = !I.swapOperands();
if (!I.isAssociative()) return Changed;
BinaryOperator *Op0 = dyn_cast<BinaryOperator>(I.getOperand(0));
BinaryOperator *Op1 = dyn_cast<BinaryOperator>(I.getOperand(1));
Instruction::BinaryOps Opcode = I.getOpcode();
if (BinaryOperator *Op = dyn_cast<BinaryOperator>(I.getOperand(0)))
if (Op->getOpcode() == Opcode && isa<Constant>(Op->getOperand(1))) {
if (isa<Constant>(I.getOperand(1))) {
Constant *Folded = ConstantExpr::get(I.getOpcode(),
cast<Constant>(I.getOperand(1)),
cast<Constant>(Op->getOperand(1)));
I.setOperand(0, Op->getOperand(0));
I.setOperand(1, Folded);
return true;
if (I.isAssociative()) {
// Transform: "(A op B) op C" ==> "A op (B op C)" if "B op C" simplifies.
if (Op0 && Op0->getOpcode() == Opcode) {
Value *A = Op0->getOperand(0);
Value *B = Op0->getOperand(1);
Value *C = I.getOperand(1);
// Does "B op C" simplify?
if (Value *V = SimplifyBinOp(Opcode, B, C, TD)) {
// It simplifies to V. Form "A op V".
I.setOperand(0, A);
I.setOperand(1, V);
Changed = true;
continue;
}
}
if (BinaryOperator *Op1 = dyn_cast<BinaryOperator>(I.getOperand(1)))
if (Op1->getOpcode() == Opcode && isa<Constant>(Op1->getOperand(1)) &&
Op->hasOneUse() && Op1->hasOneUse()) {
Constant *C1 = cast<Constant>(Op->getOperand(1));
// Transform: "A op (B op C)" ==> "(A op B) op C" if "A op B" simplifies.
if (Op1 && Op1->getOpcode() == Opcode) {
Value *A = I.getOperand(0);
Value *B = Op1->getOperand(0);
Value *C = Op1->getOperand(1);
// Does "A op B" simplify?
if (Value *V = SimplifyBinOp(Opcode, A, B, TD)) {
// It simplifies to V. Form "V op C".
I.setOperand(0, V);
I.setOperand(1, C);
Changed = true;
continue;
}
}
}
if (I.isAssociative() && I.isCommutative()) {
// Transform: "(A op B) op C" ==> "(C op A) op B" if "C op A" simplifies.
if (Op0 && Op0->getOpcode() == Opcode) {
Value *A = Op0->getOperand(0);
Value *B = Op0->getOperand(1);
Value *C = I.getOperand(1);
// Does "C op A" simplify?
if (Value *V = SimplifyBinOp(Opcode, C, A, TD)) {
// It simplifies to V. Form "V op B".
I.setOperand(0, V);
I.setOperand(1, B);
Changed = true;
continue;
}
}
// Transform: "A op (B op C)" ==> "B op (C op A)" if "C op A" simplifies.
if (Op1 && Op1->getOpcode() == Opcode) {
Value *A = I.getOperand(0);
Value *B = Op1->getOperand(0);
Value *C = Op1->getOperand(1);
// Does "C op A" simplify?
if (Value *V = SimplifyBinOp(Opcode, C, A, TD)) {
// It simplifies to V. Form "B op V".
I.setOperand(0, B);
I.setOperand(1, V);
Changed = true;
continue;
}
}
// Transform: "(A op C1) op (B op C2)" ==> "(A op B) op (C1 op C2)"
// if C1 and C2 are constants.
if (Op0 && Op1 &&
Op0->getOpcode() == Opcode && Op1->getOpcode() == Opcode &&
isa<Constant>(Op0->getOperand(1)) &&
isa<Constant>(Op1->getOperand(1)) &&
Op0->hasOneUse() && Op1->hasOneUse()) {
Value *A = Op0->getOperand(0);
Constant *C1 = cast<Constant>(Op0->getOperand(1));
Value *B = Op1->getOperand(0);
Constant *C2 = cast<Constant>(Op1->getOperand(1));
// Fold (op (op V1, C1), (op V2, C2)) ==> (op (op V1, V2), (op C1,C2))
Constant *Folded = ConstantExpr::get(I.getOpcode(), C1, C2);
Instruction *New = BinaryOperator::Create(Opcode, Op->getOperand(0),
Op1->getOperand(0),
Op1->getName(), &I);
Constant *Folded = ConstantExpr::get(Opcode, C1, C2);
Instruction *New = BinaryOperator::Create(Opcode, A, B, Op1->getName(),
&I);
Worklist.Add(New);
I.setOperand(0, New);
I.setOperand(1, Folded);
return true;
Changed = true;
continue;
}
}
// No further simplifications.
return Changed;
} while (1);
}
// dyn_castNegVal - Given a 'sub' instruction, return the RHS of the instruction

View File

@ -546,3 +546,13 @@ ret:
; CHECK: @test43
; CHECK: ret i1 false
}
define i32 @test44(i1 %cond, i32 %x, i32 %y) {
%z = and i32 %x, %y
%s = select i1 %cond, i32 %y, i32 %z
%r = and i32 %x, %s
ret i32 %r
; CHECK: @test44
; CHECK: %r = and i32 %x, %y
; CHECK: ret i32 %r
}