Skip to content

Commit bdf57a5

Browse files
committed
Combine (X ^ Y) and (X == Y) where appropriate
In RISCV, modify the folding of (X ^ Y == 0) -> (X == Y) to account for cases where the (X ^ Y) will be re-used. Fixes #130510.
1 parent 96a1b82 commit bdf57a5

File tree

3 files changed

+54
-9
lines changed

3 files changed

+54
-9
lines changed

llvm/lib/CodeGen/CodeGenPrepare.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8578,7 +8578,8 @@ static bool optimizeBranch(BranchInst *Branch, const TargetLowering &TLI,
85788578
}
85798579
if (Cmp->isEquality() &&
85808580
(match(UI, m_Add(m_Specific(X), m_SpecificInt(-CmpC))) ||
8581-
match(UI, m_Sub(m_Specific(X), m_SpecificInt(CmpC))))) {
8581+
match(UI, m_Sub(m_Specific(X), m_SpecificInt(CmpC))) ||
8582+
match(UI, m_Xor(m_Specific(X), m_SpecificInt(CmpC))))) {
85828583
IRBuilder<> Builder(Branch);
85838584
if (UI->getParent() != Branch->getParent())
85848585
UI->moveBefore(Branch->getIterator());

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17194,12 +17194,58 @@ static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
1719417194
return true;
1719517195
}
1719617196

17197+
// If XOR is reused and has an immediate that will fit in XORI,
17198+
// do not fold.
17199+
auto IsXorImmediate = [](const SDValue &Op) -> bool {
17200+
if (const auto XorCnst = dyn_cast<ConstantSDNode>(Op))
17201+
return isInt<12>(XorCnst->getSExtValue());
17202+
return false;
17203+
};
17204+
// Fold (X(i1) ^ 1) == 0 -> X != 0
17205+
auto SingleBitOp = [&DAG](const SDValue &VarOp,
17206+
const SDValue &ConstOp) -> bool {
17207+
if (const auto XorCnst = dyn_cast<ConstantSDNode>(ConstOp)) {
17208+
const APInt Mask = APInt::getBitsSetFrom(VarOp.getValueSizeInBits(), 1);
17209+
return (XorCnst->getSExtValue() == 1) &&
17210+
DAG.MaskedValueIsZero(VarOp, Mask);
17211+
}
17212+
return false;
17213+
};
17214+
auto OnlyUsedBySelectOrBR = [](const SDValue &Op) -> bool {
17215+
for (const SDNode *UserNode : Op->users()) {
17216+
const unsigned Opcode = UserNode->getOpcode();
17217+
if (Opcode != RISCVISD::SELECT_CC && Opcode != RISCVISD::BR_CC)
17218+
return false;
17219+
}
17220+
return true;
17221+
};
17222+
auto IsFoldableXorEq = [IsXorImmediate, SingleBitOp, OnlyUsedBySelectOrBR](
17223+
const SDValue &LHS, const SDValue &RHS) -> bool {
17224+
return LHS.getOpcode() == ISD::XOR && isNullConstant(RHS) &&
17225+
(!IsXorImmediate(LHS.getOperand(1)) ||
17226+
SingleBitOp(LHS.getOperand(0), LHS.getOperand(1)) ||
17227+
OnlyUsedBySelectOrBR(LHS));
17228+
};
1719717229
// Fold ((xor X, Y), 0, eq/ne) -> (X, Y, eq/ne)
17198-
if (LHS.getOpcode() == ISD::XOR && isNullConstant(RHS)) {
17230+
if (IsFoldableXorEq(LHS, RHS)) {
1719917231
RHS = LHS.getOperand(1);
1720017232
LHS = LHS.getOperand(0);
1720117233
return true;
1720217234
}
17235+
// Fold ((sext (xor X, C)), 0, eq/ne) -> ((sext(X), C, eq/ne)
17236+
if (LHS.getOpcode() == ISD::SIGN_EXTEND_INREG) {
17237+
const SDValue LHS0 = LHS.getOperand(0);
17238+
if (IsFoldableXorEq(LHS0, RHS) && isa<ConstantSDNode>(LHS0.getOperand(1))) {
17239+
// SEXT(XOR(X, Y)) -> XOR(SEXT(X), SEXT(Y)))
17240+
RHS = DAG.getNode(
17241+
ISD::SIGN_EXTEND_INREG, DL, LHS.getValueType(), LHS0.getOperand(1),
17242+
DAG.getValueType(cast<VTSDNode>(LHS.getOperand(1))->getVT()));
17243+
LHS = DAG.getNode(
17244+
ISD::SIGN_EXTEND_INREG, DL, LHS.getValueType(), LHS0.getOperand(0),
17245+
DAG.getValueType(cast<VTSDNode>(LHS.getOperand(1))->getVT()));
17246+
return true;
17247+
}
17248+
}
1720317249

1720417250
// Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, XLen-1-C), 0, ge/lt)
1720517251
if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&

llvm/test/CodeGen/RISCV/select-constant-xor.ll

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,9 @@ define i32 @oneusecmp(i32 %a, i32 %b, i32 %d) {
243243
define i32 @xor_branch_imm_ret(i32 %x) {
244244
; RV32-LABEL: xor_branch_imm_ret:
245245
; RV32: # %bb.0: # %entry
246-
; RV32-NEXT: li a1, -1365
247-
; RV32-NEXT: beq a0, a1, .LBB11_2
248-
; RV32-NEXT: # %bb.1: # %if.then
249246
; RV32-NEXT: xori a0, a0, -1365
247+
; RV32-NEXT: beqz a0, .LBB11_2
248+
; RV32-NEXT: # %bb.1: # %if.then
250249
; RV32-NEXT: ret
251250
; RV32-NEXT: .LBB11_2: # %if.end
252251
; RV32-NEXT: addi sp, sp, -16
@@ -257,11 +256,10 @@ define i32 @xor_branch_imm_ret(i32 %x) {
257256
;
258257
; RV64-LABEL: xor_branch_imm_ret:
259258
; RV64: # %bb.0: # %entry
259+
; RV64-NEXT: xori a0, a0, -1365
260260
; RV64-NEXT: sext.w a1, a0
261-
; RV64-NEXT: li a2, -1365
262-
; RV64-NEXT: beq a1, a2, .LBB11_2
261+
; RV64-NEXT: beqz a1, .LBB11_2
263262
; RV64-NEXT: # %bb.1: # %if.then
264-
; RV64-NEXT: xori a0, a0, -1365
265263
; RV64-NEXT: ret
266264
; RV64-NEXT: .LBB11_2: # %if.end
267265
; RV64-NEXT: addi sp, sp, -16
@@ -298,9 +296,9 @@ define i32 @xor_branch_ret(i32 %x) {
298296
;
299297
; RV64-LABEL: xor_branch_ret:
300298
; RV64: # %bb.0: # %entry
301-
; RV64-NEXT: sext.w a2, a0
302299
; RV64-NEXT: li a1, 1
303300
; RV64-NEXT: slli a1, a1, 11
301+
; RV64-NEXT: sext.w a2, a0
304302
; RV64-NEXT: beq a2, a1, .LBB12_2
305303
; RV64-NEXT: # %bb.1: # %if.then
306304
; RV64-NEXT: xor a0, a0, a1

0 commit comments

Comments
 (0)