@@ -294,6 +294,10 @@ class ConstantOffsetExtractor {
294
294
bool CanTraceInto (bool SignExtended, bool ZeroExtended, BinaryOperator *BO,
295
295
bool NonNegative);
296
296
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
+
297
301
// / The path from the constant offset to the old GEP index. e.g., if the GEP
298
302
// / index is "a * b + (c + 5)". After running function find, UserChain[0] will
299
303
// / be the constant 5, UserChain[1] will be the subexpression "c + 5", and
@@ -596,6 +600,9 @@ APInt ConstantOffsetExtractor::find(Value *V, bool SignExtended,
596
600
// Trace into subexpressions for more hoisting opportunities.
597
601
if (CanTraceInto (SignExtended, ZeroExtended, BO, NonNegative))
598
602
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);
599
606
} else if (isa<TruncInst>(V)) {
600
607
ConstantOffset =
601
608
find (U->getOperand (0 ), SignExtended, ZeroExtended, NonNegative)
@@ -708,11 +715,20 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
708
715
Value *NextInChain = removeConstOffset (ChainIndex - 1 );
709
716
Value *TheOther = BO->getOperand (1 - OpNo);
710
717
711
- // If NextInChain is 0 and not the LHS of a sub, we can simplify the
712
- // sub-expression to be just TheOther.
713
718
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
+ }
716
732
}
717
733
718
734
BinaryOperator::BinaryOps NewOp = BO->getOpcode ();
@@ -743,6 +759,67 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
743
759
return NewBO;
744
760
}
745
761
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
+
746
823
// / A helper function to check if reassociating through an entry in the user
747
824
// / chain would invalidate the GEP's nuw flag.
748
825
static bool allowsPreservingNUW (const User *U) {
0 commit comments