[llvm] [SeparateConstOffsetFromGEP] Decompose constant xor operand if possible (PR #150438)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 13 16:27:04 PDT 2025
================
@@ -743,6 +759,67 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
return NewBO;
}
+/// Analyze XOR instruction to extract disjoint constant bits for address
+/// folding
+///
+/// This function identifies bits in an XOR constant operand that are disjoint
+/// from the base operand's known set bits. For these disjoint bits, XOR behaves
+/// identically to addition, allowing us to extract them as constant offsets
+/// that can be folded into addressing modes.
+///
+/// Transformation: `Base ^ Const` becomes `(Base ^ NonDisjointBits) +
+/// DisjointBits` where DisjointBits = Const & KnownZeros(Base)
+///
+/// Example with ptr having known-zero low bit:
+/// Original: `xor %ptr, 3` ; 3 = 0b11
+/// Analysis: DisjointBits = 3 & KnownZeros(%ptr) = 0b11 & 0b01 = 0b01
+/// Result: `(xor %ptr, 2) + 1` where 1 can be folded into address mode
+///
+/// \param XorInst The XOR binary operator to analyze
+/// \return APInt containing the disjoint bits that can be extracted as offset,
+/// or zero if no disjoint bits exist
+APInt ConstantOffsetExtractor::extractDisjointBitsFromXor(
+ BinaryOperator *XorInst) {
+ assert(XorInst && XorInst->getOpcode() == Instruction::Xor &&
+ "Expected XOR instruction");
+
+ const unsigned BitWidth = XorInst->getType()->getScalarSizeInBits();
+ Value *BaseOperand;
+ ConstantInt *XorConstant;
+
+ // Match pattern: xor BaseOperand, Constant.
+ if (!match(XorInst, m_Xor(m_Value(BaseOperand), m_ConstantInt(XorConstant))))
+ return APInt::getZero(BitWidth);
+
+ // Compute known bits for the base operand.
+ const SimplifyQuery SQ(DL);
+ const KnownBits BaseKnownBits = computeKnownBits(BaseOperand, SQ);
+ const APInt &ConstantValue = XorConstant->getValue();
+
+ // Identify disjoint bits: constant bits that are known zero in base.
+ const APInt DisjointBits = ConstantValue & BaseKnownBits.Zero;
+
+ // Early exit if no disjoint bits found.
+ if (DisjointBits.isZero())
+ return APInt::getZero(BitWidth);
+
+ // Compute the remaining non-disjoint bits that stay in the XOR.
+ const APInt NonDisjointBits = ConstantValue & ~DisjointBits;
+
+ // FIXME: Enhance XOR constant extraction to handle nested binary operations.
+ // Currently we only extract disjoint bits from the immediate XOR constant,
+ // but we could recursively process cases like:
+ // xor (add %base, C1), C2 -> add %base, (C1 ^ disjoint_bits(C2))
+ // This requires careful analysis to ensure the transformation preserves
+ // semantics, particularly around sign extension and overflow behavior.
+
+ // Add the non-disjoint constant to the user chain for later transformation
+ // This will replace the original constant in the XOR with the new
+ // constant.
+ UserChain.push_back(ConstantInt::get(XorInst->getType(), NonDisjointBits));
----------------
arsenm wrote:
The caller seems like it's already trying to add this to UserChain, based on the constant being 0 already. Can this whole thing just fold to return DisjointBits above?
https://github.com/llvm/llvm-project/pull/150438
More information about the llvm-commits
mailing list