friend struct Attributor;
};
+/// Configuration for the Attributor.
+struct AttributorConfig {
+
+ AttributorConfig(CallGraphUpdater &CGUpdater) : CGUpdater(CGUpdater) {}
+
+ /// Is the user of the Attributor a module pass or not. This determines what
+ /// IR we can look at and modify. If it is a module pass we might deduce facts
+ /// outside the initial function set and modify functions outside that set,
+ /// but only as part of the optimization of the functions in the initial
+ /// function set. For CGSCC passes we can look at the IR of the module slice
+ /// but never run any deduction, or perform any modification, outside the
+ /// initial function set (which we assume is the SCC).
+ bool IsModulePass = true;
+
+ /// Flag to determine if we can delete functions or keep dead ones around.
+ bool DeleteFns = true;
+
+ /// Flag to determine if we rewrite function signatures.
+ bool RewriteSignatures = true;
+
+ /// Flag to determine if we want to initialize all default AAs for an internal
+ /// function marked live.
+ /// TODO: This should probably be a callback, or maybe
+ /// identifyDefaultAbstractAttributes should be virtual, something to allow
+ /// customizable lazy initialization for internal functions.
+ bool DefaultInitializeLiveInternals = true;
+
+ /// Helper to update an underlying call graph and to delete functions.
+ CallGraphUpdater &CGUpdater;
+
+ /// If not null, a set limiting the attribute opportunities.
+ DenseSet<const char *> *Allowed = nullptr;
+
+ /// Maximum number of iterations to run until fixpoint.
+ Optional<unsigned> MaxFixpointIterations = None;
+
+ /// A callback function that returns an ORE object from a Function pointer.
+ ///{
+ using OptimizationRemarkGetter =
+ function_ref<OptimizationRemarkEmitter &(Function *)>;
+ OptimizationRemarkGetter OREGetter = nullptr;
+ ///}
+
+ /// The name of the pass running the attributor, used to emit remarks.
+ const char *PassName = nullptr;
+};
+
/// The fixpoint analysis framework that orchestrates the attribute deduction.
///
/// The Attributor provides a general abstract analysis framework (guided
/// described in the file comment.
struct Attributor {
- using OptimizationRemarkGetter =
- function_ref<OptimizationRemarkEmitter &(Function *)>;
-
/// Constructor
///
/// \param Functions The set of functions we are deriving attributes for.
/// \param InfoCache Cache to hold various information accessible for
/// the abstract attributes.
- /// \param CGUpdater Helper to update an underlying call graph.
- /// \param Allowed If not null, a set limiting the attribute opportunities.
- /// \param DeleteFns Whether to delete functions.
- /// \param RewriteSignatures Whether to rewrite function signatures.
- /// \param DefaultInitializeLiveInternals Whether to initialize default AAs
- /// for live internal functions.
+ /// \param Configuration The Attributor configuration which determines what
+ /// generic features to use.
Attributor(SetVector<Function *> &Functions, InformationCache &InfoCache,
- CallGraphUpdater &CGUpdater,
- DenseSet<const char *> *Allowed = nullptr, bool DeleteFns = true,
- bool RewriteSignatures = true,
- bool DefaultInitializeLiveInternals = true)
+ AttributorConfig Configuration)
: Allocator(InfoCache.Allocator), Functions(Functions),
- InfoCache(InfoCache), CGUpdater(CGUpdater), Allowed(Allowed),
- DeleteFns(DeleteFns), RewriteSignatures(RewriteSignatures),
- MaxFixpointIterations(None), OREGetter(None), PassName(""),
- DefaultInitializeLiveInternals(DefaultInitializeLiveInternals) {}
-
- /// Constructor
- ///
- /// \param Functions The set of functions we are deriving attributes for.
- /// \param InfoCache Cache to hold various information accessible for
- /// the abstract attributes.
- /// \param CGUpdater Helper to update an underlying call graph.
- /// \param Allowed If not null, a set limiting the attribute opportunities.
- /// \param DeleteFns Whether to delete functions
- /// \param RewriteSignatures Whether to rewrite function signatures.
- /// \param MaxFixpointIterations Maximum number of iterations to run until
- /// fixpoint.
- /// \param OREGetter A callback function that returns an ORE object from a
- /// Function pointer.
- /// \param PassName The name of the pass emitting remarks.
- Attributor(SetVector<Function *> &Functions, InformationCache &InfoCache,
- CallGraphUpdater &CGUpdater, DenseSet<const char *> *Allowed,
- bool DeleteFns, bool RewriteSignatures,
- Optional<unsigned> MaxFixpointIterations,
- OptimizationRemarkGetter OREGetter, const char *PassName)
- : Allocator(InfoCache.Allocator), Functions(Functions),
- InfoCache(InfoCache), CGUpdater(CGUpdater), Allowed(Allowed),
- DeleteFns(DeleteFns), RewriteSignatures(RewriteSignatures),
- MaxFixpointIterations(MaxFixpointIterations),
- OREGetter(Optional<OptimizationRemarkGetter>(OREGetter)),
- PassName(PassName), DefaultInitializeLiveInternals(false) {}
+ InfoCache(InfoCache), Configuration(Configuration) {}
~Attributor();
registerAA(AA);
// For now we ignore naked and optnone functions.
- bool Invalidate = Allowed && !Allowed->count(&AAType::ID);
+ bool Invalidate =
+ Configuration.Allowed && !Configuration.Allowed->count(&AAType::ID);
const Function *FnScope = IRP.getAnchorScope();
if (FnScope)
Invalidate |= FnScope->hasFnAttribute(Attribute::Naked) ||
InformationCache &getInfoCache() { return InfoCache; }
/// Return true if this is a module pass, false otherwise.
- bool isModulePass() const {
- return !Functions.empty() &&
- Functions.size() == Functions.front()->getParent()->size();
- }
+ bool isModulePass() const { return Configuration.IsModulePass; }
/// Return true if we derive attributes for \p Fn
bool isRunOn(Function &Fn) const {
assert(F.hasLocalLinkage() &&
"Only local linkage is assumed dead initially.");
- if (DefaultInitializeLiveInternals)
+ if (Configuration.DefaultInitializeLiveInternals)
identifyDefaultAbstractAttributes(const_cast<Function &>(F));
}
if (!CI)
return;
- CGUpdater.removeCallSite(*CI);
+ Configuration.CGUpdater.removeCallSite(*CI);
}
/// Record that \p U is to be replaces with \p NV after information was
/// Record that \p F is deleted after information was manifested.
void deleteAfterManifest(Function &F) {
- if (DeleteFns)
+ errs() << "Delete " << F.getName() << " : " << (Configuration.DeleteFns)
+ << "\n";
+ if (Configuration.DeleteFns)
ToBeDeletedFunctions.insert(&F);
}
template <typename RemarkKind, typename RemarkCallBack>
void emitRemark(Instruction *I, StringRef RemarkName,
RemarkCallBack &&RemarkCB) const {
- if (!OREGetter)
+ if (!Configuration.OREGetter)
return;
Function *F = I->getFunction();
- auto &ORE = OREGetter.getValue()(F);
+ auto &ORE = Configuration.OREGetter(F);
if (RemarkName.startswith("OMP"))
ORE.emit([&]() {
- return RemarkCB(RemarkKind(PassName, RemarkName, I))
+ return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, I))
<< " [" << RemarkName << "]";
});
else
- ORE.emit([&]() { return RemarkCB(RemarkKind(PassName, RemarkName, I)); });
+ ORE.emit([&]() {
+ return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, I));
+ });
}
/// Emit a remark on a function.
template <typename RemarkKind, typename RemarkCallBack>
void emitRemark(Function *F, StringRef RemarkName,
RemarkCallBack &&RemarkCB) const {
- if (!OREGetter)
+ if (!Configuration.OREGetter)
return;
- auto &ORE = OREGetter.getValue()(F);
+ auto &ORE = Configuration.OREGetter(F);
if (RemarkName.startswith("OMP"))
ORE.emit([&]() {
- return RemarkCB(RemarkKind(PassName, RemarkName, F))
+ return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, F))
<< " [" << RemarkName << "]";
});
else
- ORE.emit([&]() { return RemarkCB(RemarkKind(PassName, RemarkName, F)); });
+ ORE.emit([&]() {
+ return RemarkCB(RemarkKind(Configuration.PassName, RemarkName, F));
+ });
}
/// Helper struct used in the communication between an abstract attribute (AA)
/// The information cache that holds pre-processed (LLVM-IR) information.
InformationCache &InfoCache;
- /// Helper to update an underlying call graph.
- CallGraphUpdater &CGUpdater;
-
/// Abstract Attribute dependency graph
AADepGraph DG;
using DependenceVector = SmallVector<DepInfo, 8>;
SmallVector<DependenceVector *, 16> DependenceStack;
- /// If not null, a set limiting the attribute opportunities.
- const DenseSet<const char *> *Allowed;
-
- /// Whether to delete functions.
- const bool DeleteFns;
-
- /// Whether to rewrite signatures.
- const bool RewriteSignatures;
-
- /// Maximum number of fixedpoint iterations.
- Optional<unsigned> MaxFixpointIterations;
-
/// A set to remember the functions we already assume to be live and visited.
DenseSet<const Function *> VisitedFunctions;
SmallSetVector<WeakVH, 8> ToBeDeletedInsts;
///}
- /// Callback to get an OptimizationRemarkEmitter from a Function *.
- Optional<OptimizationRemarkGetter> OREGetter;
-
/// Container with all the query AAs that requested an update via
/// registerForUpdate.
SmallSetVector<AbstractAttribute *, 16> QueryAAsAwaitingUpdate;
- /// The name of the pass to emit remarks for.
- const char *PassName = "";
-
- /// Flag to determine if we want to initialize all default AAs for an internal
- /// function marked live.
- /// TODO: This should probably be a callback, or maybe
- /// identifyDefaultAbstractAttributes should be virtual, something to allow
- /// customizable lazy initialization for internal functions.
- const bool DefaultInitializeLiveInternals;
+ /// User provided configuration for this Attributor instance.
+ const AttributorConfig Configuration;
friend AADepGraph;
friend AttributorCallGraph;
// the abstract analysis.
unsigned IterationCounter = 1;
- unsigned MaxFixedPointIterations;
- if (MaxFixpointIterations)
- MaxFixedPointIterations = MaxFixpointIterations.getValue();
- else
- MaxFixedPointIterations = SetFixpointIterations;
+ unsigned MaxIterations =
+ Configuration.MaxFixpointIterations.getValueOr(SetFixpointIterations);
SmallVector<AbstractAttribute *, 32> ChangedAAs;
SetVector<AbstractAttribute *> Worklist, InvalidAAs;
QueryAAsAwaitingUpdate.end());
QueryAAsAwaitingUpdate.clear();
- } while (!Worklist.empty() && (IterationCounter++ < MaxFixedPointIterations ||
- VerifyMaxFixpointIterations));
+ } while (!Worklist.empty() &&
+ (IterationCounter++ < MaxIterations || VerifyMaxFixpointIterations));
- if (IterationCounter > MaxFixedPointIterations && !Functions.empty()) {
+ if (IterationCounter > MaxIterations && !Functions.empty()) {
auto Remark = [&](OptimizationRemarkMissed ORM) {
return ORM << "Attributor did not reach a fixpoint after "
- << ore::NV("Iterations", MaxFixedPointIterations)
- << " iterations.";
+ << ore::NV("Iterations", MaxIterations) << " iterations.";
};
Function *F = Functions.front();
emitRemark<OptimizationRemarkMissed>(F, "FixedPoint", Remark);
}
LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: "
- << IterationCounter << "/" << MaxFixpointIterations
+ << IterationCounter << "/" << MaxIterations
<< " iterations\n");
// Reset abstract arguments not settled in a sound fixpoint by now. This
<< " abstract attributes.\n";
});
- if (VerifyMaxFixpointIterations &&
- IterationCounter != MaxFixedPointIterations) {
+ if (VerifyMaxFixpointIterations && IterationCounter != MaxIterations) {
errs() << "\n[Attributor] Fixpoint iteration done after: "
- << IterationCounter << "/" << MaxFixedPointIterations
- << " iterations\n";
+ << IterationCounter << "/" << MaxIterations << " iterations\n";
llvm_unreachable("The fixpoint was not reached with exactly the number of "
"specified iterations!");
}
void Attributor::identifyDeadInternalFunctions() {
// Early exit if we don't intend to delete functions.
- if (!DeleteFns)
+ if (!Configuration.DeleteFns)
return;
// Identify dead internal functions and delete them. This happens outside
assert(isRunOn(*I->getFunction()) &&
"Cannot delete an instruction outside the current SCC!");
if (!isa<IntrinsicInst>(CB))
- CGUpdater.removeCallSite(*CB);
+ Configuration.CGUpdater.removeCallSite(*CB);
}
I->dropDroppableUses();
CGModifiedFunctions.insert(I->getFunction());
for (Function *Fn : CGModifiedFunctions)
if (!ToBeDeletedFunctions.count(Fn) && Functions.count(Fn))
- CGUpdater.reanalyzeFunction(*Fn);
+ Configuration.CGUpdater.reanalyzeFunction(*Fn);
for (Function *Fn : ToBeDeletedFunctions) {
if (!Functions.count(Fn))
continue;
- CGUpdater.removeFunction(*Fn);
+ Configuration.CGUpdater.removeFunction(*Fn);
}
if (!ToBeChangedUses.empty())
bool Attributor::isValidFunctionSignatureRewrite(
Argument &Arg, ArrayRef<Type *> ReplacementTypes) {
- if (!RewriteSignatures)
+ if (!Configuration.RewriteSignatures)
return false;
Function *Fn = Arg.getParent();
assert(OldCB.getType() == NewCB.getType() &&
"Cannot handle call sites with different types!");
ModifiedFns.insert(OldCB.getFunction());
- CGUpdater.replaceCallSite(OldCB, NewCB);
+ Configuration.CGUpdater.replaceCallSite(OldCB, NewCB);
OldCB.replaceAllUsesWith(&NewCB);
OldCB.eraseFromParent();
}
// Replace the function in the call graph (if any).
- CGUpdater.replaceFunctionWith(*OldFn, *NewFn);
+ Configuration.CGUpdater.replaceFunctionWith(*OldFn, *NewFn);
// If the old function was modified and needed to be reanalyzed, the new one
// does now.
SetVector<Function *> &Functions,
AnalysisGetter &AG,
CallGraphUpdater &CGUpdater,
- bool DeleteFns) {
+ bool DeleteFns, bool IsModulePass) {
if (Functions.empty())
return false;
// Create an Attributor and initially empty information cache that is filled
// while we identify default attribute opportunities.
- Attributor A(Functions, InfoCache, CGUpdater, /* Allowed */ nullptr,
- DeleteFns);
+ AttributorConfig AC(CGUpdater);
+ AC.IsModulePass = IsModulePass;
+ AC.DeleteFns = DeleteFns;
+ Attributor A(Functions, InfoCache, AC);
// Create shallow wrappers for all functions that are not IPO amendable
if (AllowShallowWrappers)
BumpPtrAllocator Allocator;
InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr);
if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater,
- /* DeleteFns */ true)) {
+ /* DeleteFns */ true, /* IsModulePass */ true)) {
// FIXME: Think about passes we will preserve and add them here.
return PreservedAnalyses::none();
}
BumpPtrAllocator Allocator;
InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions);
if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater,
- /* DeleteFns */ false)) {
+ /* DeleteFns */ false,
+ /* IsModulePass */ false)) {
// FIXME: Think about passes we will preserve and add them here.
PreservedAnalyses PA;
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
BumpPtrAllocator Allocator;
InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr);
return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater,
- /* DeleteFns*/ true);
+ /* DeleteFns*/ true,
+ /* IsModulePass */ true);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
BumpPtrAllocator Allocator;
InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions);
return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater,
- /* DeleteFns */ false);
+ /* DeleteFns */ false,
+ /* IsModulePass */ false);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
unsigned MaxFixpointIterations =
(isOpenMPDevice(M)) ? SetFixpointIterations : 32;
- Attributor A(Functions, InfoCache, CGUpdater, nullptr, true, false,
- MaxFixpointIterations, OREGetter, DEBUG_TYPE);
+
+ AttributorConfig AC(CGUpdater);
+ AC.DefaultInitializeLiveInternals = false;
+ AC.RewriteSignatures = false;
+ AC.MaxFixpointIterations = MaxFixpointIterations;
+ AC.OREGetter = OREGetter;
+ AC.PassName = DEBUG_TYPE;
+
+ Attributor A(Functions, InfoCache, AC);
OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
bool Changed = OMPOpt.run(true);
unsigned MaxFixpointIterations =
(isOpenMPDevice(M)) ? SetFixpointIterations : 32;
- Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true,
- MaxFixpointIterations, OREGetter, DEBUG_TYPE);
+
+ AttributorConfig AC(CGUpdater);
+ AC.DefaultInitializeLiveInternals = false;
+ AC.IsModulePass = false;
+ AC.RewriteSignatures = false;
+ AC.MaxFixpointIterations = MaxFixpointIterations;
+ AC.OREGetter = OREGetter;
+ AC.PassName = DEBUG_TYPE;
+
+ Attributor A(Functions, InfoCache, AC);
OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
bool Changed = OMPOpt.run(false);
unsigned MaxFixpointIterations =
(isOpenMPDevice(M)) ? SetFixpointIterations : 32;
- Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true,
- MaxFixpointIterations, OREGetter, DEBUG_TYPE);
+
+ AttributorConfig AC(CGUpdater);
+ AC.DefaultInitializeLiveInternals = false;
+ AC.IsModulePass = false;
+ AC.RewriteSignatures = false;
+ AC.MaxFixpointIterations = MaxFixpointIterations;
+ AC.OREGetter = OREGetter;
+ AC.PassName = DEBUG_TYPE;
+
+ Attributor A(Functions, InfoCache, AC);
OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
bool Result = OMPOpt.run(false);