forked from OSchip/llvm-project
NewGVN: Start making use of predicateinfo pass.
Summary: This begins using the predicateinfo pass in NewGVN. Reviewers: davide Subscribers: llvm-commits, Prazek Differential Revision: https://reviews.llvm.org/D29682 llvm-svn: 295583
This commit is contained in:
parent
b355c4ff5f
commit
f7d9580a08
|
@ -81,13 +81,13 @@
|
|||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/MemorySSA.h"
|
||||
#include "llvm/Transforms/Utils/PredicateInfo.h"
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
using namespace llvm;
|
||||
using namespace PatternMatch;
|
||||
using namespace llvm::GVNExpression;
|
||||
|
||||
#define DEBUG_TYPE "newgvn"
|
||||
|
||||
STATISTIC(NumGVNInstrDeleted, "Number of instructions deleted");
|
||||
|
@ -209,6 +209,7 @@ class NewGVN : public FunctionPass {
|
|||
AliasAnalysis *AA;
|
||||
MemorySSA *MSSA;
|
||||
MemorySSAWalker *MSSAWalker;
|
||||
std::unique_ptr<PredicateInfo> PredInfo;
|
||||
BumpPtrAllocator ExpressionAllocator;
|
||||
ArrayRecycler<Value *> ArgRecycler;
|
||||
|
||||
|
@ -229,6 +230,12 @@ class NewGVN : public FunctionPass {
|
|||
DenseMap<Value *, CongruenceClass *> ValueToClass;
|
||||
DenseMap<Value *, const Expression *> ValueToExpression;
|
||||
|
||||
// Mapping from predicate info we used to the instructions we used it with.
|
||||
// In order to correctly ensure propagation, we must keep track of what
|
||||
// comparisons we used, so that when the values of the comparisons change, we
|
||||
// propagate the information to the places we used the comparison.
|
||||
DenseMap<const Value *, SmallPtrSet<Instruction *, 2>> PredicateToUsers;
|
||||
|
||||
// A table storing which memorydefs/phis represent a memory state provably
|
||||
// equivalent to another memory state.
|
||||
// We could use the congruence class machinery, but the MemoryAccess's are
|
||||
|
@ -297,7 +304,6 @@ private:
|
|||
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||||
AU.addRequired<MemorySSAWrapperPass>();
|
||||
AU.addRequired<AAResultsWrapperPass>();
|
||||
|
||||
AU.addPreserved<DominatorTreeWrapperPass>();
|
||||
AU.addPreserved<GlobalsAAWrapperPass>();
|
||||
}
|
||||
|
@ -308,6 +314,7 @@ private:
|
|||
PHIExpression *createPHIExpression(Instruction *);
|
||||
const VariableExpression *createVariableExpression(Value *);
|
||||
const ConstantExpression *createConstantExpression(Constant *);
|
||||
const Expression *createVariableOrConstant(Value *V);
|
||||
const UnknownExpression *createUnknownExpression(Instruction *);
|
||||
const StoreExpression *createStoreExpression(StoreInst *, MemoryAccess *);
|
||||
LoadExpression *createLoadExpression(Type *, Value *, LoadInst *,
|
||||
|
@ -345,6 +352,7 @@ private:
|
|||
const Expression *performSymbolicPHIEvaluation(Instruction *);
|
||||
const Expression *performSymbolicAggrValueEvaluation(Instruction *);
|
||||
const Expression *performSymbolicCmpEvaluation(Instruction *);
|
||||
const Expression *performSymbolicPredicateInfoEvaluation(Instruction *);
|
||||
|
||||
// Congruence finding.
|
||||
Value *lookupOperandLeader(Value *) const;
|
||||
|
@ -382,13 +390,16 @@ private:
|
|||
// Various instruction touch utilities
|
||||
void markUsersTouched(Value *);
|
||||
void markMemoryUsersTouched(MemoryAccess *);
|
||||
void markPredicateUsersTouched(Instruction *);
|
||||
void markLeaderChangeTouched(CongruenceClass *CC);
|
||||
void addPredicateUsers(const PredicateBase *, Instruction *);
|
||||
|
||||
// Utilities.
|
||||
void cleanupTables();
|
||||
std::pair<unsigned, unsigned> assignDFSNumbers(BasicBlock *, unsigned);
|
||||
void updateProcessedCount(Value *V);
|
||||
void verifyMemoryCongruency() const;
|
||||
void verifyComparisons(Function &F);
|
||||
bool singleReachablePHIPath(const MemoryAccess *, const MemoryAccess *) const;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
@ -669,6 +680,12 @@ const VariableExpression *NewGVN::createVariableExpression(Value *V) {
|
|||
return E;
|
||||
}
|
||||
|
||||
const Expression *NewGVN::createVariableOrConstant(Value *V) {
|
||||
if (auto *C = dyn_cast<Constant>(V))
|
||||
return createConstantExpression(C);
|
||||
return createVariableExpression(V);
|
||||
}
|
||||
|
||||
const ConstantExpression *NewGVN::createConstantExpression(Constant *C) {
|
||||
auto *E = new (ExpressionAllocator) ConstantExpression(C);
|
||||
E->setOpcode(C->getValueID());
|
||||
|
@ -831,12 +848,103 @@ const Expression *NewGVN::performSymbolicLoadEvaluation(Instruction *I) {
|
|||
return E;
|
||||
}
|
||||
|
||||
const Expression *
|
||||
NewGVN::performSymbolicPredicateInfoEvaluation(Instruction *I) {
|
||||
auto *PI = PredInfo->getPredicateInfoFor(I);
|
||||
if (!PI)
|
||||
return nullptr;
|
||||
|
||||
DEBUG(dbgs() << "Found predicate info from instruction !\n");
|
||||
auto *CopyOf = I->getOperand(0);
|
||||
auto *Cond = dyn_cast<Instruction>(PI->Condition);
|
||||
if (!Cond)
|
||||
return nullptr;
|
||||
|
||||
// If this a copy of the condition, it must be either true or false depending
|
||||
// on the predicate info type and edge
|
||||
if (CopyOf == Cond) {
|
||||
addPredicateUsers(PI, I);
|
||||
if (isa<PredicateAssume>(PI))
|
||||
return createConstantExpression(ConstantInt::getTrue(Cond->getType()));
|
||||
if (auto *PBranch = dyn_cast<PredicateBranch>(PI)) {
|
||||
if (PBranch->TrueEdge)
|
||||
return createConstantExpression(ConstantInt::getTrue(Cond->getType()));
|
||||
return createConstantExpression(ConstantInt::getFalse(Cond->getType()));
|
||||
}
|
||||
}
|
||||
// Not a copy of the condition, so see what the predicates tell us about this
|
||||
// value.
|
||||
// Not a copy of the condition, so see what the predicates tell us about this
|
||||
// value. First, though, we check to make sure the value is actually a copy
|
||||
// of one of the condition operands. It's possible, in certain cases, for it
|
||||
// to be a copy of a predicateinfo copy. In particular, if two branch
|
||||
// operations use the same condition, and one branch dominates the other, we
|
||||
// will end up with a copy of a copy. This is currently a small deficiency in
|
||||
// predicateinfo. What will end up happening here is that we will value
|
||||
// number both copies the same anyway.
|
||||
if (CopyOf != Cond->getOperand(0) && CopyOf != Cond->getOperand(1)) {
|
||||
DEBUG(dbgs() << "Copy is not of any condition operands!");
|
||||
return nullptr;
|
||||
}
|
||||
Value *FirstOp = lookupOperandLeader(Cond->getOperand(0));
|
||||
Value *SecondOp = lookupOperandLeader(Cond->getOperand(1));
|
||||
bool SwappedOps = false;
|
||||
// Sort the ops
|
||||
if (shouldSwapOperands(FirstOp, SecondOp)) {
|
||||
std::swap(FirstOp, SecondOp);
|
||||
SwappedOps = true;
|
||||
}
|
||||
|
||||
// Everything below relies on the condition being a comparison.
|
||||
auto *Cmp = dyn_cast<CmpInst>(Cond);
|
||||
CmpInst::Predicate Predicate =
|
||||
SwappedOps ? Cmp->getSwappedPredicate() : Cmp->getPredicate();
|
||||
|
||||
if (isa<PredicateAssume>(PI)) {
|
||||
// If the comparison is true when the operands are equal, then we know the
|
||||
// operands are equal, because assumes must always be true.
|
||||
if (CmpInst::isTrueWhenEqual(Predicate)) {
|
||||
addPredicateUsers(PI, I);
|
||||
return createVariableOrConstant(FirstOp);
|
||||
}
|
||||
}
|
||||
if (const auto *PBranch = dyn_cast<PredicateBranch>(PI)) {
|
||||
// If we are *not* a copy of the comparison, we may equal to the other
|
||||
// operand when the predicate implies something about equality of
|
||||
// operations. In particular, if the comparison is true/false when the
|
||||
// operands are equal, and we are on the right edge, we know this operation
|
||||
// is equal to something.
|
||||
if ((PBranch->TrueEdge && Predicate == CmpInst::ICMP_EQ) ||
|
||||
(!PBranch->TrueEdge && Predicate == CmpInst::ICMP_NE)) {
|
||||
addPredicateUsers(PI, I);
|
||||
return createVariableOrConstant(FirstOp);
|
||||
}
|
||||
// Handle the special case of floating point.
|
||||
if (((PBranch->TrueEdge && Predicate == CmpInst::FCMP_OEQ) ||
|
||||
(!PBranch->TrueEdge && Predicate == CmpInst::FCMP_UNE)) &&
|
||||
isa<ConstantFP>(FirstOp) && !cast<ConstantFP>(FirstOp)->isZero()) {
|
||||
addPredicateUsers(PI, I);
|
||||
return createConstantExpression(cast<Constant>(FirstOp));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Evaluate read only and pure calls, and create an expression result.
|
||||
const Expression *NewGVN::performSymbolicCallEvaluation(Instruction *I) {
|
||||
auto *CI = cast<CallInst>(I);
|
||||
if (AA->doesNotAccessMemory(CI))
|
||||
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
|
||||
// Instrinsics with the returned attribute are copies of arguments.
|
||||
if (auto *ReturnedValue = II->getReturnedArgOperand()) {
|
||||
if (II->getIntrinsicID() == Intrinsic::ssa_copy)
|
||||
if (const auto *Result = performSymbolicPredicateInfoEvaluation(I))
|
||||
return Result;
|
||||
return createVariableOrConstant(ReturnedValue);
|
||||
}
|
||||
}
|
||||
if (AA->doesNotAccessMemory(CI)) {
|
||||
return createCallExpression(CI, nullptr);
|
||||
if (AA->onlyReadsMemory(CI)) {
|
||||
} else if (AA->onlyReadsMemory(CI)) {
|
||||
MemoryAccess *DefiningAccess = MSSAWalker->getClobberingMemoryAccess(CI);
|
||||
return createCallExpression(CI, lookupMemoryAccessEquiv(DefiningAccess));
|
||||
}
|
||||
|
@ -930,9 +1038,7 @@ const Expression *NewGVN::performSymbolicPHIEvaluation(Instruction *I) {
|
|||
<< "\n");
|
||||
E->deallocateOperands(ArgRecycler);
|
||||
ExpressionAllocator.Deallocate(E);
|
||||
if (auto *C = dyn_cast<Constant>(AllSameValue))
|
||||
return createConstantExpression(C);
|
||||
return createVariableExpression(AllSameValue);
|
||||
return createVariableOrConstant(AllSameValue);
|
||||
}
|
||||
return E;
|
||||
}
|
||||
|
@ -976,16 +1082,117 @@ const Expression *NewGVN::performSymbolicAggrValueEvaluation(Instruction *I) {
|
|||
return createAggregateValueExpression(I);
|
||||
}
|
||||
const Expression *NewGVN::performSymbolicCmpEvaluation(Instruction *I) {
|
||||
CmpInst *CI = dyn_cast<CmpInst>(I);
|
||||
// See if our operands are equal and that implies something.
|
||||
auto *CI = dyn_cast<CmpInst>(I);
|
||||
// See if our operands are equal to those of a previous predicate, and if so,
|
||||
// if it implies true or false.
|
||||
auto Op0 = lookupOperandLeader(CI->getOperand(0));
|
||||
auto Op1 = lookupOperandLeader(CI->getOperand(1));
|
||||
auto OurPredicate = CI->getPredicate();
|
||||
if (shouldSwapOperands(Op1, Op0)) {
|
||||
std::swap(Op0, Op1);
|
||||
OurPredicate = CI->getSwappedPredicate();
|
||||
}
|
||||
|
||||
// Avoid processing the same info twice
|
||||
const PredicateBase *LastPredInfo = nullptr;
|
||||
|
||||
// See if we know something about the comparison itself, like it is the target
|
||||
// of an assume.
|
||||
auto *CmpPI = PredInfo->getPredicateInfoFor(I);
|
||||
if (dyn_cast_or_null<PredicateAssume>(CmpPI))
|
||||
return createConstantExpression(ConstantInt::getTrue(CI->getType()));
|
||||
|
||||
if (Op0 == Op1) {
|
||||
// This condition does not depend on predicates, no need to add users
|
||||
if (CI->isTrueWhenEqual())
|
||||
return createConstantExpression(ConstantInt::getTrue(CI->getType()));
|
||||
else if (CI->isFalseWhenEqual())
|
||||
return createConstantExpression(ConstantInt::getFalse(CI->getType()));
|
||||
}
|
||||
|
||||
// NOTE: Because we are comparing both operands here and below, and using
|
||||
// previous comparisons, we rely on fact that predicateinfo knows to mark
|
||||
// comparisons that use renamed operands as users of the earlier comparisons.
|
||||
// It is *not* enough to just mark predicateinfo renamed operands as users of
|
||||
// the earlier comparisons, because the *other* operand may have changed in a
|
||||
// previous iteration.
|
||||
// Example:
|
||||
// icmp slt %a, %b
|
||||
// %b.0 = ssa.copy(%b)
|
||||
// false branch:
|
||||
// icmp slt %c, %b.0
|
||||
|
||||
// %c and %a may start out equal, and thus, the code below will say the second
|
||||
// %icmp is false. c may become equal to something else, and in that case the
|
||||
// %second icmp *must* be reexamined, but would not if only the renamed
|
||||
// %operands are considered users of the icmp.
|
||||
|
||||
// *Currently* we only check one level of comparisons back, and only mark one
|
||||
// level back as touched when changes appen . If you modify this code to look
|
||||
// back farther through comparisons, you *must* mark the appropriate
|
||||
// comparisons as users in PredicateInfo.cpp, or you will cause bugs. See if
|
||||
// we know something just from the operands themselves
|
||||
|
||||
// See if our operands have predicate info, so that we may be able to derive
|
||||
// something from a previous comparison.
|
||||
for (const auto &Op : CI->operands()) {
|
||||
auto *PI = PredInfo->getPredicateInfoFor(Op);
|
||||
if (const auto *PBranch = dyn_cast_or_null<PredicateBranch>(PI)) {
|
||||
if (PI == LastPredInfo)
|
||||
continue;
|
||||
LastPredInfo = PI;
|
||||
// TODO: Along the false edge, we may know more things too, like icmp of
|
||||
// same operands is false.
|
||||
// TODO: We only handle actual comparison conditions below, not and/or.
|
||||
auto *BranchCond = dyn_cast<CmpInst>(PBranch->Condition);
|
||||
if (!BranchCond)
|
||||
continue;
|
||||
auto *BranchOp0 = lookupOperandLeader(BranchCond->getOperand(0));
|
||||
auto *BranchOp1 = lookupOperandLeader(BranchCond->getOperand(1));
|
||||
auto BranchPredicate = BranchCond->getPredicate();
|
||||
if (shouldSwapOperands(BranchOp1, BranchOp0)) {
|
||||
std::swap(BranchOp0, BranchOp1);
|
||||
BranchPredicate = BranchCond->getSwappedPredicate();
|
||||
}
|
||||
if (BranchOp0 == Op0 && BranchOp1 == Op1) {
|
||||
if (PBranch->TrueEdge) {
|
||||
// If we know the previous predicate is true and we are in the true
|
||||
// edge then we may be implied true or false.
|
||||
if (CmpInst::isImpliedTrueByMatchingCmp(OurPredicate,
|
||||
BranchPredicate)) {
|
||||
addPredicateUsers(PI, I);
|
||||
return createConstantExpression(
|
||||
ConstantInt::getTrue(CI->getType()));
|
||||
}
|
||||
|
||||
if (CmpInst::isImpliedFalseByMatchingCmp(OurPredicate,
|
||||
BranchPredicate)) {
|
||||
addPredicateUsers(PI, I);
|
||||
return createConstantExpression(
|
||||
ConstantInt::getFalse(CI->getType()));
|
||||
}
|
||||
|
||||
} else {
|
||||
// Just handle the ne and eq cases, where if we have the same
|
||||
// operands, we may know something.
|
||||
if (BranchPredicate == OurPredicate) {
|
||||
addPredicateUsers(PI, I);
|
||||
// Same predicate, same ops,we know it was false, so this is false.
|
||||
return createConstantExpression(
|
||||
ConstantInt::getFalse(CI->getType()));
|
||||
} else if (BranchPredicate ==
|
||||
CmpInst::getInversePredicate(OurPredicate)) {
|
||||
addPredicateUsers(PI, I);
|
||||
// Inverse predicate, we know the other was false, so this is true.
|
||||
// FIXME: Double check this
|
||||
return createConstantExpression(
|
||||
ConstantInt::getTrue(CI->getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create expression will take care of simplifyCmpInst
|
||||
return createExpression(I);
|
||||
}
|
||||
|
||||
|
@ -1085,6 +1292,22 @@ void NewGVN::markMemoryUsersTouched(MemoryAccess *MA) {
|
|||
}
|
||||
}
|
||||
|
||||
// Add I to the set of users of a given predicate.
|
||||
void NewGVN::addPredicateUsers(const PredicateBase *PB, Instruction *I) {
|
||||
if (auto *PBranch = dyn_cast<PredicateBranch>(PB))
|
||||
PredicateToUsers[PBranch->Condition].insert(I);
|
||||
else if (auto *PAssume = dyn_cast<PredicateBranch>(PB))
|
||||
PredicateToUsers[PAssume->Condition].insert(I);
|
||||
}
|
||||
|
||||
// Touch all the predicates that depend on this instruction.
|
||||
void NewGVN::markPredicateUsersTouched(Instruction *I) {
|
||||
const auto Result = PredicateToUsers.find(I);
|
||||
if (Result != PredicateToUsers.end())
|
||||
for (auto *User : Result->second)
|
||||
TouchedInstructions.set(InstrDFS.lookup(User));
|
||||
}
|
||||
|
||||
// Touch the instructions that need to be updated after a congruence class has a
|
||||
// leader change, and mark changed values.
|
||||
void NewGVN::markLeaderChangeTouched(CongruenceClass *CC) {
|
||||
|
@ -1286,6 +1509,8 @@ void NewGVN::performCongruenceFinding(Instruction *I, const Expression *E) {
|
|||
markUsersTouched(I);
|
||||
if (MemoryAccess *MA = MSSA->getMemoryAccess(I))
|
||||
markMemoryUsersTouched(MA);
|
||||
if (auto *CI = dyn_cast<CmpInst>(I))
|
||||
markPredicateUsersTouched(CI);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1481,6 +1706,7 @@ void NewGVN::cleanupTables() {
|
|||
TouchedInstructions.clear();
|
||||
DominatedInstRange.clear();
|
||||
MemoryAccessToClass.clear();
|
||||
PredicateToUsers.clear();
|
||||
}
|
||||
|
||||
std::pair<unsigned, unsigned> NewGVN::assignDFSNumbers(BasicBlock *B,
|
||||
|
@ -1681,6 +1907,27 @@ void NewGVN::verifyMemoryCongruency() const {
|
|||
}
|
||||
}
|
||||
|
||||
// Re-evaluate all the comparisons after value numbering and ensure they don't
|
||||
// change. If they changed, we didn't mark them touched properly.
|
||||
void NewGVN::verifyComparisons(Function &F) {
|
||||
#ifndef NDEBUG
|
||||
for (auto &BB : F) {
|
||||
if (!ReachableBlocks.count(&BB))
|
||||
continue;
|
||||
for (auto &I : BB) {
|
||||
if (InstructionsToErase.count(&I))
|
||||
continue;
|
||||
if (isa<CmpInst>(&I)) {
|
||||
auto *CurrentVal = ValueToClass.lookup(&I);
|
||||
valueNumberInstruction(&I);
|
||||
assert(CurrentVal == ValueToClass.lookup(&I) &&
|
||||
"Re-evaluating comparison changed value");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is the main transformation entry point.
|
||||
bool NewGVN::runGVN(Function &F, DominatorTree *_DT, AssumptionCache *_AC,
|
||||
TargetLibraryInfo *_TLI, AliasAnalysis *_AA,
|
||||
|
@ -1692,6 +1939,7 @@ bool NewGVN::runGVN(Function &F, DominatorTree *_DT, AssumptionCache *_AC,
|
|||
TLI = _TLI;
|
||||
AA = _AA;
|
||||
MSSA = _MSSA;
|
||||
PredInfo = make_unique<PredicateInfo>(F, *DT, *AC);
|
||||
DL = &F.getParent()->getDataLayout();
|
||||
MSSAWalker = MSSA->getWalker();
|
||||
|
||||
|
@ -1700,9 +1948,9 @@ bool NewGVN::runGVN(Function &F, DominatorTree *_DT, AssumptionCache *_AC,
|
|||
unsigned ICount = 1;
|
||||
// Add an empty instruction to account for the fact that we start at 1
|
||||
DFSToInstr.emplace_back(nullptr);
|
||||
// Note: We want RPO traversal of the blocks, which is not quite the same as
|
||||
// dominator tree order, particularly with regard whether backedges get
|
||||
// visited first or second, given a block with multiple successors.
|
||||
// Note: We want ideal RPO traversal of the blocks, which is not quite the
|
||||
// same as dominator tree order, particularly with regard whether backedges
|
||||
// get visited first or second, given a block with multiple successors.
|
||||
// If we visit in the wrong order, we will end up performing N times as many
|
||||
// iterations.
|
||||
// The dominator tree does guarantee that, for a given dom tree node, it's
|
||||
|
@ -1766,6 +2014,9 @@ bool NewGVN::runGVN(Function &F, DominatorTree *_DT, AssumptionCache *_AC,
|
|||
while (TouchedInstructions.any()) {
|
||||
++Iterations;
|
||||
// Walk through all the instructions in all the blocks in RPO.
|
||||
// TODO: As we hit a new block, we should push and pop equalities into a
|
||||
// table lookupOperandLeader can use, to catch things PredicateInfo
|
||||
// might miss, like edge-only equivalences.
|
||||
for (int InstrNum = TouchedInstructions.find_first(); InstrNum != -1;
|
||||
InstrNum = TouchedInstructions.find_next(InstrNum)) {
|
||||
|
||||
|
@ -1820,7 +2071,9 @@ bool NewGVN::runGVN(Function &F, DominatorTree *_DT, AssumptionCache *_AC,
|
|||
NumGVNMaxIterations = std::max(NumGVNMaxIterations.getValue(), Iterations);
|
||||
#ifndef NDEBUG
|
||||
verifyMemoryCongruency();
|
||||
verifyComparisons(F);
|
||||
#endif
|
||||
|
||||
Changed |= eliminateInstructions(F);
|
||||
|
||||
// Delete all instructions marked for deletion.
|
||||
|
@ -2295,15 +2548,14 @@ bool NewGVN::eliminateInstructions(Function &F) {
|
|||
// start using, we also push.
|
||||
// Otherwise, we walk along, processing members who are
|
||||
// dominated by this scope, and eliminate them.
|
||||
bool ShouldPush =
|
||||
Member && (EliminationStack.empty() || isa<Constant>(Member));
|
||||
bool ShouldPush = Member && EliminationStack.empty();
|
||||
bool OutOfScope =
|
||||
!EliminationStack.isInScope(MemberDFSIn, MemberDFSOut);
|
||||
|
||||
if (OutOfScope || ShouldPush) {
|
||||
// Sync to our current scope.
|
||||
EliminationStack.popUntilDFSScope(MemberDFSIn, MemberDFSOut);
|
||||
ShouldPush |= Member && EliminationStack.empty();
|
||||
bool ShouldPush = Member && EliminationStack.empty();
|
||||
if (ShouldPush) {
|
||||
EliminationStack.push_back(Member, MemberDFSIn, MemberDFSOut);
|
||||
}
|
||||
|
@ -2329,8 +2581,13 @@ bool NewGVN::eliminateInstructions(Function &F) {
|
|||
|
||||
// If we replaced something in an instruction, handle the patching of
|
||||
// metadata.
|
||||
if (auto *ReplacedInst = dyn_cast<Instruction>(MemberUse->get()))
|
||||
patchReplacementInstruction(ReplacedInst, Result);
|
||||
if (auto *ReplacedInst = dyn_cast<Instruction>(MemberUse->get())) {
|
||||
// Skip this if we are replacing predicateinfo with its original
|
||||
// operand, as we already know we can just drop it.
|
||||
auto *PI = PredInfo->getPredicateInfoFor(ReplacedInst);
|
||||
if (!PI || Result != PI->OriginalOp)
|
||||
patchReplacementInstruction(ReplacedInst, Result);
|
||||
}
|
||||
|
||||
assert(isa<Instruction>(MemberUse->getUser()));
|
||||
MemberUse->set(Result);
|
||||
|
@ -2425,5 +2682,5 @@ bool NewGVN::shouldSwapOperands(const Value *A, const Value *B) const {
|
|||
// Because we only care about a total ordering, and don't rewrite expressions
|
||||
// in this order, we order by rank, which will give a strict weak ordering to
|
||||
// everything but constants, and then we order by pointer address.
|
||||
return std::make_pair(getRank(A), A) > std::make_pair(getRank(B), B);
|
||||
return std::make_pair(getRank(A), A) > std::make_pair(getRank(B), B);
|
||||
}
|
||||
|
|
|
@ -1,59 +1,5 @@
|
|||
; XFAIL: *
|
||||
; RUN: opt < %s -basicaa -newgvn -S | FileCheck %s
|
||||
|
||||
@a = external global i32 ; <i32*> [#uses=7]
|
||||
|
||||
; CHECK-LABEL: @test1(
|
||||
define i32 @test1() nounwind {
|
||||
entry:
|
||||
%0 = load i32, i32* @a, align 4
|
||||
%1 = icmp eq i32 %0, 4
|
||||
br i1 %1, label %bb, label %bb1
|
||||
|
||||
bb: ; preds = %entry
|
||||
br label %bb8
|
||||
|
||||
bb1: ; preds = %entry
|
||||
%2 = load i32, i32* @a, align 4
|
||||
%3 = icmp eq i32 %2, 5
|
||||
br i1 %3, label %bb2, label %bb3
|
||||
|
||||
bb2: ; preds = %bb1
|
||||
br label %bb8
|
||||
|
||||
bb3: ; preds = %bb1
|
||||
%4 = load i32, i32* @a, align 4
|
||||
%5 = icmp eq i32 %4, 4
|
||||
; CHECK: br i1 false, label %bb4, label %bb5
|
||||
br i1 %5, label %bb4, label %bb5
|
||||
|
||||
bb4: ; preds = %bb3
|
||||
%6 = load i32, i32* @a, align 4
|
||||
%7 = add i32 %6, 5
|
||||
br label %bb8
|
||||
|
||||
bb5: ; preds = %bb3
|
||||
%8 = load i32, i32* @a, align 4
|
||||
%9 = icmp eq i32 %8, 5
|
||||
; CHECK: br i1 false, label %bb6, label %bb7
|
||||
br i1 %9, label %bb6, label %bb7
|
||||
|
||||
bb6: ; preds = %bb5
|
||||
%10 = load i32, i32* @a, align 4
|
||||
%11 = add i32 %10, 4
|
||||
br label %bb8
|
||||
|
||||
bb7: ; preds = %bb5
|
||||
%12 = load i32, i32* @a, align 4
|
||||
br label %bb8
|
||||
|
||||
bb8: ; preds = %bb7, %bb6, %bb4, %bb2, %bb
|
||||
%.0 = phi i32 [ %12, %bb7 ], [ %11, %bb6 ], [ %7, %bb4 ], [ 4, %bb2 ], [ 5, %bb ]
|
||||
br label %return
|
||||
|
||||
return: ; preds = %bb8
|
||||
ret i32 %.0
|
||||
}
|
||||
|
||||
declare void @foo(i1)
|
||||
declare void @bar(i32)
|
||||
|
@ -80,39 +26,6 @@ nope:
|
|||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test4(
|
||||
define void @test4(i1 %b, i32 %x) {
|
||||
br i1 %b, label %sw, label %case3
|
||||
sw:
|
||||
switch i32 %x, label %default [
|
||||
i32 0, label %case0
|
||||
i32 1, label %case1
|
||||
i32 2, label %case0
|
||||
i32 3, label %case3
|
||||
i32 4, label %default
|
||||
]
|
||||
default:
|
||||
; CHECK: default:
|
||||
call void @bar(i32 %x)
|
||||
; CHECK: call void @bar(i32 %x)
|
||||
ret void
|
||||
case0:
|
||||
; CHECK: case0:
|
||||
call void @bar(i32 %x)
|
||||
; CHECK: call void @bar(i32 %x)
|
||||
ret void
|
||||
case1:
|
||||
; CHECK: case1:
|
||||
call void @bar(i32 %x)
|
||||
; CHECK: call void @bar(i32 1)
|
||||
ret void
|
||||
case3:
|
||||
; CHECK: case3:
|
||||
call void @bar(i32 %x)
|
||||
; CHECK: call void @bar(i32 %x)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test5(
|
||||
define i1 @test5(i32 %x, i32 %y) {
|
||||
%cmp = icmp eq i32 %x, %y
|
||||
|
@ -129,37 +42,6 @@ different:
|
|||
ret i1 %cmp3
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test6(
|
||||
define i1 @test6(i32 %x, i32 %y) {
|
||||
%cmp2 = icmp ne i32 %x, %y
|
||||
%cmp = icmp eq i32 %x, %y
|
||||
%cmp3 = icmp eq i32 %x, %y
|
||||
br i1 %cmp, label %same, label %different
|
||||
|
||||
same:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp2
|
||||
|
||||
different:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp3
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test6_fp(
|
||||
define i1 @test6_fp(float %x, float %y) {
|
||||
%cmp2 = fcmp une float %x, %y
|
||||
%cmp = fcmp oeq float %x, %y
|
||||
%cmp3 = fcmp oeq float %x, %y
|
||||
br i1 %cmp, label %same, label %different
|
||||
|
||||
same:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp2
|
||||
|
||||
different:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp3
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test7(
|
||||
define i1 @test7(i32 %x, i32 %y) {
|
||||
|
@ -193,38 +75,6 @@ different:
|
|||
ret i1 %cmp3
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test8(
|
||||
define i1 @test8(i32 %x, i32 %y) {
|
||||
%cmp2 = icmp sle i32 %x, %y
|
||||
%cmp = icmp sgt i32 %x, %y
|
||||
%cmp3 = icmp sgt i32 %x, %y
|
||||
br i1 %cmp, label %same, label %different
|
||||
|
||||
same:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp2
|
||||
|
||||
different:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp3
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test8_fp(
|
||||
define i1 @test8_fp(float %x, float %y) {
|
||||
%cmp2 = fcmp ule float %x, %y
|
||||
%cmp = fcmp ogt float %x, %y
|
||||
%cmp3 = fcmp ogt float %x, %y
|
||||
br i1 %cmp, label %same, label %different
|
||||
|
||||
same:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp2
|
||||
|
||||
different:
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %cmp3
|
||||
}
|
||||
|
||||
; PR1768
|
||||
; CHECK-LABEL: @test9(
|
||||
define i32 @test9(i32 %i, i32 %j) {
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -basicaa -newgvn -S < %s | FileCheck %s
|
||||
|
||||
; Function Attrs: noinline norecurse nounwind readonly ssp uwtable
|
||||
define i32 @mp_unsgn_cmp(i32 %n, i32* nocapture readonly %in1, i32* nocapture readonly %in2) local_unnamed_addr {
|
||||
; CHECK-LABEL: @mp_unsgn_cmp(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP11:%.*]] = icmp sgt i32 [[N:%.*]], -1
|
||||
; CHECK-NEXT: br i1 [[CMP11]], label [[FOR_INC_PREHEADER:%.*]], label [[IF_ELSE:%.*]]
|
||||
; CHECK: for.inc.preheader:
|
||||
; CHECK-NEXT: br label [[FOR_INC:%.*]]
|
||||
; CHECK: for.inc:
|
||||
; CHECK-NEXT: [[STOREMERGE2:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_INC]] ], [ 0, [[FOR_INC_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[STOREMERGE2]] to i64
|
||||
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[IN1:%.*]], i64 [[IDXPROM]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
|
||||
; CHECK-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds i32, i32* [[IN2:%.*]], i64 [[IDXPROM]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARRAYIDX4]], align 4
|
||||
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP0]], [[TMP1]]
|
||||
; CHECK-NEXT: [[INC]] = add nsw i32 [[STOREMERGE2]], 1
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[STOREMERGE2]], [[N]]
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[SUB]], 0
|
||||
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[CMP2]], [[CMP1]]
|
||||
; CHECK-NEXT: br i1 [[OR_COND]], label [[FOR_INC]], label [[FOR_END:%.*]]
|
||||
; CHECK: for.end:
|
||||
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[SUB]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP5]], label [[IF_END8:%.*]], label [[IF_ELSE]]
|
||||
; CHECK: if.else:
|
||||
; CHECK-NEXT: [[SUB1_LCSSA4:%.*]] = phi i32 [ [[SUB]], [[FOR_END]] ], [ 0, [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: [[CMP6:%.*]] = icmp slt i32 [[SUB1_LCSSA4]], 0
|
||||
; CHECK-NEXT: [[DOTSUB1_LCSSA:%.*]] = select i1 [[CMP6]], i32 -1, i32 [[SUB1_LCSSA4]]
|
||||
; CHECK-NEXT: ret i32 [[DOTSUB1_LCSSA]]
|
||||
; CHECK: if.end8:
|
||||
; CHECK-NEXT: ret i32 1
|
||||
;
|
||||
entry:
|
||||
%cmp11 = icmp sgt i32 %n, -1
|
||||
br i1 %cmp11, label %for.inc.preheader, label %if.else
|
||||
|
||||
for.inc.preheader: ; preds = %entry
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.inc.preheader, %for.inc
|
||||
%storemerge2 = phi i32 [ %inc, %for.inc ], [ 0, %for.inc.preheader ]
|
||||
%idxprom = sext i32 %storemerge2 to i64
|
||||
%arrayidx = getelementptr inbounds i32, i32* %in1, i64 %idxprom
|
||||
%0 = load i32, i32* %arrayidx, align 4
|
||||
%arrayidx4 = getelementptr inbounds i32, i32* %in2, i64 %idxprom
|
||||
%1 = load i32, i32* %arrayidx4, align 4
|
||||
%sub = sub nsw i32 %0, %1
|
||||
%inc = add nsw i32 %storemerge2, 1
|
||||
%cmp1 = icmp slt i32 %storemerge2, %n
|
||||
%cmp2 = icmp eq i32 %sub, 0
|
||||
%or.cond = and i1 %cmp2, %cmp1
|
||||
;; This is a self-critical edge to for.inc. If we insert predicate info on it, we will insert
|
||||
;; predicateinfo at the end of this block, and think it dominates everthing using only dfs
|
||||
;; numbers, instead of proper edge dominance. We would then proceed to propagate the true value
|
||||
;; of sub == 0 everywhere, making this function only ever return 0.
|
||||
br i1 %or.cond, label %for.inc, label %for.end
|
||||
|
||||
for.end: ; preds = %for.inc
|
||||
%sub.lcssa = phi i32 [ %sub, %for.inc ]
|
||||
%cmp5 = icmp sgt i32 %sub.lcssa, 0
|
||||
br i1 %cmp5, label %if.end8, label %if.else
|
||||
|
||||
if.else: ; preds = %entry, %for.end
|
||||
%sub1.lcssa4 = phi i32 [ %sub.lcssa, %for.end ], [ 0, %entry ]
|
||||
%cmp6 = icmp slt i32 %sub1.lcssa4, 0
|
||||
%.sub1.lcssa = select i1 %cmp6, i32 -1, i32 %sub1.lcssa4
|
||||
ret i32 %.sub1.lcssa
|
||||
|
||||
if.end8: ; preds = %for.end
|
||||
ret i32 1
|
||||
}
|
||||
|
||||
|
||||
;; This test will generate a copy of a copy of predicateinfo to the multiple uses
|
||||
;; of branch conditions below. Make sure we don't try to extract operand info.
|
||||
; Function Attrs: uwtable
|
||||
define fastcc void @barney() {
|
||||
; CHECK-LABEL: @barney(
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: br label [[BB22:%.*]]
|
||||
; CHECK: bb22:
|
||||
; CHECK-NEXT: br i1 undef, label [[BB29:%.*]], label [[BB35:%.*]]
|
||||
; CHECK: bb29:
|
||||
; CHECK-NEXT: br i1 true, label [[BB33:%.*]], label [[BB35]]
|
||||
; CHECK: bb33:
|
||||
; CHECK-NEXT: br i1 true, label [[BB35]], label [[BB35]]
|
||||
; CHECK: bb35:
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
bb:
|
||||
br label %bb22
|
||||
bb22: ; preds = %bb21
|
||||
%tmp23 = icmp eq i32 undef, 2
|
||||
br i1 %tmp23, label %bb29, label %bb35
|
||||
|
||||
|
||||
bb29: ; preds = %bb28
|
||||
br i1 %tmp23, label %bb33, label %bb35
|
||||
|
||||
|
||||
bb33: ; preds = %bb31
|
||||
br i1 %tmp23, label %bb35, label %bb35
|
||||
|
||||
|
||||
bb35: ; preds = %bb33, %bb29, %bb22
|
||||
unreachable
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -newgvn -S < %s | FileCheck %s
|
||||
; RUN: opt -passes=newgvn -S -o - %s | FileCheck %s
|
||||
|
||||
|
@ -7,31 +8,35 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
|||
;; stores of the same value do not change the memory state to eliminate them.
|
||||
|
||||
define i32 @foo(i32*, i32) {
|
||||
; CHECK-LABEL: @foo
|
||||
; CHECK-LABEL: @foo(
|
||||
; CHECK-NEXT: store i32 5, i32* [[TMP0:%.*]], align 4
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
|
||||
; CHECK: br label [[TMP5]]
|
||||
; CHECK: [[DOT0:%.*]] = phi i32 [ 10, [[TMP4]] ], [ 5, [[TMP2:%.*]] ]
|
||||
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP6:%.*]], label [[TMP8:%.*]]
|
||||
; CHECK: [[TMP7:%.*]] = add nsw i32 [[DOT0]], 5
|
||||
; CHECK-NEXT: br label [[TMP8]]
|
||||
; CHECK: [[DOT1:%.*]] = phi i32 [ [[TMP7]], [[TMP6]] ], [ [[DOT0]], [[TMP5]] ]
|
||||
; CHECK-NEXT: ret i32 [[DOT1]]
|
||||
;
|
||||
store i32 5, i32* %0, align 4
|
||||
%3 = icmp ne i32 %1, 0
|
||||
br i1 %3, label %4, label %7
|
||||
|
||||
; <label>:4: ; preds = %2
|
||||
; CHECK-NOT: load
|
||||
%5 = load i32, i32* %0, align 4
|
||||
; CHECK-NOT: add
|
||||
%6 = add nsw i32 5, %5
|
||||
br label %7
|
||||
|
||||
; <label>:7: ; preds = %4, %2
|
||||
%.0 = phi i32 [ %6, %4 ], [ 5, %2 ]
|
||||
; CHECK: phi i32 [ 10, %4 ], [ 5, %2 ]
|
||||
store i32 5, i32* %0, align 4
|
||||
; CHECK-NOT: icmp
|
||||
%8 = icmp ne i32 %1, 0
|
||||
; CHECK: br i1 %3
|
||||
br i1 %8, label %9, label %12
|
||||
|
||||
; <label>:9: ; preds = %7
|
||||
; CHECK-NOT: load
|
||||
%10 = load i32, i32* %0, align 4
|
||||
; CHECK: add nsw i32 %.0, 5
|
||||
%11 = add nsw i32 %.0, %10
|
||||
br label %12
|
||||
|
||||
|
@ -43,15 +48,25 @@ define i32 @foo(i32*, i32) {
|
|||
;; This is similar to the above, but it is a conditional store of the same value
|
||||
;; which requires value numbering MemoryPhi properly to resolve.
|
||||
define i32 @foo2(i32*, i32) {
|
||||
; CHECK-LABEL: @foo2
|
||||
; CHECK-LABEL: @foo2(
|
||||
; CHECK-NEXT: store i32 5, i32* [[TMP0:%.*]], align 4
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
|
||||
; CHECK: br label [[TMP6:%.*]]
|
||||
; CHECK: br label [[TMP6]]
|
||||
; CHECK: [[DOT0:%.*]] = phi i32 [ 10, [[TMP4]] ], [ 5, [[TMP5]] ]
|
||||
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP7:%.*]], label [[TMP9:%.*]]
|
||||
; CHECK: [[TMP8:%.*]] = add nsw i32 [[DOT0]], 5
|
||||
; CHECK-NEXT: br label [[TMP9]]
|
||||
; CHECK: [[DOT1:%.*]] = phi i32 [ [[TMP8]], [[TMP7]] ], [ [[DOT0]], [[TMP6]] ]
|
||||
; CHECK-NEXT: ret i32 [[DOT1]]
|
||||
;
|
||||
store i32 5, i32* %0, align 4
|
||||
%3 = icmp ne i32 %1, 0
|
||||
br i1 %3, label %4, label %7
|
||||
|
||||
; <label>:4: ; preds = %2
|
||||
; CHECK-NOT: load
|
||||
%5 = load i32, i32* %0, align 4
|
||||
; CHECK-NOT: add
|
||||
%6 = add nsw i32 5, %5
|
||||
br label %8
|
||||
|
||||
|
@ -60,17 +75,12 @@ define i32 @foo2(i32*, i32) {
|
|||
br label %8
|
||||
|
||||
; <label>:8: ; preds = %7, %4
|
||||
; CHECK: phi i32 [ 10, %4 ], [ 5, %5 ]
|
||||
%.0 = phi i32 [ %6, %4 ], [ 5, %7 ]
|
||||
; CHECK-NOT: icmp
|
||||
%9 = icmp ne i32 %1, 0
|
||||
; CHECK: br i1 %3
|
||||
br i1 %9, label %10, label %13
|
||||
|
||||
; <label>:10: ; preds = %8
|
||||
; CHECK-NOT: load
|
||||
%11 = load i32, i32* %0, align 4
|
||||
; CHECK: add nsw i32 %.0, 5
|
||||
%12 = add nsw i32 %.0, %11
|
||||
br label %13
|
||||
|
||||
|
|
Loading…
Reference in New Issue