mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-25 20:59:51 +00:00
Added isValidRewrite() to check the result of ScalarEvolutionExpander.
SCEV may generate expressions composed of multiple pointers, which can lead to invalid GEP expansion. Until we can teach SCEV to follow strict pointer rules, make sure no bad GEPs creep into IR. Fixes rdar://problem/9038671. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@127839 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ead71d59a7
commit
b12a754cce
@ -618,6 +618,12 @@ namespace llvm {
|
|||||||
const SCEV *getUMinFromMismatchedTypes(const SCEV *LHS,
|
const SCEV *getUMinFromMismatchedTypes(const SCEV *LHS,
|
||||||
const SCEV *RHS);
|
const SCEV *RHS);
|
||||||
|
|
||||||
|
/// getPointerBase - Transitively follow the chain of pointer-type operands
|
||||||
|
/// until reaching a SCEV that does not have a single pointer operand. This
|
||||||
|
/// returns a SCEVUnknown pointer for well-formed pointer-type expressions,
|
||||||
|
/// but corner cases do exist.
|
||||||
|
const SCEV *getPointerBase(const SCEV *V);
|
||||||
|
|
||||||
/// getSCEVAtScope - Return a SCEV expression for the specified value
|
/// getSCEVAtScope - Return a SCEV expression for the specified value
|
||||||
/// at the specified scope in the program. The L value specifies a loop
|
/// at the specified scope in the program. The L value specifies a loop
|
||||||
/// nest to evaluate the expression at, where null is the top-level or a
|
/// nest to evaluate the expression at, where null is the top-level or a
|
||||||
|
@ -2718,6 +2718,36 @@ const SCEV *ScalarEvolution::getUMinFromMismatchedTypes(const SCEV *LHS,
|
|||||||
return getUMinExpr(PromotedLHS, PromotedRHS);
|
return getUMinExpr(PromotedLHS, PromotedRHS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getPointerBase - Transitively follow the chain of pointer-type operands
|
||||||
|
/// until reaching a SCEV that does not have a single pointer operand. This
|
||||||
|
/// returns a SCEVUnknown pointer for well-formed pointer-type expressions,
|
||||||
|
/// but corner cases do exist.
|
||||||
|
const SCEV *ScalarEvolution::getPointerBase(const SCEV *V) {
|
||||||
|
// A pointer operand may evaluate to a nonpointer expression, such as null.
|
||||||
|
if (!V->getType()->isPointerTy())
|
||||||
|
return V;
|
||||||
|
|
||||||
|
if (const SCEVCastExpr *Cast = dyn_cast<SCEVCastExpr>(V)) {
|
||||||
|
return getPointerBase(Cast->getOperand());
|
||||||
|
}
|
||||||
|
else if (const SCEVNAryExpr *NAry = dyn_cast<SCEVNAryExpr>(V)) {
|
||||||
|
const SCEV *PtrOp = 0;
|
||||||
|
for (SCEVNAryExpr::op_iterator I = NAry->op_begin(), E = NAry->op_end();
|
||||||
|
I != E; ++I) {
|
||||||
|
if ((*I)->getType()->isPointerTy()) {
|
||||||
|
// Cannot find the base of an expression with multiple pointer operands.
|
||||||
|
if (PtrOp)
|
||||||
|
return V;
|
||||||
|
PtrOp = *I;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!PtrOp)
|
||||||
|
return V;
|
||||||
|
return getPointerBase(PtrOp);
|
||||||
|
}
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
|
||||||
/// PushDefUseChildren - Push users of the given Instruction
|
/// PushDefUseChildren - Push users of the given Instruction
|
||||||
/// onto the given Worklist.
|
/// onto the given Worklist.
|
||||||
static void
|
static void
|
||||||
|
@ -51,12 +51,14 @@
|
|||||||
#include "llvm/Analysis/ScalarEvolutionExpander.h"
|
#include "llvm/Analysis/ScalarEvolutionExpander.h"
|
||||||
#include "llvm/Analysis/LoopInfo.h"
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
#include "llvm/Analysis/LoopPass.h"
|
#include "llvm/Analysis/LoopPass.h"
|
||||||
|
#include "llvm/Analysis/ValueTracking.h"
|
||||||
#include "llvm/Support/CFG.h"
|
#include "llvm/Support/CFG.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Transforms/Utils/Local.h"
|
#include "llvm/Transforms/Utils/Local.h"
|
||||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
@ -73,6 +75,8 @@ namespace {
|
|||||||
LoopInfo *LI;
|
LoopInfo *LI;
|
||||||
ScalarEvolution *SE;
|
ScalarEvolution *SE;
|
||||||
DominatorTree *DT;
|
DominatorTree *DT;
|
||||||
|
const TargetData *TD;
|
||||||
|
SmallVector<WeakVH, 16> DeadInsts;
|
||||||
bool Changed;
|
bool Changed;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -98,6 +102,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool isValidRewrite(Value *FromVal, Value *ToVal);
|
||||||
|
|
||||||
void EliminateIVComparisons();
|
void EliminateIVComparisons();
|
||||||
void EliminateIVRemainders();
|
void EliminateIVRemainders();
|
||||||
@ -134,6 +139,53 @@ Pass *llvm::createIndVarSimplifyPass() {
|
|||||||
return new IndVarSimplify();
|
return new IndVarSimplify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// isValidRewrite - Return true if the SCEV expansion generated by the
|
||||||
|
/// rewriter can replace the original value. SCEV guarantees that it
|
||||||
|
/// produces the same value, but the way it is produced may be illegal IR.
|
||||||
|
/// Ideally, this function will only be called for verification.
|
||||||
|
bool IndVarSimplify::isValidRewrite(Value *FromVal, Value *ToVal) {
|
||||||
|
// If an SCEV expression subsumed multiple pointers, its expansion could
|
||||||
|
// reassociate the GEP changing the base pointer. This is illegal because the
|
||||||
|
// final address produced by a GEP chain must be inbounds relative to its
|
||||||
|
// underlying object. Otherwise basic alias analysis, among other things,
|
||||||
|
// could fail in a dangerous way. Ultimately, SCEV will be improved to avoid
|
||||||
|
// producing an expression involving multiple pointers. Until then, we must
|
||||||
|
// bail out here.
|
||||||
|
//
|
||||||
|
// Retrieve the pointer operand of the GEP. Don't use GetUnderlyingObject
|
||||||
|
// because it understands lcssa phis while SCEV does not.
|
||||||
|
Value *FromPtr = FromVal;
|
||||||
|
Value *ToPtr = ToVal;
|
||||||
|
if (GEPOperator *GEP = dyn_cast<GEPOperator>(FromVal)) {
|
||||||
|
FromPtr = GEP->getPointerOperand();
|
||||||
|
}
|
||||||
|
if (GEPOperator *GEP = dyn_cast<GEPOperator>(ToVal)) {
|
||||||
|
ToPtr = GEP->getPointerOperand();
|
||||||
|
}
|
||||||
|
if (FromPtr != FromVal || ToPtr != ToVal) {
|
||||||
|
// Quickly check the common case
|
||||||
|
if (FromPtr == ToPtr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// SCEV may have rewritten an expression that produces the GEP's pointer
|
||||||
|
// operand. That's ok as long as the pointer operand has the same base
|
||||||
|
// pointer. Unlike GetUnderlyingObject(), getPointerBase() will find the
|
||||||
|
// base of a recurrence. This handles the case in which SCEV expansion
|
||||||
|
// converts a pointer type recurrence into a nonrecurrent pointer base
|
||||||
|
// indexed by an integer recurrence.
|
||||||
|
const SCEV *FromBase = SE->getPointerBase(SE->getSCEV(FromPtr));
|
||||||
|
const SCEV *ToBase = SE->getPointerBase(SE->getSCEV(ToPtr));
|
||||||
|
if (FromBase == ToBase)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "INDVARS: GEP rewrite bail out "
|
||||||
|
<< *FromBase << " != " << *ToBase << "\n");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// LinearFunctionTestReplace - This method rewrites the exit condition of the
|
/// LinearFunctionTestReplace - This method rewrites the exit condition of the
|
||||||
/// loop to be a canonical != comparison against the incremented loop induction
|
/// loop to be a canonical != comparison against the incremented loop induction
|
||||||
/// variable. This pass is able to rewrite the exit tests of any loop where the
|
/// variable. This pass is able to rewrite the exit tests of any loop where the
|
||||||
@ -304,14 +356,18 @@ void IndVarSimplify::RewriteLoopExitValues(Loop *L, SCEVExpander &Rewriter) {
|
|||||||
if (!SE->isLoopInvariant(ExitValue, L))
|
if (!SE->isLoopInvariant(ExitValue, L))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Changed = true;
|
|
||||||
++NumReplaced;
|
|
||||||
|
|
||||||
Value *ExitVal = Rewriter.expandCodeFor(ExitValue, PN->getType(), Inst);
|
Value *ExitVal = Rewriter.expandCodeFor(ExitValue, PN->getType(), Inst);
|
||||||
|
|
||||||
DEBUG(dbgs() << "INDVARS: RLEV: AfterLoopVal = " << *ExitVal << '\n'
|
DEBUG(dbgs() << "INDVARS: RLEV: AfterLoopVal = " << *ExitVal << '\n'
|
||||||
<< " LoopVal = " << *Inst << "\n");
|
<< " LoopVal = " << *Inst << "\n");
|
||||||
|
|
||||||
|
if (!isValidRewrite(Inst, ExitVal)) {
|
||||||
|
DeadInsts.push_back(ExitVal);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Changed = true;
|
||||||
|
++NumReplaced;
|
||||||
|
|
||||||
PN->setIncomingValue(i, ExitVal);
|
PN->setIncomingValue(i, ExitVal);
|
||||||
|
|
||||||
// If this instruction is dead now, delete it.
|
// If this instruction is dead now, delete it.
|
||||||
@ -366,8 +422,6 @@ void IndVarSimplify::RewriteNonIntegerIVs(Loop *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IndVarSimplify::EliminateIVComparisons() {
|
void IndVarSimplify::EliminateIVComparisons() {
|
||||||
SmallVector<WeakVH, 16> DeadInsts;
|
|
||||||
|
|
||||||
// Look for ICmp users.
|
// Look for ICmp users.
|
||||||
for (IVUsers::iterator I = IU->begin(), E = IU->end(); I != E; ++I) {
|
for (IVUsers::iterator I = IU->begin(), E = IU->end(); I != E; ++I) {
|
||||||
IVStrideUse &UI = *I;
|
IVStrideUse &UI = *I;
|
||||||
@ -399,18 +453,9 @@ void IndVarSimplify::EliminateIVComparisons() {
|
|||||||
DEBUG(dbgs() << "INDVARS: Eliminated comparison: " << *ICmp << '\n');
|
DEBUG(dbgs() << "INDVARS: Eliminated comparison: " << *ICmp << '\n');
|
||||||
DeadInsts.push_back(ICmp);
|
DeadInsts.push_back(ICmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we're done iterating through lists, clean up any instructions
|
|
||||||
// which are now dead.
|
|
||||||
while (!DeadInsts.empty())
|
|
||||||
if (Instruction *Inst =
|
|
||||||
dyn_cast_or_null<Instruction>(&*DeadInsts.pop_back_val()))
|
|
||||||
RecursivelyDeleteTriviallyDeadInstructions(Inst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndVarSimplify::EliminateIVRemainders() {
|
void IndVarSimplify::EliminateIVRemainders() {
|
||||||
SmallVector<WeakVH, 16> DeadInsts;
|
|
||||||
|
|
||||||
// Look for SRem and URem users.
|
// Look for SRem and URem users.
|
||||||
for (IVUsers::iterator I = IU->begin(), E = IU->end(); I != E; ++I) {
|
for (IVUsers::iterator I = IU->begin(), E = IU->end(); I != E; ++I) {
|
||||||
IVStrideUse &UI = *I;
|
IVStrideUse &UI = *I;
|
||||||
@ -466,13 +511,6 @@ void IndVarSimplify::EliminateIVRemainders() {
|
|||||||
DEBUG(dbgs() << "INDVARS: Simplified rem: " << *Rem << '\n');
|
DEBUG(dbgs() << "INDVARS: Simplified rem: " << *Rem << '\n');
|
||||||
DeadInsts.push_back(Rem);
|
DeadInsts.push_back(Rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we're done iterating through lists, clean up any instructions
|
|
||||||
// which are now dead.
|
|
||||||
while (!DeadInsts.empty())
|
|
||||||
if (Instruction *Inst =
|
|
||||||
dyn_cast_or_null<Instruction>(&*DeadInsts.pop_back_val()))
|
|
||||||
RecursivelyDeleteTriviallyDeadInstructions(Inst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
|
bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||||
@ -491,6 +529,8 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
|
|||||||
LI = &getAnalysis<LoopInfo>();
|
LI = &getAnalysis<LoopInfo>();
|
||||||
SE = &getAnalysis<ScalarEvolution>();
|
SE = &getAnalysis<ScalarEvolution>();
|
||||||
DT = &getAnalysis<DominatorTree>();
|
DT = &getAnalysis<DominatorTree>();
|
||||||
|
TD = getAnalysisIfAvailable<TargetData>();
|
||||||
|
DeadInsts.clear();
|
||||||
Changed = false;
|
Changed = false;
|
||||||
|
|
||||||
// If there are any floating-point recurrences, attempt to
|
// If there are any floating-point recurrences, attempt to
|
||||||
@ -589,9 +629,21 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
|
|||||||
ExitingBlock, BI, Rewriter);
|
ExitingBlock, BI, Rewriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite IV-derived expressions. Clears the rewriter cache.
|
// Rewrite IV-derived expressions.
|
||||||
RewriteIVExpressions(L, Rewriter);
|
RewriteIVExpressions(L, Rewriter);
|
||||||
|
|
||||||
|
// Clear the rewriter cache, because values that are in the rewriter's cache
|
||||||
|
// can be deleted in the loop below, causing the AssertingVH in the cache to
|
||||||
|
// trigger.
|
||||||
|
Rewriter.clear();
|
||||||
|
|
||||||
|
// Now that we're done iterating through lists, clean up any instructions
|
||||||
|
// which are now dead.
|
||||||
|
while (!DeadInsts.empty())
|
||||||
|
if (Instruction *Inst =
|
||||||
|
dyn_cast_or_null<Instruction>(&*DeadInsts.pop_back_val()))
|
||||||
|
RecursivelyDeleteTriviallyDeadInstructions(Inst);
|
||||||
|
|
||||||
// The Rewriter may not be used from this point on.
|
// The Rewriter may not be used from this point on.
|
||||||
|
|
||||||
// Loop-invariant instructions in the preheader that aren't used in the
|
// Loop-invariant instructions in the preheader that aren't used in the
|
||||||
@ -651,8 +703,6 @@ static bool isSafe(const SCEV *S, const Loop *L, ScalarEvolution *SE) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IndVarSimplify::RewriteIVExpressions(Loop *L, SCEVExpander &Rewriter) {
|
void IndVarSimplify::RewriteIVExpressions(Loop *L, SCEVExpander &Rewriter) {
|
||||||
SmallVector<WeakVH, 16> DeadInsts;
|
|
||||||
|
|
||||||
// Rewrite all induction variable expressions in terms of the canonical
|
// Rewrite all induction variable expressions in terms of the canonical
|
||||||
// induction variable.
|
// induction variable.
|
||||||
//
|
//
|
||||||
@ -705,6 +755,13 @@ void IndVarSimplify::RewriteIVExpressions(Loop *L, SCEVExpander &Rewriter) {
|
|||||||
// Now expand it into actual Instructions and patch it into place.
|
// Now expand it into actual Instructions and patch it into place.
|
||||||
Value *NewVal = Rewriter.expandCodeFor(AR, UseTy, InsertPt);
|
Value *NewVal = Rewriter.expandCodeFor(AR, UseTy, InsertPt);
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "INDVARS: Rewrote IV '" << *AR << "' " << *Op << '\n'
|
||||||
|
<< " into = " << *NewVal << "\n");
|
||||||
|
|
||||||
|
if (!isValidRewrite(Op, NewVal)) {
|
||||||
|
DeadInsts.push_back(NewVal);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Inform ScalarEvolution that this value is changing. The change doesn't
|
// Inform ScalarEvolution that this value is changing. The change doesn't
|
||||||
// affect its value, but it does potentially affect which use lists the
|
// affect its value, but it does potentially affect which use lists the
|
||||||
// value will be on after the replacement, which affects ScalarEvolution's
|
// value will be on after the replacement, which affects ScalarEvolution's
|
||||||
@ -717,25 +774,13 @@ void IndVarSimplify::RewriteIVExpressions(Loop *L, SCEVExpander &Rewriter) {
|
|||||||
NewVal->takeName(Op);
|
NewVal->takeName(Op);
|
||||||
User->replaceUsesOfWith(Op, NewVal);
|
User->replaceUsesOfWith(Op, NewVal);
|
||||||
UI->setOperandValToReplace(NewVal);
|
UI->setOperandValToReplace(NewVal);
|
||||||
DEBUG(dbgs() << "INDVARS: Rewrote IV '" << *AR << "' " << *Op << '\n'
|
|
||||||
<< " into = " << *NewVal << "\n");
|
|
||||||
++NumRemoved;
|
++NumRemoved;
|
||||||
Changed = true;
|
Changed = true;
|
||||||
|
|
||||||
// The old value may be dead now.
|
// The old value may be dead now.
|
||||||
DeadInsts.push_back(Op);
|
DeadInsts.push_back(Op);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the rewriter cache, because values that are in the rewriter's cache
|
|
||||||
// can be deleted in the loop below, causing the AssertingVH in the cache to
|
|
||||||
// trigger.
|
|
||||||
Rewriter.clear();
|
|
||||||
// Now that we're done iterating through lists, clean up any instructions
|
|
||||||
// which are now dead.
|
|
||||||
while (!DeadInsts.empty())
|
|
||||||
if (Instruction *Inst =
|
|
||||||
dyn_cast_or_null<Instruction>(&*DeadInsts.pop_back_val()))
|
|
||||||
RecursivelyDeleteTriviallyDeadInstructions(Inst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If there's a single exit block, sink any loop-invariant values that
|
/// If there's a single exit block, sink any loop-invariant values that
|
||||||
|
Loading…
Reference in New Issue
Block a user