diff options
Diffstat (limited to 'llvm/lib/Transforms/Scalar/EarlyCSE.cpp')
-rw-r--r-- | llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 244 |
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; } |