[llvm-branch-commits] [llvm] ad35cfe - [AggressiveInstCombine] Factor out the beginning of foldSelectSplitCTTZ/CTLZ into common entry point. NFC (#206220)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Jun 27 08:58:19 PDT 2026
Author: Craig Topper
Date: 2026-06-27T08:13:26-07:00
New Revision: ad35cfed2d2bd8a373ced8bd7d91e1505ba99d17
URL: https://github.com/llvm/llvm-project/commit/ad35cfed2d2bd8a373ced8bd7d91e1505ba99d17
DIFF: https://github.com/llvm/llvm-project/commit/ad35cfed2d2bd8a373ced8bd7d91e1505ba99d17.diff
LOG: [AggressiveInstCombine] Factor out the beginning of foldSelectSplitCTTZ/CTLZ into common entry point. NFC (#206220)
Both start by matching a select and a eq/ne compare with 0.
Assisted-by: claude
Added:
Modified:
llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
index b3a89f5e16258..59b00ea5e8018 100644
--- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
+++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
@@ -86,40 +86,12 @@ static cl::opt<unsigned>
/// %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;
+// TrueVal/FalseVal are pre-normalized by the caller to the EQ/NE cases.
+static bool foldSelectSplitCTTZ(Instruction &I, Value *LoTrunc, Value *HiResult,
+ Value *LoResult, Type *HalfTy) {
unsigned HalfWidth = HalfTy->getIntegerBitWidth();
-
- // Bail out on very small types (i1, i2): the full-width cttz can return
- // values not representable in the half type (e.g., cttz.i4 can return 4,
- // which doesn't fit in i2).
- if (HalfWidth <= 2)
- return false;
-
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))))
@@ -171,51 +143,20 @@ static bool foldSelectSplitCTTZ(Instruction &I) {
/// %result = trunc iN %ctlz_wide to i(N/2)
///
/// Alive proof (for i64/i32): https://alive2.llvm.org/ce/z/WfQepH
-static bool foldSelectSplitCTLZ(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;
+// TrueVal/FalseVal are pre-normalized by the caller to the EQ/NE cases.
+static bool foldSelectSplitCTLZ(Instruction &I, Value *HiPart, Value *LoResult,
+ Value *HiResult, Type *HalfTy) {
unsigned HalfWidth = HalfTy->getIntegerBitWidth();
-
- // Bail out on very small types (i1, i2): the full-width ctlz can return
- // values not representable in the half type (e.g., ctlz.i4 can return 4,
- // which doesn't fit in i2).
- if (HalfWidth <= 2)
- return false;
-
unsigned FullWidth = HalfWidth * 2;
- // select (icmp eq HiPart, 0), LoResult, HiResult
- // HiPart could be (trunc (lshr SrcVal, N/2) to i(N/2)) or (lshr SrcVal, N/2)
- Value *HiPart;
- Value *LoResult, *HiResult;
- if (match(Cond,
- m_SpecificICmp(CmpInst::ICMP_EQ, m_Value(HiPart), m_ZeroInt()))) {
- LoResult = TrueVal; // upper is zero: count in lower + N/2
- HiResult = FalseVal; // upper non-zero: count in upper
- } else if (match(Cond, m_SpecificICmp(CmpInst::ICMP_NE, m_Value(HiPart),
- m_ZeroInt()))) {
- LoResult = FalseVal;
- HiResult = TrueVal;
- } else {
- return false;
- }
-
// Extract SrcVal from HiPart: either trunc(lshr(SrcVal, N/2)) or
// lshr(SrcVal, N/2)
Value *SrcVal;
- if (match(HiPart,
- m_Trunc(m_LShr(m_Value(SrcVal), m_SpecificInt(HalfWidth))))) {
- // HiPart is trunc(lshr(SrcVal, N/2))
- } else if (match(HiPart, m_LShr(m_Value(SrcVal), m_SpecificInt(HalfWidth)))) {
- // HiPart is lshr(SrcVal, N/2)
- } else {
+ if (match(HiPart, m_Trunc(m_Value(SrcVal))))
+ HiPart = SrcVal;
+
+ if (!match(HiPart, m_LShr(m_Value(SrcVal), m_SpecificInt(HalfWidth))))
return false;
- }
if (!SrcVal->getType()->isIntegerTy(FullWidth))
return false;
@@ -252,6 +193,38 @@ static bool foldSelectSplitCTLZ(Instruction &I) {
return true;
}
+/// Common entry point for folding select-based split cttz/ctlz patterns.
+/// Performs the initial select and type matching shared by both transforms,
+/// then delegates to foldSelectSplitCTTZ and foldSelectSplitCTLZ.
+static bool foldSelectSplitCTLZCTTZ(Instruction &I) {
+ Value *Cond, *TrueVal, *FalseVal;
+ if (!match(&I, m_Select(m_Value(Cond), m_Value(TrueVal), m_Value(FalseVal))))
+ return false;
+
+ Type *Ty = I.getType();
+ if (!Ty->isIntegerTy())
+ return false;
+
+ // Bail out on very small types (i1, i2): the full-width cttz/ctlz can return
+ // values not representable in the half type (e.g., cttz.i4 can return 4,
+ // which doesn't fit in i2).
+ if (Ty->getIntegerBitWidth() <= 2)
+ return false;
+
+ CmpPredicate Pred;
+ Value *CmpOp;
+ if (!match(Cond, m_ICmp(Pred, m_Value(CmpOp), m_ZeroInt())) ||
+ !ICmpInst::isEquality(Pred))
+ return false;
+
+ // Canonicalize select operands.
+ if (Pred == CmpInst::ICMP_NE)
+ std::swap(TrueVal, FalseVal);
+
+ return foldSelectSplitCTTZ(I, CmpOp, TrueVal, FalseVal, Ty) ||
+ foldSelectSplitCTLZ(I, CmpOp, TrueVal, FalseVal, Ty);
+}
+
/// Match a pattern for a bitwise funnel/rotate operation that partially guards
/// against undefined behavior by branching around the funnel-shift/rotation
/// when the shift amount is 0.
@@ -2449,8 +2422,7 @@ static bool foldUnusualPatterns(Function &F, DominatorTree &DT,
for (Instruction &I : make_early_inc_range(llvm::reverse(BB))) {
MadeChange |= foldAnyOrAllBitsSet(I);
MadeChange |= foldGuardedFunnelShift(I, DT);
- MadeChange |= foldSelectSplitCTTZ(I);
- MadeChange |= foldSelectSplitCTLZ(I);
+ MadeChange |= foldSelectSplitCTLZCTTZ(I);
MadeChange |= tryToRecognizePopCount(I);
MadeChange |= tryToRecognizePopCount1(I);
MadeChange |= tryToRecognizePopCount2n3(I);
More information about the llvm-branch-commits
mailing list