[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