void exploreFromEntry(Attributor &A, const Function *F) {
ToBeExploredPaths.insert(&(F->getEntryBlock().front()));
- assumeLive(A, F->getEntryBlock());
for (size_t i = 0; i < ToBeExploredPaths.size(); ++i)
if (const Instruction *NextNoReturnI =
findNextNoReturn(A, ToBeExploredPaths[i]))
NoReturnCalls.insert(NextNoReturnI);
+
+ // Mark the block live after we looked for no-return instructions.
+ assumeLive(A, F->getEntryBlock());
}
/// Find the next assumed noreturn instruction in the block of \p I starting
});
}
+static bool
+checkForAllInstructionsImpl(InformationCache::OpcodeInstMapTy &OpcodeInstMap,
+ const function_ref<bool(Instruction &)> &Pred,
+ const AAIsDead *LivenessAA, bool &AnyDead,
+ const ArrayRef<unsigned> &Opcodes) {
+ for (unsigned Opcode : Opcodes) {
+ for (Instruction *I : OpcodeInstMap[Opcode]) {
+ // Skip dead instructions.
+ if (LivenessAA && LivenessAA->isAssumedDead(I)) {
+ AnyDead = true;
+ continue;
+ }
+
+ if (!Pred(*I))
+ return false;
+ }
+ }
+ return true;
+}
+
bool Attributor::checkForAllInstructions(
const llvm::function_ref<bool(Instruction &)> &Pred,
const AbstractAttribute &QueryingAA, const ArrayRef<unsigned> &Opcodes) {
auto &OpcodeInstMap =
InfoCache.getOpcodeInstMapForFunction(*AssociatedFunction);
- for (unsigned Opcode : Opcodes) {
- for (Instruction *I : OpcodeInstMap[Opcode]) {
- // Skip dead instructions.
- if (LivenessAA.isAssumedDead(I)) {
- AnyDead = true;
- continue;
- }
-
- if (!Pred(*I))
- return false;
- }
- }
+ if (!checkForAllInstructionsImpl(OpcodeInstMap, Pred, &LivenessAA, AnyDead, Opcodes))
+ return false;
// If we actually used liveness information so we have to record a dependence.
if (AnyDead)
return ManifestChange;
}
+void Attributor::initializeInformationCache(Function &F) {
+
+ // Walk all instructions to find interesting instructions that might be
+ // queried by abstract attributes during their initialization or update.
+ // This has to happen before we create attributes.
+ auto &ReadOrWriteInsts = InfoCache.FuncRWInstsMap[&F];
+ auto &InstOpcodeMap = InfoCache.FuncInstOpcodeMap[&F];
+
+ for (Instruction &I : instructions(&F)) {
+ bool IsInterestingOpcode = false;
+
+ // To allow easy access to all instructions in a function with a given
+ // opcode we store them in the InfoCache. As not all opcodes are interesting
+ // to concrete attributes we only cache the ones that are as identified in
+ // the following switch.
+ // Note: There are no concrete attributes now so this is initially empty.
+ switch (I.getOpcode()) {
+ default:
+ assert((!ImmutableCallSite(&I)) && (!isa<CallBase>(&I)) &&
+ "New call site/base instruction type needs to be known int the "
+ "Attributor.");
+ break;
+ case Instruction::Load:
+ // The alignment of a pointer is interesting for loads.
+ case Instruction::Store:
+ // The alignment of a pointer is interesting for stores.
+ case Instruction::Call:
+ case Instruction::CallBr:
+ case Instruction::Invoke:
+ case Instruction::CleanupRet:
+ case Instruction::CatchSwitch:
+ case Instruction::Resume:
+ case Instruction::Ret:
+ IsInterestingOpcode = true;
+ }
+ if (IsInterestingOpcode)
+ InstOpcodeMap[I.getOpcode()].push_back(&I);
+ if (I.mayReadOrWriteMemory())
+ ReadOrWriteInsts.push_back(&I);
+ }
+}
+
void Attributor::identifyDefaultAbstractAttributes(Function &F) {
if (!VisitedFunctions.insert(&F).second)
return;
}
}
- // Walk all instructions to find more attribute opportunities and also
- // interesting instructions that might be queried by abstract attributes
- // during their initialization or update.
- auto &ReadOrWriteInsts = InfoCache.FuncRWInstsMap[&F];
- auto &InstOpcodeMap = InfoCache.FuncInstOpcodeMap[&F];
-
- for (Instruction &I : instructions(&F)) {
- bool IsInterestingOpcode = false;
-
- // To allow easy access to all instructions in a function with a given
- // opcode we store them in the InfoCache. As not all opcodes are interesting
- // to concrete attributes we only cache the ones that are as identified in
- // the following switch.
- // Note: There are no concrete attributes now so this is initially empty.
- switch (I.getOpcode()) {
- default:
- assert((!ImmutableCallSite(&I)) && (!isa<CallBase>(&I)) &&
- "New call site/base instruction type needs to be known int the "
- "attributor.");
- break;
- case Instruction::Load:
- // The alignment of a pointer is interesting for loads.
- getOrCreateAAFor<AAAlign>(
- IRPosition::value(*cast<LoadInst>(I).getPointerOperand()));
- break;
- case Instruction::Store:
- // The alignment of a pointer is interesting for stores.
- getOrCreateAAFor<AAAlign>(
- IRPosition::value(*cast<StoreInst>(I).getPointerOperand()));
- break;
- case Instruction::Call:
- case Instruction::CallBr:
- case Instruction::Invoke:
- case Instruction::CleanupRet:
- case Instruction::CatchSwitch:
- case Instruction::Resume:
- case Instruction::Ret:
- IsInterestingOpcode = true;
- }
- if (IsInterestingOpcode)
- InstOpcodeMap[I.getOpcode()].push_back(&I);
- if (I.mayReadOrWriteMemory())
- ReadOrWriteInsts.push_back(&I);
-
+ auto CallSitePred = [&](Instruction &I) -> bool {
CallSite CS(&I);
- if (CS && CS.getCalledFunction()) {
+ if (CS.getCalledFunction()) {
for (int i = 0, e = CS.getCalledFunction()->arg_size(); i < e; i++) {
IRPosition CSArgPos = IRPosition::callsite_argument(CS, i);
getOrCreateAAFor<AAAlign>(CSArgPos);
}
}
- }
+ return true;
+ };
+
+ auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
+ bool Success, AnyDead = false;
+ Success = checkForAllInstructionsImpl(
+ OpcodeInstMap, CallSitePred, nullptr, AnyDead,
+ {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
+ (unsigned)Instruction::Call});
+ (void)Success;
+ assert(Success && !AnyDead && "Expected the check call to be successful!");
+
+ auto LoadStorePred = [&](Instruction &I) -> bool {
+ if (isa<LoadInst>(I))
+ getOrCreateAAFor<AAAlign>(
+ IRPosition::value(*cast<LoadInst>(I).getPointerOperand()));
+ else
+ getOrCreateAAFor<AAAlign>(
+ IRPosition::value(*cast<StoreInst>(I).getPointerOperand()));
+ return true;
+ };
+ Success = checkForAllInstructionsImpl(
+ OpcodeInstMap, LoadStorePred, nullptr, AnyDead,
+ {(unsigned)Instruction::Load, (unsigned)Instruction::Store});
+ (void)Success;
+ assert(Success && !AnyDead && "Expected the check call to be successful!");
}
/// Helpers to ease debugging through output streams and print calls.
InformationCache InfoCache(M.getDataLayout(), AG);
Attributor A(InfoCache, DepRecInterval);
+ for (Function &F : M)
+ A.initializeInformationCache(F);
+
for (Function &F : M) {
if (F.hasExactDefinition())
NumFnWithExactDefinition++;