[RISCV] Generate QC_INSB/QC_INSBI instructions from OR of AND Imm (#154023)

Generate QC_INSB/QC_INSBI from `or (and X, MaskImm), OrImm` iff the
value being inserted only sets known zero bits. This is based on a
similar DAG to DAG transform done in `AArch64`.
This commit is contained in:
Sudharsan Veeravalli 2025-08-19 11:14:14 +05:30 committed by GitHub
parent 6f7c77fe90
commit c00b04a7e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 262 additions and 0 deletions

View File

@ -713,6 +713,59 @@ bool RISCVDAGToDAGISel::trySignedBitfieldInsertInMask(SDNode *Node) {
return true;
}
// Generate a QC_INSB/QC_INSBI from 'or (and X, MaskImm), OrImm' iff the value
// being inserted only sets known zero bits.
bool RISCVDAGToDAGISel::tryBitfieldInsertOpFromOrAndImm(SDNode *Node) {
// Supported only in Xqcibm for now.
if (!Subtarget->hasVendorXqcibm())
return false;
using namespace SDPatternMatch;
SDValue And;
APInt MaskImm, OrImm;
if (!sd_match(Node, m_Or(m_OneUse(m_And(m_Value(And), m_ConstInt(MaskImm))),
m_ConstInt(OrImm))))
return false;
// Compute the Known Zero for the AND as this allows us to catch more general
// cases than just looking for AND with imm.
KnownBits Known = CurDAG->computeKnownBits(Node->getOperand(0));
// The bits being inserted must only set those bits that are known to be zero.
if (!OrImm.isSubsetOf(Known.Zero)) {
// FIXME: It's okay if the OrImm sets NotKnownZero bits to 1, but we don't
// currently handle this case.
return false;
}
unsigned ShAmt, Width;
// The KnownZero mask must be a shifted mask (e.g., 1110..011, 11100..00).
if (!Known.Zero.isShiftedMask(ShAmt, Width))
return false;
// QC_INSB(I) dst, src, #width, #shamt.
SDLoc DL(Node);
MVT VT = Node->getSimpleValueType(0);
SDValue ImmNode;
auto Opc = RISCV::QC_INSB;
int32_t LIImm = OrImm.getSExtValue() >> ShAmt;
if (isInt<5>(LIImm)) {
Opc = RISCV::QC_INSBI;
ImmNode = CurDAG->getSignedTargetConstant(LIImm, DL, MVT::i32);
} else {
ImmNode = selectImm(CurDAG, DL, MVT::i32, LIImm, *Subtarget);
}
SDValue Ops[] = {And, ImmNode, CurDAG->getTargetConstant(Width, DL, VT),
CurDAG->getTargetConstant(ShAmt, DL, VT)};
SDNode *BitIns = CurDAG->getMachineNode(Opc, DL, VT, Ops);
ReplaceNode(Node, BitIns);
return true;
}
bool RISCVDAGToDAGISel::trySignedBitfieldInsertInSign(SDNode *Node) {
// Only supported with XAndesPerf at the moment.
if (!Subtarget->hasVendorXAndesPerf())
@ -1377,6 +1430,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
if (trySignedBitfieldInsertInMask(Node))
return;
if (tryBitfieldInsertOpFromOrAndImm(Node))
return;
if (tryShrinkShlLogicImm(Node))
return;

View File

@ -76,6 +76,7 @@ public:
bool trySignedBitfieldInsertInSign(SDNode *Node);
bool trySignedBitfieldInsertInMask(SDNode *Node);
bool tryBitfieldInsertOpFromXor(SDNode *Node);
bool tryBitfieldInsertOpFromOrAndImm(SDNode *Node);
bool tryUnsignedBitfieldExtract(SDNode *Node, const SDLoc &DL, MVT VT,
SDValue X, unsigned Msb, unsigned Lsb);
bool tryUnsignedBitfieldInsertInZero(SDNode *Node, const SDLoc &DL, MVT VT,

View File

@ -139,3 +139,208 @@ define i32 @test_single_bit_set(i32 %a) nounwind {
%or = or i32 %a, 4096
ret i32 %or
}
; Tests for INSB(I) generation from OR and AND
define i32 @test1(i32 %a) {
; RV32I-LABEL: test1:
; RV32I: # %bb.0:
; RV32I-NEXT: andi a0, a0, -16
; RV32I-NEXT: addi a0, a0, 5
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test1:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: qc.insbi a0, 5, 4, 0
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test1:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: qc.insbi a0, 5, 4, 0
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i32 %a, -16 ; 0xfffffff0
%2 = or i32 %1, 5 ; 0x00000005
ret i32 %2
}
define i32 @test2(i32 %a) {
; RV32I-LABEL: test2:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 1033216
; RV32I-NEXT: addi a1, a1, -1
; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: lui a1, 10240
; RV32I-NEXT: or a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test2:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: qc.insbi a0, 10, 4, 22
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test2:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: qc.insbi a0, 10, 4, 22
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i32 %a, -62914561 ; 0xfc3fffff
%2 = or i32 %1, 41943040 ; 0x02800000
ret i32 %2
}
define i64 @test3(i64 %a) {
; RV32I-LABEL: test3:
; RV32I: # %bb.0:
; RV32I-NEXT: andi a0, a0, -8
; RV32I-NEXT: addi a0, a0, 5
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test3:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: qc.insbi a0, 5, 3, 0
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test3:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: qc.insbi a0, 5, 3, 0
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i64 %a, -8 ; 0xfffffffffffffff8
%2 = or i64 %1, 5 ; 0x0000000000000005
ret i64 %2
}
define i64 @test4(i64 %a) {
; RV32I-LABEL: test4:
; RV32I: # %bb.0:
; RV32I-NEXT: andi a0, a0, -255
; RV32I-NEXT: addi a0, a0, 18
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test4:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: qc.insbi a0, 9, 7, 1
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test4:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: qc.insbi a0, 9, 7, 1
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i64 %a, -255 ; 0xffffffffffffff01
%2 = or i64 %1, 18 ; 0x0000000000000012
ret i64 %2
}
define i32 @test5(i32 %a) {
; RV32I-LABEL: test5:
; RV32I: # %bb.0:
; RV32I-NEXT: andi a0, a0, -16
; RV32I-NEXT: addi a0, a0, 6
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test5:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: qc.insbi a0, 6, 4, 0
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test5:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: qc.insbi a0, 6, 4, 0
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i32 %a, 4294967280 ; 0xfffffff0
%2 = or i32 %1, 6 ; 0x00000006
ret i32 %2
}
define i32 @test6(i32 %a) {
; RV32I-LABEL: test6:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 1048320
; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: lui a1, 182
; RV32I-NEXT: addi a1, a1, -1326
; RV32I-NEXT: or a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test6:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: lui a1, 182
; RV32IXQCIBM-NEXT: addi a1, a1, -1326
; RV32IXQCIBM-NEXT: qc.insb a0, a1, 20, 0
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test6:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: lui a1, 182
; RV32IXQCIBMZBS-NEXT: addi a1, a1, -1326
; RV32IXQCIBMZBS-NEXT: qc.insb a0, a1, 20, 0
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i32 %a, 4293918720 ; 0xfff00000
%2 = or i32 %1, 744146 ; 0x000b5ad2
ret i32 %2
}
define i32 @test7(i32 %a) {
; RV32I-LABEL: test7:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 1048320
; RV32I-NEXT: addi a1, a1, 1
; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: lui a1, 182
; RV32I-NEXT: addi a1, a1, -1326
; RV32I-NEXT: or a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test7:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: lui a1, 91
; RV32IXQCIBM-NEXT: addi a1, a1, -663
; RV32IXQCIBM-NEXT: qc.insb a0, a1, 19, 1
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test7:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: lui a1, 91
; RV32IXQCIBMZBS-NEXT: addi a1, a1, -663
; RV32IXQCIBMZBS-NEXT: qc.insb a0, a1, 19, 1
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i32 %a, 4293918721 ; 0xfff00001
%2 = or i32 %1, 744146 ; 0x000b5ad2
ret i32 %2
}
define i64 @test8(i64 %a) {
; RV32I-LABEL: test8:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a2, 1044480
; RV32I-NEXT: zext.b a0, a0
; RV32I-NEXT: and a1, a1, a2
; RV32I-NEXT: lui a2, 496944
; RV32I-NEXT: or a0, a0, a2
; RV32I-NEXT: lui a2, 9
; RV32I-NEXT: addi a2, a2, -170
; RV32I-NEXT: or a1, a1, a2
; RV32I-NEXT: ret
;
; RV32IXQCIBM-LABEL: test8:
; RV32IXQCIBM: # %bb.0:
; RV32IXQCIBM-NEXT: lui a2, 1941
; RV32IXQCIBM-NEXT: addi a2, a2, 768
; RV32IXQCIBM-NEXT: qc.insb a0, a2, 24, 8
; RV32IXQCIBM-NEXT: lui a2, 9
; RV32IXQCIBM-NEXT: addi a2, a2, -170
; RV32IXQCIBM-NEXT: qc.insb a1, a2, 24, 0
; RV32IXQCIBM-NEXT: ret
;
; RV32IXQCIBMZBS-LABEL: test8:
; RV32IXQCIBMZBS: # %bb.0:
; RV32IXQCIBMZBS-NEXT: lui a2, 1941
; RV32IXQCIBMZBS-NEXT: addi a2, a2, 768
; RV32IXQCIBMZBS-NEXT: qc.insb a0, a2, 24, 8
; RV32IXQCIBMZBS-NEXT: lui a2, 9
; RV32IXQCIBMZBS-NEXT: addi a2, a2, -170
; RV32IXQCIBMZBS-NEXT: qc.insb a1, a2, 24, 0
; RV32IXQCIBMZBS-NEXT: ret
%1 = and i64 %a, -72057594037927681 ; 0xff000000000000ff
%2 = or i64 %1, 157601565442048 ; 0x00008f5679530000
ret i64 %2
}