/// idea here is that we don't want to mess with the convention if the user
/// explicitly requested something with performance implications like coldcc,
/// GHC, or anyregcc.
-static bool hasChangeableCC(Function *F) {
+static bool hasChangeableCCImpl(Function *F) {
CallingConv::ID CC = F->getCallingConv();
// FIXME: Is it worth transforming x86_stdcallcc and x86_fastcallcc?
if (CC != CallingConv::C && CC != CallingConv::X86_ThisCall)
return false;
+ if (F->isVarArg())
+ return false;
+
// FIXME: Change CC for the whole chain of musttail calls when possible.
//
// Can't change CC of the function that either has musttail calls, or is a
if (BB.getTerminatingMustTailCall())
return false;
- return true;
+ return !F->hasAddressTaken();
+}
+
+using ChangeableCCCacheTy = SmallDenseMap<Function *, bool, 8>;
+static bool hasChangeableCC(Function *F,
+ ChangeableCCCacheTy &ChangeableCCCache) {
+ auto Res = ChangeableCCCache.try_emplace(F, false);
+ if (Res.second)
+ Res.first->second = hasChangeableCCImpl(F);
+ return Res.first->second;
}
/// Return true if the block containing the call site has a BlockFrequency of
// coldcc calling convention.
static bool
hasOnlyColdCalls(Function &F,
- function_ref<BlockFrequencyInfo &(Function &)> GetBFI) {
+ function_ref<BlockFrequencyInfo &(Function &)> GetBFI,
+ ChangeableCCCacheTy &ChangeableCCCache) {
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
if (CallInst *CI = dyn_cast<CallInst>(&I)) {
if (!CalledFn->hasLocalLinkage())
return false;
// Check if it's valid to use coldcc calling convention.
- if (!hasChangeableCC(CalledFn) || CalledFn->isVarArg() ||
- CalledFn->hasAddressTaken())
+ if (!hasChangeableCC(CalledFn, ChangeableCCCache))
return false;
BlockFrequencyInfo &CallerBFI = GetBFI(F);
if (!isColdCallSite(*CI, CallerBFI))
bool Changed = false;
+ ChangeableCCCacheTy ChangeableCCCache;
std::vector<Function *> AllCallsCold;
for (Function &F : llvm::make_early_inc_range(M))
- if (hasOnlyColdCalls(F, GetBFI))
+ if (hasOnlyColdCalls(F, GetBFI, ChangeableCCCache))
AllCallsCold.push_back(&F);
// Optimize functions.
continue;
}
- if (hasChangeableCC(&F) && !F.isVarArg() && !F.hasAddressTaken()) {
+ if (hasChangeableCC(&F, ChangeableCCCache)) {
NumInternalFunc++;
TargetTransformInfo &TTI = GetTTI(F);
// Change the calling convention to coldcc if either stress testing is
if (EnableColdCCStressTest ||
(TTI.useColdCCForColdCall(F) &&
isValidCandidateForColdCC(F, GetBFI, AllCallsCold))) {
+ ChangeableCCCache.erase(&F);
F.setCallingConv(CallingConv::Cold);
changeCallSitesToColdCC(&F);
Changed = true;
}
}
- if (hasChangeableCC(&F) && !F.isVarArg() && !F.hasAddressTaken()) {
+ if (hasChangeableCC(&F, ChangeableCCCache)) {
// If this function has a calling convention worth changing, is not a
// varargs function, and is only called directly, promote it to use the
// Fast calling convention.