[llvm] [TailRecElim] Introduce support for shift accumulator optimization (PR #181331)
Antonio Frighetto via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 10 03:52:01 PDT 2026
================
@@ -374,29 +376,110 @@ 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));
+}
+
+// Find the base-case return value for function F: examine all
+// return instructions and pick return values that do not depend on a
+// recursive call to F. If there is exactly one distinct such value,
+// return it. If there are none or more than one distinct value, 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();
+ Constant *Candidate = nullptr;
+
+ if (match(RV, m_Constant(Candidate))) {
+ // Direct constant return.
+ } else if (auto *PN = dyn_cast<PHINode>(RV)) {
+ for (Value *Inc : PN->incoming_values())
+ if (match(Inc, m_Constant(Candidate)))
+ break;
+ } else if (match(RV,
+ m_Select(m_Value(), m_Constant(Candidate), m_Value())) ||
+ match(RV,
+ m_Select(m_Value(), m_Value(), m_Constant(Candidate)))) {
+ // Select with a constant arm.
+ }
+
+ if (!Candidate)
+ return nullptr;
+
+ if (!BaseCaseVal)
+ BaseCaseVal = Candidate;
+ else if (BaseCaseVal != Candidate)
+ 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.
+static Constant *canTransformAccumulatorRecursion(Instruction *I,
+ CallInst *CI) {
+ auto IsPseudoAssociative = isPseudoAssociative(I);
+ if ((!I->isAssociative() || !I->isCommutative()) && !IsPseudoAssociative)
+ return nullptr;
assert(I->getNumOperands() >= 2 &&
"Associative/commutative operations should have at least 2 args!");
- if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
- // Accumulators must have an identity.
- if (!ConstantExpr::getIntrinsicIdentity(II->getIntrinsicID(), I->getType()))
- return false;
- }
+ Constant *AccInitVal = nullptr;
+ if (IsPseudoAssociative) {
+ // For pseudo-associative operations, we require that the recursive call
+ // is always on the first operand.
+ if (I->getOperand(0) != CI)
+ return nullptr;
- // Exactly one operand should be the result of the call instruction.
- if ((I->getOperand(0) == CI && I->getOperand(1) == CI) ||
- (I->getOperand(0) != CI && I->getOperand(1) != CI))
- return false;
+ AccInitVal = getReturnValue(*CI->getCalledFunction());
----------------
antoniofrighetto wrote:
Why are we passing the whole function here in getReturnValue()? We should already be in the return basic block when encountering a tail call (see the logic in eliminateCall()). I think we should only ensure to match a recursive call.
https://github.com/llvm/llvm-project/pull/181331
More information about the llvm-commits
mailing list