[llvm] [VectorCombine] Fold scalar selects from bitcast into vector select (PR #173990)
Pankaj Dwivedi via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 7 04:27:39 PST 2026
================
@@ -1546,6 +1547,121 @@ bool VectorCombine::foldExtractedCmps(Instruction &I) {
return true;
}
+/// Try to fold scalar selects that select between extracted elements and zero
+/// into extracting from a vector select. This is rooted at the bitcast.
+///
+/// This pattern arises when a vector is bitcast to a smaller element type,
+/// elements are extracted, and then conditionally selected with zero:
+///
+/// %bc = bitcast <4 x i32> %src to <16 x i8>
+/// %e0 = extractelement <16 x i8> %bc, i32 0
+/// %s0 = select i1 %cond, i8 %e0, i8 0
+/// %e1 = extractelement <16 x i8> %bc, i32 1
+/// %s1 = select i1 %cond, i8 %e1, i8 0
+/// ...
+///
+/// Transforms to:
+/// %sel = select i1 %cond, <4 x i32> %src, <4 x i32> zeroinitializer
+/// %bc = bitcast <4 x i32> %sel to <16 x i8>
+/// %e0 = extractelement <16 x i8> %bc, i32 0
+/// %e1 = extractelement <16 x i8> %bc, i32 1
+/// ...
+///
+/// This is profitable because vector select on wider types produces fewer
+/// select/cndmask instructions than scalar selects on each element.
+bool VectorCombine::foldSelectsFromBitcast(Instruction &I) {
+ auto *BC = dyn_cast<BitCastInst>(&I);
+ if (!BC)
+ return false;
+
+ auto *SrcVecTy = dyn_cast<FixedVectorType>(BC->getSrcTy());
+ auto *DstVecTy = dyn_cast<FixedVectorType>(BC->getDestTy());
+ if (!SrcVecTy || !DstVecTy)
+ return false;
+
+ // Source must be 32-bit or 64-bit elements, destination must be smaller
+ // integer elements. Zero in all these types is all-bits-zero.
+ Type *SrcEltTy = SrcVecTy->getElementType();
+ Type *DstEltTy = DstVecTy->getElementType();
+ unsigned SrcEltBits = SrcEltTy->getPrimitiveSizeInBits();
+ unsigned DstEltBits = DstEltTy->getPrimitiveSizeInBits();
+
+ if (SrcEltBits != 32 && SrcEltBits != 64)
+ return false;
+
+ if (!DstEltTy->isIntegerTy() || DstEltBits >= SrcEltBits)
+ return false;
+
+ // Collect all select users that match the pattern, grouped by condition.
+ // Pattern: select i1 %cond, (extractelement %bc, idx), 0
+ DenseMap<Value *, SmallVector<SelectInst *, 8>> CondToSelects;
+
+ for (User *U : BC->users()) {
+ auto *Ext = dyn_cast<ExtractElementInst>(U);
+ if (!Ext)
+ continue;
+
+ for (User *ExtUser : Ext->users()) {
+ Value *Cond;
+ // Match: select i1 %cond, %ext, 0
+ if (match(ExtUser, m_Select(m_Value(Cond), m_Specific(Ext), m_Zero())) &&
+ Cond->getType()->isIntegerTy(1))
+ CondToSelects[Cond].push_back(cast<SelectInst>(ExtUser));
+ }
+ }
+
+ if (CondToSelects.empty())
+ return false;
+
+ // Check profitability using TTI.
+ auto *CondTy = CmpInst::makeCmpResultType(DstEltTy);
+ auto *VecCondTy = CmpInst::makeCmpResultType(SrcVecTy);
+
+ InstructionCost ScalarSelCost =
+ TTI.getCmpSelInstrCost(Instruction::Select, DstEltTy, CondTy,
+ CmpInst::BAD_ICMP_PREDICATE, CostKind);
+ InstructionCost VecSelCost =
+ TTI.getCmpSelInstrCost(Instruction::Select, SrcVecTy, VecCondTy,
+ CmpInst::BAD_ICMP_PREDICATE, CostKind);
+
+ bool MadeChange = false;
+ Value *SrcVec = BC->getOperand(0);
+
+ // Process each group of selects with the same condition.
+ for (auto &[Cond, Selects] : CondToSelects) {
+ // Only profitable if vector select cost < total scalar select cost.
+ if (VecSelCost >= ScalarSelCost * Selects.size()) {
----------------
PankajDwivedi-25 wrote:
Yes, makes sense.
https://github.com/llvm/llvm-project/pull/173990
More information about the llvm-commits
mailing list