#define DEBUG_TYPE "reassociate"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Pass.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/DenseMap.h"
#include <algorithm>
using namespace llvm;
STATISTIC(NumLinear , "Number of insts linearized");
STATISTIC(NumChanged, "Number of insts reassociated");
STATISTIC(NumAnnihil, "Number of expr tree annihilated");
STATISTIC(NumFactor , "Number of multiplies factored");
namespace {
struct ValueEntry {
unsigned Rank;
Value *Op;
ValueEntry(unsigned R, Value *O) : Rank(R), Op(O) {}
};
inline bool operator<(const ValueEntry &LHS, const ValueEntry &RHS) {
return LHS.Rank > RHS.Rank; }
}
#ifndef NDEBUG
static void PrintOps(Instruction *I, const SmallVectorImpl<ValueEntry> &Ops) {
Module *M = I->getParent()->getParent()->getParent();
dbgs() << Instruction::getOpcodeName(I->getOpcode()) << " "
<< *Ops[0].Op->getType() << '\t';
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
dbgs() << "[ ";
WriteAsOperand(dbgs(), Ops[i].Op, false, M);
dbgs() << ", #" << Ops[i].Rank << "] ";
}
}
#endif
namespace {
class Reassociate : public FunctionPass {
DenseMap<BasicBlock*, unsigned> RankMap;
DenseMap<AssertingVH<>, unsigned> ValueRankMap;
SmallVector<WeakVH, 8> RedoInsts;
SmallVector<WeakVH, 8> DeadInsts;
bool MadeChange;
public:
static char ID; Reassociate() : FunctionPass(ID) {
initializeReassociatePass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F);
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
}
private:
void BuildRankMap(Function &F);
unsigned getRank(Value *V);
Value *ReassociateExpression(BinaryOperator *I);
void RewriteExprTree(BinaryOperator *I, SmallVectorImpl<ValueEntry> &Ops,
unsigned Idx = 0);
Value *OptimizeExpression(BinaryOperator *I,
SmallVectorImpl<ValueEntry> &Ops);
Value *OptimizeAdd(Instruction *I, SmallVectorImpl<ValueEntry> &Ops);
void LinearizeExprTree(BinaryOperator *I, SmallVectorImpl<ValueEntry> &Ops);
void LinearizeExpr(BinaryOperator *I);
Value *RemoveFactorFromExpression(Value *V, Value *Factor);
void ReassociateInst(BasicBlock::iterator &BBI);
void RemoveDeadBinaryOp(Value *V);
};
}
char Reassociate::ID = 0;
INITIALIZE_PASS(Reassociate, "reassociate",
"Reassociate expressions", false, false)
FunctionPass *llvm::createReassociatePass() { return new Reassociate(); }
void Reassociate::RemoveDeadBinaryOp(Value *V) {
Instruction *Op = dyn_cast<Instruction>(V);
if (!Op || !isa<BinaryOperator>(Op))
return;
Value *LHS = Op->getOperand(0), *RHS = Op->getOperand(1);
ValueRankMap.erase(Op);
DeadInsts.push_back(Op);
RemoveDeadBinaryOp(LHS);
RemoveDeadBinaryOp(RHS);
}
static bool isUnmovableInstruction(Instruction *I) {
if (I->getOpcode() == Instruction::PHI ||
I->getOpcode() == Instruction::Alloca ||
I->getOpcode() == Instruction::Load ||
I->getOpcode() == Instruction::Invoke ||
(I->getOpcode() == Instruction::Call &&
!isa<DbgInfoIntrinsic>(I)) ||
I->getOpcode() == Instruction::UDiv ||
I->getOpcode() == Instruction::SDiv ||
I->getOpcode() == Instruction::FDiv ||
I->getOpcode() == Instruction::URem ||
I->getOpcode() == Instruction::SRem ||
I->getOpcode() == Instruction::FRem)
return true;
return false;
}
void Reassociate::BuildRankMap(Function &F) {
unsigned i = 2;
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I)
ValueRankMap[&*I] = ++i;
ReversePostOrderTraversal<Function*> RPOT(&F);
for (ReversePostOrderTraversal<Function*>::rpo_iterator I = RPOT.begin(),
E = RPOT.end(); I != E; ++I) {
BasicBlock *BB = *I;
unsigned BBRank = RankMap[BB] = ++i << 16;
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
if (isUnmovableInstruction(I))
ValueRankMap[&*I] = ++BBRank;
}
}
unsigned Reassociate::getRank(Value *V) {
Instruction *I = dyn_cast<Instruction>(V);
if (I == 0) {
if (isa<Argument>(V)) return ValueRankMap[V]; return 0; }
if (unsigned Rank = ValueRankMap[I])
return Rank;
unsigned Rank = 0, MaxRank = RankMap[I->getParent()];
for (unsigned i = 0, e = I->getNumOperands();
i != e && Rank != MaxRank; ++i)
Rank = std::max(Rank, getRank(I->getOperand(i)));
if (!I->getType()->isIntegerTy() ||
(!BinaryOperator::isNot(I) && !BinaryOperator::isNeg(I)))
++Rank;
return ValueRankMap[I] = Rank;
}
static BinaryOperator *isReassociableOp(Value *V, unsigned Opcode) {
if ((V->hasOneUse() || V->use_empty()) && isa<Instruction>(V) &&
cast<Instruction>(V)->getOpcode() == Opcode)
return cast<BinaryOperator>(V);
return 0;
}
static Instruction *LowerNegateToMultiply(Instruction *Neg,
DenseMap<AssertingVH<>, unsigned> &ValueRankMap) {
Constant *Cst = Constant::getAllOnesValue(Neg->getType());
Instruction *Res = BinaryOperator::CreateMul(Neg->getOperand(1), Cst, "",Neg);
ValueRankMap.erase(Neg);
Res->takeName(Neg);
Neg->replaceAllUsesWith(Res);
Res->setDebugLoc(Neg->getDebugLoc());
Neg->eraseFromParent();
return Res;
}
void Reassociate::LinearizeExpr(BinaryOperator *I) {
BinaryOperator *LHS = cast<BinaryOperator>(I->getOperand(0));
BinaryOperator *RHS = cast<BinaryOperator>(I->getOperand(1));
assert(isReassociableOp(LHS, I->getOpcode()) &&
isReassociableOp(RHS, I->getOpcode()) &&
"Not an expression that needs linearization?");
DEBUG(dbgs() << "Linear" << *LHS << '\n' << *RHS << '\n' << *I << '\n');
RHS->moveBefore(I);
I->setOperand(1, RHS->getOperand(0));
RHS->setOperand(0, LHS);
I->setOperand(0, RHS);
I->clearSubclassOptionalData();
LHS->clearSubclassOptionalData();
RHS->clearSubclassOptionalData();
++NumLinear;
MadeChange = true;
DEBUG(dbgs() << "Linearized: " << *I << '\n');
if (isReassociableOp(I->getOperand(1), I->getOpcode()))
LinearizeExpr(I);
}
void Reassociate::LinearizeExprTree(BinaryOperator *I,
SmallVectorImpl<ValueEntry> &Ops) {
Value *LHS = I->getOperand(0), *RHS = I->getOperand(1);
unsigned Opcode = I->getOpcode();
BinaryOperator *LHSBO = isReassociableOp(LHS, Opcode);
BinaryOperator *RHSBO = isReassociableOp(RHS, Opcode);
if (I->getOpcode() == Instruction::Mul) {
if (!LHSBO && LHS->hasOneUse() && BinaryOperator::isNeg(LHS)) {
LHS = LowerNegateToMultiply(cast<Instruction>(LHS), ValueRankMap);
LHSBO = isReassociableOp(LHS, Opcode);
}
if (!RHSBO && RHS->hasOneUse() && BinaryOperator::isNeg(RHS)) {
RHS = LowerNegateToMultiply(cast<Instruction>(RHS), ValueRankMap);
RHSBO = isReassociableOp(RHS, Opcode);
}
}
if (!LHSBO) {
if (!RHSBO) {
Ops.push_back(ValueEntry(getRank(LHS), LHS));
Ops.push_back(ValueEntry(getRank(RHS), RHS));
I->setOperand(0, UndefValue::get(I->getType()));
I->setOperand(1, UndefValue::get(I->getType()));
return;
}
std::swap(LHSBO, RHSBO);
std::swap(LHS, RHS);
bool Success = !I->swapOperands();
assert(Success && "swapOperands failed");
(void)Success;
MadeChange = true;
} else if (RHSBO) {
LinearizeExpr(I);
LHS = LHSBO = cast<BinaryOperator>(I->getOperand(0));
RHS = I->getOperand(1);
RHSBO = 0;
}
assert(!isReassociableOp(RHS, Opcode) && "LinearizeExpr failed!");
LHSBO->moveBefore(I);
LinearizeExprTree(LHSBO, Ops);
Ops.push_back(ValueEntry(getRank(RHS), RHS));
I->setOperand(1, UndefValue::get(I->getType()));
}
void Reassociate::RewriteExprTree(BinaryOperator *I,
SmallVectorImpl<ValueEntry> &Ops,
unsigned i) {
if (i+2 == Ops.size()) {
if (I->getOperand(0) != Ops[i].Op ||
I->getOperand(1) != Ops[i+1].Op) {
Value *OldLHS = I->getOperand(0);
DEBUG(dbgs() << "RA: " << *I << '\n');
I->setOperand(0, Ops[i].Op);
I->setOperand(1, Ops[i+1].Op);
if (Ops.size() != 2)
I->clearSubclassOptionalData();
DEBUG(dbgs() << "TO: " << *I << '\n');
MadeChange = true;
++NumChanged;
RemoveDeadBinaryOp(OldLHS);
}
return;
}
assert(i+2 < Ops.size() && "Ops index out of range!");
if (I->getOperand(1) != Ops[i].Op) {
DEBUG(dbgs() << "RA: " << *I << '\n');
I->setOperand(1, Ops[i].Op);
I->clearSubclassOptionalData();
DEBUG(dbgs() << "TO: " << *I << '\n');
MadeChange = true;
++NumChanged;
}
BinaryOperator *LHS = cast<BinaryOperator>(I->getOperand(0));
assert(LHS->getOpcode() == I->getOpcode() &&
"Improper expression tree!");
LHS->moveBefore(I);
RewriteExprTree(LHS, Ops, i+1);
}
static Value *NegateValue(Value *V, Instruction *BI) {
if (Constant *C = dyn_cast<Constant>(V))
return ConstantExpr::getNeg(C);
if (Instruction *I = dyn_cast<Instruction>(V))
if (I->getOpcode() == Instruction::Add && I->hasOneUse()) {
I->setOperand(0, NegateValue(I->getOperand(0), BI));
I->setOperand(1, NegateValue(I->getOperand(1), BI));
I->moveBefore(BI);
I->setName(I->getName()+".neg");
return I;
}
for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){
User *U = *UI;
if (!BinaryOperator::isNeg(U)) continue;
BinaryOperator *TheNeg = cast<BinaryOperator>(U);
if (TheNeg->getParent()->getParent() != BI->getParent()->getParent())
continue;
BasicBlock::iterator InsertPt;
if (Instruction *InstInput = dyn_cast<Instruction>(V)) {
if (InvokeInst *II = dyn_cast<InvokeInst>(InstInput)) {
InsertPt = II->getNormalDest()->begin();
} else {
InsertPt = InstInput;
++InsertPt;
}
while (isa<PHINode>(InsertPt)) ++InsertPt;
} else {
InsertPt = TheNeg->getParent()->getParent()->getEntryBlock().begin();
}
TheNeg->moveBefore(InsertPt);
return TheNeg;
}
return BinaryOperator::CreateNeg(V, V->getName() + ".neg", BI);
}
static bool ShouldBreakUpSubtract(Instruction *Sub) {
if (BinaryOperator::isNeg(Sub))
return false;
if (isReassociableOp(Sub->getOperand(0), Instruction::Add) ||
isReassociableOp(Sub->getOperand(0), Instruction::Sub))
return true;
if (isReassociableOp(Sub->getOperand(1), Instruction::Add) ||
isReassociableOp(Sub->getOperand(1), Instruction::Sub))
return true;
if (Sub->hasOneUse() &&
(isReassociableOp(Sub->use_back(), Instruction::Add) ||
isReassociableOp(Sub->use_back(), Instruction::Sub)))
return true;
return false;
}
static Instruction *BreakUpSubtract(Instruction *Sub,
DenseMap<AssertingVH<>, unsigned> &ValueRankMap) {
Value *NegVal = NegateValue(Sub->getOperand(1), Sub);
Instruction *New =
BinaryOperator::CreateAdd(Sub->getOperand(0), NegVal, "", Sub);
New->takeName(Sub);
ValueRankMap.erase(Sub);
Sub->replaceAllUsesWith(New);
New->setDebugLoc(Sub->getDebugLoc());
Sub->eraseFromParent();
DEBUG(dbgs() << "Negated: " << *New << '\n');
return New;
}
static Instruction *ConvertShiftToMul(Instruction *Shl,
DenseMap<AssertingVH<>, unsigned> &ValueRankMap) {
if (isReassociableOp(Shl->getOperand(0), Instruction::Mul) ||
(Shl->hasOneUse() &&
(isReassociableOp(Shl->use_back(), Instruction::Mul) ||
isReassociableOp(Shl->use_back(), Instruction::Add)))) {
Constant *MulCst = ConstantInt::get(Shl->getType(), 1);
MulCst = ConstantExpr::getShl(MulCst, cast<Constant>(Shl->getOperand(1)));
Instruction *Mul =
BinaryOperator::CreateMul(Shl->getOperand(0), MulCst, "", Shl);
ValueRankMap.erase(Shl);
Mul->takeName(Shl);
Shl->replaceAllUsesWith(Mul);
Mul->setDebugLoc(Shl->getDebugLoc());
Shl->eraseFromParent();
return Mul;
}
return 0;
}
static unsigned FindInOperandList(SmallVectorImpl<ValueEntry> &Ops, unsigned i,
Value *X) {
unsigned XRank = Ops[i].Rank;
unsigned e = Ops.size();
for (unsigned j = i+1; j != e && Ops[j].Rank == XRank; ++j)
if (Ops[j].Op == X)
return j;
for (unsigned j = i-1; j != ~0U && Ops[j].Rank == XRank; --j)
if (Ops[j].Op == X)
return j;
return i;
}
static Value *EmitAddTreeOfValues(Instruction *I, SmallVectorImpl<Value*> &Ops){
if (Ops.size() == 1) return Ops.back();
Value *V1 = Ops.back();
Ops.pop_back();
Value *V2 = EmitAddTreeOfValues(I, Ops);
return BinaryOperator::CreateAdd(V2, V1, "tmp", I);
}
Value *Reassociate::RemoveFactorFromExpression(Value *V, Value *Factor) {
BinaryOperator *BO = isReassociableOp(V, Instruction::Mul);
if (!BO) return 0;
SmallVector<ValueEntry, 8> Factors;
LinearizeExprTree(BO, Factors);
bool FoundFactor = false;
bool NeedsNegate = false;
for (unsigned i = 0, e = Factors.size(); i != e; ++i) {
if (Factors[i].Op == Factor) {
FoundFactor = true;
Factors.erase(Factors.begin()+i);
break;
}
if (ConstantInt *FC1 = dyn_cast<ConstantInt>(Factor))
if (ConstantInt *FC2 = dyn_cast<ConstantInt>(Factors[i].Op))
if (FC1->getValue() == -FC2->getValue()) {
FoundFactor = NeedsNegate = true;
Factors.erase(Factors.begin()+i);
break;
}
}
if (!FoundFactor) {
RewriteExprTree(BO, Factors);
return 0;
}
BasicBlock::iterator InsertPt = BO; ++InsertPt;
if (Factors.size() == 1) {
ValueRankMap.erase(BO);
DeadInsts.push_back(BO);
V = Factors[0].Op;
} else {
RewriteExprTree(BO, Factors);
V = BO;
}
if (NeedsNegate)
V = BinaryOperator::CreateNeg(V, "neg", InsertPt);
return V;
}
static void FindSingleUseMultiplyFactors(Value *V,
SmallVectorImpl<Value*> &Factors,
const SmallVectorImpl<ValueEntry> &Ops,
bool IsRoot) {
BinaryOperator *BO;
if (!(V->hasOneUse() || V->use_empty()) || !(BO = dyn_cast<BinaryOperator>(V)) ||
BO->getOpcode() != Instruction::Mul) {
Factors.push_back(V);
return;
}
if (!IsRoot) {
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
if (Ops[i].Op == V) {
Factors.push_back(V);
return;
}
}
FindSingleUseMultiplyFactors(BO->getOperand(1), Factors, Ops, false);
FindSingleUseMultiplyFactors(BO->getOperand(0), Factors, Ops, false);
}
static Value *OptimizeAndOrXor(unsigned Opcode,
SmallVectorImpl<ValueEntry> &Ops) {
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
assert(i < Ops.size());
if (BinaryOperator::isNot(Ops[i].Op)) { Value *X = BinaryOperator::getNotArgument(Ops[i].Op);
unsigned FoundX = FindInOperandList(Ops, i, X);
if (FoundX != i) {
if (Opcode == Instruction::And) return Constant::getNullValue(X->getType());
if (Opcode == Instruction::Or) return Constant::getAllOnesValue(X->getType());
}
}
assert(i < Ops.size());
if (i+1 != Ops.size() && Ops[i+1].Op == Ops[i].Op) {
if (Opcode == Instruction::And || Opcode == Instruction::Or) {
Ops.erase(Ops.begin()+i);
--i; --e;
++NumAnnihil;
continue;
}
assert(Opcode == Instruction::Xor);
if (e == 2)
return Constant::getNullValue(Ops[0].Op->getType());
Ops.erase(Ops.begin()+i, Ops.begin()+i+2);
i -= 1; e -= 2;
++NumAnnihil;
}
}
return 0;
}
Value *Reassociate::OptimizeAdd(Instruction *I,
SmallVectorImpl<ValueEntry> &Ops) {
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
Value *TheOp = Ops[i].Op;
if (i+1 != Ops.size() && Ops[i+1].Op == TheOp) {
unsigned NumFound = 0;
do {
Ops.erase(Ops.begin()+i);
++NumFound;
} while (i != Ops.size() && Ops[i].Op == TheOp);
DEBUG(errs() << "\nFACTORING [" << NumFound << "]: " << *TheOp << '\n');
++NumFactor;
Value *Mul = ConstantInt::get(cast<IntegerType>(I->getType()), NumFound);
Mul = BinaryOperator::CreateMul(TheOp, Mul, "factor", I);
RedoInsts.push_back(Mul);
if (Ops.empty())
return Mul;
Ops.insert(Ops.begin(), ValueEntry(getRank(Mul), Mul));
--i;
e = Ops.size();
continue;
}
if (!BinaryOperator::isNeg(TheOp))
continue;
Value *X = BinaryOperator::getNegArgument(TheOp);
unsigned FoundX = FindInOperandList(Ops, i, X);
if (FoundX == i)
continue;
if (Ops.size() == 2)
return Constant::getNullValue(X->getType());
Ops.erase(Ops.begin()+i);
if (i < FoundX)
--FoundX;
else
--i; Ops.erase(Ops.begin()+FoundX);
++NumAnnihil;
--i; e -= 2; }
DenseMap<Value*, unsigned> FactorOccurrences;
unsigned MaxOcc = 0;
Value *MaxOccVal = 0;
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
BinaryOperator *BOp = dyn_cast<BinaryOperator>(Ops[i].Op);
if (BOp == 0 || BOp->getOpcode() != Instruction::Mul || !BOp->use_empty())
continue;
SmallVector<Value*, 8> Factors;
FindSingleUseMultiplyFactors(BOp, Factors, Ops, true);
assert(Factors.size() > 1 && "Bad linearize!");
SmallPtrSet<Value*, 8> Duplicates;
for (unsigned i = 0, e = Factors.size(); i != e; ++i) {
Value *Factor = Factors[i];
if (!Duplicates.insert(Factor)) continue;
unsigned Occ = ++FactorOccurrences[Factor];
if (Occ > MaxOcc) { MaxOcc = Occ; MaxOccVal = Factor; }
if (ConstantInt *CI = dyn_cast<ConstantInt>(Factor))
if (CI->isNegative() && !CI->isMinValue(true)) {
Factor = ConstantInt::get(CI->getContext(), -CI->getValue());
assert(!Duplicates.count(Factor) &&
"Shouldn't have two constant factors, missed a canonicalize");
unsigned Occ = ++FactorOccurrences[Factor];
if (Occ > MaxOcc) { MaxOcc = Occ; MaxOccVal = Factor; }
}
}
}
if (MaxOcc > 1) {
DEBUG(errs() << "\nFACTORING [" << MaxOcc << "]: " << *MaxOccVal << '\n');
++NumFactor;
Instruction *DummyInst = BinaryOperator::CreateAdd(MaxOccVal, MaxOccVal);
SmallVector<Value*, 4> NewMulOps;
for (unsigned i = 0; i != Ops.size(); ++i) {
BinaryOperator *BOp = dyn_cast<BinaryOperator>(Ops[i].Op);
if (BOp == 0 || BOp->getOpcode() != Instruction::Mul || !BOp->use_empty())
continue;
if (Value *V = RemoveFactorFromExpression(Ops[i].Op, MaxOccVal)) {
for (unsigned j = Ops.size(); j != i;) {
--j;
if (Ops[j].Op == Ops[i].Op) {
NewMulOps.push_back(V);
Ops.erase(Ops.begin()+j);
}
}
--i;
}
}
delete DummyInst;
unsigned NumAddedValues = NewMulOps.size();
Value *V = EmitAddTreeOfValues(I, NewMulOps);
assert(NumAddedValues > 1 && "Each occurrence should contribute a value");
(void)NumAddedValues;
V = ReassociateExpression(cast<BinaryOperator>(V));
Value *V2 = BinaryOperator::CreateMul(V, MaxOccVal, "tmp", I);
V2 = ReassociateExpression(cast<BinaryOperator>(V2));
if (Ops.empty())
return V2;
Ops.insert(Ops.begin(), ValueEntry(getRank(V2), V2));
}
return 0;
}
Value *Reassociate::OptimizeExpression(BinaryOperator *I,
SmallVectorImpl<ValueEntry> &Ops) {
bool IterateOptimization = false;
if (Ops.size() == 1) return Ops[0].Op;
unsigned Opcode = I->getOpcode();
if (Constant *V1 = dyn_cast<Constant>(Ops[Ops.size()-2].Op))
if (Constant *V2 = dyn_cast<Constant>(Ops.back().Op)) {
Ops.pop_back();
Ops.back().Op = ConstantExpr::get(Opcode, V1, V2);
return OptimizeExpression(I, Ops);
}
if (ConstantInt *CstVal = dyn_cast<ConstantInt>(Ops.back().Op))
switch (Opcode) {
default: break;
case Instruction::And:
if (CstVal->isZero()) return CstVal;
if (CstVal->isAllOnesValue()) Ops.pop_back();
break;
case Instruction::Mul:
if (CstVal->isZero()) { ++NumAnnihil;
return CstVal;
}
if (cast<ConstantInt>(CstVal)->isOne())
Ops.pop_back(); break;
case Instruction::Or:
if (CstVal->isAllOnesValue()) return CstVal;
case Instruction::Add:
case Instruction::Xor:
if (CstVal->isZero()) Ops.pop_back();
break;
}
if (Ops.size() == 1) return Ops[0].Op;
switch (Opcode) {
default: break;
case Instruction::And:
case Instruction::Or:
case Instruction::Xor: {
unsigned NumOps = Ops.size();
if (Value *Result = OptimizeAndOrXor(Opcode, Ops))
return Result;
IterateOptimization |= Ops.size() != NumOps;
break;
}
case Instruction::Add: {
unsigned NumOps = Ops.size();
if (Value *Result = OptimizeAdd(I, Ops))
return Result;
IterateOptimization |= Ops.size() != NumOps;
}
break;
}
if (IterateOptimization)
return OptimizeExpression(I, Ops);
return 0;
}
void Reassociate::ReassociateInst(BasicBlock::iterator &BBI) {
Instruction *BI = BBI++;
if (BI->getOpcode() == Instruction::Shl &&
isa<ConstantInt>(BI->getOperand(1)))
if (Instruction *NI = ConvertShiftToMul(BI, ValueRankMap)) {
MadeChange = true;
BI = NI;
}
if (!isa<BinaryOperator>(BI) || BI->getType()->isFloatingPointTy() ||
BI->getType()->isVectorTy())
return;
if (BI->getType()->isIntegerTy(1))
return;
if (BI->getOpcode() == Instruction::Sub) {
if (ShouldBreakUpSubtract(BI)) {
BI = BreakUpSubtract(BI, ValueRankMap);
BBI = BI;
++BBI;
MadeChange = true;
} else if (BinaryOperator::isNeg(BI)) {
if (isReassociableOp(BI->getOperand(1), Instruction::Mul) &&
(!BI->hasOneUse() ||
!isReassociableOp(BI->use_back(), Instruction::Mul))) {
BI = LowerNegateToMultiply(BI, ValueRankMap);
MadeChange = true;
}
}
}
if (!BI->isAssociative()) return;
BinaryOperator *I = cast<BinaryOperator>(BI);
if (I->hasOneUse() && isReassociableOp(I->use_back(), I->getOpcode()))
return;
if (I->hasOneUse() && I->getOpcode() == Instruction::Add &&
cast<Instruction>(I->use_back())->getOpcode() == Instruction::Sub)
return;
ReassociateExpression(I);
}
Value *Reassociate::ReassociateExpression(BinaryOperator *I) {
SmallVector<ValueEntry, 8> Ops;
LinearizeExprTree(I, Ops);
DEBUG(dbgs() << "RAIn:\t"; PrintOps(I, Ops); dbgs() << '\n');
std::stable_sort(Ops.begin(), Ops.end());
if (Value *V = OptimizeExpression(I, Ops)) {
DEBUG(dbgs() << "Reassoc to scalar: " << *V << '\n');
I->replaceAllUsesWith(V);
if (Instruction *VI = dyn_cast<Instruction>(V))
VI->setDebugLoc(I->getDebugLoc());
RemoveDeadBinaryOp(I);
++NumAnnihil;
return V;
}
if (I->getOpcode() == Instruction::Mul && I->hasOneUse() &&
cast<Instruction>(I->use_back())->getOpcode() == Instruction::Add &&
isa<ConstantInt>(Ops.back().Op) &&
cast<ConstantInt>(Ops.back().Op)->isAllOnesValue()) {
ValueEntry Tmp = Ops.pop_back_val();
Ops.insert(Ops.begin(), Tmp);
}
DEBUG(dbgs() << "RAOut:\t"; PrintOps(I, Ops); dbgs() << '\n');
if (Ops.size() == 1) {
I->replaceAllUsesWith(Ops[0].Op);
if (Instruction *OI = dyn_cast<Instruction>(Ops[0].Op))
OI->setDebugLoc(I->getDebugLoc());
RemoveDeadBinaryOp(I);
return Ops[0].Op;
}
RewriteExprTree(I, Ops);
return I;
}
bool Reassociate::runOnFunction(Function &F) {
BuildRankMap(F);
MadeChange = false;
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
for (BasicBlock::iterator BBI = FI->begin(); BBI != FI->end(); )
ReassociateInst(BBI);
while (!RedoInsts.empty())
if (Value *V = RedoInsts.pop_back_val()) {
BasicBlock::iterator BBI = cast<Instruction>(V);
ReassociateInst(BBI);
}
while (!DeadInsts.empty())
if (Value *V = DeadInsts.pop_back_val())
RecursivelyDeleteTriviallyDeadInstructions(V);
RankMap.clear();
ValueRankMap.clear();
return MadeChange;
}