aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/Scalar/EarlyCSE.cpp')
-rw-r--r--llvm/lib/Transforms/Scalar/EarlyCSE.cpp244
1 files changed, 154 insertions, 90 deletions
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index 40c1ba88354f..ddfc8555b0a0 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -41,6 +41,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/PatternMatch.h"
+#include "llvm/IR/Statepoint.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/Value.h"
@@ -54,6 +55,7 @@
#include "llvm/Support/RecyclingAllocator.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
#include "llvm/Transforms/Utils/GuardUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cassert>
@@ -114,7 +116,7 @@ struct SimpleValue {
isa<CmpInst>(Inst) || isa<SelectInst>(Inst) ||
isa<ExtractElementInst>(Inst) || isa<InsertElementInst>(Inst) ||
isa<ShuffleVectorInst>(Inst) || isa<ExtractValueInst>(Inst) ||
- isa<InsertValueInst>(Inst);
+ isa<InsertValueInst>(Inst) || isa<FreezeInst>(Inst);
}
};
@@ -152,13 +154,50 @@ static bool matchSelectWithOptionalNotCond(Value *V, Value *&Cond, Value *&A,
std::swap(A, B);
}
- // Set flavor if we find a match, or set it to unknown otherwise; in
- // either case, return true to indicate that this is a select we can
- // process.
- if (auto *CmpI = dyn_cast<ICmpInst>(Cond))
- Flavor = matchDecomposedSelectPattern(CmpI, A, B, A, B).Flavor;
- else
- Flavor = SPF_UNKNOWN;
+ // Match canonical forms of abs/nabs/min/max. We are not using ValueTracking's
+ // more powerful matchSelectPattern() because it may rely on instruction flags
+ // such as "nsw". That would be incompatible with the current hashing
+ // mechanism that may remove flags to increase the likelihood of CSE.
+
+ // These are the canonical forms of abs(X) and nabs(X) created by instcombine:
+ // %N = sub i32 0, %X
+ // %C = icmp slt i32 %X, 0
+ // %ABS = select i1 %C, i32 %N, i32 %X
+ //
+ // %N = sub i32 0, %X
+ // %C = icmp slt i32 %X, 0
+ // %NABS = select i1 %C, i32 %X, i32 %N
+ Flavor = SPF_UNKNOWN;
+ CmpInst::Predicate Pred;
+ if (match(Cond, m_ICmp(Pred, m_Specific(B), m_ZeroInt())) &&
+ Pred == ICmpInst::ICMP_SLT && match(A, m_Neg(m_Specific(B)))) {
+ // ABS: B < 0 ? -B : B
+ Flavor = SPF_ABS;
+ return true;
+ }
+ if (match(Cond, m_ICmp(Pred, m_Specific(A), m_ZeroInt())) &&
+ Pred == ICmpInst::ICMP_SLT && match(B, m_Neg(m_Specific(A)))) {
+ // NABS: A < 0 ? A : -A
+ Flavor = SPF_NABS;
+ return true;
+ }
+
+ if (!match(Cond, m_ICmp(Pred, m_Specific(A), m_Specific(B)))) {
+ // Check for commuted variants of min/max by swapping predicate.
+ // If we do not match the standard or commuted patterns, this is not a
+ // recognized form of min/max, but it is still a select, so return true.
+ if (!match(Cond, m_ICmp(Pred, m_Specific(B), m_Specific(A))))
+ return true;
+ Pred = ICmpInst::getSwappedPredicate(Pred);
+ }
+
+ switch (Pred) {
+ case CmpInst::ICMP_UGT: Flavor = SPF_UMAX; break;
+ case CmpInst::ICMP_ULT: Flavor = SPF_UMIN; break;
+ case CmpInst::ICMP_SGT: Flavor = SPF_SMAX; break;
+ case CmpInst::ICMP_SLT: Flavor = SPF_SMIN; break;
+ default: break;
+ }
return true;
}
@@ -231,6 +270,9 @@ static unsigned getHashValueImpl(SimpleValue Val) {
if (CastInst *CI = dyn_cast<CastInst>(Inst))
return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
+ if (FreezeInst *FI = dyn_cast<FreezeInst>(Inst))
+ return hash_combine(FI->getOpcode(), FI->getOperand(0));
+
if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(Inst))
return hash_combine(EVI->getOpcode(), EVI->getOperand(0),
hash_combine_range(EVI->idx_begin(), EVI->idx_end()));
@@ -242,7 +284,8 @@ static unsigned getHashValueImpl(SimpleValue Val) {
assert((isa<CallInst>(Inst) || isa<GetElementPtrInst>(Inst) ||
isa<ExtractElementInst>(Inst) || isa<InsertElementInst>(Inst) ||
- isa<ShuffleVectorInst>(Inst) || isa<UnaryOperator>(Inst)) &&
+ isa<ShuffleVectorInst>(Inst) || isa<UnaryOperator>(Inst) ||
+ isa<FreezeInst>(Inst)) &&
"Invalid/unknown instruction");
// Mix in the opcode.
@@ -414,6 +457,14 @@ template <> struct DenseMapInfo<CallValue> {
unsigned DenseMapInfo<CallValue>::getHashValue(CallValue Val) {
Instruction *Inst = Val.Inst;
+
+ // gc.relocate is 'special' call: its second and third operands are
+ // not real values, but indices into statepoint's argument list.
+ // Get values they point to.
+ if (const GCRelocateInst *GCR = dyn_cast<GCRelocateInst>(Inst))
+ return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
+ GCR->getBasePtr(), GCR->getDerivedPtr());
+
// Hash all of the operands as pointers and mix in the opcode.
return hash_combine(
Inst->getOpcode(),
@@ -424,6 +475,14 @@ bool DenseMapInfo<CallValue>::isEqual(CallValue LHS, CallValue RHS) {
Instruction *LHSI = LHS.Inst, *RHSI = RHS.Inst;
if (LHS.isSentinel() || RHS.isSentinel())
return LHSI == RHSI;
+
+ // See comment above in `getHashValue()`.
+ if (const GCRelocateInst *GCR1 = dyn_cast<GCRelocateInst>(LHSI))
+ if (const GCRelocateInst *GCR2 = dyn_cast<GCRelocateInst>(RHSI))
+ return GCR1->getOperand(0) == GCR2->getOperand(0) &&
+ GCR1->getBasePtr() == GCR2->getBasePtr() &&
+ GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
+
return LHSI->isIdenticalTo(RHSI);
}
@@ -561,8 +620,8 @@ private:
public:
StackNode(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
- unsigned cg, DomTreeNode *n, DomTreeNode::iterator child,
- DomTreeNode::iterator end)
+ unsigned cg, DomTreeNode *n, DomTreeNode::const_iterator child,
+ DomTreeNode::const_iterator end)
: CurrentGeneration(cg), ChildGeneration(cg), Node(n), ChildIter(child),
EndIter(end),
Scopes(AvailableValues, AvailableLoads, AvailableInvariants,
@@ -576,7 +635,7 @@ private:
unsigned childGeneration() { return ChildGeneration; }
void childGeneration(unsigned generation) { ChildGeneration = generation; }
DomTreeNode *node() { return Node; }
- DomTreeNode::iterator childIter() { return ChildIter; }
+ DomTreeNode::const_iterator childIter() { return ChildIter; }
DomTreeNode *nextChild() {
DomTreeNode *child = *ChildIter;
@@ -584,7 +643,7 @@ private:
return child;
}
- DomTreeNode::iterator end() { return EndIter; }
+ DomTreeNode::const_iterator end() { return EndIter; }
bool isProcessed() { return Processed; }
void process() { Processed = true; }
@@ -592,8 +651,8 @@ private:
unsigned CurrentGeneration;
unsigned ChildGeneration;
DomTreeNode *Node;
- DomTreeNode::iterator ChildIter;
- DomTreeNode::iterator EndIter;
+ DomTreeNode::const_iterator ChildIter;
+ DomTreeNode::const_iterator EndIter;
NodeScope Scopes;
bool Processed = false;
};
@@ -716,7 +775,7 @@ private:
bool isSameMemGeneration(unsigned EarlierGeneration, unsigned LaterGeneration,
Instruction *EarlierInst, Instruction *LaterInst);
- void removeMSSA(Instruction *Inst) {
+ void removeMSSA(Instruction &Inst) {
if (!MSSA)
return;
if (VerifyMemorySSA)
@@ -727,7 +786,7 @@ private:
// is handled by MemorySSA when passing OptimizePhis = true to
// removeMemoryAccess. The non-optimized MemoryUse case is lazily updated
// by MemorySSA's getClobberingMemoryAccess.
- MSSAUpdater->removeMemoryAccess(Inst, true);
+ MSSAUpdater->removeMemoryAccess(&Inst, true);
}
};
@@ -897,20 +956,19 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// See if any instructions in the block can be eliminated. If so, do it. If
// not, add them to AvailableValues.
- for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E;) {
- Instruction *Inst = &*I++;
-
+ for (Instruction &Inst : make_early_inc_range(BB->getInstList())) {
// Dead instructions should just be removed.
- if (isInstructionTriviallyDead(Inst, &TLI)) {
- LLVM_DEBUG(dbgs() << "EarlyCSE DCE: " << *Inst << '\n');
+ if (isInstructionTriviallyDead(&Inst, &TLI)) {
+ LLVM_DEBUG(dbgs() << "EarlyCSE DCE: " << Inst << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
- salvageDebugInfoOrMarkUndef(*Inst);
+ salvageKnowledge(&Inst, &AC);
+ salvageDebugInfo(Inst);
removeMSSA(Inst);
- Inst->eraseFromParent();
+ Inst.eraseFromParent();
Changed = true;
++NumSimplify;
continue;
@@ -920,21 +978,21 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// they're marked as such to ensure preservation of control dependencies),
// and this pass will not bother with its removal. However, we should mark
// its condition as true for all dominated blocks.
- if (match(Inst, m_Intrinsic<Intrinsic::assume>())) {
+ if (match(&Inst, m_Intrinsic<Intrinsic::assume>())) {
auto *CondI =
- dyn_cast<Instruction>(cast<CallInst>(Inst)->getArgOperand(0));
+ dyn_cast<Instruction>(cast<CallInst>(Inst).getArgOperand(0));
if (CondI && SimpleValue::canHandle(CondI)) {
- LLVM_DEBUG(dbgs() << "EarlyCSE considering assumption: " << *Inst
+ LLVM_DEBUG(dbgs() << "EarlyCSE considering assumption: " << Inst
<< '\n');
AvailableValues.insert(CondI, ConstantInt::getTrue(BB->getContext()));
} else
- LLVM_DEBUG(dbgs() << "EarlyCSE skipping assumption: " << *Inst << '\n');
+ LLVM_DEBUG(dbgs() << "EarlyCSE skipping assumption: " << Inst << '\n');
continue;
}
// Skip sideeffect intrinsics, for the same reason as assume intrinsics.
- if (match(Inst, m_Intrinsic<Intrinsic::sideeffect>())) {
- LLVM_DEBUG(dbgs() << "EarlyCSE skipping sideeffect: " << *Inst << '\n');
+ if (match(&Inst, m_Intrinsic<Intrinsic::sideeffect>())) {
+ LLVM_DEBUG(dbgs() << "EarlyCSE skipping sideeffect: " << Inst << '\n');
continue;
}
@@ -951,21 +1009,21 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// store 40, i8* p
// We can DSE the store to 30, since the store 40 to invariant location p
// causes undefined behaviour.
- if (match(Inst, m_Intrinsic<Intrinsic::invariant_start>())) {
+ if (match(&Inst, m_Intrinsic<Intrinsic::invariant_start>())) {
// If there are any uses, the scope might end.
- if (!Inst->use_empty())
+ if (!Inst.use_empty())
continue;
- auto *CI = cast<CallInst>(Inst);
- MemoryLocation MemLoc = MemoryLocation::getForArgument(CI, 1, TLI);
+ MemoryLocation MemLoc =
+ MemoryLocation::getForArgument(&cast<CallInst>(Inst), 1, TLI);
// Don't start a scope if we already have a better one pushed
if (!AvailableInvariants.count(MemLoc))
AvailableInvariants.insert(MemLoc, CurrentGeneration);
continue;
}
- if (isGuard(Inst)) {
+ if (isGuard(&Inst)) {
if (auto *CondI =
- dyn_cast<Instruction>(cast<CallInst>(Inst)->getArgOperand(0))) {
+ dyn_cast<Instruction>(cast<CallInst>(Inst).getArgOperand(0))) {
if (SimpleValue::canHandle(CondI)) {
// Do we already know the actual value of this condition?
if (auto *KnownCond = AvailableValues.lookup(CondI)) {
@@ -973,14 +1031,15 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
if (isa<ConstantInt>(KnownCond) &&
cast<ConstantInt>(KnownCond)->isOne()) {
LLVM_DEBUG(dbgs()
- << "EarlyCSE removing guard: " << *Inst << '\n');
+ << "EarlyCSE removing guard: " << Inst << '\n');
+ salvageKnowledge(&Inst, &AC);
removeMSSA(Inst);
- Inst->eraseFromParent();
+ Inst.eraseFromParent();
Changed = true;
continue;
} else
// Use the known value if it wasn't true.
- cast<CallInst>(Inst)->setArgOperand(0, KnownCond);
+ cast<CallInst>(Inst).setArgOperand(0, KnownCond);
}
// The condition we're on guarding here is true for all dominated
// locations.
@@ -997,20 +1056,21 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// If the instruction can be simplified (e.g. X+0 = X) then replace it with
// its simpler value.
- if (Value *V = SimplifyInstruction(Inst, SQ)) {
- LLVM_DEBUG(dbgs() << "EarlyCSE Simplify: " << *Inst << " to: " << *V
+ if (Value *V = SimplifyInstruction(&Inst, SQ)) {
+ LLVM_DEBUG(dbgs() << "EarlyCSE Simplify: " << Inst << " to: " << *V
<< '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
} else {
bool Killed = false;
- if (!Inst->use_empty()) {
- Inst->replaceAllUsesWith(V);
+ if (!Inst.use_empty()) {
+ Inst.replaceAllUsesWith(V);
Changed = true;
}
- if (isInstructionTriviallyDead(Inst, &TLI)) {
+ if (isInstructionTriviallyDead(&Inst, &TLI)) {
+ salvageKnowledge(&Inst, &AC);
removeMSSA(Inst);
- Inst->eraseFromParent();
+ Inst.eraseFromParent();
Changed = true;
Killed = true;
}
@@ -1022,31 +1082,32 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
}
// If this is a simple instruction that we can value number, process it.
- if (SimpleValue::canHandle(Inst)) {
+ if (SimpleValue::canHandle(&Inst)) {
// See if the instruction has an available value. If so, use it.
- if (Value *V = AvailableValues.lookup(Inst)) {
- LLVM_DEBUG(dbgs() << "EarlyCSE CSE: " << *Inst << " to: " << *V
+ if (Value *V = AvailableValues.lookup(&Inst)) {
+ LLVM_DEBUG(dbgs() << "EarlyCSE CSE: " << Inst << " to: " << *V
<< '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
if (auto *I = dyn_cast<Instruction>(V))
- I->andIRFlags(Inst);
- Inst->replaceAllUsesWith(V);
+ I->andIRFlags(&Inst);
+ Inst.replaceAllUsesWith(V);
+ salvageKnowledge(&Inst, &AC);
removeMSSA(Inst);
- Inst->eraseFromParent();
+ Inst.eraseFromParent();
Changed = true;
++NumCSE;
continue;
}
// Otherwise, just remember that this value is available.
- AvailableValues.insert(Inst, Inst);
+ AvailableValues.insert(&Inst, &Inst);
continue;
}
- ParseMemoryInst MemInst(Inst, TTI);
+ ParseMemoryInst MemInst(&Inst, TTI);
// If this is a non-volatile load, process it.
if (MemInst.isValid() && MemInst.isLoad()) {
// (conservatively) we can't peak past the ordering implied by this
@@ -1062,7 +1123,7 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// We conservatively treat the invariant_load as that moment. If we
// pass a invariant load after already establishing a scope, don't
// restart it since we want to preserve the earliest point seen.
- auto MemLoc = MemoryLocation::get(Inst);
+ auto MemLoc = MemoryLocation::get(&Inst);
if (!AvailableInvariants.count(MemLoc))
AvailableInvariants.insert(MemLoc, CurrentGeneration);
}
@@ -1081,21 +1142,22 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
!MemInst.isVolatile() && MemInst.isUnordered() &&
// We can't replace an atomic load with one which isn't also atomic.
InVal.IsAtomic >= MemInst.isAtomic() &&
- (isOperatingOnInvariantMemAt(Inst, InVal.Generation) ||
+ (isOperatingOnInvariantMemAt(&Inst, InVal.Generation) ||
isSameMemGeneration(InVal.Generation, CurrentGeneration,
- InVal.DefInst, Inst))) {
- Value *Op = getOrCreateResult(InVal.DefInst, Inst->getType());
+ InVal.DefInst, &Inst))) {
+ Value *Op = getOrCreateResult(InVal.DefInst, Inst.getType());
if (Op != nullptr) {
- LLVM_DEBUG(dbgs() << "EarlyCSE CSE LOAD: " << *Inst
+ LLVM_DEBUG(dbgs() << "EarlyCSE CSE LOAD: " << Inst
<< " to: " << *InVal.DefInst << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
- if (!Inst->use_empty())
- Inst->replaceAllUsesWith(Op);
+ if (!Inst.use_empty())
+ Inst.replaceAllUsesWith(Op);
+ salvageKnowledge(&Inst, &AC);
removeMSSA(Inst);
- Inst->eraseFromParent();
+ Inst.eraseFromParent();
Changed = true;
++NumCSELoad;
continue;
@@ -1103,10 +1165,10 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
}
// Otherwise, remember that we have this instruction.
- AvailableLoads.insert(
- MemInst.getPointerOperand(),
- LoadValue(Inst, CurrentGeneration, MemInst.getMatchingId(),
- MemInst.isAtomic()));
+ AvailableLoads.insert(MemInst.getPointerOperand(),
+ LoadValue(&Inst, CurrentGeneration,
+ MemInst.getMatchingId(),
+ MemInst.isAtomic()));
LastStore = nullptr;
continue;
}
@@ -1117,36 +1179,36 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// may override this (e.g. so that a store intrinsic does not read from
// memory, and thus will be treated the same as a regular store for
// commoning purposes).
- if ((Inst->mayReadFromMemory() || Inst->mayThrow()) &&
+ if ((Inst.mayReadFromMemory() || Inst.mayThrow()) &&
!(MemInst.isValid() && !MemInst.mayReadFromMemory()))
LastStore = nullptr;
// If this is a read-only call, process it.
- if (CallValue::canHandle(Inst)) {
+ if (CallValue::canHandle(&Inst)) {
// If we have an available version of this call, and if it is the right
// generation, replace this instruction.
- std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(Inst);
+ std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
if (InVal.first != nullptr &&
isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
- Inst)) {
- LLVM_DEBUG(dbgs() << "EarlyCSE CSE CALL: " << *Inst
+ &Inst)) {
+ LLVM_DEBUG(dbgs() << "EarlyCSE CSE CALL: " << Inst
<< " to: " << *InVal.first << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
- if (!Inst->use_empty())
- Inst->replaceAllUsesWith(InVal.first);
+ if (!Inst.use_empty())
+ Inst.replaceAllUsesWith(InVal.first);
+ salvageKnowledge(&Inst, &AC);
removeMSSA(Inst);
- Inst->eraseFromParent();
+ Inst.eraseFromParent();
Changed = true;
++NumCSECall;
continue;
}
// Otherwise, remember that we have this instruction.
- AvailableCalls.insert(
- Inst, std::pair<Instruction *, unsigned>(Inst, CurrentGeneration));
+ AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
continue;
}
@@ -1155,9 +1217,9 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// result, we don't need to consider it as writing to memory and don't need
// to advance the generation. We do need to prevent DSE across the fence,
// but that's handled above.
- if (FenceInst *FI = dyn_cast<FenceInst>(Inst))
+ if (auto *FI = dyn_cast<FenceInst>(&Inst))
if (FI->getOrdering() == AtomicOrdering::Release) {
- assert(Inst->mayReadFromMemory() && "relied on to prevent DSE above");
+ assert(Inst.mayReadFromMemory() && "relied on to prevent DSE above");
continue;
}
@@ -1169,13 +1231,13 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
if (MemInst.isValid() && MemInst.isStore()) {
LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
if (InVal.DefInst &&
- InVal.DefInst == getOrCreateResult(Inst, InVal.DefInst->getType()) &&
+ InVal.DefInst == getOrCreateResult(&Inst, InVal.DefInst->getType()) &&
InVal.MatchingId == MemInst.getMatchingId() &&
// We don't yet handle removing stores with ordering of any kind.
!MemInst.isVolatile() && MemInst.isUnordered() &&
- (isOperatingOnInvariantMemAt(Inst, InVal.Generation) ||
+ (isOperatingOnInvariantMemAt(&Inst, InVal.Generation) ||
isSameMemGeneration(InVal.Generation, CurrentGeneration,
- InVal.DefInst, Inst))) {
+ InVal.DefInst, &Inst))) {
// It is okay to have a LastStore to a different pointer here if MemorySSA
// tells us that the load and store are from the same memory generation.
// In that case, LastStore should keep its present value since we're
@@ -1185,13 +1247,14 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
MemInst.getPointerOperand() ||
MSSA) &&
"can't have an intervening store if not using MemorySSA!");
- LLVM_DEBUG(dbgs() << "EarlyCSE DSE (writeback): " << *Inst << '\n');
+ LLVM_DEBUG(dbgs() << "EarlyCSE DSE (writeback): " << Inst << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
+ salvageKnowledge(&Inst, &AC);
removeMSSA(Inst);
- Inst->eraseFromParent();
+ Inst.eraseFromParent();
Changed = true;
++NumDSE;
// We can avoid incrementing the generation count since we were able
@@ -1203,7 +1266,7 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// Okay, this isn't something we can CSE at all. Check to see if it is
// something that could modify memory. If so, our available memory values
// cannot be used so bump the generation count.
- if (Inst->mayWriteToMemory()) {
+ if (Inst.mayWriteToMemory()) {
++CurrentGeneration;
if (MemInst.isValid() && MemInst.isStore()) {
@@ -1221,11 +1284,12 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
"Violated invariant");
if (LastStoreMemInst.isMatchingMemLoc(MemInst)) {
LLVM_DEBUG(dbgs() << "EarlyCSE DEAD STORE: " << *LastStore
- << " due to: " << *Inst << '\n');
+ << " due to: " << Inst << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
} else {
- removeMSSA(LastStore);
+ salvageKnowledge(&Inst, &AC);
+ removeMSSA(*LastStore);
LastStore->eraseFromParent();
Changed = true;
++NumDSE;
@@ -1240,10 +1304,10 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// version of the pointer. It is safe to forward from volatile stores
// to non-volatile loads, so we don't have to check for volatility of
// the store.
- AvailableLoads.insert(
- MemInst.getPointerOperand(),
- LoadValue(Inst, CurrentGeneration, MemInst.getMatchingId(),
- MemInst.isAtomic()));
+ AvailableLoads.insert(MemInst.getPointerOperand(),
+ LoadValue(&Inst, CurrentGeneration,
+ MemInst.getMatchingId(),
+ MemInst.isAtomic()));
// Remember that this was the last unordered store we saw for DSE. We
// don't yet handle DSE on ordered or volatile stores since we don't
@@ -1253,7 +1317,7 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// it's not clear this is a profitable transform. Another option would
// be to merge the ordering with that of the post dominating store.
if (MemInst.isUnordered() && !MemInst.isVolatile())
- LastStore = Inst;
+ LastStore = &Inst;
else
LastStore = nullptr;
}