[llvm] [InstCombine] Lower flag check pattern to use a bitmask-shift (PR #169557)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 2 21:25:34 PST 2025
================
@@ -3119,6 +3119,127 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC) {
return nullptr;
}
+static Value *combineOrOfImmCmpToBitExtract(Instruction &Or,
+ InstCombiner::BuilderTy &Builder,
+ const DataLayout &DL) {
+
+ auto isICmpEqImm = [](Value *N, ConstantInt *&Imm, Value *&X) -> bool {
+ if (X)
+ return match(N, m_OneUse(m_SpecificICmp(ICmpInst::ICMP_EQ, m_Specific(X),
+ m_ConstantInt(Imm))));
+
+ return match(N, m_OneUse(m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(X),
+ m_ConstantInt(Imm))));
+ };
+
+ // %srl = lshr %bitmap, %X
+ // %icmp = icmp ult %X, %max_value
+ // %trunc = trunc %srl to i1
+ // %sel = select %icmp, %trunc, false
+ auto CreateBitExtractSeq = [&](APInt BitMap, APInt MaxValue,
+ Value *X) -> Value * {
+ LLVMContext &Context = Or.getContext();
+
+ // %srl = lshr %bitmap, %X
+ // It is okay for the shift amount to be truncated because
+ // if information is lost then it is garunteed to fail the bounds
+ // check and the shift result will be discarded
+ ConstantInt *BitMapConst = ConstantInt::get(Context, BitMap);
+ Value *ShiftAmt =
+ Builder.CreateZExtOrTrunc(X, BitMapConst->getIntegerType());
+ Value *LShr = Builder.CreateLShr(BitMapConst, ShiftAmt);
+
+ // %icmp = icmp ult %X, %max_value
+ // Use the type that is the larger of 'X' and the bounds integer
+ // so that no information is lost
+ Value *MaxVal = ConstantInt::get(Context, MaxValue);
+ if (MaxVal->getType()->getIntegerBitWidth() >
+ X->getType()->getIntegerBitWidth())
+ X = Builder.CreateZExt(X, MaxVal->getType());
+ else
+ MaxVal = Builder.CreateZExt(MaxVal, X->getType());
+ Value *BoundsCheck = Builder.CreateICmp(ICmpInst::ICMP_ULT, X, MaxVal);
+
+ // %trunc = trunc %srl to i1
+ // Only care about the low bit
+ Value *ShrTrunc = Builder.CreateTrunc(LShr, IntegerType::get(Context, 1));
+
+ // %sel = select %icmp, %trunc, false
+ return Builder.CreateSelect(BoundsCheck, ShrTrunc,
+ ConstantInt::getFalse(Context));
+ };
+
+ // Our BitMap should be able to fit into a single arch register
+ // otherwise the tranformation won't be profitable
+ unsigned XLen = DL.getLargestLegalIntTypeSizeInBits();
+ auto validImm = [&](APInt APImm) -> bool {
+ auto Imm = APImm.tryZExtValue();
+ return Imm && (*Imm < XLen);
+ };
+
+ // Match (or (icmp eq X, Imm0), (icmp eq X, Imm1))
+ ConstantInt *LHS, *RHS;
+ Value *X = nullptr;
+ if (isICmpEqImm(Or.getOperand(0), LHS, X) &&
+ isICmpEqImm(Or.getOperand(1), RHS, X)) {
+ // The Shr with become poison when shifted by Undef
+ if (!isGuaranteedNotToBeUndefOrPoison(X))
+ return nullptr;
+
+ APInt LHSAP = LHS->getValue();
+ APInt RHSAP = RHS->getValue();
+ if (!validImm(LHSAP) || !validImm(RHSAP))
+ return nullptr;
+ LHSAP = LHSAP.zextOrTrunc(XLen);
+ RHSAP = RHSAP.zextOrTrunc(XLen);
+
+ // Create the BitMap and Bounds check immediates
+ // +1 to bound becuase strictly less than
+ APInt BitMap = (APInt(XLen, 1) << LHSAP) | (APInt(XLen, 1) << RHSAP);
+ APInt Bound = RHSAP.ugt(LHSAP) ? RHSAP : LHSAP;
+ return CreateBitExtractSeq(BitMap, Bound + 1, X);
+ }
+
+ // Expand an already existing BitMap sequence
+ // Match: (or (%BitMapSeq(X)), (icmp eq X, Imm))
+ ConstantInt *BitMap, *Bound, *CmpImm;
+ Value *Cmp;
+ if (match(&Or, m_OneUse(m_c_Or(m_Value(Cmp),
+ m_OneUse(m_Select(
+ m_SpecificICmp(ICmpInst::ICMP_ULT,
+ m_ZExtOrSelf(m_Value(X)),
+ m_ConstantInt(Bound)),
+ m_OneUse(m_Trunc(m_OneUse(m_Shr(
+ m_ConstantInt(BitMap),
+ m_ZExtOrTruncOrSelf(m_Deferred(X)))))),
+ m_Zero()))))) &&
+ isICmpEqImm(Cmp, CmpImm, X)) {
+ if (!isGuaranteedNotToBeUndefOrPoison(X))
+ return nullptr;
+
+ APInt NewAP = CmpImm->getValue();
+ APInt BitMapAP = BitMap->getValue();
+ APInt BoundAP = Bound->getValue().zextOrTrunc(XLen);
+ // BitMap must fit in native arch register
+ if (!validImm(NewAP) || !DL.fitsInLegalInteger(BitMapAP.getActiveBits()))
+ return nullptr;
+
+ NewAP = NewAP.zextOrTrunc(XLen);
----------------
topperc wrote:
Can we convert NewAP to an `unsigned` here since we know it is smaller than `XLen`? That would allow `BitMapAP |= (APInt(XLen, 1) << NewAP)` later to be replaced with `BitMapAP.setBit(NewAP)`.
https://github.com/llvm/llvm-project/pull/169557
More information about the llvm-commits
mailing list