/// remove - Remove the specified (potentially non-empty) alias set from the /// tracker. void AliasSetTracker::remove(AliasSet &AS) { // Drop all call sites. AS.UnknownInsts.clear(); // Clear the alias set. unsigned NumRefs = 0; while (!AS.empty()) { AliasSet::PointerRec *P = AS.PtrList; Value *ValToRemove = P->getValue(); // Unlink and delete entry from the list of values. P->eraseFromList(); // Remember how many references need to be dropped. ++NumRefs; // Finally, remove the entry. PointerMap.erase(ValToRemove); } // Stop using the alias set, removing it. AS.RefCount -= NumRefs; if (AS.RefCount == 0) AS.removeFromTracker(*this); }
// deleteValue method - This method is used to remove a pointer value from the // AliasSetTracker entirely. It should be used when an instruction is deleted // from the program to update the AST. If you don't use this, you would have // dangling pointers to deleted instructions. // void AliasSetTracker::deleteValue(Value *PtrVal) { // Notify the alias analysis implementation that this value is gone. AA.deleteValue(PtrVal); // If this is a call instruction, remove the callsite from the appropriate // AliasSet. CallSite CS = CallSite::get(PtrVal); if (CS.getInstruction()) { Function *F = CS.getCalledFunction(); if (!F || !AA.doesNotAccessMemory(F)) { if (AliasSet *AS = findAliasSetForCallSite(CS)) AS->removeCallSite(CS); } } // First, look up the PointerRec for this pointer. hash_map<Value*, AliasSet::PointerRec>::iterator I = PointerMap.find(PtrVal); if (I == PointerMap.end()) return; // Noop // If we found one, remove the pointer from the alias set it is in. AliasSet::HashNodePair &PtrValEnt = *I; AliasSet *AS = PtrValEnt.second.getAliasSet(*this); // Unlink from the list of values... PtrValEnt.second.removeFromList(); // Stop using the alias set AS->dropRef(*this); PointerMap.erase(I); }
// deleteValue method - This method is used to remove a pointer value from the // AliasSetTracker entirely. It should be used when an instruction is deleted // from the program to update the AST. If you don't use this, you would have // dangling pointers to deleted instructions. // void AliasSetTracker::deleteValue(Value *PtrVal) { // Notify the alias analysis implementation that this value is gone. AA.deleteValue(PtrVal); // If this is a call instruction, remove the callsite from the appropriate // AliasSet (if present). if (Instruction *Inst = dyn_cast<Instruction>(PtrVal)) { if (Inst->mayReadOrWriteMemory()) { // Scan all the alias sets to see if this call site is contained. for (iterator I = begin(), E = end(); I != E; ++I) { if (I->Forward) continue; I->removeUnknownInst(Inst); } } } // First, look up the PointerRec for this pointer. PointerMapType::iterator I = PointerMap.find(PtrVal); if (I == PointerMap.end()) return; // Noop // If we found one, remove the pointer from the alias set it is in. AliasSet::PointerRec *PtrValEnt = I->second; AliasSet *AS = PtrValEnt->getAliasSet(*this); // Unlink and delete from the list of values. PtrValEnt->eraseFromList(); // Stop using the alias set. AS->dropRef(*this); PointerMap.erase(I); }
/// mergeSetIn - Merge the specified alias set into this alias set. /// void AliasSet::mergeSetIn(AliasSet &AS, AliasSetTracker &AST) { assert(!AS.Forward && "Alias set is already forwarding!"); assert(!Forward && "This set is a forwarding set!!"); bool WasMustAlias = (Alias == SetMustAlias); // Update the alias and access types of this set... Access |= AS.Access; Alias |= AS.Alias; if (Alias == SetMustAlias) { // Check that these two merged sets really are must aliases. Since both // used to be must-alias sets, we can just check any pointer from each set // for aliasing. AliasAnalysis &AA = AST.getAliasAnalysis(); PointerRec *L = getSomePointer(); PointerRec *R = AS.getSomePointer(); // If the pointers are not a must-alias pair, this set becomes a may alias. if (AA.alias(MemoryLocation(L->getValue(), L->getSize(), L->getAAInfo()), MemoryLocation(R->getValue(), R->getSize(), R->getAAInfo())) != MustAlias) Alias = SetMayAlias; } if (Alias == SetMayAlias) { if (WasMustAlias) AST.TotalMayAliasSetSize += size(); if (AS.Alias == SetMustAlias) AST.TotalMayAliasSetSize += AS.size(); } bool ASHadUnknownInsts = !AS.UnknownInsts.empty(); if (UnknownInsts.empty()) { // Merge call sites... if (ASHadUnknownInsts) { std::swap(UnknownInsts, AS.UnknownInsts); addRef(); } } else if (ASHadUnknownInsts) { UnknownInsts.insert(UnknownInsts.end(), AS.UnknownInsts.begin(), AS.UnknownInsts.end()); AS.UnknownInsts.clear(); } AS.Forward = this; // Forward across AS now... addRef(); // AS is now pointing to us... // Merge the list of constituent pointers... if (AS.PtrList) { SetSize += AS.size(); AS.SetSize = 0; *PtrListEnd = AS.PtrList; AS.PtrList->setPrevInList(PtrListEnd); PtrListEnd = AS.PtrListEnd; AS.PtrList = nullptr; AS.PtrListEnd = &AS.PtrList; assert(*AS.PtrListEnd == nullptr && "End of list is not null?"); } if (ASHadUnknownInsts) AS.dropRef(AST); }
// deleteValue method - This method is used to remove a pointer value from the // AliasSetTracker entirely. It should be used when an instruction is deleted // from the program to update the AST. If you don't use this, you would have // dangling pointers to deleted instructions. // void AliasSetTracker::deleteValue(Value *PtrVal) { // Notify the alias analysis implementation that this value is gone. AA.deleteValue(PtrVal); // If this is a call instruction, remove the callsite from the appropriate // AliasSet. CallSite CS = CallSite::get(PtrVal); if (CS.getInstruction()) if (!AA.doesNotAccessMemory(CS)) if (AliasSet *AS = findAliasSetForCallSite(CS)) AS->removeCallSite(CS); // First, look up the PointerRec for this pointer. PointerMapType::iterator I = PointerMap.find(PtrVal); if (I == PointerMap.end()) return; // Noop // If we found one, remove the pointer from the alias set it is in. AliasSet::PointerRec *PtrValEnt = I->second; AliasSet *AS = PtrValEnt->getAliasSet(*this); // Unlink and delete from the list of values. PtrValEnt->eraseFromList(); // Stop using the alias set. AS->dropRef(*this); PointerMap.erase(I); }
/// remove - Remove the specified (potentially non-empty) alias set from the /// tracker. void AliasSetTracker::remove(AliasSet &AS) { // Drop all call sites. AS.CallSites.clear(); // Clear the alias set. unsigned NumRefs = 0; while (!AS.empty()) { AliasSet::HashNodePair *P = AS.PtrList; // Unlink from the list of values. P->second.removeFromList(); // Remember how many references need to be dropped. ++NumRefs; // Finally, remove the entry. Value *Remove = P->first; // Take a copy because it is invalid to pass PointerMap.erase(Remove); // a reference to the data being erased. } // Stop using the alias set, removing it. AS.RefCount -= NumRefs; if (AS.RefCount == 0) AS.removeFromTracker(*this); }
/// mergeAliasSetsForPointer - Given a pointer, merge all alias sets that may /// alias the pointer. Return the unified set, or nullptr if no set that aliases /// the pointer was found. MustAliasAll is updated to true/false if the pointer /// is found to MustAlias all the sets it merged. AliasSet *AliasSetTracker::mergeAliasSetsForPointer(const Value *Ptr, LocationSize Size, const AAMDNodes &AAInfo, bool &MustAliasAll) { AliasSet *FoundSet = nullptr; AliasResult AllAR = MustAlias; for (iterator I = begin(), E = end(); I != E;) { iterator Cur = I++; if (Cur->Forward) continue; AliasResult AR = Cur->aliasesPointer(Ptr, Size, AAInfo, AA); if (AR == NoAlias) continue; AllAR = AliasResult(AllAR & AR); // Possible downgrade to May/Partial, even No if (!FoundSet) { // If this is the first alias set ptr can go into, remember it. FoundSet = &*Cur; } else { // Otherwise, we must merge the sets. FoundSet->mergeSetIn(*Cur, *this); } } MustAliasAll = (AllAR == MustAlias); return FoundSet; }
void AliasSetTracker::addUnknown(Instruction *Inst) { if (isa<DbgInfoIntrinsic>(Inst)) return; // Ignore DbgInfo Intrinsics. if (auto *II = dyn_cast<IntrinsicInst>(Inst)) { // These intrinsics will show up as affecting memory, but they are just // markers. switch (II->getIntrinsicID()) { default: break; // FIXME: Add lifetime/invariant intrinsics (See: PR30807). case Intrinsic::assume: case Intrinsic::sideeffect: return; } } if (!Inst->mayReadOrWriteMemory()) return; // doesn't alias anything AliasSet *AS = findAliasSetForUnknownInst(Inst); if (AS) { AS->addUnknownInst(Inst, AA); return; } AliasSets.push_back(new AliasSet()); AS = &AliasSets.back(); AS->addUnknownInst(Inst, AA); }
AliasSet *AliasSetTracker::findAliasSetForUnknownInst(Instruction *Inst) { AliasSet *FoundSet = nullptr; for (iterator I = begin(), E = end(); I != E;) { iterator Cur = I++; if (Cur->Forward || !Cur->aliasesUnknownInst(Inst, AA)) continue; if (!FoundSet) // If this is the first alias set ptr can go into. FoundSet = &*Cur; // Remember it. else // Otherwise, we must merge the sets. FoundSet->mergeSetIn(*Cur, *this); // Merge in contents. } return FoundSet; }
AliasSet *AliasSetTracker::findAliasSetForUnknownInst(Instruction *Inst) { AliasSet *FoundSet = 0; for (iterator I = begin(), E = end(); I != E; ++I) { if (I->Forward || !I->aliasesUnknownInst(Inst, AA)) continue; if (FoundSet == 0) // If this is the first alias set ptr can go into. FoundSet = I; // Remember it. else if (!I->Forward) // Otherwise, we must merge the sets. FoundSet->mergeSetIn(*I, *this); // Merge in contents. } return FoundSet; }
AliasSet *AliasSetTracker::findAliasSetForCallSite(CallSite CS) { AliasSet *FoundSet = 0; for (iterator I = begin(), E = end(); I != E; ++I) if (!I->Forward && I->aliasesCallSite(CS, AA)) { if (FoundSet == 0) { // If this is the first alias set ptr can go into. FoundSet = I; // Remember it. } else if (!I->Forward) { // Otherwise, we must merge the sets. FoundSet->mergeSetIn(*I, *this); // Merge in contents. } } return FoundSet; }
/// findAliasSetForPointer - Given a pointer, find the one alias set to put the /// instruction referring to the pointer into. If there are multiple alias sets /// that may alias the pointer, merge them together and return the unified set. /// AliasSet *AliasSetTracker::findAliasSetForPointer(const Value *Ptr, unsigned Size) { AliasSet *FoundSet = 0; for (iterator I = begin(), E = end(); I != E; ++I) if (!I->Forward && I->aliasesPointer(Ptr, Size, AA)) { if (FoundSet == 0) { // If this is the first alias set ptr can go into. FoundSet = I; // Remember it. } else { // Otherwise, we must merge the sets. FoundSet->mergeSetIn(*I, *this); // Merge in contents. } } return FoundSet; }
/// findAliasSetForPointer - Given a pointer, find the one alias set to put the /// instruction referring to the pointer into. If there are multiple alias sets /// that may alias the pointer, merge them together and return the unified set. /// AliasSet *AliasSetTracker::findAliasSetForPointer(const Value *Ptr, uint64_t Size, const MDNode *TBAAInfo) { AliasSet *FoundSet = 0; for (iterator I = begin(), E = end(); I != E; ++I) { if (I->Forward || !I->aliasesPointer(Ptr, Size, TBAAInfo, AA)) continue; if (FoundSet == 0) { // If this is the first alias set ptr can go into. FoundSet = I; // Remember it. } else { // Otherwise, we must merge the sets. FoundSet->mergeSetIn(*I, *this); // Merge in contents. } } return FoundSet; }
// copyValue - This method should be used whenever a preexisting value in the // program is copied or cloned, introducing a new value. Note that it is ok for // clients that use this method to introduce the same value multiple times: if // the tracker already knows about a value, it will ignore the request. // void AliasSetTracker::copyValue(Value *From, Value *To) { // Notify the alias analysis implementation that this value is copied. AA.copyValue(From, To); // First, look up the PointerRec for this pointer. hash_map<Value*, AliasSet::PointerRec>::iterator I = PointerMap.find(From); if (I == PointerMap.end() || !I->second.hasAliasSet()) return; // Noop AliasSet::HashNodePair &Entry = getEntryFor(To); if (Entry.second.hasAliasSet()) return; // Already in the tracker! // Add it to the alias set it aliases... AliasSet *AS = I->second.getAliasSet(*this); AS->addPointer(*this, Entry, I->second.getSize(), true); }
bool AliasSetTracker::add(CallSite CS) { if (Function *F = CS.getCalledFunction()) if (AA.doesNotAccessMemory(F)) return true; // doesn't alias anything AliasSet *AS = findAliasSetForCallSite(CS); if (!AS) { AliasSets.push_back(new AliasSet()); AS = &AliasSets.back(); AS->addCallSite(CS, AA); return true; } else { AS->addCallSite(CS, AA); return false; } }
bool AliasSetTracker::add(CallSite CS) { if (isa<DbgInfoIntrinsic>(CS.getInstruction())) return true; // Ignore DbgInfo Intrinsics. if (AA.doesNotAccessMemory(CS)) return true; // doesn't alias anything AliasSet *AS = findAliasSetForCallSite(CS); if (AS) { AS->addCallSite(CS, AA); return false; } AliasSets.push_back(new AliasSet()); AS = &AliasSets.back(); AS->addCallSite(CS, AA); return true; }
bool AliasSetTracker::addUnknown(Instruction *Inst) { if (isa<DbgInfoIntrinsic>(Inst)) return true; // Ignore DbgInfo Intrinsics. if (!Inst->mayReadOrWriteMemory()) return true; // doesn't alias anything AliasSet *AS = findAliasSetForUnknownInst(Inst); if (AS) { AS->addUnknownInst(Inst, AA); return false; } AliasSets.push_back(new AliasSet()); AS = &AliasSets.back(); AS->addUnknownInst(Inst, AA); return true; }
/// mergeAliasSetsForPointer - Given a pointer, merge all alias sets that may /// alias the pointer. Return the unified set, or nullptr if no set that aliases /// the pointer was found. AliasSet *AliasSetTracker::mergeAliasSetsForPointer(const Value *Ptr, LocationSize Size, const AAMDNodes &AAInfo) { AliasSet *FoundSet = nullptr; for (iterator I = begin(), E = end(); I != E;) { iterator Cur = I++; if (Cur->Forward || !Cur->aliasesPointer(Ptr, Size, AAInfo, AA)) continue; if (!FoundSet) { // If this is the first alias set ptr can go into. FoundSet = &*Cur; // Remember it. } else { // Otherwise, we must merge the sets. FoundSet->mergeSetIn(*Cur, *this); // Merge in contents. } } return FoundSet; }
// copyValue - This method should be used whenever a preexisting value in the // program is copied or cloned, introducing a new value. Note that it is ok for // clients that use this method to introduce the same value multiple times: if // the tracker already knows about a value, it will ignore the request. // void AliasSetTracker::copyValue(Value *From, Value *To) { // First, look up the PointerRec for this pointer. PointerMapType::iterator I = PointerMap.find_as(From); if (I == PointerMap.end()) return; // Noop assert(I->second->hasAliasSet() && "Dead entry?"); AliasSet::PointerRec &Entry = getEntryFor(To); if (Entry.hasAliasSet()) return; // Already in the tracker! // getEntryFor above may invalidate iterator \c I, so reinitialize it. I = PointerMap.find_as(From); // Add it to the alias set it aliases... AliasSet *AS = I->second->getAliasSet(*this); AS->addPointer(*this, Entry, I->second->getSize(), I->second->getAAInfo(), true, true); }
AliasSetIterator(AliasSet set) : flags(set.flags()), pos(0) { while (flags && (flags & 1) == 0) { flags >>= 1; pos++; } }
// copyValue - This method should be used whenever a preexisting value in the // program is copied or cloned, introducing a new value. Note that it is ok for // clients that use this method to introduce the same value multiple times: if // the tracker already knows about a value, it will ignore the request. // void AliasSetTracker::copyValue(Value *From, Value *To) { // Notify the alias analysis implementation that this value is copied. AA.copyValue(From, To); // First, look up the PointerRec for this pointer. PointerMapType::iterator I = PointerMap.find(From); if (I == PointerMap.end()) return; // Noop assert(I->second->hasAliasSet() && "Dead entry?"); AliasSet::PointerRec &Entry = getEntryFor(To); if (Entry.hasAliasSet()) return; // Already in the tracker! // Add it to the alias set it aliases... I = PointerMap.find(From); AliasSet *AS = I->second->getAliasSet(*this); AS->addPointer(*this, Entry, I->second->getSize(), true); }
// deleteValue method - This method is used to remove a pointer value from the // AliasSetTracker entirely. It should be used when an instruction is deleted // from the program to update the AST. If you don't use this, you would have // dangling pointers to deleted instructions. // void AliasSetTracker::deleteValue(Value *PtrVal) { // First, look up the PointerRec for this pointer. PointerMapType::iterator I = PointerMap.find_as(PtrVal); if (I == PointerMap.end()) return; // Noop // If we found one, remove the pointer from the alias set it is in. AliasSet::PointerRec *PtrValEnt = I->second; AliasSet *AS = PtrValEnt->getAliasSet(*this); // Unlink and delete from the list of values. PtrValEnt->eraseFromList(); if (AS->Alias == AliasSet::SetMayAlias) { AS->SetSize--; TotalMayAliasSetSize--; } // Stop using the alias set. AS->dropRef(*this); PointerMap.erase(I); }
/// mergeSetIn - Merge the specified alias set into this alias set. /// void AliasSet::mergeSetIn(AliasSet &AS, AliasSetTracker &AST) { assert(!AS.Forward && "Alias set is already forwarding!"); assert(!Forward && "This set is a forwarding set!!"); // Update the alias and access types of this set... AccessTy |= AS.AccessTy; AliasTy |= AS.AliasTy; Volatile |= AS.Volatile; if (AliasTy == MustAlias) { // Check that these two merged sets really are must aliases. Since both // used to be must-alias sets, we can just check any pointer from each set // for aliasing. AliasAnalysis &AA = AST.getAliasAnalysis(); PointerRec *L = getSomePointer(); PointerRec *R = AS.getSomePointer(); // If the pointers are not a must-alias pair, this set becomes a may alias. if (AA.alias(AliasAnalysis::Location(L->getValue(), L->getSize(), L->getTBAAInfo()), AliasAnalysis::Location(R->getValue(), R->getSize(), R->getTBAAInfo())) != AliasAnalysis::MustAlias) AliasTy = MayAlias; } if (CallSites.empty()) { // Merge call sites... if (!AS.CallSites.empty()) std::swap(CallSites, AS.CallSites); } else if (!AS.CallSites.empty()) { CallSites.insert(CallSites.end(), AS.CallSites.begin(), AS.CallSites.end()); AS.CallSites.clear(); } AS.Forward = this; // Forward across AS now... addRef(); // AS is now pointing to us... // Merge the list of constituent pointers... if (AS.PtrList) { *PtrListEnd = AS.PtrList; AS.PtrList->setPrevInList(PtrListEnd); PtrListEnd = AS.PtrListEnd; AS.PtrList = 0; AS.PtrListEnd = &AS.PtrList; assert(*AS.PtrListEnd == 0 && "End of list is not null?"); } }
AliasSet &AliasSetTracker::mergeAllAliasSets() { assert(!AliasAnyAS && (TotalMayAliasSetSize > SaturationThreshold) && "Full merge should happen once, when the saturation threshold is " "reached"); // Collect all alias sets, so that we can drop references with impunity // without worrying about iterator invalidation. std::vector<AliasSet *> ASVector; ASVector.reserve(SaturationThreshold); for (iterator I = begin(), E = end(); I != E; I++) ASVector.push_back(&*I); // Copy all instructions and pointers into a new set, and forward all other // sets to it. AliasSets.push_back(new AliasSet()); AliasAnyAS = &AliasSets.back(); AliasAnyAS->Alias = AliasSet::SetMayAlias; AliasAnyAS->Access = AliasSet::ModRefAccess; AliasAnyAS->AliasAny = true; for (auto Cur : ASVector) { // If Cur was already forwarding, just forward to the new AS instead. AliasSet *FwdTo = Cur->Forward; if (FwdTo) { Cur->Forward = AliasAnyAS; AliasAnyAS->addRef(); FwdTo->dropRef(*this); continue; } // Otherwise, perform the actual merge. AliasAnyAS->mergeSetIn(*Cur, *this); } return *AliasAnyAS; }
DeadMemOpElimination::instr_iterator DeadMemOpElimination::handleMemOp(instr_iterator I, DefMapTy &Defs, AliasSetTracker &AST) { MachineInstr *MI = I; MachineMemOperand *MO = *MI->memoperands_begin(); // AliasAnalysis cannot handle offset right now, so we pretend to write a // a big enough size to the location pointed by the base pointer. uint64_t Size = MO->getSize() + MO->getOffset(); AliasSet *ASet = &AST.getAliasSetForPointer(const_cast<Value*>(MO->getValue()), Size, 0); MachineInstr *&LastMI = Defs[ASet]; bool canHandleLastStore = LastMI && ASet->isMustAlias() && LastMI->getOpcode() != VTM::VOpInternalCall // FIXME: We may need to remember the last // definition for all predicates. && isPredIdentical(LastMI, MI); if (canHandleLastStore) { MachineMemOperand *LastMO = *LastMI->memoperands_begin(); // We can only handle last store if and only if their memory operand have // the must-alias address and the same size. canHandleLastStore = LastMO->getSize() == MO->getSize() && !LastMO->isVolatile() && MachineMemOperandAlias(MO, LastMO, AA, SE) == AliasAnalysis::MustAlias; } // FIXME: These elimination is only valid if we are in single-thread mode! if (VInstrInfo::mayStore(MI)) { if (canHandleLastStore) { // Dead store find, remove it. LastMI->eraseFromParent(); ++DeadStoreEliminated; } // Update the definition. LastMI = MI; return I; } // Now MI is a load. if (!canHandleLastStore) return I; // Loading the value that just be stored, the load is not necessary. MachineOperand LoadedMO = MI->getOperand(0); MachineOperand StoredMO = LastMI->getOperand(2); // Simply replace the load by a copy. DebugLoc dl = MI->getDebugLoc(); I = *BuildMI(*MI->getParent(), I, dl, VInstrInfo::getDesc(VTM::VOpMove)) .addOperand(LoadedMO).addOperand(StoredMO). addOperand(*VInstrInfo::getPredOperand(MI)). addOperand(*VInstrInfo::getTraceOperand(MI)); MI->eraseFromParent(); ++DeadLoadEliminated; return I; }
/// PromoteAliasSet - Try to promote memory values to scalars by sinking /// stores out of the loop and moving loads to before the loop. We do this by /// looping over the stores in the loop, looking for stores to Must pointers /// which are loop invariant. /// void LICM::PromoteAliasSet(AliasSet &AS) { // We can promote this alias set if it has a store, if it is a "Must" alias // set, if the pointer is loop invariant, and if we are not eliminating any // volatile loads or stores. if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() || AS.isVolatile() || !CurLoop->isLoopInvariant(AS.begin()->getValue())) return; assert(!AS.empty() && "Must alias set should have at least one pointer element in it!"); Value *SomePtr = AS.begin()->getValue(); // It isn't safe to promote a load/store from the loop if the load/store is // conditional. For example, turning: // // for () { if (c) *P += 1; } // // into: // // tmp = *P; for () { if (c) tmp +=1; } *P = tmp; // // is not safe, because *P may only be valid to access if 'c' is true. // // It is safe to promote P if all uses are direct load/stores and if at // least one is guaranteed to be executed. bool GuaranteedToExecute = false; SmallVector<Instruction*, 64> LoopUses; SmallPtrSet<Value*, 4> PointerMustAliases; // Check that all of the pointers in the alias set have the same type. We // cannot (yet) promote a memory location that is loaded and stored in // different sizes. for (AliasSet::iterator ASI = AS.begin(), E = AS.end(); ASI != E; ++ASI) { Value *ASIV = ASI->getValue(); PointerMustAliases.insert(ASIV); // Check that all of the pointers in the alias set have the same type. We // cannot (yet) promote a memory location that is loaded and stored in // different sizes. if (SomePtr->getType() != ASIV->getType()) return; for (Value::use_iterator UI = ASIV->use_begin(), UE = ASIV->use_end(); UI != UE; ++UI) { // Ignore instructions that are outside the loop. Instruction *Use = dyn_cast<Instruction>(*UI); if (!Use || !CurLoop->contains(Use)) continue; // If there is an non-load/store instruction in the loop, we can't promote // it. if (isa<LoadInst>(Use)) assert(!cast<LoadInst>(Use)->isVolatile() && "AST broken"); else if (isa<StoreInst>(Use)) { assert(!cast<StoreInst>(Use)->isVolatile() && "AST broken"); if (Use->getOperand(0) == ASIV) return; } else return; // Not a load or store. if (!GuaranteedToExecute) GuaranteedToExecute = isSafeToExecuteUnconditionally(*Use); LoopUses.push_back(Use); } } // If there isn't a guaranteed-to-execute instruction, we can't promote. if (!GuaranteedToExecute) return; // Otherwise, this is safe to promote, lets do it! DEBUG(dbgs() << "LICM: Promoting value stored to in loop: " <<*SomePtr<<'\n'); Changed = true; ++NumPromoted; // We use the SSAUpdater interface to insert phi nodes as required. SmallVector<PHINode*, 16> NewPHIs; SSAUpdater SSA(&NewPHIs); // It wants to know some value of the same type as what we'll be inserting. Value *SomeValue; if (isa<LoadInst>(LoopUses[0])) SomeValue = LoopUses[0]; else SomeValue = cast<StoreInst>(LoopUses[0])->getOperand(0); SSA.Initialize(SomeValue->getType(), SomeValue->getName()); // First step: bucket up uses of the pointers by the block they occur in. // This is important because we have to handle multiple defs/uses in a block // ourselves: SSAUpdater is purely for cross-block references. // FIXME: Want a TinyVector<Instruction*> since there is usually 0/1 element. DenseMap<BasicBlock*, std::vector<Instruction*> > UsesByBlock; for (unsigned i = 0, e = LoopUses.size(); i != e; ++i) { Instruction *User = LoopUses[i]; UsesByBlock[User->getParent()].push_back(User); } // Okay, now we can iterate over all the blocks in the loop with uses, // processing them. Keep track of which loads are loading a live-in value. SmallVector<LoadInst*, 32> LiveInLoads; DenseMap<Value*, Value*> ReplacedLoads; for (unsigned LoopUse = 0, e = LoopUses.size(); LoopUse != e; ++LoopUse) { Instruction *User = LoopUses[LoopUse]; std::vector<Instruction*> &BlockUses = UsesByBlock[User->getParent()]; // If this block has already been processed, ignore this repeat use. if (BlockUses.empty()) continue; // Okay, this is the first use in the block. If this block just has a // single user in it, we can rewrite it trivially. if (BlockUses.size() == 1) { // If it is a store, it is a trivial def of the value in the block. if (isa<StoreInst>(User)) { SSA.AddAvailableValue(User->getParent(), cast<StoreInst>(User)->getOperand(0)); } else { // Otherwise it is a load, queue it to rewrite as a live-in load. LiveInLoads.push_back(cast<LoadInst>(User)); } BlockUses.clear(); continue; } // Otherwise, check to see if this block is all loads. If so, we can queue // them all as live in loads. bool HasStore = false; for (unsigned i = 0, e = BlockUses.size(); i != e; ++i) { if (isa<StoreInst>(BlockUses[i])) { HasStore = true; break; } } if (!HasStore) { for (unsigned i = 0, e = BlockUses.size(); i != e; ++i) LiveInLoads.push_back(cast<LoadInst>(BlockUses[i])); BlockUses.clear(); continue; } // Otherwise, we have mixed loads and stores (or just a bunch of stores). // Since SSAUpdater is purely for cross-block values, we need to determine // the order of these instructions in the block. If the first use in the // block is a load, then it uses the live in value. The last store defines // the live out value. We handle this by doing a linear scan of the block. BasicBlock *BB = User->getParent(); Value *StoredValue = 0; for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) { if (LoadInst *L = dyn_cast<LoadInst>(II)) { // If this is a load from an unrelated pointer, ignore it. if (!PointerMustAliases.count(L->getOperand(0))) continue; // If we haven't seen a store yet, this is a live in use, otherwise // use the stored value. if (StoredValue) { L->replaceAllUsesWith(StoredValue); ReplacedLoads[L] = StoredValue; } else { LiveInLoads.push_back(L); } continue; } if (StoreInst *S = dyn_cast<StoreInst>(II)) { // If this is a store to an unrelated pointer, ignore it. if (!PointerMustAliases.count(S->getOperand(1))) continue; // Remember that this is the active value in the block. StoredValue = S->getOperand(0); } } // The last stored value that happened is the live-out for the block. assert(StoredValue && "Already checked that there is a store in block"); SSA.AddAvailableValue(BB, StoredValue); BlockUses.clear(); } // Now that all the intra-loop values are classified, set up the preheader. // It gets a load of the pointer we're promoting, and it is the live-out value // from the preheader. LoadInst *PreheaderLoad = new LoadInst(SomePtr,SomePtr->getName()+".promoted", Preheader->getTerminator()); SSA.AddAvailableValue(Preheader, PreheaderLoad); // Now that the preheader is good to go, set up the exit blocks. Each exit // block gets a store of the live-out values that feed them. Since we've // already told the SSA updater about the defs in the loop and the preheader // definition, it is all set and we can start using it. SmallVector<BasicBlock*, 8> ExitBlocks; CurLoop->getUniqueExitBlocks(ExitBlocks); for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) { BasicBlock *ExitBlock = ExitBlocks[i]; Value *LiveInValue = SSA.GetValueInMiddleOfBlock(ExitBlock); Instruction *InsertPos = ExitBlock->getFirstNonPHI(); new StoreInst(LiveInValue, SomePtr, InsertPos); } // Okay, now we rewrite all loads that use live-in values in the loop, // inserting PHI nodes as necessary. for (unsigned i = 0, e = LiveInLoads.size(); i != e; ++i) { LoadInst *ALoad = LiveInLoads[i]; Value *NewVal = SSA.GetValueInMiddleOfBlock(ALoad->getParent()); ALoad->replaceAllUsesWith(NewVal); CurAST->copyValue(ALoad, NewVal); ReplacedLoads[ALoad] = NewVal; } // If the preheader load is itself a pointer, we need to tell alias analysis // about the new pointer we created in the preheader block and about any PHI // nodes that just got inserted. if (PreheaderLoad->getType()->isPointerTy()) { // Copy any value stored to or loaded from a must-alias of the pointer. CurAST->copyValue(SomeValue, PreheaderLoad); for (unsigned i = 0, e = NewPHIs.size(); i != e; ++i) CurAST->copyValue(SomeValue, NewPHIs[i]); } // Now that everything is rewritten, delete the old instructions from the body // of the loop. They should all be dead now. for (unsigned i = 0, e = LoopUses.size(); i != e; ++i) { Instruction *User = LoopUses[i]; // If this is a load that still has uses, then the load must have been added // as a live value in the SSAUpdate data structure for a block (e.g. because // the loaded value was stored later). In this case, we need to recursively // propagate the updates until we get to the real value. if (!User->use_empty()) { Value *NewVal = ReplacedLoads[User]; assert(NewVal && "not a replaced load?"); // Propagate down to the ultimate replacee. The intermediately loads // could theoretically already have been deleted, so we don't want to // dereference the Value*'s. DenseMap<Value*, Value*>::iterator RLI = ReplacedLoads.find(NewVal); while (RLI != ReplacedLoads.end()) { NewVal = RLI->second; RLI = ReplacedLoads.find(NewVal); } User->replaceAllUsesWith(NewVal); CurAST->copyValue(User, NewVal); } CurAST->deleteValue(User); User->eraseFromParent(); } // fwew, we're done! }
/// PromoteAliasSet - Try to promote memory values to scalars by sinking /// stores out of the loop and moving loads to before the loop. We do this by /// looping over the stores in the loop, looking for stores to Must pointers /// which are loop invariant. /// void LICM::PromoteAliasSet(AliasSet &AS) { // We can promote this alias set if it has a store, if it is a "Must" alias // set, if the pointer is loop invariant, and if we are not eliminating any // volatile loads or stores. if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() || AS.isVolatile() || !CurLoop->isLoopInvariant(AS.begin()->getValue())) return; assert(!AS.empty() && "Must alias set should have at least one pointer element in it!"); Value *SomePtr = AS.begin()->getValue(); // It isn't safe to promote a load/store from the loop if the load/store is // conditional. For example, turning: // // for () { if (c) *P += 1; } // // into: // // tmp = *P; for () { if (c) tmp +=1; } *P = tmp; // // is not safe, because *P may only be valid to access if 'c' is true. // // It is safe to promote P if all uses are direct load/stores and if at // least one is guaranteed to be executed. bool GuaranteedToExecute = false; SmallVector<Instruction*, 64> LoopUses; SmallPtrSet<Value*, 4> PointerMustAliases; // We start with an alignment of one and try to find instructions that allow // us to prove better alignment. unsigned Alignment = 1; // Check that all of the pointers in the alias set have the same type. We // cannot (yet) promote a memory location that is loaded and stored in // different sizes. for (AliasSet::iterator ASI = AS.begin(), E = AS.end(); ASI != E; ++ASI) { Value *ASIV = ASI->getValue(); PointerMustAliases.insert(ASIV); // Check that all of the pointers in the alias set have the same type. We // cannot (yet) promote a memory location that is loaded and stored in // different sizes. if (SomePtr->getType() != ASIV->getType()) return; for (Value::use_iterator UI = ASIV->use_begin(), UE = ASIV->use_end(); UI != UE; ++UI) { // Ignore instructions that are outside the loop. Instruction *Use = dyn_cast<Instruction>(*UI); if (!Use || !CurLoop->contains(Use)) continue; // If there is an non-load/store instruction in the loop, we can't promote // it. if (LoadInst *load = dyn_cast<LoadInst>(Use)) { assert(!load->isVolatile() && "AST broken"); if (!load->isSimple()) return; } else if (StoreInst *store = dyn_cast<StoreInst>(Use)) { // Stores *of* the pointer are not interesting, only stores *to* the // pointer. if (Use->getOperand(1) != ASIV) continue; assert(!store->isVolatile() && "AST broken"); if (!store->isSimple()) return; // Note that we only check GuaranteedToExecute inside the store case // so that we do not introduce stores where they did not exist before // (which would break the LLVM concurrency model). // If the alignment of this instruction allows us to specify a more // restrictive (and performant) alignment and if we are sure this // instruction will be executed, update the alignment. // Larger is better, with the exception of 0 being the best alignment. unsigned InstAlignment = store->getAlignment(); if ((InstAlignment > Alignment || InstAlignment == 0) && (Alignment != 0)) if (isGuaranteedToExecute(*Use)) { GuaranteedToExecute = true; Alignment = InstAlignment; } if (!GuaranteedToExecute) GuaranteedToExecute = isGuaranteedToExecute(*Use); } else return; // Not a load or store. LoopUses.push_back(Use); } } // If there isn't a guaranteed-to-execute instruction, we can't promote. if (!GuaranteedToExecute) return; // Otherwise, this is safe to promote, lets do it! DEBUG(dbgs() << "LICM: Promoting value stored to in loop: " <<*SomePtr<<'\n'); Changed = true; ++NumPromoted; // Grab a debug location for the inserted loads/stores; given that the // inserted loads/stores have little relation to the original loads/stores, // this code just arbitrarily picks a location from one, since any debug // location is better than none. DebugLoc DL = LoopUses[0]->getDebugLoc(); SmallVector<BasicBlock*, 8> ExitBlocks; CurLoop->getUniqueExitBlocks(ExitBlocks); // We use the SSAUpdater interface to insert phi nodes as required. SmallVector<PHINode*, 16> NewPHIs; SSAUpdater SSA(&NewPHIs); LoopPromoter Promoter(SomePtr, LoopUses, SSA, PointerMustAliases, ExitBlocks, *CurAST, DL, Alignment); // Set up the preheader to have a definition of the value. It is the live-out // value from the preheader that uses in the loop will use. LoadInst *PreheaderLoad = new LoadInst(SomePtr, SomePtr->getName()+".promoted", Preheader->getTerminator()); PreheaderLoad->setAlignment(Alignment); PreheaderLoad->setDebugLoc(DL); SSA.AddAvailableValue(Preheader, PreheaderLoad); // Rewrite all the loads in the loop and remember all the definitions from // stores in the loop. Promoter.run(LoopUses); // If the SSAUpdater didn't use the load in the preheader, just zap it now. if (PreheaderLoad->use_empty()) PreheaderLoad->eraseFromParent(); }
// This pass annotates every load instruction with the last store instruction // on which it depends. The algorithm is optimistic in that it ignores explicit // dependencies and only considers loads and stores. // // Loads inside loops only have an implicit dependency on a store before the // loop header if no instruction inside the loop body aliases it. To calculate // this efficiently, we maintain a list of maybe-invariant loads and the combined // alias set for all stores inside the loop. When we see the loop's backedge, this // information is used to mark every load we wrongly assumed to be loop invariant as // having an implicit dependency on the last instruction of the loop header, so that // it's never moved before the loop header. // // The algorithm depends on the invariant that both control instructions and effectful // instructions (stores) are never hoisted. bool AliasAnalysis::analyze() { Vector<MInstructionVector, AliasSet::NumCategories, JitAllocPolicy> stores(alloc()); // Initialize to the first instruction. MInstruction* firstIns = *graph_.entryBlock()->begin(); for (unsigned i = 0; i < AliasSet::NumCategories; i++) { MInstructionVector defs(alloc()); if (!defs.append(firstIns)) return false; if (!stores.append(Move(defs))) return false; } // Type analysis may have inserted new instructions. Since this pass depends // on the instruction number ordering, all instructions are renumbered. uint32_t newId = 0; for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { if (mir->shouldCancel("Alias Analysis (main loop)")) return false; if (block->isLoopHeader()) { JitSpew(JitSpew_Alias, "Processing loop header %d", block->id()); loop_ = new(alloc()) LoopAliasInfo(alloc(), loop_, *block); } for (MPhiIterator def(block->phisBegin()), end(block->phisEnd()); def != end; ++def) def->setId(newId++); for (MInstructionIterator def(block->begin()), end(block->begin(block->lastIns())); def != end; ++def) { def->setId(newId++); AliasSet set = def->getAliasSet(); if (set.isNone()) continue; // For the purposes of alias analysis, all recoverable operations // are treated as effect free as the memory represented by these // operations cannot be aliased by others. if (def->canRecoverOnBailout()) continue; if (set.isStore()) { for (AliasSetIterator iter(set); iter; iter++) { if (!stores[*iter].append(*def)) return false; } if (JitSpewEnabled(JitSpew_Alias)) { Fprinter& out = JitSpewPrinter(); out.printf("Processing store "); def->printName(out); out.printf(" (flags %x)\n", set.flags()); } } else { // Find the most recent store on which this instruction depends. MInstruction* lastStore = firstIns; for (AliasSetIterator iter(set); iter; iter++) { MInstructionVector& aliasedStores = stores[*iter]; for (int i = aliasedStores.length() - 1; i >= 0; i--) { MInstruction* store = aliasedStores[i]; if (genericMightAlias(*def, store) != MDefinition::AliasType::NoAlias && def->mightAlias(store) != MDefinition::AliasType::NoAlias && BlockMightReach(store->block(), *block)) { if (lastStore->id() < store->id()) lastStore = store; break; } } } def->setDependency(lastStore); IonSpewDependency(*def, lastStore, "depends", ""); // If the last store was before the current loop, we assume this load // is loop invariant. If a later instruction writes to the same location, // we will fix this at the end of the loop. if (loop_ && lastStore->id() < loop_->firstInstruction()->id()) { if (!loop_->addInvariantLoad(*def)) return false; } } } // Renumber the last instruction, as the analysis depends on this and the order. block->lastIns()->setId(newId++); if (block->isLoopBackedge()) { MOZ_ASSERT(loop_->loopHeader() == block->loopHeaderOfBackedge()); JitSpew(JitSpew_Alias, "Processing loop backedge %d (header %d)", block->id(), loop_->loopHeader()->id()); LoopAliasInfo* outerLoop = loop_->outer(); MInstruction* firstLoopIns = *loop_->loopHeader()->begin(); const MInstructionVector& invariant = loop_->invariantLoads(); for (unsigned i = 0; i < invariant.length(); i++) { MInstruction* ins = invariant[i]; AliasSet set = ins->getAliasSet(); MOZ_ASSERT(set.isLoad()); bool hasAlias = false; for (AliasSetIterator iter(set); iter; iter++) { MInstructionVector& aliasedStores = stores[*iter]; for (int i = aliasedStores.length() - 1;; i--) { MInstruction* store = aliasedStores[i]; if (store->id() < firstLoopIns->id()) break; if (genericMightAlias(ins, store) != MDefinition::AliasType::NoAlias && ins->mightAlias(store) != MDefinition::AliasType::NoAlias) { hasAlias = true; IonSpewDependency(ins, store, "aliases", "store in loop body"); break; } } if (hasAlias) break; } if (hasAlias) { // This instruction depends on stores inside the loop body. Mark it as having a // dependency on the last instruction of the loop header. The last instruction is a // control instruction and these are never hoisted. MControlInstruction* controlIns = loop_->loopHeader()->lastIns(); IonSpewDependency(ins, controlIns, "depends", "due to stores in loop body"); ins->setDependency(controlIns); } else { IonSpewAliasInfo("Load", ins, "does not depend on any stores in this loop"); if (outerLoop && ins->dependency()->id() < outerLoop->firstInstruction()->id()) { IonSpewAliasInfo("Load", ins, "may be invariant in outer loop"); if (!outerLoop->addInvariantLoad(ins)) return false; } } } loop_ = loop_->outer(); } } spewDependencyList(); MOZ_ASSERT(loop_ == nullptr); return true; }