Skip to content

Commit d84eb12

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 b6f502d commit d84eb12

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
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: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17194,8 +17194,47 @@ 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 Is12BitConstant = [](const SDValue &Op) -> bool {
17200+
if (Op.getOpcode() == ISD::Constant) {
17201+
const int64_t RiscvAluImmBits = 12;
17202+
const int64_t RiscvAluImmUpperBound = (1 << RiscvAluImmBits) - 1;
17203+
const int64_t RiscvAluImmLowerBound = -(1 << RiscvAluImmBits);
17204+
const int64_t XorCnst =
17205+
llvm::dyn_cast<llvm::ConstantSDNode>(Op)->getSExtValue();
17206+
return (XorCnst >= RiscvAluImmLowerBound) &&
17207+
(XorCnst <= RiscvAluImmUpperBound);
17208+
}
17209+
return false;
17210+
};
17211+
// Fold (X(i1) ^ 1) == 0 -> X != 0
17212+
auto SingleBitOp = [&DAG](const SDValue &VarOp,
17213+
const SDValue &ConstOp) -> bool {
17214+
if (ConstOp.getOpcode() == ISD::Constant) {
17215+
const int64_t XorCnst =
17216+
llvm::dyn_cast<llvm::ConstantSDNode>(ConstOp)->getSExtValue();
17217+
const APInt Mask = APInt::getBitsSetFrom(VarOp.getValueSizeInBits(), 1);
17218+
return (XorCnst == 1) && DAG.MaskedValueIsZero(VarOp, Mask);
17219+
}
17220+
return false;
17221+
};
17222+
auto OnlyUsedBySelectOrBR = [](const SDValue &Op) -> bool {
17223+
for (const SDUse &Use : Op->uses()) {
17224+
const SDNode *UseNode = Use.getUser();
17225+
const unsigned Opcode = UseNode->getOpcode();
17226+
if (Opcode != RISCVISD::SELECT_CC && Opcode != RISCVISD::BR_CC) {
17227+
return false;
17228+
}
17229+
}
17230+
return true;
17231+
};
17232+
1719717233
// Fold ((xor X, Y), 0, eq/ne) -> (X, Y, eq/ne)
17198-
if (LHS.getOpcode() == ISD::XOR && isNullConstant(RHS)) {
17234+
if (LHS.getOpcode() == ISD::XOR && isNullConstant(RHS) &&
17235+
(!Is12BitConstant(LHS.getOperand(1)) ||
17236+
SingleBitOp(LHS.getOperand(0), LHS.getOperand(1))) &&
17237+
OnlyUsedBySelectOrBR(LHS)) {
1719917238
RHS = LHS.getOperand(1);
1720017239
LHS = LHS.getOperand(0);
1720117240
return true;

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,43 @@ define i32 @oneusecmp(i32 %a, i32 %b, i32 %d) {
239239
%x = add i32 %s, %s2
240240
ret i32 %x
241241
}
242+
243+
define i32 @xor_branch_ret(i32 %x) {
244+
; RV32-LABEL: xor_branch_ret:
245+
; RV32: # %bb.0: # %entry
246+
; RV32-NEXT: xori a0, a0, -1365
247+
; RV32-NEXT: beqz a0, .LBB11_2
248+
; RV32-NEXT: # %bb.1: # %if.then
249+
; RV32-NEXT: ret
250+
; RV32-NEXT: .LBB11_2: # %if.end
251+
; RV32-NEXT: addi sp, sp, -16
252+
; RV32-NEXT: .cfi_def_cfa_offset 16
253+
; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
254+
; RV32-NEXT: .cfi_offset ra, -4
255+
; RV32-NEXT: call abort
256+
;
257+
; RV64-LABEL: xor_branch_ret:
258+
; RV64: # %bb.0: # %entry
259+
; RV64-NEXT: xori a0, a0, -1365
260+
; RV64-NEXT: sext.w a1, a0
261+
; RV64-NEXT: beqz a1, .LBB11_2
262+
; RV64-NEXT: # %bb.1: # %if.then
263+
; RV64-NEXT: ret
264+
; RV64-NEXT: .LBB11_2: # %if.end
265+
; RV64-NEXT: addi sp, sp, -16
266+
; RV64-NEXT: .cfi_def_cfa_offset 16
267+
; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
268+
; RV64-NEXT: .cfi_offset ra, -8
269+
; RV64-NEXT: call abort
270+
entry:
271+
%cmp.not = icmp eq i32 %x, -1365
272+
br i1 %cmp.not, label %if.end, label %if.then
273+
if.then:
274+
%xor = xor i32 %x, -1365
275+
ret i32 %xor
276+
if.end:
277+
tail call void @abort() #2
278+
unreachable
279+
}
280+
281+
declare void @abort()

0 commit comments

Comments
 (0)