[llvm] [SeparateConstOffsetFromGEP] Decompose constant xor operand if possible (PR #150438)

Jeffrey Byrnes via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 29 19:16:52 PDT 2025


================
@@ -514,12 +518,14 @@ bool ConstantOffsetExtractor::CanTraceInto(bool SignExtended,
                                             bool ZeroExtended,
                                             BinaryOperator *BO,
                                             bool NonNegative) {
-  // We only consider ADD, SUB and OR, because a non-zero constant found in
+  // We only consider ADD, SUB, OR and XOR, because a non-zero constant found in
   // expressions composed of these operations can be easily hoisted as a
-  // constant offset by reassociation.
+  // constant offset by reassociation. XOR is a special case and can be folded
+  // in to gep if the constant is proven to be disjoint.
   if (BO->getOpcode() != Instruction::Add &&
       BO->getOpcode() != Instruction::Sub &&
-      BO->getOpcode() != Instruction::Or) {
+      BO->getOpcode() != Instruction::Or &&
+      BO->getOpcode() != Instruction::Xor) {
----------------
jrbyrnes wrote:

Actually, I don't think we should be whitelisting Xor in `CanTraceInto` as this will tell `find` to continue looking into the operands of the Xor. 

Also, doing the custom extraction during `CanTraceInto` will bypass some profitability checks between the point where we check what the extractable offset is, and the point where we commit to this extraction.

Instead, I think that we should have special handling for Xors in `find`. Something like this:

```
  } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(V)) {
    // Trace into subexpressions for more hoisting opportunities.
    bool IsXor = BO->getOpcode() == Instruction::Xor;
    if (CanTraceInto(SignExtended, ZeroExtended, BO, NonNegative))
      ConstantOffset = findInEitherOperand(BO, SignExtended, ZeroExtended);
      if (BO->getOpcode() == Instruction::Xor) {
        Value *BaseOperand;
        ConstantInt *XorConst;
        if (match(BO, m_Xor(m_Value(BaseOperand), m_ConstantInt(XorConst)))) {
          const SimplifyQuery SQ(DL);
          const KnownBits BaseKnown = computeKnownBits(BaseOperand, SQ);
          const APInt &ConstValue = XorConst->getValue();
          UserChain.push_back(dyn_cast<User>(BO->getOperand(1)));

          // Check if any bits of the constant can be treated as disjoint
          // (addition-like).
          ConstantOffset = ConstValue & BaseKnown.Zero;
        }
      }
  }
```

I'm not sure if we should be adding the constant to the user chain at the point of analyzing the xor, but I think that's more of a stylistic concern. Passing the constant operand to `find` is more in-line with the general algorithm, and will add the constant to the user chain, just seems like an unnecessary function call.

This should work well with `rebuildWithoutConstOffset` to fold out the constant from the chain.

https://github.com/llvm/llvm-project/pull/150438


More information about the llvm-commits mailing list