forked from OSchip/llvm-project
Recommit "[FuncSpec] Decouple cost/benefit analysis, allowing sorting of candidates."
Replaced llvm:sort with llvm::stable_sort, this was failing on the bot with expensive checks enabled.
This commit is contained in:
parent
705c722ba5
commit
89bcfd1632
|
@ -92,6 +92,25 @@ static cl::opt<bool> EnableSpecializationForLiteralConstant(
|
|||
cl::desc("Enable specialization of functions that take a literal constant "
|
||||
"as an argument."));
|
||||
|
||||
namespace {
|
||||
// Bookkeeping struct to pass data from the analysis and profitability phase
|
||||
// to the actual transform helper functions.
|
||||
struct ArgInfo {
|
||||
Function *Fn; // The function to perform specialisation on.
|
||||
Argument *Arg; // The Formal argument being analysed.
|
||||
Constant *Const; // A corresponding actual constant argument.
|
||||
InstructionCost Gain; // Profitability: Gain = Bonus - Cost.
|
||||
|
||||
// Flag if this will be a partial specialization, in which case we will need
|
||||
// to keep the original function around in addition to the added
|
||||
// specializations.
|
||||
bool Partial = false;
|
||||
|
||||
ArgInfo(Function *F, Argument *A, Constant *C, InstructionCost G)
|
||||
: Fn(F), Arg(A), Const(C), Gain(G){};
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
// Helper to check if \p LV is either a constant or a constant
|
||||
// range with a single element. This should cover exactly the same cases as the
|
||||
// old ValueLatticeElement::isConstant() and is intended to be used in the
|
||||
|
@ -256,16 +275,27 @@ public:
|
|||
bool
|
||||
specializeFunctions(SmallVectorImpl<Function *> &FuncDecls,
|
||||
SmallVectorImpl<Function *> &CurrentSpecializations) {
|
||||
|
||||
// Attempt to specialize the argument-tracked functions.
|
||||
bool Changed = false;
|
||||
for (auto *F : FuncDecls) {
|
||||
if (specializeFunction(F, CurrentSpecializations)) {
|
||||
Changed = true;
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Can specialize this func.\n");
|
||||
} else {
|
||||
if (!isCandidateFunction(F, CurrentSpecializations))
|
||||
continue;
|
||||
|
||||
auto Cost = getSpecializationCost(F);
|
||||
if (!Cost.isValid()) {
|
||||
LLVM_DEBUG(
|
||||
dbgs() << "FnSpecialization: Cannot specialize this func.\n");
|
||||
dbgs() << "FnSpecialization: Invalid specialisation cost.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ConstArgs = calculateGains(F, Cost);
|
||||
if (ConstArgs.empty()) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: no possible constants found\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &CA : ConstArgs) {
|
||||
specializeFunction(CA, CurrentSpecializations);
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,15 +363,80 @@ private:
|
|||
return Clone;
|
||||
}
|
||||
|
||||
/// This function decides whether to specialize function \p F based on the
|
||||
/// known constant values its arguments can take on. Specialization is
|
||||
/// performed on the first interesting argument. Specializations based on
|
||||
/// additional arguments will be evaluated on following iterations of the
|
||||
/// main IPSCCP solve loop. \returns true if the function is specialized and
|
||||
/// false otherwise.
|
||||
bool specializeFunction(Function *F,
|
||||
SmallVectorImpl<Function *> &Specializations) {
|
||||
/// This function decides whether it's worthwhile to specialize function \p F
|
||||
/// based on the known constant values its arguments can take on, i.e. it
|
||||
/// calculates a gain and returns a list of actual arguments that are deemed
|
||||
/// profitable to specialize. Specialization is performed on the first
|
||||
/// interesting argument. Specializations based on additional arguments will
|
||||
/// be evaluated on following iterations of the main IPSCCP solve loop.
|
||||
SmallVector<ArgInfo> calculateGains(Function *F, InstructionCost Cost) {
|
||||
SmallVector<ArgInfo> Worklist;
|
||||
// Determine if we should specialize the function based on the values the
|
||||
// argument can take on. If specialization is not profitable, we continue
|
||||
// on to the next argument.
|
||||
for (Argument &FormalArg : F->args()) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing arg: "
|
||||
<< FormalArg.getName() << "\n");
|
||||
// Determine if this argument is interesting. If we know the argument can
|
||||
// take on any constant values, they are collected in Constants. If the
|
||||
// argument can only ever equal a constant value in Constants, the
|
||||
// function will be completely specialized, and the IsPartial flag will
|
||||
// be set to false by isArgumentInteresting (that function only adds
|
||||
// values to the Constants list that are deemed profitable).
|
||||
bool IsPartial = true;
|
||||
SmallVector<Constant *> ActualConstArg;
|
||||
if (!isArgumentInteresting(&FormalArg, ActualConstArg, IsPartial)) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is not interesting\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto *ActualArg : ActualConstArg) {
|
||||
InstructionCost Gain =
|
||||
ForceFunctionSpecialization
|
||||
? 1
|
||||
: getSpecializationBonus(&FormalArg, ActualArg) - Cost;
|
||||
|
||||
if (Gain <= 0)
|
||||
continue;
|
||||
Worklist.push_back({F, &FormalArg, ActualArg, Gain});
|
||||
}
|
||||
|
||||
if (Worklist.empty())
|
||||
continue;
|
||||
|
||||
// Sort the candidates in descending order.
|
||||
llvm::stable_sort(Worklist, [](const ArgInfo &L, const ArgInfo &R) {
|
||||
return L.Gain > R.Gain;
|
||||
});
|
||||
|
||||
// TODO: truncate the worklist to 'MaxConstantsThreshold' candidates if
|
||||
// necessary.
|
||||
if (Worklist.size() > MaxConstantsThreshold) {
|
||||
Worklist.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsPartial || Worklist.size() < ActualConstArg.size())
|
||||
for (auto &ActualArg : Worklist)
|
||||
ActualArg.Partial = true;
|
||||
|
||||
LLVM_DEBUG(dbgs() << "Sorted list of candidates by gain:\n";
|
||||
for (auto &C
|
||||
: Worklist) {
|
||||
dbgs() << "- Function = " << C.Fn->getName() << ", ";
|
||||
dbgs() << "FormalArg = " << C.Arg->getName() << ", ";
|
||||
dbgs() << "ActualArg = " << C.Const->getName() << ", ";
|
||||
dbgs() << "Gain = " << C.Gain << "\n";
|
||||
});
|
||||
|
||||
// FIXME: Only one argument per function.
|
||||
break;
|
||||
}
|
||||
return Worklist;
|
||||
}
|
||||
|
||||
bool isCandidateFunction(Function *F,
|
||||
SmallVectorImpl<Function *> &Specializations) {
|
||||
// Do not specialize the cloned function again.
|
||||
if (SpecializedFuncs.contains(F))
|
||||
return false;
|
||||
|
@ -362,84 +457,33 @@ private:
|
|||
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Try function: " << F->getName()
|
||||
<< "\n");
|
||||
|
||||
// Determine if it would be profitable to create a specialization of the
|
||||
// function where the argument takes on the given constant value. If so,
|
||||
// add the constant to Constants.
|
||||
auto FnSpecCost = getSpecializationCost(F);
|
||||
if (!FnSpecCost.isValid()) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Invalid specialisation cost.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: func specialisation cost: ";
|
||||
FnSpecCost.print(dbgs()); dbgs() << "\n");
|
||||
|
||||
// Determine if we should specialize the function based on the values the
|
||||
// argument can take on. If specialization is not profitable, we continue
|
||||
// on to the next argument.
|
||||
for (Argument &A : F->args()) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing arg: " << A.getName()
|
||||
<< "\n");
|
||||
// True if this will be a partial specialization. We will need to keep
|
||||
// the original function around in addition to the added specializations.
|
||||
bool IsPartial = true;
|
||||
|
||||
// Determine if this argument is interesting. If we know the argument can
|
||||
// take on any constant values, they are collected in Constants. If the
|
||||
// argument can only ever equal a constant value in Constants, the
|
||||
// function will be completely specialized, and the IsPartial flag will
|
||||
// be set to false by isArgumentInteresting (that function only adds
|
||||
// values to the Constants list that are deemed profitable).
|
||||
SmallVector<Constant *, 4> Constants;
|
||||
if (!isArgumentInteresting(&A, Constants, FnSpecCost, IsPartial)) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is not interesting\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(!Constants.empty() && "No constants on which to specialize");
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is interesting!\n"
|
||||
<< "FnSpecialization: Specializing '" << F->getName()
|
||||
<< "' on argument: " << A << "\n"
|
||||
<< "FnSpecialization: Constants are:\n\n";
|
||||
for (unsigned I = 0; I < Constants.size(); ++I) dbgs()
|
||||
<< *Constants[I] << "\n";
|
||||
dbgs() << "FnSpecialization: End of constants\n\n");
|
||||
|
||||
// Create a version of the function in which the argument is marked
|
||||
// constant with the given value.
|
||||
for (auto *C : Constants) {
|
||||
// Clone the function. We leave the ValueToValueMap empty to allow
|
||||
// IPSCCP to propagate the constant arguments.
|
||||
Function *Clone = cloneCandidateFunction(F);
|
||||
Argument *ClonedArg = Clone->arg_begin() + A.getArgNo();
|
||||
|
||||
// Rewrite calls to the function so that they call the clone instead.
|
||||
rewriteCallSites(F, Clone, *ClonedArg, C);
|
||||
|
||||
// Initialize the lattice state of the arguments of the function clone,
|
||||
// marking the argument on which we specialized the function constant
|
||||
// with the given value.
|
||||
Solver.markArgInFuncSpecialization(F, ClonedArg, C);
|
||||
|
||||
// Mark all the specialized functions
|
||||
Specializations.push_back(Clone);
|
||||
NbFunctionsSpecialized++;
|
||||
}
|
||||
|
||||
// If the function has been completely specialized, the original function
|
||||
// is no longer needed. Mark it unreachable.
|
||||
if (!IsPartial)
|
||||
Solver.markFunctionUnreachable(F);
|
||||
|
||||
// FIXME: Only one argument per function.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Compute the cost of specializing function \p F.
|
||||
void specializeFunction(ArgInfo &AI,
|
||||
SmallVectorImpl<Function *> &Specializations) {
|
||||
Function *Clone = cloneCandidateFunction(AI.Fn);
|
||||
Argument *ClonedArg = Clone->getArg(AI.Arg->getArgNo());
|
||||
|
||||
// Rewrite calls to the function so that they call the clone instead.
|
||||
rewriteCallSites(AI.Fn, Clone, *ClonedArg, AI.Const);
|
||||
|
||||
// Initialize the lattice state of the arguments of the function clone,
|
||||
// marking the argument on which we specialized the function constant
|
||||
// with the given value.
|
||||
Solver.markArgInFuncSpecialization(AI.Fn, ClonedArg, AI.Const);
|
||||
|
||||
// Mark all the specialized functions
|
||||
Specializations.push_back(Clone);
|
||||
NbFunctionsSpecialized++;
|
||||
|
||||
// If the function has been completely specialized, the original function
|
||||
// is no longer needed. Mark it unreachable.
|
||||
if (!AI.Partial)
|
||||
Solver.markFunctionUnreachable(AI.Fn);
|
||||
}
|
||||
|
||||
/// Compute and return the cost of specializing function \p F.
|
||||
InstructionCost getSpecializationCost(Function *F) {
|
||||
// Compute the code metrics for the function.
|
||||
SmallPtrSet<const Value *, 32> EphValues;
|
||||
|
@ -580,7 +624,6 @@ private:
|
|||
/// argument.
|
||||
bool isArgumentInteresting(Argument *A,
|
||||
SmallVectorImpl<Constant *> &Constants,
|
||||
const InstructionCost &FnSpecCost,
|
||||
bool &IsPartial) {
|
||||
// For now, don't attempt to specialize functions based on the values of
|
||||
// composite types.
|
||||
|
@ -608,42 +651,8 @@ private:
|
|||
//
|
||||
// TODO 2: this currently does not support constants, i.e. integer ranges.
|
||||
//
|
||||
SmallVector<Constant *, 4> PossibleConstants;
|
||||
bool AllConstant = getPossibleConstants(A, PossibleConstants);
|
||||
if (PossibleConstants.empty()) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: no possible constants found\n");
|
||||
return false;
|
||||
}
|
||||
if (PossibleConstants.size() > MaxConstantsThreshold) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: number of constants found exceed "
|
||||
<< "the maximum number of constants threshold.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto *C : PossibleConstants) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Constant: " << *C << "\n");
|
||||
if (ForceFunctionSpecialization) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: Forced!\n");
|
||||
Constants.push_back(C);
|
||||
continue;
|
||||
}
|
||||
if (getSpecializationBonus(A, C) > FnSpecCost) {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: profitable!\n");
|
||||
Constants.push_back(C);
|
||||
} else {
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: not profitable\n");
|
||||
}
|
||||
}
|
||||
|
||||
// None of the constant values the argument can take on were deemed good
|
||||
// candidates on which to specialize the function.
|
||||
if (Constants.empty())
|
||||
return false;
|
||||
|
||||
// This will be a partial specialization if some of the constants were
|
||||
// rejected due to their profitability.
|
||||
IsPartial = !AllConstant || PossibleConstants.size() != Constants.size();
|
||||
|
||||
IsPartial = !getPossibleConstants(A, Constants);
|
||||
LLVM_DEBUG(dbgs() << "FnSpecialization: interesting arg: " << *A << "\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -681,7 +690,7 @@ private:
|
|||
|
||||
// For now, constant expressions are fine but only if they are function
|
||||
// calls.
|
||||
if (auto *CE = dyn_cast<ConstantExpr>(V))
|
||||
if (auto *CE = dyn_cast<ConstantExpr>(V))
|
||||
if (!isa<Function>(CE->getOperand(0)))
|
||||
return false;
|
||||
|
||||
|
|
Loading…
Reference in New Issue