Skip to content

Commit 71b066e

Browse files
authored
[RISCV] Add CodeGen support for qc.insbi and qc.insb insert instructions (#152447)
This patch adds CodeGen support for qc.insbi and qc.insb instructions defined in the Qualcomm uC Xqcibm extension. qc.insbi and qc.insb inserts bits into destination register from immediate and register operand respectively. A sequence of `xor`, `and` & `xor` depending on appropriate conditions are converted to `qc.insbi` or `qc.insb` which depends on the immediate's value.
1 parent ab5a5a9 commit 71b066e

File tree

3 files changed

+310
-0
lines changed

3 files changed

+310
-0
lines changed

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "RISCVInstrInfo.h"
1919
#include "RISCVSelectionDAGInfo.h"
2020
#include "llvm/CodeGen/MachineFrameInfo.h"
21+
#include "llvm/CodeGen/SDPatternMatch.h"
2122
#include "llvm/IR/IntrinsicsRISCV.h"
2223
#include "llvm/Support/Alignment.h"
2324
#include "llvm/Support/Debug.h"
@@ -772,6 +773,49 @@ bool RISCVDAGToDAGISel::trySignedBitfieldInsertInSign(SDNode *Node) {
772773
return false;
773774
}
774775

776+
// (xor X, (and (xor X, C1), C2))
777+
// -> (qc.insbi X, (C1 >> ShAmt), Width, ShAmt)
778+
// where C2 is a shifted mask with width=Width and shift=ShAmt
779+
bool RISCVDAGToDAGISel::tryBitfieldInsertOpFromXor(SDNode *Node) {
780+
781+
if (!Subtarget->hasVendorXqcibm())
782+
return false;
783+
784+
using namespace SDPatternMatch;
785+
786+
SDValue X;
787+
APInt CImm, CMask;
788+
if (!sd_match(
789+
Node,
790+
m_Xor(m_Value(X),
791+
m_OneUse(m_And(m_OneUse(m_Xor(m_Deferred(X), m_ConstInt(CImm))),
792+
m_ConstInt(CMask))))))
793+
return false;
794+
795+
unsigned Width, ShAmt;
796+
if (!CMask.isShiftedMask(ShAmt, Width))
797+
return false;
798+
799+
int64_t Imm = CImm.getSExtValue();
800+
Imm >>= ShAmt;
801+
802+
SDLoc DL(Node);
803+
SDValue ImmNode;
804+
auto Opc = RISCV::QC_INSB;
805+
806+
if (isInt<5>(Imm)) {
807+
Opc = RISCV::QC_INSBI;
808+
ImmNode = CurDAG->getSignedTargetConstant(Imm, DL, MVT::i32);
809+
} else {
810+
ImmNode = selectImm(CurDAG, DL, MVT::i32, Imm, *Subtarget);
811+
}
812+
SDValue Ops[] = {X, ImmNode, CurDAG->getTargetConstant(Width, DL, MVT::i32),
813+
CurDAG->getTargetConstant(ShAmt, DL, MVT::i32)};
814+
ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, MVT::i32, Ops));
815+
816+
return true;
817+
}
818+
775819
bool RISCVDAGToDAGISel::tryUnsignedBitfieldExtract(SDNode *Node,
776820
const SDLoc &DL, MVT VT,
777821
SDValue X, unsigned Msb,
@@ -1349,6 +1393,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
13491393
if (tryShrinkShlLogicImm(Node))
13501394
return;
13511395

1396+
if (tryBitfieldInsertOpFromXor(Node))
1397+
return;
1398+
13521399
break;
13531400
case ISD::AND: {
13541401
auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
7575
bool trySignedBitfieldExtract(SDNode *Node);
7676
bool trySignedBitfieldInsertInSign(SDNode *Node);
7777
bool trySignedBitfieldInsertInMask(SDNode *Node);
78+
bool tryBitfieldInsertOpFromXor(SDNode *Node);
7879
bool tryUnsignedBitfieldExtract(SDNode *Node, const SDLoc &DL, MVT VT,
7980
SDValue X, unsigned Msb, unsigned Lsb);
8081
bool tryUnsignedBitfieldInsertInZero(SDNode *Node, const SDLoc &DL, MVT VT,
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -mtriple=riscv32 --verify-machineinstrs < %s \
3+
; RUN: | FileCheck %s -check-prefixes=RV32I
4+
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcibm --verify-machineinstrs < %s \
5+
; RUN: | FileCheck %s -check-prefixes=RV32XQCIBM
6+
7+
define i32 @insbi(i32 %in1) nounwind {
8+
; RV32I-LABEL: insbi:
9+
; RV32I: # %bb.0:
10+
; RV32I-NEXT: xori a1, a0, 176
11+
; RV32I-NEXT: andi a1, a1, 496
12+
; RV32I-NEXT: xor a0, a1, a0
13+
; RV32I-NEXT: ret
14+
;
15+
; RV32XQCIBM-LABEL: insbi:
16+
; RV32XQCIBM: # %bb.0:
17+
; RV32XQCIBM-NEXT: qc.insbi a0, 11, 5, 4
18+
; RV32XQCIBM-NEXT: ret
19+
%xor1 = xor i32 %in1, 176
20+
%and1 = and i32 %xor1, 496
21+
%xor2 = xor i32 %and1, %in1
22+
ret i32 %xor2
23+
}
24+
25+
define i32 @insbi_comm_xor(i32 %in1) nounwind {
26+
; RV32I-LABEL: insbi_comm_xor:
27+
; RV32I: # %bb.0:
28+
; RV32I-NEXT: li a1, 9
29+
; RV32I-NEXT: li a2, 15
30+
; RV32I-NEXT: slli a1, a1, 9
31+
; RV32I-NEXT: xor a1, a0, a1
32+
; RV32I-NEXT: slli a2, a2, 9
33+
; RV32I-NEXT: and a1, a1, a2
34+
; RV32I-NEXT: xor a0, a1, a0
35+
; RV32I-NEXT: ret
36+
;
37+
; RV32XQCIBM-LABEL: insbi_comm_xor:
38+
; RV32XQCIBM: # %bb.0:
39+
; RV32XQCIBM-NEXT: qc.insbi a0, 9, 4, 9
40+
; RV32XQCIBM-NEXT: ret
41+
%xor1 = xor i32 4608, %in1
42+
%and1 = and i32 %xor1, 7680
43+
%xor2 = xor i32 %and1, %in1
44+
ret i32 %xor2
45+
}
46+
47+
define i32 @insbi_comm_and(i32 %in1) nounwind {
48+
; RV32I-LABEL: insbi_comm_and:
49+
; RV32I: # %bb.0:
50+
; RV32I-NEXT: li a1, 11
51+
; RV32I-NEXT: li a2, 15
52+
; RV32I-NEXT: slli a1, a1, 9
53+
; RV32I-NEXT: xor a1, a0, a1
54+
; RV32I-NEXT: slli a2, a2, 9
55+
; RV32I-NEXT: and a1, a1, a2
56+
; RV32I-NEXT: xor a0, a1, a0
57+
; RV32I-NEXT: ret
58+
;
59+
; RV32XQCIBM-LABEL: insbi_comm_and:
60+
; RV32XQCIBM: # %bb.0:
61+
; RV32XQCIBM-NEXT: qc.insbi a0, 11, 4, 9
62+
; RV32XQCIBM-NEXT: ret
63+
%xor1 = xor i32 %in1, 5632
64+
%and1 = and i32 7680, %xor1
65+
%xor2 = xor i32 %and1, %in1
66+
ret i32 %xor2
67+
}
68+
69+
define i32 @insbi_comm_xor2(i32 %in1) nounwind {
70+
; RV32I-LABEL: insbi_comm_xor2:
71+
; RV32I: # %bb.0:
72+
; RV32I-NEXT: xori a1, a0, 176
73+
; RV32I-NEXT: andi a1, a1, 496
74+
; RV32I-NEXT: xor a0, a0, a1
75+
; RV32I-NEXT: ret
76+
;
77+
; RV32XQCIBM-LABEL: insbi_comm_xor2:
78+
; RV32XQCIBM: # %bb.0:
79+
; RV32XQCIBM-NEXT: qc.insbi a0, 11, 5, 4
80+
; RV32XQCIBM-NEXT: ret
81+
%xor1 = xor i32 %in1, 176
82+
%and1 = and i32 %xor1, 496
83+
%xor2 = xor i32 %in1, %and1
84+
ret i32 %xor2
85+
}
86+
87+
define i32 @insbi_immg(i32 %in1) nounwind {
88+
; RV32I-LABEL: insbi_immg:
89+
; RV32I: # %bb.0:
90+
; RV32I-NEXT: xori a1, a0, 256
91+
; RV32I-NEXT: andi a1, a1, 496
92+
; RV32I-NEXT: xor a0, a1, a0
93+
; RV32I-NEXT: ret
94+
;
95+
; RV32XQCIBM-LABEL: insbi_immg:
96+
; RV32XQCIBM: # %bb.0:
97+
; RV32XQCIBM-NEXT: li a1, 16
98+
; RV32XQCIBM-NEXT: qc.insb a0, a1, 5, 4
99+
; RV32XQCIBM-NEXT: ret
100+
%xor1 = xor i32 %in1, 256
101+
%and1 = and i32 %xor1, 496
102+
%xor2 = xor i32 %and1, %in1
103+
ret i32 %xor2
104+
}
105+
106+
define i32 @insbi_not_shifted_mask(i32 %in1) nounwind {
107+
; RV32I-LABEL: insbi_not_shifted_mask:
108+
; RV32I: # %bb.0:
109+
; RV32I-NEXT: xori a1, a0, 128
110+
; RV32I-NEXT: andi a1, a1, 716
111+
; RV32I-NEXT: xor a0, a1, a0
112+
; RV32I-NEXT: ret
113+
;
114+
; RV32XQCIBM-LABEL: insbi_not_shifted_mask:
115+
; RV32XQCIBM: # %bb.0:
116+
; RV32XQCIBM-NEXT: xori a1, a0, 128
117+
; RV32XQCIBM-NEXT: andi a1, a1, 716
118+
; RV32XQCIBM-NEXT: xor a0, a0, a1
119+
; RV32XQCIBM-NEXT: ret
120+
%xor1 = xor i32 %in1, 176
121+
%and1 = and i32 %xor1, 716
122+
%xor2 = xor i32 %and1, %in1
123+
ret i32 %xor2
124+
}
125+
126+
define i32 @insbi_width_z(i32 %in1) nounwind {
127+
; RV32I-LABEL: insbi_width_z:
128+
; RV32I: # %bb.0:
129+
; RV32I-NEXT: andi a1, a0, 256
130+
; RV32I-NEXT: xor a0, a1, a0
131+
; RV32I-NEXT: ret
132+
;
133+
; RV32XQCIBM-LABEL: insbi_width_z:
134+
; RV32XQCIBM: # %bb.0:
135+
; RV32XQCIBM-NEXT: andi a1, a0, 256
136+
; RV32XQCIBM-NEXT: xor a0, a0, a1
137+
; RV32XQCIBM-NEXT: ret
138+
%xor1 = xor i32 %in1, 176
139+
%and1 = and i32 %xor1, 256
140+
%xor2 = xor i32 %and1, %in1
141+
ret i32 %xor2
142+
}
143+
144+
define i32 @insbi_mul_use_and(i32 %in1, i32 %in2) nounwind {
145+
; RV32I-LABEL: insbi_mul_use_and:
146+
; RV32I: # %bb.0:
147+
; RV32I-NEXT: li a1, 11
148+
; RV32I-NEXT: li a2, 15
149+
; RV32I-NEXT: slli a1, a1, 9
150+
; RV32I-NEXT: slli a2, a2, 9
151+
; RV32I-NEXT: xor a1, a0, a1
152+
; RV32I-NEXT: and a1, a1, a2
153+
; RV32I-NEXT: xor a2, a1, a0
154+
; RV32I-NEXT: add a0, a0, a1
155+
; RV32I-NEXT: add a0, a0, a2
156+
; RV32I-NEXT: ret
157+
;
158+
; RV32XQCIBM-LABEL: insbi_mul_use_and:
159+
; RV32XQCIBM: # %bb.0:
160+
; RV32XQCIBM-NEXT: li a1, 11
161+
; RV32XQCIBM-NEXT: li a2, 15
162+
; RV32XQCIBM-NEXT: slli a1, a1, 9
163+
; RV32XQCIBM-NEXT: slli a2, a2, 9
164+
; RV32XQCIBM-NEXT: xor a1, a1, a0
165+
; RV32XQCIBM-NEXT: and a1, a1, a2
166+
; RV32XQCIBM-NEXT: xor a2, a1, a0
167+
; RV32XQCIBM-NEXT: add a0, a0, a1
168+
; RV32XQCIBM-NEXT: add a0, a0, a2
169+
; RV32XQCIBM-NEXT: ret
170+
%xor1 = xor i32 %in1, 5632
171+
%and1 = and i32 %xor1, 7680
172+
%xor2 = xor i32 %and1, %in1
173+
%add1 = add i32 %in1, %and1
174+
%add2 = add i32 %add1, %xor2
175+
ret i32 %add2
176+
}
177+
178+
define i32 @insbi_mul_use_xor(i32 %in1, i32 %in2) nounwind {
179+
; RV32I-LABEL: insbi_mul_use_xor:
180+
; RV32I: # %bb.0:
181+
; RV32I-NEXT: xori a1, a0, 176
182+
; RV32I-NEXT: andi a2, a1, 496
183+
; RV32I-NEXT: xor a2, a2, a0
184+
; RV32I-NEXT: add a0, a0, a1
185+
; RV32I-NEXT: add a0, a0, a2
186+
; RV32I-NEXT: ret
187+
;
188+
; RV32XQCIBM-LABEL: insbi_mul_use_xor:
189+
; RV32XQCIBM: # %bb.0:
190+
; RV32XQCIBM-NEXT: xori a1, a0, 176
191+
; RV32XQCIBM-NEXT: andi a2, a1, 496
192+
; RV32XQCIBM-NEXT: xor a2, a2, a0
193+
; RV32XQCIBM-NEXT: add a0, a0, a1
194+
; RV32XQCIBM-NEXT: add a0, a0, a2
195+
; RV32XQCIBM-NEXT: ret
196+
%xor1 = xor i32 %in1, 176
197+
%and1 = and i32 %xor1, 496
198+
%xor2 = xor i32 %and1, %in1
199+
%add1 = add i32 %in1, %xor1
200+
%add2 = add i32 %add1, %xor2
201+
ret i32 %add2
202+
}
203+
204+
define i32 @insbi_imm_too_neg(i32 %in1) nounwind {
205+
; RV32I-LABEL: insbi_imm_too_neg:
206+
; RV32I: # %bb.0:
207+
; RV32I-NEXT: xori a1, a0, -34
208+
; RV32I-NEXT: andi a1, a1, -2
209+
; RV32I-NEXT: xor a0, a1, a0
210+
; RV32I-NEXT: ret
211+
;
212+
; RV32XQCIBM-LABEL: insbi_imm_too_neg:
213+
; RV32XQCIBM: # %bb.0:
214+
; RV32XQCIBM-NEXT: li a1, -17
215+
; RV32XQCIBM-NEXT: qc.insb a0, a1, 31, 1
216+
; RV32XQCIBM-NEXT: ret
217+
%xor1 = xor i32 %in1, -34
218+
%and1 = and i32 %xor1, -2
219+
%xor2 = xor i32 %and1, %in1
220+
ret i32 %xor2
221+
}
222+
223+
define i64 @insbi_i64(i64 %in1) nounwind {
224+
; RV32I-LABEL: insbi_i64:
225+
; RV32I: # %bb.0:
226+
; RV32I-NEXT: lui a2, 57344
227+
; RV32I-NEXT: lui a3, 1044480
228+
; RV32I-NEXT: xor a2, a0, a2
229+
; RV32I-NEXT: and a2, a2, a3
230+
; RV32I-NEXT: zext.b a3, a1
231+
; RV32I-NEXT: xor a1, a3, a1
232+
; RV32I-NEXT: xor a0, a2, a0
233+
; RV32I-NEXT: ret
234+
;
235+
; RV32XQCIBM-LABEL: insbi_i64:
236+
; RV32XQCIBM: # %bb.0:
237+
; RV32XQCIBM-NEXT: qc.extu a2, a1, 8, 0
238+
; RV32XQCIBM-NEXT: xor a1, a1, a2
239+
; RV32XQCIBM-NEXT: qc.insbi a0, 14, 8, 24
240+
; RV32XQCIBM-NEXT: ret
241+
%xor1 = xor i64 %in1, 234881024
242+
%and1 = and i64 %xor1, 1099494850560
243+
%xor2 = xor i64 %and1, %in1
244+
ret i64 %xor2
245+
}
246+
define i64 @insbi_i64_large_mask(i64 %in1) nounwind {
247+
; RV32I-LABEL: insbi_i64_large_mask:
248+
; RV32I: # %bb.0:
249+
; RV32I-NEXT: xori a2, a1, 9
250+
; RV32I-NEXT: andi a2, a2, 15
251+
; RV32I-NEXT: xor a1, a2, a1
252+
; RV32I-NEXT: ret
253+
;
254+
; RV32XQCIBM-LABEL: insbi_i64_large_mask:
255+
; RV32XQCIBM: # %bb.0:
256+
; RV32XQCIBM-NEXT: qc.insbi a1, 9, 4, 0
257+
; RV32XQCIBM-NEXT: ret
258+
%xor1 = xor i64 %in1, 38654705664
259+
%and1 = and i64 %xor1, 64424509440
260+
%xor2 = xor i64 %and1, %in1
261+
ret i64 %xor2
262+
}

0 commit comments

Comments
 (0)