[Attributor][NFC] Performance improvements (#122923)
` forallInterferingAccesses` is a hotspot and for large modules these
changes make a measurable improvement in compilation time.
For LTO kernel compilation of 519.clvleaf (SPEChpc 2021) I measured the
following:
```
| Measured times (s) | Average | speedup
--------------------+------------------------+---------+---------
Baseline | 33.268 33.332 33.275 | 33.292 | 0%
Cache "kernel" | 30.543 30.339 30.607 | 30.496 | 9.2%
templatize callback | 30.981 30.97 30.964 | 30.972 | 7.5%
Both changes | 29.284 29.201 29.053 | 29.179 | 14.1%
```
This commit is contained in:
@@ -1287,6 +1287,12 @@ struct InformationCache {
|
||||
return AG.getAnalysis<TargetLibraryAnalysis>(F);
|
||||
}
|
||||
|
||||
/// Return true if \p F has the "kernel" function attribute
|
||||
bool isKernel(const Function &F) {
|
||||
FunctionInfo &FI = getFunctionInfo(F);
|
||||
return FI.IsKernel;
|
||||
}
|
||||
|
||||
/// Return true if \p Arg is involved in a must-tail call, thus the argument
|
||||
/// of the caller or callee.
|
||||
bool isInvolvedInMustTailCall(const Argument &Arg) {
|
||||
@@ -1361,6 +1367,9 @@ private:
|
||||
|
||||
/// Function contains a `musttail` call.
|
||||
bool ContainsMustTailCall;
|
||||
|
||||
/// Function has the `"kernel"` attribute
|
||||
bool IsKernel;
|
||||
};
|
||||
|
||||
/// A map type from functions to informatio about it.
|
||||
|
||||
@@ -678,8 +678,8 @@ isPotentiallyReachable(Attributor &A, const Instruction &FromI,
|
||||
// kernel, values like allocas and shared memory are not accessible. We
|
||||
// implicitly check for this situation to avoid costly lookups.
|
||||
if (GoBackwardsCB && &ToFn != FromI.getFunction() &&
|
||||
!GoBackwardsCB(*FromI.getFunction()) && ToFn.hasFnAttribute("kernel") &&
|
||||
FromI.getFunction()->hasFnAttribute("kernel")) {
|
||||
!GoBackwardsCB(*FromI.getFunction()) && A.getInfoCache().isKernel(ToFn) &&
|
||||
A.getInfoCache().isKernel(*FromI.getFunction())) {
|
||||
LLVM_DEBUG(dbgs() << "[AA] assume kernel cannot be reached from within the "
|
||||
"module; success\n";);
|
||||
return false;
|
||||
@@ -3191,6 +3191,8 @@ void InformationCache::initializeInformationCache(const Function &CF,
|
||||
// initialize the cache eagerly which would look the same to the users.
|
||||
Function &F = const_cast<Function &>(CF);
|
||||
|
||||
FI.IsKernel = F.hasFnAttribute("kernel");
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -885,9 +885,8 @@ protected:
|
||||
AAPointerInfo::OffsetInfo ReturnedOffsets;
|
||||
|
||||
/// See AAPointerInfo::forallInterferingAccesses.
|
||||
bool forallInterferingAccesses(
|
||||
AA::RangeTy Range,
|
||||
function_ref<bool(const AAPointerInfo::Access &, bool)> CB) const {
|
||||
template <typename F>
|
||||
bool forallInterferingAccesses(AA::RangeTy Range, F CB) const {
|
||||
if (!isValidState() || !ReturnedOffsets.isUnassigned())
|
||||
return false;
|
||||
|
||||
@@ -906,10 +905,9 @@ protected:
|
||||
}
|
||||
|
||||
/// See AAPointerInfo::forallInterferingAccesses.
|
||||
bool forallInterferingAccesses(
|
||||
Instruction &I,
|
||||
function_ref<bool(const AAPointerInfo::Access &, bool)> CB,
|
||||
AA::RangeTy &Range) const {
|
||||
template <typename F>
|
||||
bool forallInterferingAccesses(Instruction &I, F CB,
|
||||
AA::RangeTy &Range) const {
|
||||
if (!isValidState() || !ReturnedOffsets.isUnassigned())
|
||||
return false;
|
||||
|
||||
@@ -1176,7 +1174,7 @@ struct AAPointerInfoImpl
|
||||
// TODO: Use reaching kernels from AAKernelInfo (or move it to
|
||||
// AAExecutionDomain) such that we allow scopes other than kernels as long
|
||||
// as the reaching kernels are disjoint.
|
||||
bool InstInKernel = Scope.hasFnAttribute("kernel");
|
||||
bool InstInKernel = A.getInfoCache().isKernel(Scope);
|
||||
bool ObjHasKernelLifetime = false;
|
||||
const bool UseDominanceReasoning =
|
||||
FindInterferingWrites && IsKnownNoRecurse;
|
||||
@@ -1210,7 +1208,7 @@ struct AAPointerInfoImpl
|
||||
// If the alloca containing function is not recursive the alloca
|
||||
// must be dead in the callee.
|
||||
const Function *AIFn = AI->getFunction();
|
||||
ObjHasKernelLifetime = AIFn->hasFnAttribute("kernel");
|
||||
ObjHasKernelLifetime = A.getInfoCache().isKernel(*AIFn);
|
||||
bool IsKnownNoRecurse;
|
||||
if (AA::hasAssumedIRAttr<Attribute::NoRecurse>(
|
||||
A, this, IRPosition::function(*AIFn), DepClassTy::OPTIONAL,
|
||||
@@ -1222,8 +1220,8 @@ struct AAPointerInfoImpl
|
||||
// as it is "dead" in the (unknown) callees.
|
||||
ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());
|
||||
if (ObjHasKernelLifetime)
|
||||
IsLiveInCalleeCB = [](const Function &Fn) {
|
||||
return !Fn.hasFnAttribute("kernel");
|
||||
IsLiveInCalleeCB = [&A](const Function &Fn) {
|
||||
return !A.getInfoCache().isKernel(Fn);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1238,7 +1236,7 @@ struct AAPointerInfoImpl
|
||||
// If the object has kernel lifetime we can ignore accesses only reachable
|
||||
// by other kernels. For now we only skip accesses *in* other kernels.
|
||||
if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&
|
||||
AccScope->hasFnAttribute("kernel"))
|
||||
A.getInfoCache().isKernel(*AccScope))
|
||||
return true;
|
||||
|
||||
if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &I) {
|
||||
|
||||
Reference in New Issue
Block a user