@@ -294,6 +294,10 @@ class ConstantOffsetExtractor {
294294 bool CanTraceInto (bool SignExtended, bool ZeroExtended, BinaryOperator *BO,
295295 bool NonNegative);
296296
297+ // / Analyze XOR instruction to extract disjoint constant bits that behave
298+ // / like addition operations for improved address mode folding.
299+ APInt extractDisjointBitsFromXor (BinaryOperator *XorInst);
300+
297301 // / The path from the constant offset to the old GEP index. e.g., if the GEP
298302 // / index is "a * b + (c + 5)". After running function find, UserChain[0] will
299303 // / be the constant 5, UserChain[1] will be the subexpression "c + 5", and
@@ -596,6 +600,9 @@ APInt ConstantOffsetExtractor::find(Value *V, bool SignExtended,
596600 // Trace into subexpressions for more hoisting opportunities.
597601 if (CanTraceInto (SignExtended, ZeroExtended, BO, NonNegative))
598602 ConstantOffset = findInEitherOperand (BO, SignExtended, ZeroExtended);
603+ // Handle XOR with disjoint bits that can be treated as addition.
604+ else if (BO->getOpcode () == Instruction::Xor)
605+ ConstantOffset = extractDisjointBitsFromXor (BO);
599606 } else if (isa<TruncInst>(V)) {
600607 ConstantOffset =
601608 find (U->getOperand (0 ), SignExtended, ZeroExtended, NonNegative)
@@ -708,11 +715,20 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
708715 Value *NextInChain = removeConstOffset (ChainIndex - 1 );
709716 Value *TheOther = BO->getOperand (1 - OpNo);
710717
711- // If NextInChain is 0 and not the LHS of a sub, we can simplify the
712- // sub-expression to be just TheOther.
713718 if (ConstantInt *CI = dyn_cast<ConstantInt>(NextInChain)) {
714- if (CI->isZero () && !(BO->getOpcode () == Instruction::Sub && OpNo == 0 ))
715- return TheOther;
719+ if (CI->isZero ()) {
720+ // Custom XOR handling for disjoint bits - preserves original XOR
721+ // with non-disjoint constant bits.
722+ // TODO: The design should be updated to support partial constant
723+ // extraction.
724+ if (BO->getOpcode () == Instruction::Xor)
725+ return BO;
726+
727+ // If NextInChain is 0 and not the LHS of a sub, we can simplify the
728+ // sub-expression to be just TheOther.
729+ if (!(BO->getOpcode () == Instruction::Sub && OpNo == 0 ))
730+ return TheOther;
731+ }
716732 }
717733
718734 BinaryOperator::BinaryOps NewOp = BO->getOpcode ();
@@ -743,6 +759,67 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
743759 return NewBO;
744760}
745761
762+ // / Analyze XOR instruction to extract disjoint constant bits for address
763+ // / folding
764+ // /
765+ // / This function identifies bits in an XOR constant operand that are disjoint
766+ // / from the base operand's known set bits. For these disjoint bits, XOR behaves
767+ // / identically to addition, allowing us to extract them as constant offsets
768+ // / that can be folded into addressing modes.
769+ // /
770+ // / Transformation: `Base ^ Const` becomes `(Base ^ NonDisjointBits) +
771+ // / DisjointBits` where DisjointBits = Const & KnownZeros(Base)
772+ // /
773+ // / Example with ptr having known-zero low bit:
774+ // / Original: `xor %ptr, 3` ; 3 = 0b11
775+ // / Analysis: DisjointBits = 3 & KnownZeros(%ptr) = 0b11 & 0b01 = 0b01
776+ // / Result: `(xor %ptr, 2) + 1` where 1 can be folded into address mode
777+ // /
778+ // / \param XorInst The XOR binary operator to analyze
779+ // / \return APInt containing the disjoint bits that can be extracted as offset,
780+ // / or zero if no disjoint bits exist
781+ APInt ConstantOffsetExtractor::extractDisjointBitsFromXor (
782+ BinaryOperator *XorInst) {
783+ assert (XorInst && XorInst->getOpcode () == Instruction::Xor &&
784+ " Expected XOR instruction" );
785+
786+ const unsigned BitWidth = XorInst->getType ()->getScalarSizeInBits ();
787+ Value *BaseOperand;
788+ ConstantInt *XorConstant;
789+
790+ // Match pattern: xor BaseOperand, Constant.
791+ if (!match (XorInst, m_Xor (m_Value (BaseOperand), m_ConstantInt (XorConstant))))
792+ return APInt::getZero (BitWidth);
793+
794+ // Compute known bits for the base operand.
795+ const SimplifyQuery SQ (DL);
796+ const KnownBits BaseKnownBits = computeKnownBits (BaseOperand, SQ);
797+ const APInt &ConstantValue = XorConstant->getValue ();
798+
799+ // Identify disjoint bits: constant bits that are known zero in base.
800+ const APInt DisjointBits = ConstantValue & BaseKnownBits.Zero ;
801+
802+ // Early exit if no disjoint bits found.
803+ if (DisjointBits.isZero ())
804+ return APInt::getZero (BitWidth);
805+
806+ // Compute the remaining non-disjoint bits that stay in the XOR.
807+ const APInt NonDisjointBits = ConstantValue & ~DisjointBits;
808+
809+ // FIXME: Enhance XOR constant extraction to handle nested binary operations.
810+ // Currently we only extract disjoint bits from the immediate XOR constant,
811+ // but we could recursively process cases like:
812+ // xor (add %base, C1), C2 -> add %base, (C1 ^ disjoint_bits(C2))
813+ // This requires careful analysis to ensure the transformation preserves
814+ // semantics, particularly around sign extension and overflow behavior.
815+
816+ // Add the non-disjoint constant to the user chain for later transformation
817+ // This will replace the original constant in the XOR with the new
818+ // constant.
819+ UserChain.push_back (ConstantInt::get (XorInst->getType (), NonDisjointBits));
820+ return DisjointBits;
821+ }
822+
746823// / A helper function to check if reassociating through an entry in the user
747824// / chain would invalidate the GEP's nuw flag.
748825static bool allowsPreservingNUW (const User *U) {
0 commit comments