mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-04 09:54:09 +00:00
Implement more aggressive folding of add operand lists when
they contain multiplications of constants with add operations. This helps simplify several kinds of things; in particular it helps simplify expressions like ((-1 * (%a + %b)) + %a) to %b, as expressions like this often come up in loop trip count computations. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@73361 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
444f49150d
commit
bd59d7b603
@ -988,6 +988,102 @@ SCEVHandle ScalarEvolution::getAnyExtendExpr(const SCEVHandle &Op,
|
||||
return ZExt;
|
||||
}
|
||||
|
||||
/// CollectAddOperandsWithScales - Process the given Ops list, which is
|
||||
/// a list of operands to be added under the given scale, update the given
|
||||
/// map. This is a helper function for getAddRecExpr. As an example of
|
||||
/// what it does, given a sequence of operands that would form an add
|
||||
/// expression like this:
|
||||
///
|
||||
/// m + n + 13 + (A * (o + p + (B * q + m + 29))) + r + (-1 * r)
|
||||
///
|
||||
/// where A and B are constants, update the map with these values:
|
||||
///
|
||||
/// (m, 1+A*B), (n, 1), (o, A), (p, A), (q, A*B), (r, 0)
|
||||
///
|
||||
/// and add 13 + A*B*29 to AccumulatedConstant.
|
||||
/// This will allow getAddRecExpr to produce this:
|
||||
///
|
||||
/// 13+A*B*29 + n + (m * (1+A*B)) + ((o + p) * A) + (q * A*B)
|
||||
///
|
||||
/// This form often exposes folding opportunities that are hidden in
|
||||
/// the original operand list.
|
||||
///
|
||||
/// Return true iff it appears that any interesting folding opportunities
|
||||
/// may be exposed. This helps getAddRecExpr short-circuit extra work in
|
||||
/// the common case where no interesting opportunities are present, and
|
||||
/// is also used as a check to avoid infinite recursion.
|
||||
///
|
||||
static bool
|
||||
CollectAddOperandsWithScales(DenseMap<SCEVHandle, APInt> &M,
|
||||
SmallVector<SCEVHandle, 8> &NewOps,
|
||||
APInt &AccumulatedConstant,
|
||||
const SmallVectorImpl<SCEVHandle> &Ops,
|
||||
const APInt &Scale,
|
||||
ScalarEvolution &SE) {
|
||||
bool Interesting = false;
|
||||
|
||||
// Iterate over the add operands.
|
||||
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
|
||||
const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(Ops[i]);
|
||||
if (Mul && isa<SCEVConstant>(Mul->getOperand(0))) {
|
||||
APInt NewScale =
|
||||
Scale * cast<SCEVConstant>(Mul->getOperand(0))->getValue()->getValue();
|
||||
if (Mul->getNumOperands() == 2 && isa<SCEVAddExpr>(Mul->getOperand(1))) {
|
||||
// A multiplication of a constant with another add; recurse.
|
||||
Interesting |=
|
||||
CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant,
|
||||
cast<SCEVAddExpr>(Mul->getOperand(1))
|
||||
->getOperands(),
|
||||
NewScale, SE);
|
||||
} else {
|
||||
// A multiplication of a constant with some other value. Update
|
||||
// the map.
|
||||
SmallVector<SCEVHandle, 4> MulOps(Mul->op_begin()+1, Mul->op_end());
|
||||
SCEVHandle Key = SE.getMulExpr(MulOps);
|
||||
std::pair<DenseMap<SCEVHandle, APInt>::iterator, bool> Pair =
|
||||
M.insert(std::make_pair(Key, APInt()));
|
||||
if (Pair.second) {
|
||||
Pair.first->second = NewScale;
|
||||
NewOps.push_back(Pair.first->first);
|
||||
} else {
|
||||
Pair.first->second += NewScale;
|
||||
// The map already had an entry for this value, which may indicate
|
||||
// a folding opportunity.
|
||||
Interesting = true;
|
||||
}
|
||||
}
|
||||
} else if (const SCEVConstant *C = dyn_cast<SCEVConstant>(Ops[i])) {
|
||||
// Pull a buried constant out to the outside.
|
||||
if (Scale != 1 || AccumulatedConstant != 0 || C->isZero())
|
||||
Interesting = true;
|
||||
AccumulatedConstant += Scale * C->getValue()->getValue();
|
||||
} else {
|
||||
// An ordinary operand. Update the map.
|
||||
std::pair<DenseMap<SCEVHandle, APInt>::iterator, bool> Pair =
|
||||
M.insert(std::make_pair(Ops[i], APInt()));
|
||||
if (Pair.second) {
|
||||
Pair.first->second = Scale;
|
||||
NewOps.push_back(Pair.first->first);
|
||||
} else {
|
||||
Pair.first->second += Scale;
|
||||
// The map already had an entry for this value, which may indicate
|
||||
// a folding opportunity.
|
||||
Interesting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Interesting;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct APIntCompare {
|
||||
bool operator()(const APInt &LHS, const APInt &RHS) const {
|
||||
return LHS.ult(RHS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// getAddExpr - Get a canonical add expression, or something simpler if
|
||||
/// possible.
|
||||
SCEVHandle ScalarEvolution::getAddExpr(SmallVectorImpl<SCEVHandle> &Ops) {
|
||||
@ -1128,6 +1224,38 @@ SCEVHandle ScalarEvolution::getAddExpr(SmallVectorImpl<SCEVHandle> &Ops) {
|
||||
while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scMulExpr)
|
||||
++Idx;
|
||||
|
||||
// Check to see if there are any folding opportunities present with
|
||||
// operands multiplied by constant values.
|
||||
if (Idx < Ops.size() && isa<SCEVMulExpr>(Ops[Idx])) {
|
||||
uint64_t BitWidth = getTypeSizeInBits(Ty);
|
||||
DenseMap<SCEVHandle, APInt> M;
|
||||
SmallVector<SCEVHandle, 8> NewOps;
|
||||
APInt AccumulatedConstant(BitWidth, 0);
|
||||
if (CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant,
|
||||
Ops, APInt(BitWidth, 1), *this)) {
|
||||
// Some interesting folding opportunity is present, so its worthwhile to
|
||||
// re-generate the operands list. Group the operands by constant scale,
|
||||
// to avoid multiplying by the same constant scale multiple times.
|
||||
std::map<APInt, SmallVector<SCEVHandle, 4>, APIntCompare> MulOpLists;
|
||||
for (SmallVector<SCEVHandle, 8>::iterator I = NewOps.begin(),
|
||||
E = NewOps.end(); I != E; ++I)
|
||||
MulOpLists[M.find(*I)->second].push_back(*I);
|
||||
// Re-generate the operands list.
|
||||
Ops.clear();
|
||||
if (AccumulatedConstant != 0)
|
||||
Ops.push_back(getConstant(AccumulatedConstant));
|
||||
for (std::map<APInt, SmallVector<SCEVHandle, 4>, APIntCompare>::iterator I =
|
||||
MulOpLists.begin(), E = MulOpLists.end(); I != E; ++I)
|
||||
if (I->first != 0)
|
||||
Ops.push_back(getMulExpr(getConstant(I->first), getAddExpr(I->second)));
|
||||
if (Ops.empty())
|
||||
return getIntegerSCEV(0, Ty);
|
||||
if (Ops.size() == 1)
|
||||
return Ops[0];
|
||||
return getAddExpr(Ops);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are adding something to a multiply expression, make sure the
|
||||
// something is not already an operand of the multiply. If so, merge it into
|
||||
// the multiply.
|
||||
|
38
test/Transforms/IndVarSimplify/pointer.ll
Normal file
38
test/Transforms/IndVarSimplify/pointer.ll
Normal file
@ -0,0 +1,38 @@
|
||||
; RUN: llvm-as < %s | opt -indvars | llvm-dis > %t
|
||||
; RUN: grep {%exitcond = icmp eq i64 %indvar.next, %n} %t
|
||||
; RUN: grep {getelementptr i8\\* %A, i64 %indvar} %t
|
||||
; RUN: grep getelementptr %t | count 1
|
||||
; RUN: grep add %t | count 1
|
||||
; RUN: not grep scevgep %t
|
||||
; RUN: not grep ptrtoint %t
|
||||
|
||||
; Indvars should be able to expand the pointer-arithmetic
|
||||
; IV into an integer IV indexing into a simple getelementptr.
|
||||
|
||||
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64"
|
||||
|
||||
define void @foo(i8* %A, i64 %n) nounwind {
|
||||
entry:
|
||||
%0 = icmp eq i64 %n, 0 ; <i1> [#uses=1]
|
||||
br i1 %0, label %return, label %bb.nph
|
||||
|
||||
bb.nph: ; preds = %entry
|
||||
%1 = getelementptr i8* %A, i64 %n ; <i8*> [#uses=1]
|
||||
br label %bb
|
||||
|
||||
bb: ; preds = %bb1, %bb.nph
|
||||
%q.01 = phi i8* [ %2, %bb1 ], [ %A, %bb.nph ] ; <i8*> [#uses=2]
|
||||
store i8 0, i8* %q.01, align 1
|
||||
%2 = getelementptr i8* %q.01, i64 1 ; <i8*> [#uses=2]
|
||||
br label %bb1
|
||||
|
||||
bb1: ; preds = %bb
|
||||
%3 = icmp eq i8* %1, %2 ; <i1> [#uses=1]
|
||||
br i1 %3, label %bb1.return_crit_edge, label %bb
|
||||
|
||||
bb1.return_crit_edge: ; preds = %bb1
|
||||
br label %return
|
||||
|
||||
return: ; preds = %bb1.return_crit_edge, %entry
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user