[llvm] [AggressiveInstCombine] Fold split-width i32 cttz/ctlz patterns into wide i64 intrinsics (PR #192296)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 22 11:57:47 PDT 2026
================
@@ -68,6 +72,179 @@ static cl::opt<unsigned>
cl::desc("The maximum length of a constant string to "
"inline a memchr call."));
+/// Try to fold a select-based split cttz pattern into a single full-width cttz.
+///
+/// %lo = trunc iN %val to i(N/2)
+/// %cmp = icmp eq i(N/2) %lo, 0
+/// %shr = lshr iN %val, N/2
+/// %hi = trunc iN %shr to i(N/2)
+/// %cttz_hi = call i(N/2) @llvm.cttz.i(N/2)(i(N/2) %hi, ...)
+/// %hi_plus = add/or_disjoint i(N/2) %cttz_hi, N/2
+/// %cttz_lo = call i(N/2) @llvm.cttz.i(N/2)(i(N/2) %lo, ...)
+/// %result = select i1 %cmp, i(N/2) %hi_plus, i(N/2) %cttz_lo
+/// -->
+/// %cttz_wide = call iN @llvm.cttz.iN(iN %val, i1 false)
+/// %result = trunc iN %cttz_wide to i(N/2)
+/// Alive proof (for i64/i32): https://alive2.llvm.org/ce/z/-s14-s
+static bool foldSelectSplitCTTZ(Instruction &I) {
+ Value *Cond, *TrueVal, *FalseVal;
+ if (!match(&I, m_Select(m_Value(Cond), m_Value(TrueVal), m_Value(FalseVal))))
+ return false;
+
+ Type *HalfTy = I.getType();
+ if (!HalfTy->isIntegerTy())
+ return false;
+ unsigned HalfWidth = HalfTy->getIntegerBitWidth();
+ unsigned FullWidth = HalfWidth * 2;
+
+ // select (icmp eq (trunc SrcVal to i(N/2)), 0), HiResult, LoResult
+ // Or select (icmp ne ...), LoResult, HiResult
+ Value *LoTrunc;
+ Value *HiResult, *LoResult;
+ if (match(Cond,
+ m_SpecificICmp(CmpInst::ICMP_EQ, m_Value(LoTrunc), m_ZeroInt()))) {
+ HiResult = TrueVal;
+ LoResult = FalseVal;
+ } else if (match(Cond, m_SpecificICmp(CmpInst::ICMP_NE, m_Value(LoTrunc),
+ m_ZeroInt()))) {
+ HiResult = FalseVal;
+ LoResult = TrueVal;
+ } else {
+ return false;
+ }
+
+ // LoTrunc: trunc iN SrcVal to i(N/2)
+ Value *SrcVal;
+ if (!match(LoTrunc, m_Trunc(m_Value(SrcVal))))
+ return false;
+ if (!SrcVal->getType()->isIntegerTy(FullWidth))
+ return false;
+
+ // LoResult: cttz(trunc(SrcVal), _), must use same truncated value
+ Value *LoCttzArg;
+ if (!match(LoResult, m_OneUse(m_Intrinsic<Intrinsic::cttz>(m_Value(LoCttzArg),
+ m_Value()))))
+ return false;
+ if (LoCttzArg != LoTrunc)
----------------
topperc wrote:
Can we use a m_Specific in the previous match to avoid this check?
https://github.com/llvm/llvm-project/pull/192296
More information about the llvm-commits
mailing list