/// HandleFree - Handle frees of entire structures whose dependency is a store /// to a field of that structure. bool DSE::HandleFree(CallInst *F) { MemDepResult Dep = MD->getDependency(F); do { if (Dep.isNonLocal()) return false; Instruction *Dependency = Dep.getInst(); if (!hasMemoryWrite(Dependency) || !isRemovable(Dependency)) return false; Value *DepPointer = getStoredPointerOperand(Dependency)->getUnderlyingObject(); // Check for aliasing. if (!AA->isMustAlias(F->getArgOperand(0), DepPointer)) return false; // DCE instructions only used to calculate that store DeleteDeadInstruction(Dependency, *MD); ++NumFastStores; // Inst's old Dependency is now deleted. Compute the next dependency, // which may also be dead, as in // s[0] = 0; // s[1] = 0; // This has just been deleted. // free(s); Dep = MD->getDependency(F); } while (!Dep.isNonLocal()); return true; }
/// Handle frees of entire structures whose dependency is a store /// to a field of that structure. static bool handleFree(CallInst *F, AliasAnalysis *AA, MemoryDependenceResults *MD, DominatorTree *DT, const TargetLibraryInfo *TLI, InstOverlapIntervalsTy &IOL, DenseMap<Instruction*, size_t> *InstrOrdering) { bool MadeChange = false; MemoryLocation Loc = MemoryLocation(F->getOperand(0)); SmallVector<BasicBlock *, 16> Blocks; Blocks.push_back(F->getParent()); const DataLayout &DL = F->getModule()->getDataLayout(); while (!Blocks.empty()) { BasicBlock *BB = Blocks.pop_back_val(); Instruction *InstPt = BB->getTerminator(); if (BB == F->getParent()) InstPt = F; MemDepResult Dep = MD->getPointerDependencyFrom(Loc, false, InstPt->getIterator(), BB); while (Dep.isDef() || Dep.isClobber()) { Instruction *Dependency = Dep.getInst(); if (!hasMemoryWrite(Dependency, *TLI) || !isRemovable(Dependency)) break; Value *DepPointer = GetUnderlyingObject(getStoredPointerOperand(Dependency), DL); // Check for aliasing. if (!AA->isMustAlias(F->getArgOperand(0), DepPointer)) break; DEBUG(dbgs() << "DSE: Dead Store to soon to be freed memory:\n DEAD: " << *Dependency << '\n'); // DCE instructions only used to calculate that store. BasicBlock::iterator BBI(Dependency); deleteDeadInstruction(Dependency, &BBI, *MD, *TLI, IOL, InstrOrdering); ++NumFastStores; MadeChange = true; // Inst's old Dependency is now deleted. Compute the next dependency, // which may also be dead, as in // s[0] = 0; // s[1] = 0; // This has just been deleted. // free(s); Dep = MD->getPointerDependencyFrom(Loc, false, BBI, BB); } if (Dep.isNonLocal()) findUnconditionalPreds(Blocks, BB, DT); } return MadeChange; }
DataDependence::DepInfo DataDependence::getDepInfo(MemDepResult dep) { if (dep.isClobber()) return DepInfo(dep.getInst(), Clobber); if (dep.isDef()) return DepInfo(dep.getInst(), Def); if (dep.isNonFuncLocal()) return DepInfo(dep.getInst(), NonFuncLocal); if (dep.isUnknown()) return DepInfo(dep.getInst(), Unknown); if (dep.isNonLocal()) return DepInfo(dep.getInst(), NonLocal); llvm_unreachable("unknown dependence type"); }
/// HandleFree - Handle frees of entire structures whose dependency is a store /// to a field of that structure. bool DSE::HandleFree(CallInst *F) { bool MadeChange = false; MemoryLocation Loc = MemoryLocation(F->getOperand(0)); SmallVector<BasicBlock *, 16> Blocks; Blocks.push_back(F->getParent()); const DataLayout &DL = F->getModule()->getDataLayout(); while (!Blocks.empty()) { BasicBlock *BB = Blocks.pop_back_val(); Instruction *InstPt = BB->getTerminator(); if (BB == F->getParent()) InstPt = F; MemDepResult Dep = MD->getPointerDependencyFrom(Loc, false, InstPt, BB); while (Dep.isDef() || Dep.isClobber()) { Instruction *Dependency = Dep.getInst(); if (!hasMemoryWrite(Dependency, *TLI) || !isRemovable(Dependency)) break; Value *DepPointer = GetUnderlyingObject(getStoredPointerOperand(Dependency), DL); // Check for aliasing. if (!AA->isMustAlias(F->getArgOperand(0), DepPointer)) break; Instruction *Next = std::next(BasicBlock::iterator(Dependency)); // DCE instructions only used to calculate that store DeleteDeadInstruction(Dependency, *MD, *TLI); ++NumFastStores; MadeChange = true; // Inst's old Dependency is now deleted. Compute the next dependency, // which may also be dead, as in // s[0] = 0; // s[1] = 0; // This has just been deleted. // free(s); Dep = MD->getPointerDependencyFrom(Loc, false, Next, BB); } if (Dep.isNonLocal()) FindUnconditionalPreds(Blocks, BB, DT); } return MadeChange; }
bool MemDepPrinter::runOnFunction(Function &F) { this->F = &F; MemoryDependenceAnalysis &MDA = getAnalysis<MemoryDependenceAnalysis>(); // All this code uses non-const interfaces because MemDep is not // const-friendly, though nothing is actually modified. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { Instruction *Inst = &*I; if (!Inst->mayReadFromMemory() && !Inst->mayWriteToMemory()) continue; MemDepResult Res = MDA.getDependency(Inst); if (!Res.isNonLocal()) { Deps[Inst].insert(std::make_pair(getInstTypePair(Res), static_cast<BasicBlock *>(nullptr))); } else if (CallSite CS = cast<Value>(Inst)) { const MemoryDependenceAnalysis::NonLocalDepInfo &NLDI = MDA.getNonLocalCallDependency(CS); DepSet &InstDeps = Deps[Inst]; for (MemoryDependenceAnalysis::NonLocalDepInfo::const_iterator I = NLDI.begin(), E = NLDI.end(); I != E; ++I) { const MemDepResult &Res = I->getResult(); InstDeps.insert(std::make_pair(getInstTypePair(Res), I->getBB())); } } else { SmallVector<NonLocalDepResult, 4> NLDI; assert( (isa<LoadInst>(Inst) || isa<StoreInst>(Inst) || isa<VAArgInst>(Inst)) && "Unknown memory instruction!"); MDA.getNonLocalPointerDependency(Inst, NLDI); DepSet &InstDeps = Deps[Inst]; for (SmallVectorImpl<NonLocalDepResult>::const_iterator I = NLDI.begin(), E = NLDI.end(); I != E; ++I) { const MemDepResult &Res = I->getResult(); InstDeps.insert(std::make_pair(getInstTypePair(Res), I->getBB())); } } } return false; }
bool MemDepPrinter::runOnFunction(Function &F) { this->F = &F; MemoryDependenceResults &MDA = getAnalysis<MemoryDependenceWrapperPass>().getMemDep(); // All this code uses non-const interfaces because MemDep is not // const-friendly, though nothing is actually modified. for (auto &I : instructions(F)) { Instruction *Inst = &I; if (!Inst->mayReadFromMemory() && !Inst->mayWriteToMemory()) continue; MemDepResult Res = MDA.getDependency(Inst); if (!Res.isNonLocal()) { Deps[Inst].insert(std::make_pair(getInstTypePair(Res), static_cast<BasicBlock *>(nullptr))); } else if (auto CS = CallSite(Inst)) { const MemoryDependenceResults::NonLocalDepInfo &NLDI = MDA.getNonLocalCallDependency(CS); DepSet &InstDeps = Deps[Inst]; for (const NonLocalDepEntry &I : NLDI) { const MemDepResult &Res = I.getResult(); InstDeps.insert(std::make_pair(getInstTypePair(Res), I.getBB())); } } else { SmallVector<NonLocalDepResult, 4> NLDI; assert( (isa<LoadInst>(Inst) || isa<StoreInst>(Inst) || isa<VAArgInst>(Inst)) && "Unknown memory instruction!"); MDA.getNonLocalPointerDependency(Inst, NLDI); DepSet &InstDeps = Deps[Inst]; for (const NonLocalDepResult &I : NLDI) { const MemDepResult &Res = I.getResult(); InstDeps.insert(std::make_pair(getInstTypePair(Res), I.getBB())); } } } return false; }
/// getNonLocalPointerDepFromBB - Perform a dependency query based on /// pointer/pointeesize starting at the end of StartBB. Add any clobber/def /// results to the results vector and keep track of which blocks are visited in /// 'Visited'. /// /// This has special behavior for the first block queries (when SkipFirstBlock /// is true). In this special case, it ignores the contents of the specified /// block and starts returning dependence info for its predecessors. /// /// This function returns false on success, or true to indicate that it could /// not compute dependence information for some reason. This should be treated /// as a clobber dependence on the first instruction in the predecessor block. bool MemoryDependenceAnalysis:: getNonLocalPointerDepFromBB(Value *Pointer, uint64_t PointeeSize, bool isLoad, BasicBlock *StartBB, SmallVectorImpl<NonLocalDepEntry> &Result, DenseMap<BasicBlock*, Value*> &Visited, bool SkipFirstBlock) { // Look up the cached info for Pointer. ValueIsLoadPair CacheKey(Pointer, isLoad); std::pair<BBSkipFirstBlockPair, NonLocalDepInfo> *CacheInfo = &NonLocalPointerDeps[CacheKey]; NonLocalDepInfo *Cache = &CacheInfo->second; // If we have valid cached information for exactly the block we are // investigating, just return it with no recomputation. if (CacheInfo->first == BBSkipFirstBlockPair(StartBB, SkipFirstBlock)) { // We have a fully cached result for this query then we can just return the // cached results and populate the visited set. However, we have to verify // that we don't already have conflicting results for these blocks. Check // to ensure that if a block in the results set is in the visited set that // it was for the same pointer query. if (!Visited.empty()) { for (NonLocalDepInfo::iterator I = Cache->begin(), E = Cache->end(); I != E; ++I) { DenseMap<BasicBlock*, Value*>::iterator VI = Visited.find(I->first); if (VI == Visited.end() || VI->second == Pointer) continue; // We have a pointer mismatch in a block. Just return clobber, saying // that something was clobbered in this result. We could also do a // non-fully cached query, but there is little point in doing this. return true; } } for (NonLocalDepInfo::iterator I = Cache->begin(), E = Cache->end(); I != E; ++I) { Visited.insert(std::make_pair(I->first, Pointer)); if (!I->second.isNonLocal()) Result.push_back(*I); } ++NumCacheCompleteNonLocalPtr; return false; } // Otherwise, either this is a new block, a block with an invalid cache // pointer or one that we're about to invalidate by putting more info into it // than its valid cache info. If empty, the result will be valid cache info, // otherwise it isn't. if (Cache->empty()) CacheInfo->first = BBSkipFirstBlockPair(StartBB, SkipFirstBlock); else CacheInfo->first = BBSkipFirstBlockPair(); SmallVector<BasicBlock*, 32> Worklist; Worklist.push_back(StartBB); // Keep track of the entries that we know are sorted. Previously cached // entries will all be sorted. The entries we add we only sort on demand (we // don't insert every element into its sorted position). We know that we // won't get any reuse from currently inserted values, because we don't // revisit blocks after we insert info for them. unsigned NumSortedEntries = Cache->size(); DEBUG(AssertSorted(*Cache)); while (!Worklist.empty()) { BasicBlock *BB = Worklist.pop_back_val(); // Skip the first block if we have it. if (!SkipFirstBlock) { // Analyze the dependency of *Pointer in FromBB. See if we already have // been here. assert(Visited.count(BB) && "Should check 'visited' before adding to WL"); // Get the dependency info for Pointer in BB. If we have cached // information, we will use it, otherwise we compute it. DEBUG(AssertSorted(*Cache, NumSortedEntries)); MemDepResult Dep = GetNonLocalInfoForBlock(Pointer, PointeeSize, isLoad, BB, Cache, NumSortedEntries); // If we got a Def or Clobber, add this to the list of results. if (!Dep.isNonLocal()) { Result.push_back(NonLocalDepEntry(BB, Dep)); continue; } } // If 'Pointer' is an instruction defined in this block, then we need to do // phi translation to change it into a value live in the predecessor block. // If phi translation fails, then we can't continue dependence analysis. Instruction *PtrInst = dyn_cast<Instruction>(Pointer); bool NeedsPHITranslation = PtrInst && PtrInst->getParent() == BB; // If no PHI translation is needed, just add all the predecessors of this // block to scan them as well. if (!NeedsPHITranslation) { SkipFirstBlock = false; for (BasicBlock **PI = PredCache->GetPreds(BB); *PI; ++PI) { // Verify that we haven't looked at this block yet. std::pair<DenseMap<BasicBlock*,Value*>::iterator, bool> InsertRes = Visited.insert(std::make_pair(*PI, Pointer)); if (InsertRes.second) { // First time we've looked at *PI. Worklist.push_back(*PI); continue; } // If we have seen this block before, but it was with a different // pointer then we have a phi translation failure and we have to treat // this as a clobber. if (InsertRes.first->second != Pointer) goto PredTranslationFailure; } continue; } // If we do need to do phi translation, then there are a bunch of different // cases, because we have to find a Value* live in the predecessor block. We // know that PtrInst is defined in this block at least. // If this is directly a PHI node, just use the incoming values for each // pred as the phi translated version. if (PHINode *PtrPHI = dyn_cast<PHINode>(PtrInst)) { for (BasicBlock **PI = PredCache->GetPreds(BB); *PI; ++PI) { BasicBlock *Pred = *PI; Value *PredPtr = PtrPHI->getIncomingValueForBlock(Pred); // Check to see if we have already visited this pred block with another // pointer. If so, we can't do this lookup. This failure can occur // with PHI translation when a critical edge exists and the PHI node in // the successor translates to a pointer value different than the // pointer the block was first analyzed with. std::pair<DenseMap<BasicBlock*,Value*>::iterator, bool> InsertRes = Visited.insert(std::make_pair(Pred, PredPtr)); if (!InsertRes.second) { // If the predecessor was visited with PredPtr, then we already did // the analysis and can ignore it. if (InsertRes.first->second == PredPtr) continue; // Otherwise, the block was previously analyzed with a different // pointer. We can't represent the result of this case, so we just // treat this as a phi translation failure. goto PredTranslationFailure; } // We may have added values to the cache list before this PHI // translation. If so, we haven't done anything to ensure that the // cache remains sorted. Sort it now (if needed) so that recursive // invocations of getNonLocalPointerDepFromBB that could reuse the cache // value will only see properly sorted cache arrays. if (Cache && NumSortedEntries != Cache->size()) std::sort(Cache->begin(), Cache->end()); Cache = 0; // FIXME: it is entirely possible that PHI translating will end up with // the same value. Consider PHI translating something like: // X = phi [x, bb1], [y, bb2]. PHI translating for bb1 doesn't *need* // to recurse here, pedantically speaking. // If we have a problem phi translating, fall through to the code below // to handle the failure condition. if (getNonLocalPointerDepFromBB(PredPtr, PointeeSize, isLoad, Pred, Result, Visited)) goto PredTranslationFailure; } // Refresh the CacheInfo/Cache pointer so that it isn't invalidated. CacheInfo = &NonLocalPointerDeps[CacheKey]; Cache = &CacheInfo->second; NumSortedEntries = Cache->size(); // Since we did phi translation, the "Cache" set won't contain all of the // results for the query. This is ok (we can still use it to accelerate // specific block queries) but we can't do the fastpath "return all // results from the set" Clear out the indicator for this. CacheInfo->first = BBSkipFirstBlockPair(); SkipFirstBlock = false; continue; } // TODO: BITCAST, GEP. // cerr << "MEMDEP: Could not PHI translate: " << *Pointer; // if (isa<BitCastInst>(PtrInst) || isa<GetElementPtrInst>(PtrInst)) // cerr << "OP:\t\t\t\t" << *PtrInst->getOperand(0); PredTranslationFailure: if (Cache == 0) { // Refresh the CacheInfo/Cache pointer if it got invalidated. CacheInfo = &NonLocalPointerDeps[CacheKey]; Cache = &CacheInfo->second; NumSortedEntries = Cache->size(); } else if (NumSortedEntries != Cache->size()) { std::sort(Cache->begin(), Cache->end()); NumSortedEntries = Cache->size(); } // Since we did phi translation, the "Cache" set won't contain all of the // results for the query. This is ok (we can still use it to accelerate // specific block queries) but we can't do the fastpath "return all // results from the set" Clear out the indicator for this. CacheInfo->first = BBSkipFirstBlockPair(); // If *nothing* works, mark the pointer as being clobbered by the first // instruction in this block. // // If this is the magic first block, return this as a clobber of the whole // incoming value. Since we can't phi translate to one of the predecessors, // we have to bail out. if (SkipFirstBlock) return true; for (NonLocalDepInfo::reverse_iterator I = Cache->rbegin(); ; ++I) { assert(I != Cache->rend() && "Didn't find current block??"); if (I->first != BB) continue; assert(I->second.isNonLocal() && "Should only be here with transparent block"); I->second = MemDepResult::getClobber(BB->begin()); ReverseNonLocalPtrDeps[BB->begin()].insert(CacheKey.getOpaqueValue()); Result.push_back(*I); break; } } // Okay, we're done now. If we added new values to the cache, re-sort it. switch (Cache->size()-NumSortedEntries) { case 0: // done, no new entries. break; case 2: { // Two new entries, insert the last one into place. NonLocalDepEntry Val = Cache->back(); Cache->pop_back(); NonLocalDepInfo::iterator Entry = std::upper_bound(Cache->begin(), Cache->end()-1, Val); Cache->insert(Entry, Val); // FALL THROUGH. } case 1: // One new entry, Just insert the new value at the appropriate position. if (Cache->size() != 1) { NonLocalDepEntry Val = Cache->back(); Cache->pop_back(); NonLocalDepInfo::iterator Entry = std::upper_bound(Cache->begin(), Cache->end(), Val); Cache->insert(Entry, Val); } break; default: // Added many values, do a full scale sort. std::sort(Cache->begin(), Cache->end()); } DEBUG(AssertSorted(*Cache)); return false; }
/// GetNonLocalInfoForBlock - Compute the memdep value for BB with /// Pointer/PointeeSize using either cached information in Cache or by doing a /// lookup (which may use dirty cache info if available). If we do a lookup, /// add the result to the cache. MemDepResult MemoryDependenceAnalysis:: GetNonLocalInfoForBlock(Value *Pointer, uint64_t PointeeSize, bool isLoad, BasicBlock *BB, NonLocalDepInfo *Cache, unsigned NumSortedEntries) { // Do a binary search to see if we already have an entry for this block in // the cache set. If so, find it. NonLocalDepInfo::iterator Entry = std::upper_bound(Cache->begin(), Cache->begin()+NumSortedEntries, std::make_pair(BB, MemDepResult())); if (Entry != Cache->begin() && prior(Entry)->first == BB) --Entry; MemDepResult *ExistingResult = 0; if (Entry != Cache->begin()+NumSortedEntries && Entry->first == BB) ExistingResult = &Entry->second; // If we have a cached entry, and it is non-dirty, use it as the value for // this dependency. if (ExistingResult && !ExistingResult->isDirty()) { ++NumCacheNonLocalPtr; return *ExistingResult; } // Otherwise, we have to scan for the value. If we have a dirty cache // entry, start scanning from its position, otherwise we scan from the end // of the block. BasicBlock::iterator ScanPos = BB->end(); if (ExistingResult && ExistingResult->getInst()) { assert(ExistingResult->getInst()->getParent() == BB && "Instruction invalidated?"); ++NumCacheDirtyNonLocalPtr; ScanPos = ExistingResult->getInst(); // Eliminating the dirty entry from 'Cache', so update the reverse info. ValueIsLoadPair CacheKey(Pointer, isLoad); RemoveFromReverseMap(ReverseNonLocalPtrDeps, ScanPos, CacheKey.getOpaqueValue()); } else { ++NumUncacheNonLocalPtr; } // Scan the block for the dependency. MemDepResult Dep = getPointerDependencyFrom(Pointer, PointeeSize, isLoad, ScanPos, BB); // If we had a dirty entry for the block, update it. Otherwise, just add // a new entry. if (ExistingResult) *ExistingResult = Dep; else Cache->push_back(std::make_pair(BB, Dep)); // If the block has a dependency (i.e. it isn't completely transparent to // the value), remember the reverse association because we just added it // to Cache! if (Dep.isNonLocal()) return Dep; // Keep the ReverseNonLocalPtrDeps map up to date so we can efficiently // update MemDep when we remove instructions. Instruction *Inst = Dep.getInst(); assert(Inst && "Didn't depend on anything?"); ValueIsLoadPair CacheKey(Pointer, isLoad); ReverseNonLocalPtrDeps[Inst].insert(CacheKey.getOpaqueValue()); return Dep; }
/// getNonLocalCallDependency - Perform a full dependency query for the /// specified call, returning the set of blocks that the value is /// potentially live across. The returned set of results will include a /// "NonLocal" result for all blocks where the value is live across. /// /// This method assumes the instruction returns a "NonLocal" dependency /// within its own block. /// /// This returns a reference to an internal data structure that may be /// invalidated on the next non-local query or when an instruction is /// removed. Clients must copy this data if they want it around longer than /// that. const MemoryDependenceAnalysis::NonLocalDepInfo & MemoryDependenceAnalysis::getNonLocalCallDependency(CallSite QueryCS) { assert(getDependency(QueryCS.getInstruction()).isNonLocal() && "getNonLocalCallDependency should only be used on calls with non-local deps!"); PerInstNLInfo &CacheP = NonLocalDeps[QueryCS.getInstruction()]; NonLocalDepInfo &Cache = CacheP.first; /// DirtyBlocks - This is the set of blocks that need to be recomputed. In /// the cached case, this can happen due to instructions being deleted etc. In /// the uncached case, this starts out as the set of predecessors we care /// about. SmallVector<BasicBlock*, 32> DirtyBlocks; if (!Cache.empty()) { // Okay, we have a cache entry. If we know it is not dirty, just return it // with no computation. if (!CacheP.second) { NumCacheNonLocal++; return Cache; } // If we already have a partially computed set of results, scan them to // determine what is dirty, seeding our initial DirtyBlocks worklist. for (NonLocalDepInfo::iterator I = Cache.begin(), E = Cache.end(); I != E; ++I) if (I->second.isDirty()) DirtyBlocks.push_back(I->first); // Sort the cache so that we can do fast binary search lookups below. std::sort(Cache.begin(), Cache.end()); ++NumCacheDirtyNonLocal; //cerr << "CACHED CASE: " << DirtyBlocks.size() << " dirty: " // << Cache.size() << " cached: " << *QueryInst; } else { // Seed DirtyBlocks with each of the preds of QueryInst's block. BasicBlock *QueryBB = QueryCS.getInstruction()->getParent(); for (BasicBlock **PI = PredCache->GetPreds(QueryBB); *PI; ++PI) DirtyBlocks.push_back(*PI); NumUncacheNonLocal++; } // isReadonlyCall - If this is a read-only call, we can be more aggressive. bool isReadonlyCall = AA->onlyReadsMemory(QueryCS); SmallPtrSet<BasicBlock*, 64> Visited; unsigned NumSortedEntries = Cache.size(); DEBUG(AssertSorted(Cache)); // Iterate while we still have blocks to update. while (!DirtyBlocks.empty()) { BasicBlock *DirtyBB = DirtyBlocks.back(); DirtyBlocks.pop_back(); // Already processed this block? if (!Visited.insert(DirtyBB)) continue; // Do a binary search to see if we already have an entry for this block in // the cache set. If so, find it. DEBUG(AssertSorted(Cache, NumSortedEntries)); NonLocalDepInfo::iterator Entry = std::upper_bound(Cache.begin(), Cache.begin()+NumSortedEntries, std::make_pair(DirtyBB, MemDepResult())); if (Entry != Cache.begin() && prior(Entry)->first == DirtyBB) --Entry; MemDepResult *ExistingResult = 0; if (Entry != Cache.begin()+NumSortedEntries && Entry->first == DirtyBB) { // If we already have an entry, and if it isn't already dirty, the block // is done. if (!Entry->second.isDirty()) continue; // Otherwise, remember this slot so we can update the value. ExistingResult = &Entry->second; } // If the dirty entry has a pointer, start scanning from it so we don't have // to rescan the entire block. BasicBlock::iterator ScanPos = DirtyBB->end(); if (ExistingResult) { if (Instruction *Inst = ExistingResult->getInst()) { ScanPos = Inst; // We're removing QueryInst's use of Inst. RemoveFromReverseMap(ReverseNonLocalDeps, Inst, QueryCS.getInstruction()); } } // Find out if this block has a local dependency for QueryInst. MemDepResult Dep; if (ScanPos != DirtyBB->begin()) { Dep = getCallSiteDependencyFrom(QueryCS, isReadonlyCall,ScanPos, DirtyBB); } else if (DirtyBB != &DirtyBB->getParent()->getEntryBlock()) { // No dependence found. If this is the entry block of the function, it is // a clobber, otherwise it is non-local. Dep = MemDepResult::getNonLocal(); } else { Dep = MemDepResult::getClobber(ScanPos); } // If we had a dirty entry for the block, update it. Otherwise, just add // a new entry. if (ExistingResult) *ExistingResult = Dep; else Cache.push_back(std::make_pair(DirtyBB, Dep)); // If the block has a dependency (i.e. it isn't completely transparent to // the value), remember the association! if (!Dep.isNonLocal()) { // Keep the ReverseNonLocalDeps map up to date so we can efficiently // update this when we remove instructions. if (Instruction *Inst = Dep.getInst()) ReverseNonLocalDeps[Inst].insert(QueryCS.getInstruction()); } else { // If the block *is* completely transparent to the load, we need to check // the predecessors of this block. Add them to our worklist. for (BasicBlock **PI = PredCache->GetPreds(DirtyBB); *PI; ++PI) DirtyBlocks.push_back(*PI); } } return Cache; }
void DataDependence::processDepResult(Instruction *inst, MemoryDependenceAnalysis &MDA, AliasAnalysis &AA) { // TODO: This is probably a good place to check of the dependency // information is calculated on-demand MemDepResult Res = MDA.getDependency(inst); if (!Res.isNonLocal()) { // local results (not-non-local) can be simply handled. They are just // a pair of insturctions and a dependency type // Get dependency information DepInfo newInfo; newInfo = getDepInfo(Res); #ifdef MK_DEBUG //errs() << "[DEBUG] newInfo depInst == " << Res.getInst() << '\n'; if (Res.getInst() == NULL) { errs() << "[DEBUG] NULL dependency found, dep type: " << depTypeToString(newInfo.Type_) << '\n'; } #endif // Save into map assert(newInfo.valid()); LocalDeps_[inst] = newInfo; } else { // Handle NonLocal dependencies. The function call // getNonLocalPointerDependency() assumes that a result of NonLocal // has already been encountered // Get dependency information DepInfo newInfo; newInfo = getDepInfo(Res); assert(newInfo.Type_ == NonLocal); assert(Res.isNonLocal()); SmallVector<NonLocalDepResult, 4> NLDep; if (LoadInst *LI = dyn_cast<LoadInst>(inst)) { if (!LI->isUnordered()) { // FIXME: Handle atomic/volatile loads. errs() << "[WARNING] atomic/volatile loads are not handled\n"; assert(false && "atomic/volatile loads not handled"); //Deps[Inst].insert(std::make_pair(getInstTypePair(0, Unknown), //static_cast<BasicBlock *>(0))); return; } AliasAnalysis::Location Loc = AA.getLocation(LI); MDA.getNonLocalPointerDependency(Loc, true, LI->getParent(), NLDep); } else if (StoreInst *SI = dyn_cast<StoreInst>(inst)) { if (!SI->isUnordered()) { // FIXME: Handle atomic/volatile stores. errs() << "[WARNING] atomic/volatile stores are not handled\n"; assert(false && "atomic/volatile stores not handled"); //Deps[Inst].insert(std::make_pair(getInstTypePair(0, Unknown), //static_cast<BasicBlock *>(0))); return; } AliasAnalysis::Location Loc = AA.getLocation(SI); MDA.getNonLocalPointerDependency(Loc, false, SI->getParent(), NLDep); } else if (VAArgInst *VI = dyn_cast<VAArgInst>(inst)) { AliasAnalysis::Location Loc = AA.getLocation(VI); MDA.getNonLocalPointerDependency(Loc, false, VI->getParent(), NLDep); } else { llvm_unreachable("Unknown memory instruction!"); } #ifdef MK_DEBUG errs() << "[DEBUG] NLDep.size() == " << NLDep.size() << '\n'; #endif for (auto I = NLDep.begin(), E = NLDep.end(); I != E; ++I) { NonLocalDeps_[inst].push_back(*I); } } // end else }
bool DSE::runOnBasicBlock(BasicBlock &BB) { bool MadeChange = false; // Do a top-down walk on the BB. for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; ) { Instruction *Inst = BBI++; // Handle 'free' calls specially. if (CallInst *F = isFreeCall(Inst)) { MadeChange |= HandleFree(F); continue; } // If we find something that writes memory, get its memory dependence. if (!hasMemoryWrite(Inst)) continue; MemDepResult InstDep = MD->getDependency(Inst); // Ignore non-local store liveness. // FIXME: cross-block DSE would be fun. :) if (InstDep.isNonLocal() || // Ignore self dependence, which happens in the entry block of the // function. InstDep.getInst() == Inst) continue; // If we're storing the same value back to a pointer that we just // loaded from, then the store can be removed. if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { if (LoadInst *DepLoad = dyn_cast<LoadInst>(InstDep.getInst())) { if (SI->getPointerOperand() == DepLoad->getPointerOperand() && SI->getOperand(0) == DepLoad && !SI->isVolatile()) { DEBUG(dbgs() << "DSE: Remove Store Of Load from same pointer:\n " << "LOAD: " << *DepLoad << "\n STORE: " << *SI << '\n'); // DeleteDeadInstruction can delete the current instruction. Save BBI // in case we need it. WeakVH NextInst(BBI); DeleteDeadInstruction(SI, *MD); if (NextInst == 0) // Next instruction deleted. BBI = BB.begin(); else if (BBI != BB.begin()) // Revisit this instruction if possible. --BBI; ++NumFastStores; MadeChange = true; continue; } } } // Figure out what location is being stored to. AliasAnalysis::Location Loc = getLocForWrite(Inst, *AA); // If we didn't get a useful location, fail. if (Loc.Ptr == 0) continue; while (!InstDep.isNonLocal()) { // Get the memory clobbered by the instruction we depend on. MemDep will // skip any instructions that 'Loc' clearly doesn't interact with. If we // end up depending on a may- or must-aliased load, then we can't optimize // away the store and we bail out. However, if we depend on on something // that overwrites the memory location we *can* potentially optimize it. // // Find out what memory location the dependant instruction stores. Instruction *DepWrite = InstDep.getInst(); AliasAnalysis::Location DepLoc = getLocForWrite(DepWrite, *AA); // If we didn't get a useful location, or if it isn't a size, bail out. if (DepLoc.Ptr == 0) break; // If we find a write that is a) removable (i.e., non-volatile), b) is // completely obliterated by the store to 'Loc', and c) which we know that // 'Inst' doesn't load from, then we can remove it. if (isRemovable(DepWrite) && isCompleteOverwrite(Loc, DepLoc, *AA) && !isPossibleSelfRead(Inst, Loc, DepWrite, *AA)) { DEBUG(dbgs() << "DSE: Remove Dead Store:\n DEAD: " << *DepWrite << "\n KILLER: " << *Inst << '\n'); // Delete the store and now-dead instructions that feed it. DeleteDeadInstruction(DepWrite, *MD); ++NumFastStores; MadeChange = true; // DeleteDeadInstruction can delete the current instruction in loop // cases, reset BBI. BBI = Inst; if (BBI != BB.begin()) --BBI; break; } // If this is a may-aliased store that is clobbering the store value, we // can keep searching past it for another must-aliased pointer that stores // to the same location. For example, in: // store -> P // store -> Q // store -> P // we can remove the first store to P even though we don't know if P and Q // alias. if (DepWrite == &BB.front()) break; // Can't look past this instruction if it might read 'Loc'. if (AA->getModRefInfo(DepWrite, Loc) & AliasAnalysis::Ref) break; InstDep = MD->getPointerDependencyFrom(Loc, false, DepWrite, &BB); } } // If this block ends in a return, unwind, or unreachable, all allocas are // dead at its end, which means stores to them are also dead. if (BB.getTerminator()->getNumSuccessors() == 0) MadeChange |= handleEndBlock(BB); return MadeChange; }
bool MemDepPrinter::runOnFunction(Function &F) { this->F = &F; AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); MemoryDependenceAnalysis &MDA = getAnalysis<MemoryDependenceAnalysis>(); // All this code uses non-const interfaces because MemDep is not // const-friendly, though nothing is actually modified. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { Instruction *Inst = &*I; if (!Inst->mayReadFromMemory() && !Inst->mayWriteToMemory()) continue; MemDepResult Res = MDA.getDependency(Inst); if (!Res.isNonLocal()) { Deps[Inst].insert(std::make_pair(getInstTypePair(Res), static_cast<BasicBlock *>(nullptr))); } else if (CallSite CS = cast<Value>(Inst)) { const MemoryDependenceAnalysis::NonLocalDepInfo &NLDI = MDA.getNonLocalCallDependency(CS); DepSet &InstDeps = Deps[Inst]; for (MemoryDependenceAnalysis::NonLocalDepInfo::const_iterator I = NLDI.begin(), E = NLDI.end(); I != E; ++I) { const MemDepResult &Res = I->getResult(); InstDeps.insert(std::make_pair(getInstTypePair(Res), I->getBB())); } } else { SmallVector<NonLocalDepResult, 4> NLDI; if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) { if (!LI->isUnordered()) { // FIXME: Handle atomic/volatile loads. Deps[Inst].insert(std::make_pair(getInstTypePair(nullptr, Unknown), static_cast<BasicBlock *>(nullptr))); continue; } AliasAnalysis::Location Loc = AA.getLocation(LI); MDA.getNonLocalPointerDependency(Loc, true, LI->getParent(), NLDI); } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { if (!SI->isUnordered()) { // FIXME: Handle atomic/volatile stores. Deps[Inst].insert(std::make_pair(getInstTypePair(nullptr, Unknown), static_cast<BasicBlock *>(nullptr))); continue; } AliasAnalysis::Location Loc = AA.getLocation(SI); MDA.getNonLocalPointerDependency(Loc, false, SI->getParent(), NLDI); } else if (VAArgInst *VI = dyn_cast<VAArgInst>(Inst)) { AliasAnalysis::Location Loc = AA.getLocation(VI); MDA.getNonLocalPointerDependency(Loc, false, VI->getParent(), NLDI); } else { llvm_unreachable("Unknown memory instruction!"); } DepSet &InstDeps = Deps[Inst]; for (SmallVectorImpl<NonLocalDepResult>::const_iterator I = NLDI.begin(), E = NLDI.end(); I != E; ++I) { const MemDepResult &Res = I->getResult(); InstDeps.insert(std::make_pair(getInstTypePair(Res), I->getBB())); } } } return false; }
bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { if (SI->isVolatile()) return false; if (TD == 0) return false; // Detect cases where we're performing call slot forwarding, but // happen to be using a load-store pair to implement it, rather than // a memcpy. if (LoadInst *LI = dyn_cast<LoadInst>(SI->getOperand(0))) { if (!LI->isVolatile() && LI->hasOneUse()) { MemDepResult ldep = MD->getDependency(LI); CallInst *C = 0; if (ldep.isClobber() && !isa<MemCpyInst>(ldep.getInst())) C = dyn_cast<CallInst>(ldep.getInst()); if (C) { // Check that nothing touches the dest of the "copy" between // the call and the store. MemDepResult sdep = MD->getDependency(SI); if (!sdep.isNonLocal()) { bool FoundCall = false; for (BasicBlock::iterator I = SI, E = sdep.getInst(); I != E; --I) { if (&*I == C) { FoundCall = true; break; } } if (!FoundCall) C = 0; } } if (C) { bool changed = performCallSlotOptzn(LI, SI->getPointerOperand()->stripPointerCasts(), LI->getPointerOperand()->stripPointerCasts(), TD->getTypeStoreSize(SI->getOperand(0)->getType()), C); if (changed) { MD->removeInstruction(SI); SI->eraseFromParent(); MD->removeInstruction(LI); LI->eraseFromParent(); ++NumMemCpyInstr; return true; } } } } // There are two cases that are interesting for this code to handle: memcpy // and memset. Right now we only handle memset. // Ensure that the value being stored is something that can be memset'able a // byte at a time like "0" or "-1" or any width, as well as things like // 0xA0A0A0A0 and 0.0. if (Value *ByteVal = isBytewiseValue(SI->getOperand(0))) if (Instruction *I = tryMergingIntoMemset(SI, SI->getPointerOperand(), ByteVal)) { BBI = I; // Don't invalidate iterator. return true; } return false; }