Skip to content

Commit ef31305

Browse files
committed
[InlineCost]: fold CmpInstr when next iteration of a recursive call can simplify the Cmp decision.
1 parent efe2fc3 commit ef31305

File tree

3 files changed

+69
-81
lines changed

3 files changed

+69
-81
lines changed

llvm/include/llvm/Analysis/InlineCost.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ struct InlineParams {
236236
std::optional<bool> EnableDeferral;
237237

238238
/// Indicate whether we allow inlining for recursive call.
239-
std::optional<bool> AllowRecursiveCall = true;
239+
std::optional<bool> AllowRecursiveCall = false;
240240
};
241241

242242
std::optional<int> getStringFnAttrAsInt(CallBase &CB, StringRef AttrKind);

llvm/lib/Analysis/InlineCost.cpp

Lines changed: 67 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> {
445445
bool canFoldInboundsGEP(GetElementPtrInst &I);
446446
bool accumulateGEPOffset(GEPOperator &GEP, APInt &Offset);
447447
bool simplifyCallSite(Function *F, CallBase &Call);
448+
bool simplifyCmpInst(Function *F, CmpInst &Cmp);
448449
bool simplifyInstruction(Instruction &I);
449450
bool simplifyIntrinsicCallIsConstant(CallBase &CB);
450451
bool simplifyIntrinsicCallObjectSize(CallBase &CB);
@@ -1171,10 +1172,6 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
11711172
std::optional<CostBenefitPair> getCostBenefitPair() { return CostBenefit; }
11721173
bool wasDecidedByCostBenefit() const { return DecidedByCostBenefit; }
11731174
bool wasDecidedByCostThreshold() const { return DecidedByCostThreshold; }
1174-
bool shouldCheckRecursiveCall() {
1175-
return IsRecursiveCall && AllowRecursiveCall;
1176-
}
1177-
bool shouldInlineRecursiveCall(CallBase &Call);
11781175
};
11791176

11801177
// Return true if CB is the sole call to local function Callee.
@@ -1681,6 +1678,68 @@ bool CallAnalyzer::visitGetElementPtr(GetElementPtrInst &I) {
16811678
return isGEPFree(I);
16821679
}
16831680

