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); _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
