[llvm] [TailRecElim] Introduce support for shift accumulator optimization (PR #181331)
Antonio Frighetto via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 25 06:49:38 PDT 2026
================
@@ -374,29 +374,117 @@ static bool canMoveAboveCall(Instruction *I, CallInst *CI, AliasAnalysis *AA) {
return !is_contained(I->operands(), CI);
}
-static bool canTransformAccumulatorRecursion(Instruction *I, CallInst *CI) {
- if (!I->isAssociative() || !I->isCommutative())
+// While shifts are neither associative nor commutative, a chain of shifts by a
+// constant amount C is equivalent to a single shift by the sum of the amounts:
+// ... (Base << C) << C) ... << C == Base << (C * Iterations)
+// This relation applies to left shifts as well as arithmetic/logical right
+// shifts when the shift amount is a constant.
+static bool isPseudoAssociative(Instruction *I) {
+ if (!I->isShift())
return false;
+ return isa<ConstantInt>(I->getOperand(1));
+}
+
+// Return true if V is a recursive call to F or an instruction directly using
+// the result of one. A depth-1 check is enough here: the value feeding a
+// return either uses the recursive call as an immediate operand (the
+// accumulator instruction, or the PHI merging it with the base case), or it
+// is rejected by getReturnValue below as a non-constant anyway.
+static bool usesRecursiveCall(Value *V, Function &F) {
+ auto IsRecursiveCall = [&F](Value *V) {
+ auto *CI = dyn_cast<CallInst>(V);
+ return CI && CI->getCalledFunction() == &F;
+ };
+ if (IsRecursiveCall(V))
+ return true;
+ auto *I = dyn_cast<Instruction>(V);
+ return I && llvm::any_of(I->operands(), IsRecursiveCall);
+}
+
+// Find the base-case return value for function F: examine all return
+// instructions, skipping those whose return value depends on a recursive call
+// to F (that value differs for each iteration of the recursion). If the
+// remaining returns yield exactly one distinct constant, return it; otherwise
+// return nullptr to indicate failure.
+//
+// FIXME: There is a room for improvement here in the future, e.g., consider
+// non-constant values and multiple base cases -- e.g., we want to be able to
+// handle code like:
+// ```
+// int f(int x) {
+// if (x == 1) return 1;
+// if (x == 10) return 10;
+// return f(x-1) << 1;
+// }
+// ```
+static Constant *getReturnValue(Function &F) {
+ Constant *BaseCaseVal = nullptr;
+
+ for (BasicBlock &BB : F) {
+ auto *RI = dyn_cast<ReturnInst>(BB.getTerminator());
+ if (!RI)
+ continue;
+
+ Value *RV = RI->getReturnValue();
+ if (usesRecursiveCall(RV, F))
+ continue;
+
+ auto *C = dyn_cast<Constant>(RV);
+ if (!C)
+ return nullptr;
+
+ if (!BaseCaseVal)
+ BaseCaseVal = C;
+ else if (BaseCaseVal != C)
+ return nullptr;
+ }
+
+ return BaseCaseVal;
+}
+
+// This function checks whether the instruction I can be used
+// to perform accumulator recursion elimination for the
+// call instruction CI.
+// In the presence of pseudo-associative operations, it returns
+// the base case constant value in BaseCaseConst to both indicate success and
+// provide the value needed to initialize the accumulator.
----------------
antoniofrighetto wrote:
```suggestion
// This function checks whether the instruction I can be used
// to perform accumulator recursion elimination for the
// call instruction CI.
```
https://github.com/llvm/llvm-project/pull/181331
More information about the llvm-commits
mailing list