1681+
/// Simplify \p Cmp if RHS is const and we can ValueTrack LHS,
1682+
// This handles the case when the Cmp instruction is guarded a recursive call
1683+
// that will cause the Cmp to fail/succeed for the next iteration.
1684+
bool CallAnalyzer::simplifyCmpInst(Function *F, CmpInst &Cmp) {
1685+
// Bail out if the RHS is NOT const:
1686+
if (!isa<Constant>(Cmp.getOperand(1)))
1687+
return false;
1688+
auto *CmpOp = Cmp.getOperand(0);
1689+
// Iterate over the users of the function to check if it's a recursive function:
1690+
for (auto *U : F->users()) {
1691+
CallInst *Call = dyn_cast<CallInst>(U);
1692+
if (!Call || Call->getFunction() != F)
1693+
continue;
1694+
auto *CallBB = Call->getParent();
1695+
auto *Predecessor = CallBB->getSinglePredecessor();
1696+
// Only handle the case when the callsite has a single predecessor:
1697+
if (!Predecessor)
1698+
continue;
1699+
1700+
auto *Br = dyn_cast<BranchInst>(Predecessor->getTerminator());
1701+
if (!Br || Br->isUnconditional())
1702+
continue;
1703+
// Check if the Br condition is the same Cmp instr we are investigating:
1704+
auto *CmpInstr = dyn_cast<CmpInst>(Br->getCondition());
1705+
if (!CmpInstr || CmpInstr != &Cmp)
1706+
continue;
1707+
// Check if there are any arg of the recursive callsite is affecting the cmp instr:
1708+
bool ArgFound = false;
1709+
Value *FuncArg = nullptr, *CallArg = nullptr;
1710+
for (unsigned ArgNum = 0; ArgNum < F->arg_size() && ArgNum < Call->arg_size(); ArgNum ++) {
1711+
FuncArg = F->getArg(ArgNum);
1712+
CallArg = Call->getArgOperand(ArgNum);
1713+
if ((FuncArg == CmpOp) &&
1714+
(CallArg != CmpOp)) {
1715+
ArgFound = true;
1716+
break;
1717+
}
1718+
}
1719+
if (!ArgFound)
1720+
continue;
1721+
// Now we have a recursive call that is guarded by a cmp instruction.
1722+
// Check if this cmp can be simplified:
1723+
SimplifyQuery SQ(DL, dyn_cast<Instruction>(CallArg));
1724+
DomConditionCache DC;
1725+
DC.registerBranch(Br);
1726+
SQ.DC = &DC;
1727+
DominatorTree DT(*F);
1728+
SQ.DT = &DT;
1729+
Value *simplifiedInstruction = llvm::simplifyInstructionWithOperands(CmpInstr, {CallArg, Cmp.getOperand(1)}, SQ);
1730+
if (!simplifiedInstruction)
1731+
continue;
1732+
if (auto *ConstVal = dyn_cast<llvm::ConstantInt>(simplifiedInstruction)) {
1733+
bool isTrueSuccessor = CallBB == Br->getSuccessor(0);
1734+
SimplifiedValues[&Cmp] = ConstVal;
1735+
if (ConstVal->isOne())
1736+
return !isTrueSuccessor;
1737+
return isTrueSuccessor;
1738+
}
1739+
}
1740+
return false;
1741+
}
1742+
16841743
/// Simplify \p I if its operands are constants and update SimplifiedValues.
16851744
bool CallAnalyzer::simplifyInstruction(Instruction &I) {
16861745
SmallVector<Constant *> COps;
@@ -2065,6 +2124,10 @@ bool CallAnalyzer::visitCmpInst(CmpInst &I) {
20652124
if (simplifyInstruction(I))
20662125
return true;
20672126

2127+
// Try to handle comparison that can be simplified using ValueTracking.
2128+
if (simplifyCmpInst(I.getFunction(), I))
2129+
return true;
2130+
20682131
if (I.getOpcode() == Instruction::FCmp)
20692132
return false;
20702133

@@ -2900,68 +2963,6 @@ InlineResult CallAnalyzer::analyze() {
29002963
return finalizeAnalysis();
29012964
}
29022965

2903-
bool InlineCostCallAnalyzer::shouldInlineRecursiveCall(CallBase &Call) {
2904-
CallInst *CI = cast<CallInst>(&Call);
2905-
auto CIB = CI->getParent();
2906-
// Only handle case when we have sinlge predecessor
2907-
if (auto Predecessor = CIB->getSinglePredecessor()) {
2908-
BranchInst *Br = dyn_cast<BranchInst>(Predecessor->getTerminator());
2909-
if (!Br || Br->isUnconditional()) {
2910-
return false;
2911-
}
2912-
Value *Var = Br->getCondition();
2913-
CmpInst *CmpInstr = dyn_cast<CmpInst>(Var);
2914-
if (CmpInstr && !isa<Constant>(CmpInstr->getOperand(1))) {
2915-
// Current logic of ValueTracking/DomConditionCache works only if RHS is
2916-
// constant.
2917-
return false;
2918-
}
2919-
unsigned ArgNum = 0;
2920-
Value *FuncArg = nullptr, *CallArg = nullptr;
2921-
// Check which func argument the cmp instr is using:
2922-
for (; ArgNum < CI->getFunction()->arg_size(); ArgNum++) {
2923-
FuncArg = CI->getFunction()->getArg(ArgNum);
2924-
CallArg = CI->getArgOperand(ArgNum);
2925-
if (CmpInstr) {
2926-
if ((FuncArg == CmpInstr->getOperand(0)) &&
2927-
(CallArg != CmpInstr->getOperand(0)))
2928-
break;
2929-
} else if (FuncArg == Var && (CallArg != Var))
2930-
break;
2931-
}
2932-
// Only handle the case when a func argument controls the cmp instruction:
2933-
if (ArgNum < CI->getFunction()->arg_size()) {
2934-
bool isTrueSuccessor = CIB == Br->getSuccessor(0);
2935-
if (CmpInstr) {
2936-
SimplifyQuery SQ(CI->getFunction()->getDataLayout(),
2937-
dyn_cast<Instruction>(CallArg));
2938-
DomConditionCache DC;
2939-
DC.registerBranch(Br);
2940-
SQ.DC = &DC;
2941-
DominatorTree DT(*CI->getFunction());
2942-
SQ.DT = &DT;
2943-
Value *simplifiedInstruction = llvm::simplifyInstructionWithOperands(
2944-
CmpInstr, {CallArg, CmpInstr->getOperand(1)}, SQ);
2945-
if (!simplifiedInstruction)
2946-
return false;
2947-
if (auto *ConstVal =
2948-
dyn_cast<llvm::ConstantInt>(simplifiedInstruction)) {
2949-
if (ConstVal->isOne())
2950-
return !isTrueSuccessor;
2951-
return isTrueSuccessor;
2952-
}
2953-
} else {
2954-
if (auto *ConstVal = dyn_cast<llvm::ConstantInt>(CallArg)) {
2955-
if (ConstVal->isOne())
2956-
return !isTrueSuccessor;
2957-
return isTrueSuccessor;
2958-
}
2959-
}
2960-
}
2961-
}
2962-
return false;
2963-
}
2964-
29652966
void InlineCostCallAnalyzer::print(raw_ostream &OS) {
29662967
#define DEBUG_PRINT_STAT(x) OS << " " #x ": " << x << "\n"
29672968
if (PrintInstructionComments)
@@ -3193,12 +3194,6 @@ InlineCost llvm::getInlineCost(
31933194

31943195
LLVM_DEBUG(CA.dump());
31953196

3196-
// Check if callee function is recursive:
3197-
if (ShouldInline.isSuccess()) {
3198-
if (CA.shouldCheckRecursiveCall() && !CA.shouldInlineRecursiveCall(Call))
3199-
return InlineCost::getNever("deep recursion");
3200-
}
3201-
32023197
// Always make cost benefit based decision explicit.
32033198
// We use always/never here since threshold is not meaningful,
32043199
// as it's not what drives cost-benefit analysis.
@@ -3241,13 +3236,6 @@ InlineResult llvm::isInlineViable(Function &F) {
32413236

32423237
// Disallow recursive calls.
32433238
Function *Callee = Call->getCalledFunction();
3244-
// This function is called when we have "alwaysinline" attribute.
3245-
// If we allowed the inlining here given that the recursive inlining is
3246-
// allowed, then there will be problem in the second trial of inlining,
3247-
// because the Inliner pass allow only one time inlining and then it
3248-
// inserts "noinline" attribute which will be in conflict with the
3249-
// attribute of "alwaysinline" so, "alwaysinline" for recursive function
3250-
// will be disallowed to avoid conflict of attributes.
32513239
if (&F == Callee)
32523240
return InlineResult::failure("recursive call");
32533241

llvm/test/Transforms/Inline/inline-remark.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@ define void @test3() {
5656
}
5757

5858
; CHECK: attributes [[ATTR1]] = { "inline-remark"="(cost=25, threshold=0)" }
59-
; CHECK: attributes [[ATTR2]] = { "inline-remark"="(cost=0, threshold=0)" }
59+
; CHECK: attributes [[ATTR2]] = { "inline-remark"="(cost=never): recursive" }
6060
; CHECK: attributes [[ATTR3]] = { "inline-remark"="unsupported operand bundle; (cost={{.*}}, threshold={{.*}})" }
6161
; CHECK: attributes [[ATTR4]] = { alwaysinline "inline-remark"="(cost=never): recursive call" }

0 commit comments

Comments
 (0)