xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td (revision 5b56413d04e608379c9a306373554a8e4d321bc0)
1//== LoongArchInstrInfo.td - Target Description for LoongArch -*- tablegen -*-//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file describes the LoongArch instructions in TableGen format.
10//
11//===----------------------------------------------------------------------===//
12
13//===----------------------------------------------------------------------===//
14// LoongArch specific DAG Nodes.
15//===----------------------------------------------------------------------===//
16
17// Target-independent type requirements, but with target-specific formats.
18def SDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>,
19                                       SDTCisVT<1, i32>]>;
20def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>,
21                                   SDTCisVT<1, i32>]>;
22
23// Target-dependent type requirements.
24def SDT_LoongArchCall : SDTypeProfile<0, -1, [SDTCisVT<0, GRLenVT>]>;
25def SDT_LoongArchIntBinOpW : SDTypeProfile<1, 2, [
26  SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<0, i64>
27]>;
28
29def SDT_LoongArchBStrIns: SDTypeProfile<1, 4, [
30  SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisInt<3>,
31  SDTCisSameAs<3, 4>
32]>;
33
34def SDT_LoongArchBStrPick: SDTypeProfile<1, 3, [
35  SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisInt<2>, SDTCisSameAs<2, 3>
36]>;
37
38// "VI" means no output and an integer input.
39def SDT_LoongArchVI : SDTypeProfile<0, 1, [SDTCisVT<0, GRLenVT>]>;
40
41def SDT_LoongArchCsrrd : SDTypeProfile<1, 1, [SDTCisInt<0>,
42                                              SDTCisVT<1, GRLenVT>]>;
43def SDT_LoongArchCsrwr : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>,
44                                              SDTCisVT<2, GRLenVT>]>;
45def SDT_LoongArchCsrxchg : SDTypeProfile<1, 3, [SDTCisInt<0>,
46                                                SDTCisSameAs<0, 1>,
47                                                SDTCisSameAs<0, 2>,
48                                                SDTCisVT<3, GRLenVT>]>;
49def SDT_LoongArchIocsrwr : SDTypeProfile<0, 2, [SDTCisInt<0>,
50                                                SDTCisSameAs<0, 1>]>;
51def SDT_LoongArchMovgr2fcsr : SDTypeProfile<0, 2, [SDTCisVT<0, GRLenVT>,
52                                                   SDTCisSameAs<0, 1>]>;
53def SDT_LoongArchMovfcsr2gr : SDTypeProfile<1, 1, [SDTCisVT<0, GRLenVT>,
54                                                   SDTCisSameAs<0, 1>]>;
55
56// TODO: Add LoongArch specific DAG Nodes
57// Target-independent nodes, but with target-specific formats.
58def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart,
59                           [SDNPHasChain, SDNPOutGlue]>;
60def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_CallSeqEnd,
61                         [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
62
63// Target-dependent nodes.
64def loongarch_call : SDNode<"LoongArchISD::CALL", SDT_LoongArchCall,
65                            [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
66                             SDNPVariadic]>;
67def loongarch_ret : SDNode<"LoongArchISD::RET", SDTNone,
68                           [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
69def loongarch_tail : SDNode<"LoongArchISD::TAIL", SDT_LoongArchCall,
70                            [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
71                             SDNPVariadic]>;
72def loongarch_call_medium : SDNode<"LoongArchISD::CALL_MEDIUM", SDT_LoongArchCall,
73                                   [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
74                                    SDNPVariadic]>;
75def loongarch_tail_medium : SDNode<"LoongArchISD::TAIL_MEDIUM", SDT_LoongArchCall,
76                                   [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
77                                    SDNPVariadic]>;
78def loongarch_call_large : SDNode<"LoongArchISD::CALL_LARGE", SDT_LoongArchCall,
79                                  [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
80                                   SDNPVariadic]>;
81def loongarch_tail_large : SDNode<"LoongArchISD::TAIL_LARGE", SDT_LoongArchCall,
82                                  [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
83                                   SDNPVariadic]>;
84def loongarch_sll_w : SDNode<"LoongArchISD::SLL_W", SDT_LoongArchIntBinOpW>;
85def loongarch_sra_w : SDNode<"LoongArchISD::SRA_W", SDT_LoongArchIntBinOpW>;
86def loongarch_srl_w : SDNode<"LoongArchISD::SRL_W", SDT_LoongArchIntBinOpW>;
87def loongarch_rotr_w : SDNode<"LoongArchISD::ROTR_W", SDT_LoongArchIntBinOpW>;
88def loongarch_rotl_w : SDNode<"LoongArchISD::ROTL_W", SDT_LoongArchIntBinOpW>;
89def loongarch_crc_w_b_w
90    : SDNode<"LoongArchISD::CRC_W_B_W", SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
91def loongarch_crc_w_h_w
92    : SDNode<"LoongArchISD::CRC_W_H_W", SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
93def loongarch_crc_w_w_w
94    : SDNode<"LoongArchISD::CRC_W_W_W", SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
95def loongarch_crc_w_d_w
96    : SDNode<"LoongArchISD::CRC_W_D_W", SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
97def loongarch_crcc_w_b_w : SDNode<"LoongArchISD::CRCC_W_B_W",
98                                  SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
99def loongarch_crcc_w_h_w : SDNode<"LoongArchISD::CRCC_W_H_W",
100                                  SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
101def loongarch_crcc_w_w_w : SDNode<"LoongArchISD::CRCC_W_W_W",
102                                  SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
103def loongarch_crcc_w_d_w : SDNode<"LoongArchISD::CRCC_W_D_W",
104                                  SDT_LoongArchIntBinOpW, [SDNPHasChain]>;
105def loongarch_bstrins
106    : SDNode<"LoongArchISD::BSTRINS", SDT_LoongArchBStrIns>;
107def loongarch_bstrpick
108    : SDNode<"LoongArchISD::BSTRPICK", SDT_LoongArchBStrPick>;
109def loongarch_revb_2h : SDNode<"LoongArchISD::REVB_2H", SDTUnaryOp>;
110def loongarch_revb_2w : SDNode<"LoongArchISD::REVB_2W", SDTUnaryOp>;
111def loongarch_bitrev_4b : SDNode<"LoongArchISD::BITREV_4B", SDTUnaryOp>;
112def loongarch_bitrev_w : SDNode<"LoongArchISD::BITREV_W", SDTUnaryOp>;
113def loongarch_clzw : SDNode<"LoongArchISD::CLZ_W", SDTIntBitCountUnaryOp>;
114def loongarch_ctzw : SDNode<"LoongArchISD::CTZ_W", SDTIntBitCountUnaryOp>;
115def loongarch_dbar : SDNode<"LoongArchISD::DBAR", SDT_LoongArchVI,
116                             [SDNPHasChain, SDNPSideEffect]>;
117def loongarch_ibar : SDNode<"LoongArchISD::IBAR", SDT_LoongArchVI,
118                             [SDNPHasChain, SDNPSideEffect]>;
119def loongarch_break : SDNode<"LoongArchISD::BREAK", SDT_LoongArchVI,
120                              [SDNPHasChain, SDNPSideEffect]>;
121def loongarch_movfcsr2gr : SDNode<"LoongArchISD::MOVFCSR2GR",
122                                  SDT_LoongArchMovfcsr2gr, [SDNPHasChain]>;
123def loongarch_movgr2fcsr : SDNode<"LoongArchISD::MOVGR2FCSR",
124                                  SDT_LoongArchMovgr2fcsr,
125                                  [SDNPHasChain, SDNPSideEffect]>;
126def loongarch_syscall : SDNode<"LoongArchISD::SYSCALL", SDT_LoongArchVI,
127                                [SDNPHasChain, SDNPSideEffect]>;
128def loongarch_csrrd : SDNode<"LoongArchISD::CSRRD", SDT_LoongArchCsrrd,
129                              [SDNPHasChain, SDNPSideEffect]>;
130def loongarch_csrwr : SDNode<"LoongArchISD::CSRWR", SDT_LoongArchCsrwr,
131                              [SDNPHasChain, SDNPSideEffect]>;
132def loongarch_csrxchg : SDNode<"LoongArchISD::CSRXCHG",
133                                SDT_LoongArchCsrxchg,
134                                [SDNPHasChain, SDNPSideEffect]>;
135def loongarch_iocsrrd_b : SDNode<"LoongArchISD::IOCSRRD_B", SDTUnaryOp,
136                                  [SDNPHasChain, SDNPSideEffect]>;
137def loongarch_iocsrrd_h : SDNode<"LoongArchISD::IOCSRRD_H", SDTUnaryOp,
138                                  [SDNPHasChain, SDNPSideEffect]>;
139def loongarch_iocsrrd_w : SDNode<"LoongArchISD::IOCSRRD_W", SDTUnaryOp,
140                                  [SDNPHasChain, SDNPSideEffect]>;
141def loongarch_iocsrrd_d : SDNode<"LoongArchISD::IOCSRRD_D", SDTUnaryOp,
142                                  [SDNPHasChain, SDNPSideEffect]>;
143def loongarch_iocsrwr_b : SDNode<"LoongArchISD::IOCSRWR_B",
144                                  SDT_LoongArchIocsrwr,
145                                  [SDNPHasChain, SDNPSideEffect]>;
146def loongarch_iocsrwr_h : SDNode<"LoongArchISD::IOCSRWR_H",
147                                  SDT_LoongArchIocsrwr,
148                                  [SDNPHasChain, SDNPSideEffect]>;
149def loongarch_iocsrwr_w : SDNode<"LoongArchISD::IOCSRWR_W",
150                                  SDT_LoongArchIocsrwr,
151                                  [SDNPHasChain, SDNPSideEffect]>;
152def loongarch_iocsrwr_d : SDNode<"LoongArchISD::IOCSRWR_D",
153                                  SDT_LoongArchIocsrwr,
154                                  [SDNPHasChain, SDNPSideEffect]>;
155def loongarch_cpucfg : SDNode<"LoongArchISD::CPUCFG", SDTUnaryOp,
156                               [SDNPHasChain]>;
157
158def to_fclass_mask: SDNodeXForm<timm, [{
159  uint64_t Check = N->getZExtValue();
160  unsigned Mask = 0;
161  if (Check & fcSNan)
162    Mask |= LoongArch::FClassMaskSignalingNaN;
163  if (Check & fcQNan)
164    Mask |= LoongArch::FClassMaskQuietNaN;
165  if (Check & fcPosInf)
166    Mask |= LoongArch::FClassMaskPositiveInfinity;
167  if (Check & fcNegInf)
168    Mask |= LoongArch::FClassMaskNegativeInfinity;
169  if (Check & fcPosNormal)
170    Mask |= LoongArch::FClassMaskPositiveNormal;
171  if (Check & fcNegNormal)
172    Mask |= LoongArch::FClassMaskNegativeNormal;
173  if (Check & fcPosSubnormal)
174    Mask |= LoongArch::FClassMaskPositiveSubnormal;
175  if (Check & fcNegSubnormal)
176    Mask |= LoongArch::FClassMaskNegativeSubnormal;
177  if (Check & fcPosZero)
178    Mask |= LoongArch::FClassMaskPositiveZero;
179  if (Check & fcNegZero)
180    Mask |= LoongArch::FClassMaskNegativeZero;
181  return CurDAG->getTargetConstant(Mask, SDLoc(N), Subtarget->getGRLenVT());
182}]>;
183
184//===----------------------------------------------------------------------===//
185// Operand and SDNode transformation definitions.
186//===----------------------------------------------------------------------===//
187
188class ImmAsmOperand<string prefix, int width, string suffix>
189    : AsmOperandClass {
190  let Name = prefix # "Imm" # width # suffix;
191  let DiagnosticType = !strconcat("Invalid", Name);
192  let RenderMethod = "addImmOperands";
193}
194
195class SImmAsmOperand<int width, string suffix = "">
196    : ImmAsmOperand<"S", width, suffix> {
197}
198
199class UImmAsmOperand<int width, string suffix = "">
200    : ImmAsmOperand<"U", width, suffix> {
201}
202
203// A parse method for "$r*" or "$r*, 0", where the 0 is be silently ignored.
204// Only used for "AM*" instructions, in order to be compatible with GAS.
205def AtomicMemAsmOperand : AsmOperandClass {
206  let Name = "AtomicMemAsmOperand";
207  let RenderMethod = "addRegOperands";
208  let PredicateMethod = "isGPR";
209  let ParserMethod = "parseAtomicMemOp";
210}
211
212def GPRMemAtomic : RegisterOperand<GPR> {
213  let ParserMatchClass = AtomicMemAsmOperand;
214  let PrintMethod = "printAtomicMemOp";
215}
216
217// A parameterized register class alternative to i32imm/i64imm from Target.td.
218def grlenimm : Operand<GRLenVT>;
219def imm32 : Operand<GRLenVT> {
220  let ParserMatchClass = ImmAsmOperand<"", 32, "">;
221}
222
223def uimm1 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isUInt<1>(Imm);}]>{
224  let ParserMatchClass = UImmAsmOperand<1>;
225}
226
227def uimm2 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isUInt<2>(Imm);}]> {
228  let ParserMatchClass = UImmAsmOperand<2>;
229}
230
231def uimm2_plus1 : Operand<GRLenVT>,
232    ImmLeaf<GRLenVT, [{return isUInt<2>(Imm - 1);}]> {
233  let ParserMatchClass = UImmAsmOperand<2, "plus1">;
234  let EncoderMethod = "getImmOpValueSub1";
235  let DecoderMethod = "decodeUImmOperand<2, 1>";
236}
237
238def uimm3 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isUInt<3>(Imm);}]> {
239  let ParserMatchClass = UImmAsmOperand<3>;
240}
241
242def uimm4 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isUInt<4>(Imm);}]> {
243  let ParserMatchClass = UImmAsmOperand<4>;
244}
245
246def uimm5 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isUInt<5>(Imm);}]> {
247  let ParserMatchClass = UImmAsmOperand<5>;
248}
249
250def uimm6 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isUInt<6>(Imm);}]> {
251  let ParserMatchClass = UImmAsmOperand<6>;
252}
253
254def uimm7 : Operand<GRLenVT> {
255  let ParserMatchClass = UImmAsmOperand<7>;
256}
257
258def uimm8 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isUInt<8>(Imm);}]> {
259  let ParserMatchClass = UImmAsmOperand<8>;
260}
261
262class UImm12Operand : Operand<GRLenVT>,
263                      ImmLeaf <GRLenVT, [{return isUInt<12>(Imm);}]> {
264  let DecoderMethod = "decodeUImmOperand<12>";
265}
266
267def uimm12 : UImm12Operand {
268  let ParserMatchClass = UImmAsmOperand<12>;
269}
270
271def uimm12_ori : UImm12Operand {
272  let ParserMatchClass = UImmAsmOperand<12, "ori">;
273}
274
275def uimm14 : Operand<GRLenVT>,
276             ImmLeaf <GRLenVT, [{return isUInt<14>(Imm);}]> {
277  let ParserMatchClass = UImmAsmOperand<14>;
278}
279
280def uimm15 : Operand<GRLenVT>,
281             ImmLeaf <GRLenVT, [{return isUInt<15>(Imm);}]> {
282  let ParserMatchClass = UImmAsmOperand<15>;
283}
284
285def simm5 : Operand<GRLenVT> {
286  let ParserMatchClass = SImmAsmOperand<5>;
287  let DecoderMethod = "decodeSImmOperand<5>";
288}
289
290def simm8 : Operand<GRLenVT> {
291  let ParserMatchClass = SImmAsmOperand<8>;
292  let DecoderMethod = "decodeSImmOperand<8>";
293}
294
295foreach I = [1, 2, 3] in {
296def simm8_lsl # I : Operand<GRLenVT> {
297  let ParserMatchClass = SImmAsmOperand<8, "lsl" # I>;
298  let EncoderMethod = "getImmOpValueAsr<" # I # ">";
299  let DecoderMethod = "decodeSImmOperand<8," # I # ">";
300}
301}
302
303def simm9_lsl3 : Operand<GRLenVT> {
304  let ParserMatchClass = SImmAsmOperand<9, "lsl3">;
305  let EncoderMethod = "getImmOpValueAsr<3>";
306  let DecoderMethod = "decodeSImmOperand<9, 3>";
307}
308
309def simm10 : Operand<GRLenVT> {
310  let ParserMatchClass = SImmAsmOperand<10>;
311}
312
313def simm10_lsl2 : Operand<GRLenVT> {
314  let ParserMatchClass = SImmAsmOperand<10, "lsl2">;
315  let EncoderMethod = "getImmOpValueAsr<2>";
316  let DecoderMethod = "decodeSImmOperand<10, 2>";
317}
318
319def simm11_lsl1 : Operand<GRLenVT> {
320  let ParserMatchClass = SImmAsmOperand<11, "lsl1">;
321  let EncoderMethod = "getImmOpValueAsr<1>";
322  let DecoderMethod = "decodeSImmOperand<11, 1>";
323}
324
325class SImm12Operand : Operand<GRLenVT>,
326                      ImmLeaf <GRLenVT, [{return isInt<12>(Imm);}]> {
327  let DecoderMethod = "decodeSImmOperand<12>";
328}
329
330def simm12 : SImm12Operand {
331  let ParserMatchClass = SImmAsmOperand<12>;
332}
333
334def simm12_addlike : SImm12Operand {
335  let ParserMatchClass = SImmAsmOperand<12, "addlike">;
336}
337
338def simm12_lu52id : SImm12Operand {
339  let ParserMatchClass = SImmAsmOperand<12, "lu52id">;
340}
341
342def simm13 : Operand<GRLenVT> {
343  let ParserMatchClass = SImmAsmOperand<13>;
344  let DecoderMethod = "decodeSImmOperand<13>";
345}
346
347def simm14_lsl2 : Operand<GRLenVT>,
348    ImmLeaf<GRLenVT, [{return isShiftedInt<14,2>(Imm);}]> {
349  let ParserMatchClass = SImmAsmOperand<14, "lsl2">;
350  let EncoderMethod = "getImmOpValueAsr<2>";
351  let DecoderMethod = "decodeSImmOperand<14, 2>";
352}
353
354def simm16 : Operand<GRLenVT> {
355  let ParserMatchClass = SImmAsmOperand<16>;
356  let DecoderMethod = "decodeSImmOperand<16>";
357}
358
359def simm16_lsl2 : Operand<GRLenVT>,
360    ImmLeaf<GRLenVT, [{return isInt<16>(Imm>>2);}]> {
361  let ParserMatchClass = SImmAsmOperand<16, "lsl2">;
362  let EncoderMethod = "getImmOpValueAsr<2>";
363  let DecoderMethod = "decodeSImmOperand<16, 2>";
364}
365
366def simm16_lsl2_br : Operand<OtherVT> {
367  let ParserMatchClass = SImmAsmOperand<16, "lsl2">;
368  let EncoderMethod = "getImmOpValueAsr<2>";
369  let DecoderMethod = "decodeSImmOperand<16, 2>";
370}
371
372class SImm20Operand : Operand<GRLenVT> {
373  let DecoderMethod = "decodeSImmOperand<20>";
374}
375
376def simm20 : SImm20Operand {
377  let ParserMatchClass = SImmAsmOperand<20>;
378}
379
380def simm20_pcalau12i : SImm20Operand {
381  let ParserMatchClass = SImmAsmOperand<20, "pcalau12i">;
382}
383
384def simm20_lu12iw : SImm20Operand {
385  let ParserMatchClass = SImmAsmOperand<20, "lu12iw">;
386}
387
388def simm20_lu32id : SImm20Operand {
389  let ParserMatchClass = SImmAsmOperand<20, "lu32id">;
390}
391
392def simm20_pcaddu18i : SImm20Operand {
393  let ParserMatchClass = SImmAsmOperand<20, "pcaddu18i">;
394}
395
396def simm21_lsl2 : Operand<OtherVT> {
397  let ParserMatchClass = SImmAsmOperand<21, "lsl2">;
398  let EncoderMethod = "getImmOpValueAsr<2>";
399  let DecoderMethod = "decodeSImmOperand<21, 2>";
400}
401
402def SImm26OperandB: AsmOperandClass {
403  let Name = "SImm26OperandB";
404  let PredicateMethod = "isSImm26Operand";
405  let RenderMethod = "addImmOperands";
406  let DiagnosticType = "InvalidSImm26Operand";
407  let ParserMethod = "parseImmediate";
408}
409
410// A symbol or an imm used in B/PseudoBR.
411def simm26_b : Operand<OtherVT> {
412  let ParserMatchClass = SImm26OperandB;
413  let EncoderMethod = "getImmOpValueAsr<2>";
414  let DecoderMethod = "decodeSImmOperand<26, 2>";
415}
416
417def SImm26OperandBL: AsmOperandClass {
418  let Name = "SImm26OperandBL";
419  let PredicateMethod = "isSImm26Operand";
420  let RenderMethod = "addImmOperands";
421  let DiagnosticType = "InvalidSImm26Operand";
422  let ParserMethod = "parseSImm26Operand";
423}
424
425// A symbol or an imm used in BL/PseudoCALL/PseudoTAIL.
426def simm26_symbol : Operand<GRLenVT> {
427  let ParserMatchClass = SImm26OperandBL;
428  let EncoderMethod = "getImmOpValueAsr<2>";
429  let DecoderMethod = "decodeSImmOperand<26, 2>";
430}
431
432// A 32-bit signed immediate with the lowest 16 bits zeroed, suitable for
433// direct use with `addu16i.d`.
434def simm16_lsl16 : Operand<GRLenVT>,
435    ImmLeaf<GRLenVT, [{return isShiftedInt<16, 16>(Imm);}]>;
436
437// A 32-bit signed immediate expressible with a pair of `addu16i.d + addi` for
438// use in additions.
439def simm32_hi16_lo12: Operand<GRLenVT>, ImmLeaf<GRLenVT, [{
440  return isShiftedInt<16, 16>(Imm - SignExtend64<12>(Imm));
441}]>;
442
443def BareSymbol : AsmOperandClass {
444  let Name = "BareSymbol";
445  let RenderMethod = "addImmOperands";
446  let DiagnosticType = "InvalidBareSymbol";
447  let ParserMethod = "parseImmediate";
448}
449
450// A bare symbol used in "PseudoLA_*" instructions.
451def bare_symbol : Operand<GRLenVT> {
452  let ParserMatchClass = BareSymbol;
453}
454
455// Standalone (codegen-only) immleaf patterns.
456
457// A 12-bit signed immediate plus one where the imm range will be [-2047, 2048].
458def simm12_plus1 : ImmLeaf<GRLenVT,
459  [{return (isInt<12>(Imm) && Imm != -2048) || Imm == 2048;}]>;
460
461// Return the negation of an immediate value.
462def NegImm : SDNodeXForm<imm, [{
463  return CurDAG->getTargetConstant(-N->getSExtValue(), SDLoc(N),
464                                   N->getValueType(0));
465}]>;
466
467// FP immediate patterns.
468def fpimm0    : PatLeaf<(fpimm), [{return N->isExactlyValue(+0.0);}]>;
469def fpimm0neg : PatLeaf<(fpimm), [{return N->isExactlyValue(-0.0);}]>;
470def fpimm1    : PatLeaf<(fpimm), [{return N->isExactlyValue(+1.0);}]>;
471
472// Return an immediate subtracted from 32.
473def ImmSubFrom32 : SDNodeXForm<imm, [{
474  return CurDAG->getTargetConstant(32 - N->getZExtValue(), SDLoc(N),
475                                   N->getValueType(0));
476}]>;
477
478// Return the lowest 12 bits of the signed immediate.
479def LO12: SDNodeXForm<imm, [{
480  return CurDAG->getTargetConstant(SignExtend64<12>(N->getSExtValue()),
481                                   SDLoc(N), N->getValueType(0));
482}]>;
483
484// Return the higher 16 bits of the signed immediate.
485def HI16 : SDNodeXForm<imm, [{
486  return CurDAG->getTargetConstant(N->getSExtValue() >> 16, SDLoc(N),
487                                   N->getValueType(0));
488}]>;
489
490// Return the higher 16 bits of the signed immediate, adjusted for use within an
491// `addu16i.d + addi` pair.
492def HI16ForAddu16idAddiPair: SDNodeXForm<imm, [{
493  auto Imm = N->getSExtValue();
494  return CurDAG->getTargetConstant((Imm - SignExtend64<12>(Imm)) >> 16,
495                                   SDLoc(N), N->getValueType(0));
496}]>;
497
498def BaseAddr : ComplexPattern<iPTR, 1, "SelectBaseAddr">;
499def AddrConstant : ComplexPattern<iPTR, 2, "SelectAddrConstant">;
500def NonFIBaseAddr : ComplexPattern<iPTR, 1, "selectNonFIBaseAddr">;
501
502def fma_nsz : PatFrag<(ops node:$fj, node:$fk, node:$fa),
503                      (fma node:$fj, node:$fk, node:$fa), [{
504  return N->getFlags().hasNoSignedZeros();
505}]>;
506
507// Check if (add r, imm) can be optimized to (ADDI (ADDI r, imm0), imm1),
508// in which imm = imm0 + imm1, and both imm0 & imm1 are simm12.
509def AddiPair : PatLeaf<(imm), [{
510  if (!N->hasOneUse())
511    return false;
512  // The immediate operand must be in range [-4096,-2049] or [2048,4094].
513  int64_t Imm = N->getSExtValue();
514  return (-4096 <= Imm && Imm <= -2049) || (2048 <= Imm && Imm <= 4094);
515}]>;
516
517// Return -2048 if immediate is negative or 2047 if positive.
518def AddiPairImmLarge : SDNodeXForm<imm, [{
519  int64_t Imm = N->getSExtValue() < 0 ? -2048 : 2047;
520  return CurDAG->getTargetConstant(Imm, SDLoc(N),
521                                   N->getValueType(0));
522}]>;
523
524// Return imm - (imm < 0 ? -2048 : 2047).
525def AddiPairImmSmall : SDNodeXForm<imm, [{
526  int64_t Imm = N->getSExtValue();
527  int64_t Adj = Imm < 0 ? -2048 : 2047;
528  return CurDAG->getTargetConstant(Imm - Adj, SDLoc(N),
529                                   N->getValueType(0));
530}]>;
531
532// Check if (mul r, imm) can be optimized to (SLLI (ALSL r, r, i0), i1),
533// in which imm = (1 + (1 << i0)) << i1.
534def AlslSlliImm : PatLeaf<(imm), [{
535  if (!N->hasOneUse())
536    return false;
537  uint64_t Imm = N->getZExtValue();
538  unsigned I1 = llvm::countr_zero(Imm);
539  uint64_t Rem = Imm >> I1;
540  return Rem == 3 || Rem == 5 || Rem == 9 || Rem == 17;
541}]>;
542
543def AlslSlliImmI1 : SDNodeXForm<imm, [{
544  uint64_t Imm = N->getZExtValue();
545  unsigned I1 = llvm::countr_zero(Imm);
546  return CurDAG->getTargetConstant(I1, SDLoc(N),
547                                   N->getValueType(0));
548}]>;
549
550def AlslSlliImmI0 : SDNodeXForm<imm, [{
551  uint64_t Imm = N->getZExtValue();
552  unsigned I1 = llvm::countr_zero(Imm);
553  uint64_t I0;
554  switch (Imm >> I1) {
555  case 3:  I0 = 1; break;
556  case 5:  I0 = 2; break;
557  case 9:  I0 = 3; break;
558  default: I0 = 4; break;
559  }
560  return CurDAG->getTargetConstant(I0, SDLoc(N),
561                                   N->getValueType(0));
562}]>;
563
564// Check if (and r, imm) can be optimized to (BSTRINS r, R0, msb, lsb),
565// in which imm = ~((2^^(msb-lsb+1) - 1) << lsb).
566def BstrinsImm : PatLeaf<(imm), [{
567  if (!N->hasOneUse())
568    return false;
569  uint64_t Imm = N->getZExtValue();
570  // andi can be used instead if Imm <= 0xfff.
571  if (Imm <= 0xfff)
572    return false;
573  unsigned MaskIdx, MaskLen;
574  return N->getValueType(0).getSizeInBits() == 32
575             ? llvm::isShiftedMask_32(~Imm, MaskIdx, MaskLen)
576             : llvm::isShiftedMask_64(~Imm, MaskIdx, MaskLen);
577}]>;
578
579def BstrinsMsb: SDNodeXForm<imm, [{
580  uint64_t Imm = N->getZExtValue();
581  unsigned MaskIdx, MaskLen;
582  N->getValueType(0).getSizeInBits() == 32
583      ? llvm::isShiftedMask_32(~Imm, MaskIdx, MaskLen)
584      : llvm::isShiftedMask_64(~Imm, MaskIdx, MaskLen);
585  return CurDAG->getTargetConstant(MaskIdx + MaskLen - 1, SDLoc(N),
586                                   N->getValueType(0));
587}]>;
588
589def BstrinsLsb: SDNodeXForm<imm, [{
590  uint64_t Imm = N->getZExtValue();
591  unsigned MaskIdx, MaskLen;
592  N->getValueType(0).getSizeInBits() == 32
593      ? llvm::isShiftedMask_32(~Imm, MaskIdx, MaskLen)
594      : llvm::isShiftedMask_64(~Imm, MaskIdx, MaskLen);
595  return CurDAG->getTargetConstant(MaskIdx, SDLoc(N), N->getValueType(0));
596}]>;
597
598//===----------------------------------------------------------------------===//
599// Instruction Formats
600//===----------------------------------------------------------------------===//
601
602include "LoongArchInstrFormats.td"
603include "LoongArchFloatInstrFormats.td"
604include "LoongArchLSXInstrFormats.td"
605include "LoongArchLASXInstrFormats.td"
606include "LoongArchLBTInstrFormats.td"
607
608//===----------------------------------------------------------------------===//
609// Instruction Class Templates
610//===----------------------------------------------------------------------===//
611
612let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
613class ALU_3R<bits<32> op>
614    : Fmt3R<op, (outs GPR:$rd), (ins GPR:$rj, GPR:$rk), "$rd, $rj, $rk">;
615class ALU_2R<bits<32> op>
616    : Fmt2R<op, (outs GPR:$rd), (ins GPR:$rj), "$rd, $rj">;
617
618class ALU_3RI2<bits<32> op, Operand ImmOpnd>
619    : Fmt3RI2<op, (outs GPR:$rd), (ins GPR:$rj, GPR:$rk, ImmOpnd:$imm2),
620              "$rd, $rj, $rk, $imm2">;
621class ALU_3RI3<bits<32> op, Operand ImmOpnd>
622    : Fmt3RI3<op, (outs GPR:$rd), (ins GPR:$rj, GPR:$rk, ImmOpnd:$imm3),
623              "$rd, $rj, $rk, $imm3">;
624class ALU_2RI5<bits<32> op, Operand ImmOpnd>
625    : Fmt2RI5<op, (outs GPR:$rd), (ins GPR:$rj, ImmOpnd:$imm5),
626              "$rd, $rj, $imm5">;
627class ALU_2RI6<bits<32> op, Operand ImmOpnd>
628    : Fmt2RI6<op, (outs GPR:$rd), (ins GPR:$rj, ImmOpnd:$imm6),
629              "$rd, $rj, $imm6">;
630class ALU_2RI12<bits<32> op, Operand ImmOpnd>
631    : Fmt2RI12<op, (outs GPR:$rd), (ins GPR:$rj, ImmOpnd:$imm12),
632               "$rd, $rj, $imm12">;
633class ALU_2RI16<bits<32> op, Operand ImmOpnd>
634    : Fmt2RI16<op, (outs GPR:$rd), (ins GPR:$rj, ImmOpnd:$imm16),
635               "$rd, $rj, $imm16">;
636class ALU_1RI20<bits<32> op, Operand ImmOpnd>
637    : Fmt1RI20<op, (outs GPR:$rd), (ins ImmOpnd:$imm20), "$rd, $imm20">;
638} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
639
640let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
641class MISC_I15<bits<32> op>
642    : FmtI15<op, (outs), (ins uimm15:$imm15), "$imm15">;
643
644let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
645class RDTIME_2R<bits<32> op>
646    : Fmt2R<op, (outs GPR:$rd, GPR:$rj), (ins), "$rd, $rj">;
647
648let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
649class BrCC_2RI16<bits<32> op>
650    : Fmt2RI16<op, (outs), (ins GPR:$rj, GPR:$rd, simm16_lsl2_br:$imm16),
651               "$rj, $rd, $imm16"> {
652  let isBranch = 1;
653  let isTerminator = 1;
654}
655class BrCCZ_1RI21<bits<32> op>
656    : Fmt1RI21<op, (outs), (ins GPR:$rj, simm21_lsl2:$imm21),
657               "$rj, $imm21"> {
658  let isBranch = 1;
659  let isTerminator = 1;
660}
661class Br_I26<bits<32> op>
662    : FmtI26<op, (outs), (ins simm26_b:$imm26), "$imm26"> {
663  let isBranch = 1;
664  let isTerminator = 1;
665  let isBarrier = 1;
666}
667} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
668
669let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
670class LOAD_3R<bits<32> op>
671    : Fmt3R<op, (outs GPR:$rd), (ins GPR:$rj, GPR:$rk), "$rd, $rj, $rk">;
672class LOAD_2RI12<bits<32> op>
673    : Fmt2RI12<op, (outs GPR:$rd), (ins GPR:$rj, simm12_addlike:$imm12),
674               "$rd, $rj, $imm12">;
675class LOAD_2RI14<bits<32> op>
676    : Fmt2RI14<op, (outs GPR:$rd), (ins GPR:$rj, simm14_lsl2:$imm14),
677               "$rd, $rj, $imm14">;
678} // hasSideEffects = 0, mayLoad = 1, mayStore = 0
679
680let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
681class STORE_3R<bits<32> op>
682    : Fmt3R<op, (outs), (ins GPR:$rd, GPR:$rj, GPR:$rk),
683            "$rd, $rj, $rk">;
684class STORE_2RI12<bits<32> op>
685    : Fmt2RI12<op, (outs), (ins GPR:$rd, GPR:$rj, simm12_addlike:$imm12),
686               "$rd, $rj, $imm12">;
687class STORE_2RI14<bits<32> op>
688    : Fmt2RI14<op, (outs), (ins GPR:$rd, GPR:$rj, simm14_lsl2:$imm14),
689               "$rd, $rj, $imm14">;
690} // hasSideEffects = 0, mayLoad = 0, mayStore = 1
691
692let hasSideEffects = 0, mayLoad = 1, mayStore = 1, Constraints = "@earlyclobber $rd" in
693class AM_3R<bits<32> op>
694    : Fmt3R<op, (outs GPR:$rd), (ins GPR:$rk, GPRMemAtomic:$rj),
695            "$rd, $rk, $rj">;
696
697let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
698class LLBase<bits<32> op>
699    : Fmt2RI14<op, (outs GPR:$rd), (ins GPR:$rj, simm14_lsl2:$imm14),
700               "$rd, $rj, $imm14">;
701class LLBase_ACQ<bits<32> op>
702    : Fmt2R<op, (outs GPR:$rd), (ins GPR:$rj), "$rd, $rj">;
703}
704
705let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Constraints = "$rd = $dst" in {
706class SCBase<bits<32> op>
707    : Fmt2RI14<op, (outs GPR:$dst), (ins GPR:$rd, GPR:$rj, simm14_lsl2:$imm14),
708               "$rd, $rj, $imm14">;
709class SCBase_128<bits<32> op>
710    : Fmt3R<op, (outs GPR:$dst), (ins GPR:$rd, GPR:$rk, GPR:$rj),
711               "$rd, $rk, $rj">;
712class SCBase_REL<bits<32> op>
713    : Fmt2R<op, (outs GPR:$dst), (ins GPR:$rd, GPR:$rj), "$rd, $rj">;
714}
715
716let hasSideEffects = 1 in
717class IOCSRRD<bits<32> op>
718    : Fmt2R<op, (outs GPR:$rd), (ins GPR:$rj), "$rd, $rj">;
719
720let hasSideEffects = 1 in
721class IOCSRWR<bits<32> op>
722    : Fmt2R<op, (outs), (ins GPR:$rd, GPR:$rj), "$rd, $rj">;
723
724//===----------------------------------------------------------------------===//
725// Basic Integer Instructions
726//===----------------------------------------------------------------------===//
727
728// Arithmetic Operation Instructions
729def ADD_W : ALU_3R<0x00100000>;
730def SUB_W : ALU_3R<0x00110000>;
731def ADDI_W : ALU_2RI12<0x02800000, simm12_addlike>;
732def ALSL_W : ALU_3RI2<0x00040000, uimm2_plus1>;
733def LU12I_W : ALU_1RI20<0x14000000, simm20_lu12iw>;
734def SLT  : ALU_3R<0x00120000>;
735def SLTU : ALU_3R<0x00128000>;
736def SLTI  : ALU_2RI12<0x02000000, simm12>;
737def SLTUI : ALU_2RI12<0x02400000, simm12>;
738def PCADDI    : ALU_1RI20<0x18000000, simm20>;
739def PCADDU12I : ALU_1RI20<0x1c000000, simm20>;
740def PCALAU12I : ALU_1RI20<0x1a000000, simm20_pcalau12i>;
741def AND  : ALU_3R<0x00148000>;
742def OR   : ALU_3R<0x00150000>;
743def NOR  : ALU_3R<0x00140000>;
744def XOR  : ALU_3R<0x00158000>;
745def ANDN : ALU_3R<0x00168000>;
746def ORN  : ALU_3R<0x00160000>;
747def ANDI : ALU_2RI12<0x03400000, uimm12>;
748def ORI  : ALU_2RI12<0x03800000, uimm12_ori>;
749def XORI : ALU_2RI12<0x03c00000, uimm12>;
750def MUL_W   : ALU_3R<0x001c0000>;
751def MULH_W  : ALU_3R<0x001c8000>;
752def MULH_WU : ALU_3R<0x001d0000>;
753let usesCustomInserter = true in {
754def DIV_W   : ALU_3R<0x00200000>;
755def MOD_W   : ALU_3R<0x00208000>;
756def DIV_WU  : ALU_3R<0x00210000>;
757def MOD_WU  : ALU_3R<0x00218000>;
758} // usesCustomInserter = true
759
760// Bit-shift Instructions
761def SLL_W  : ALU_3R<0x00170000>;
762def SRL_W  : ALU_3R<0x00178000>;
763def SRA_W  : ALU_3R<0x00180000>;
764def ROTR_W : ALU_3R<0x001b0000>;
765
766def SLLI_W  : ALU_2RI5<0x00408000, uimm5>;
767def SRLI_W  : ALU_2RI5<0x00448000, uimm5>;
768def SRAI_W  : ALU_2RI5<0x00488000, uimm5>;
769def ROTRI_W : ALU_2RI5<0x004c8000, uimm5>;
770
771// Bit-manipulation Instructions
772def EXT_W_B : ALU_2R<0x00005c00>;
773def EXT_W_H : ALU_2R<0x00005800>;
774def CLO_W   : ALU_2R<0x00001000>;
775def CLZ_W   : ALU_2R<0x00001400>;
776def CTO_W   : ALU_2R<0x00001800>;
777def CTZ_W   : ALU_2R<0x00001c00>;
778def BYTEPICK_W : ALU_3RI2<0x00080000, uimm2>;
779def REVB_2H   : ALU_2R<0x00003000>;
780def BITREV_4B : ALU_2R<0x00004800>;
781def BITREV_W  : ALU_2R<0x00005000>;
782let Constraints = "$rd = $dst" in {
783def BSTRINS_W  : FmtBSTR_W<0x00600000, (outs GPR:$dst),
784                           (ins GPR:$rd, GPR:$rj, uimm5:$msbw, uimm5:$lsbw),
785                           "$rd, $rj, $msbw, $lsbw">;
786}
787def BSTRPICK_W : FmtBSTR_W<0x00608000, (outs GPR:$rd),
788                           (ins GPR:$rj, uimm5:$msbw, uimm5:$lsbw),
789                           "$rd, $rj, $msbw, $lsbw">;
790def MASKEQZ : ALU_3R<0x00130000>;
791def MASKNEZ : ALU_3R<0x00138000>;
792
793// Branch Instructions
794def BEQ  : BrCC_2RI16<0x58000000>;
795def BNE  : BrCC_2RI16<0x5c000000>;
796def BLT  : BrCC_2RI16<0x60000000>;
797def BGE  : BrCC_2RI16<0x64000000>;
798def BLTU : BrCC_2RI16<0x68000000>;
799def BGEU : BrCC_2RI16<0x6c000000>;
800def BEQZ : BrCCZ_1RI21<0x40000000>;
801def BNEZ : BrCCZ_1RI21<0x44000000>;
802def B : Br_I26<0x50000000>;
803
804let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCall = 1, Defs=[R1] in
805def BL : FmtI26<0x54000000, (outs), (ins simm26_symbol:$imm26), "$imm26">;
806let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
807def JIRL : Fmt2RI16<0x4c000000, (outs GPR:$rd),
808                    (ins GPR:$rj, simm16_lsl2:$imm16), "$rd, $rj, $imm16">;
809
810// Common Memory Access Instructions
811def LD_B  : LOAD_2RI12<0x28000000>;
812def LD_H  : LOAD_2RI12<0x28400000>;
813def LD_W  : LOAD_2RI12<0x28800000>;
814def LD_BU : LOAD_2RI12<0x2a000000>;
815def LD_HU : LOAD_2RI12<0x2a400000>;
816def ST_B : STORE_2RI12<0x29000000>;
817def ST_H : STORE_2RI12<0x29400000>;
818def ST_W : STORE_2RI12<0x29800000>;
819let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in
820def PRELD : FmtPRELD<(outs), (ins uimm5:$imm5, GPR:$rj, simm12:$imm12),
821                     "$imm5, $rj, $imm12">;
822
823// Atomic Memory Access Instructions
824def LL_W : LLBase<0x20000000>;
825def SC_W : SCBase<0x21000000>;
826def LLACQ_W : LLBase_ACQ<0x38578000>;
827def SCREL_W : SCBase_REL<0x38578400>;
828
829// Barrier Instructions
830def DBAR : MISC_I15<0x38720000>;
831def IBAR : MISC_I15<0x38728000>;
832
833// Other Miscellaneous Instructions
834def SYSCALL : MISC_I15<0x002b0000>;
835def BREAK   : MISC_I15<0x002a0000>;
836def RDTIMEL_W : RDTIME_2R<0x00006000>;
837def RDTIMEH_W : RDTIME_2R<0x00006400>;
838def CPUCFG : ALU_2R<0x00006c00>;
839
840// Cache Maintenance Instructions
841def CACOP : FmtCACOP<(outs), (ins uimm5:$op, GPR:$rj, simm12:$imm12),
842                     "$op, $rj, $imm12">;
843
844/// LA64 instructions
845
846let Predicates = [IsLA64] in {
847
848// Arithmetic Operation Instructions for 64-bits
849def ADD_D : ALU_3R<0x00108000>;
850def SUB_D : ALU_3R<0x00118000>;
851def ADDI_D : ALU_2RI12<0x02c00000, simm12_addlike>;
852def ADDU16I_D : ALU_2RI16<0x10000000, simm16>;
853def ALSL_WU : ALU_3RI2<0x00060000, uimm2_plus1>;
854def ALSL_D  : ALU_3RI2<0x002c0000, uimm2_plus1>;
855let Constraints = "$rd = $dst" in {
856let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
857def LU32I_D : Fmt1RI20<0x16000000, (outs GPR:$dst),
858                       (ins GPR:$rd, simm20_lu32id:$imm20),
859                       "$rd, $imm20">;
860}
861def LU52I_D : ALU_2RI12<0x03000000, simm12_lu52id>;
862def PCADDU18I : ALU_1RI20<0x1e000000, simm20_pcaddu18i>;
863def MUL_D     : ALU_3R<0x001d8000>;
864def MULH_D    : ALU_3R<0x001e0000>;
865def MULH_DU   : ALU_3R<0x001e8000>;
866def MULW_D_W  : ALU_3R<0x001f0000>;
867def MULW_D_WU : ALU_3R<0x001f8000>;
868let usesCustomInserter = true in {
869def DIV_D     : ALU_3R<0x00220000>;
870def MOD_D     : ALU_3R<0x00228000>;
871def DIV_DU    : ALU_3R<0x00230000>;
872def MOD_DU    : ALU_3R<0x00238000>;
873} // usesCustomInserter = true
874
875// Bit-shift Instructions for 64-bits
876def SLL_D  : ALU_3R<0x00188000>;
877def SRL_D  : ALU_3R<0x00190000>;
878def SRA_D  : ALU_3R<0x00198000>;
879def ROTR_D : ALU_3R<0x001b8000>;
880def SLLI_D  : ALU_2RI6<0x00410000, uimm6>;
881def SRLI_D  : ALU_2RI6<0x00450000, uimm6>;
882def SRAI_D  : ALU_2RI6<0x00490000, uimm6>;
883def ROTRI_D : ALU_2RI6<0x004d0000, uimm6>;
884
885// Bit-manipulation Instructions for 64-bits
886def CLO_D : ALU_2R<0x00002000>;
887def CLZ_D : ALU_2R<0x00002400>;
888def CTO_D : ALU_2R<0x00002800>;
889def CTZ_D : ALU_2R<0x00002c00>;
890def BYTEPICK_D : ALU_3RI3<0x000c0000, uimm3>;
891def REVB_4H   : ALU_2R<0x00003400>;
892def REVB_2W   : ALU_2R<0x00003800>;
893def REVB_D    : ALU_2R<0x00003c00>;
894def REVH_2W   : ALU_2R<0x00004000>;
895def REVH_D    : ALU_2R<0x00004400>;
896def BITREV_8B : ALU_2R<0x00004c00>;
897def BITREV_D  : ALU_2R<0x00005400>;
898let Constraints = "$rd = $dst" in {
899def BSTRINS_D  : FmtBSTR_D<0x00800000, (outs GPR:$dst),
900                           (ins GPR:$rd, GPR:$rj, uimm6:$msbd, uimm6:$lsbd),
901                           "$rd, $rj, $msbd, $lsbd">;
902}
903def BSTRPICK_D : FmtBSTR_D<0x00c00000, (outs GPR:$rd),
904                           (ins GPR:$rj, uimm6:$msbd, uimm6:$lsbd),
905                           "$rd, $rj, $msbd, $lsbd">;
906
907// Common Memory Access Instructions for 64-bits
908def LD_WU : LOAD_2RI12<0x2a800000>;
909def LD_D  : LOAD_2RI12<0x28c00000>;
910def ST_D : STORE_2RI12<0x29c00000>;
911def LDX_B  : LOAD_3R<0x38000000>;
912def LDX_H  : LOAD_3R<0x38040000>;
913def LDX_W  : LOAD_3R<0x38080000>;
914def LDX_D  : LOAD_3R<0x380c0000>;
915def LDX_BU : LOAD_3R<0x38200000>;
916def LDX_HU : LOAD_3R<0x38240000>;
917def LDX_WU : LOAD_3R<0x38280000>;
918def STX_B : STORE_3R<0x38100000>;
919def STX_H : STORE_3R<0x38140000>;
920def STX_W : STORE_3R<0x38180000>;
921def STX_D : STORE_3R<0x381c0000>;
922def LDPTR_W : LOAD_2RI14<0x24000000>;
923def LDPTR_D : LOAD_2RI14<0x26000000>;
924def STPTR_W : STORE_2RI14<0x25000000>;
925def STPTR_D : STORE_2RI14<0x27000000>;
926let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in
927def PRELDX : FmtPRELDX<(outs), (ins uimm5:$imm5, GPR:$rj, GPR:$rk),
928                       "$imm5, $rj, $rk">;
929
930// Bound Check Memory Access Instructions
931def LDGT_B : LOAD_3R<0x38780000>;
932def LDGT_H : LOAD_3R<0x38788000>;
933def LDGT_W : LOAD_3R<0x38790000>;
934def LDGT_D : LOAD_3R<0x38798000>;
935def LDLE_B : LOAD_3R<0x387a0000>;
936def LDLE_H : LOAD_3R<0x387a8000>;
937def LDLE_W : LOAD_3R<0x387b0000>;
938def LDLE_D : LOAD_3R<0x387b8000>;
939def STGT_B : STORE_3R<0x387c0000>;
940def STGT_H : STORE_3R<0x387c8000>;
941def STGT_W : STORE_3R<0x387d0000>;
942def STGT_D : STORE_3R<0x387d8000>;
943def STLE_B : STORE_3R<0x387e0000>;
944def STLE_H : STORE_3R<0x387e8000>;
945def STLE_W : STORE_3R<0x387f0000>;
946def STLE_D : STORE_3R<0x387f8000>;
947
948// Atomic Memory Access Instructions for 64-bits
949def AMSWAP_B     : AM_3R<0x385c0000>;
950def AMSWAP_H     : AM_3R<0x385c8000>;
951def AMSWAP_W     : AM_3R<0x38600000>;
952def AMSWAP_D     : AM_3R<0x38608000>;
953def AMADD_B      : AM_3R<0x385d0000>;
954def AMADD_H      : AM_3R<0x385d8000>;
955def AMADD_W      : AM_3R<0x38610000>;
956def AMADD_D      : AM_3R<0x38618000>;
957def AMAND_W      : AM_3R<0x38620000>;
958def AMAND_D      : AM_3R<0x38628000>;
959def AMOR_W       : AM_3R<0x38630000>;
960def AMOR_D       : AM_3R<0x38638000>;
961def AMXOR_W      : AM_3R<0x38640000>;
962def AMXOR_D      : AM_3R<0x38648000>;
963def AMMAX_W      : AM_3R<0x38650000>;
964def AMMAX_D      : AM_3R<0x38658000>;
965def AMMIN_W      : AM_3R<0x38660000>;
966def AMMIN_D      : AM_3R<0x38668000>;
967def AMMAX_WU     : AM_3R<0x38670000>;
968def AMMAX_DU     : AM_3R<0x38678000>;
969def AMMIN_WU     : AM_3R<0x38680000>;
970def AMMIN_DU     : AM_3R<0x38688000>;
971def AMSWAP__DB_B : AM_3R<0x385e0000>;
972def AMSWAP__DB_H : AM_3R<0x385e8000>;
973def AMSWAP__DB_W : AM_3R<0x38690000>;
974def AMSWAP__DB_D : AM_3R<0x38698000>;
975def AMADD__DB_B  : AM_3R<0x385f0000>;
976def AMADD__DB_H  : AM_3R<0x385f8000>;
977def AMADD__DB_W  : AM_3R<0x386a0000>;
978def AMADD__DB_D  : AM_3R<0x386a8000>;
979def AMAND__DB_W  : AM_3R<0x386b0000>;
980def AMAND__DB_D  : AM_3R<0x386b8000>;
981def AMOR__DB_W   : AM_3R<0x386c0000>;
982def AMOR__DB_D   : AM_3R<0x386c8000>;
983def AMXOR__DB_W  : AM_3R<0x386d0000>;
984def AMXOR__DB_D  : AM_3R<0x386d8000>;
985def AMMAX__DB_W  : AM_3R<0x386e0000>;
986def AMMAX__DB_D  : AM_3R<0x386e8000>;
987def AMMIN__DB_W  : AM_3R<0x386f0000>;
988def AMMIN__DB_D  : AM_3R<0x386f8000>;
989def AMMAX__DB_WU : AM_3R<0x38700000>;
990def AMMAX__DB_DU : AM_3R<0x38708000>;
991def AMMIN__DB_WU : AM_3R<0x38710000>;
992def AMMIN__DB_DU : AM_3R<0x38718000>;
993def AMCAS_B     : AM_3R<0x38580000>;
994def AMCAS_H     : AM_3R<0x38588000>;
995def AMCAS_W     : AM_3R<0x38590000>;
996def AMCAS_D     : AM_3R<0x38598000>;
997def AMCAS__DB_B     : AM_3R<0x385a0000>;
998def AMCAS__DB_H     : AM_3R<0x385a8000>;
999def AMCAS__DB_W     : AM_3R<0x385b0000>;
1000def AMCAS__DB_D     : AM_3R<0x385b8000>;
1001def LL_D : LLBase<0x22000000>;
1002def SC_D : SCBase<0x23000000>;
1003def SC_Q : SCBase_128<0x38570000>;
1004def LLACQ_D : LLBase_ACQ<0x38578800>;
1005def SCREL_D : SCBase_REL<0x38578C00>;
1006
1007// CRC Check Instructions
1008def CRC_W_B_W  : ALU_3R<0x00240000>;
1009def CRC_W_H_W  : ALU_3R<0x00248000>;
1010def CRC_W_W_W  : ALU_3R<0x00250000>;
1011def CRC_W_D_W  : ALU_3R<0x00258000>;
1012def CRCC_W_B_W : ALU_3R<0x00260000>;
1013def CRCC_W_H_W : ALU_3R<0x00268000>;
1014def CRCC_W_W_W : ALU_3R<0x00270000>;
1015def CRCC_W_D_W : ALU_3R<0x00278000>;
1016
1017// Other Miscellaneous Instructions for 64-bits
1018def ASRTLE_D : FmtASRT<0x00010000, (outs), (ins GPR:$rj, GPR:$rk),
1019                       "$rj, $rk">;
1020def ASRTGT_D : FmtASRT<0x00018000, (outs), (ins GPR:$rj, GPR:$rk),
1021                       "$rj, $rk">;
1022def RDTIME_D : RDTIME_2R<0x00006800>;
1023} // Predicates = [IsLA64]
1024
1025//===----------------------------------------------------------------------===//
1026// Pseudo-instructions and codegen patterns
1027//
1028// Naming convention: For 'generic' pattern classes, we use the naming
1029// convention PatTy1Ty2.
1030//===----------------------------------------------------------------------===//
1031
1032/// Generic pattern classes
1033
1034class PatGprGpr<SDPatternOperator OpNode, LAInst Inst>
1035    : Pat<(OpNode GPR:$rj, GPR:$rk), (Inst GPR:$rj, GPR:$rk)>;
1036class PatGprGpr_32<SDPatternOperator OpNode, LAInst Inst>
1037    : Pat<(sext_inreg (OpNode GPR:$rj, GPR:$rk), i32), (Inst GPR:$rj, GPR:$rk)>;
1038class PatGpr<SDPatternOperator OpNode, LAInst Inst>
1039    : Pat<(OpNode GPR:$rj), (Inst GPR:$rj)>;
1040
1041class PatGprImm<SDPatternOperator OpNode, LAInst Inst, Operand ImmOpnd>
1042    : Pat<(OpNode GPR:$rj, ImmOpnd:$imm),
1043          (Inst GPR:$rj, ImmOpnd:$imm)>;
1044class PatGprImm_32<SDPatternOperator OpNode, LAInst Inst, Operand ImmOpnd>
1045    : Pat<(sext_inreg (OpNode GPR:$rj, ImmOpnd:$imm), i32),
1046          (Inst GPR:$rj, ImmOpnd:$imm)>;
1047
1048/// Predicates
1049def AddLike: PatFrags<(ops node:$A, node:$B),
1050                      [(add node:$A, node:$B), (or node:$A, node:$B)], [{
1051    return N->getOpcode() == ISD::ADD || isOrEquivalentToAdd(N);
1052}]>;
1053
1054/// Simple arithmetic operations
1055
1056// Match both a plain shift and one where the shift amount is masked (this is
1057// typically introduced when the legalizer promotes the shift amount and
1058// zero-extends it). For LoongArch, the mask is unnecessary as shifts in the
1059// base ISA only read the least significant 5 bits (LA32) or 6 bits (LA64).
1060def shiftMaskGRLen
1061    : ComplexPattern<GRLenVT, 1, "selectShiftMaskGRLen", [], [], 0>;
1062def shiftMask32 : ComplexPattern<i64, 1, "selectShiftMask32", [], [], 0>;
1063
1064def sexti32 : ComplexPattern<i64, 1, "selectSExti32">;
1065def zexti32 : ComplexPattern<i64, 1, "selectZExti32">;
1066
1067class shiftop<SDPatternOperator operator>
1068    : PatFrag<(ops node:$val, node:$count),
1069              (operator node:$val, (GRLenVT (shiftMaskGRLen node:$count)))>;
1070class shiftopw<SDPatternOperator operator>
1071    : PatFrag<(ops node:$val, node:$count),
1072              (operator node:$val, (i64 (shiftMask32 node:$count)))>;
1073
1074def mul_const_oneuse : PatFrag<(ops node:$A, node:$B),
1075                               (mul node:$A, node:$B), [{
1076  if (auto *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1)))
1077    return N1C->hasOneUse();
1078  return false;
1079}]>;
1080
1081let Predicates = [IsLA32] in {
1082def : PatGprGpr<add, ADD_W>;
1083def : PatGprImm<add, ADDI_W, simm12>;
1084def : PatGprGpr<sub, SUB_W>;
1085def : PatGprGpr<sdiv, DIV_W>;
1086def : PatGprGpr<udiv, DIV_WU>;
1087def : PatGprGpr<srem, MOD_W>;
1088def : PatGprGpr<urem, MOD_WU>;
1089def : PatGprGpr<mul, MUL_W>;
1090def : PatGprGpr<mulhs, MULH_W>;
1091def : PatGprGpr<mulhu, MULH_WU>;
1092def : PatGprGpr<rotr, ROTR_W>;
1093def : PatGprImm<rotr, ROTRI_W, uimm5>;
1094
1095foreach Idx = 1...3 in {
1096  defvar ShamtA = !mul(8, Idx);
1097  defvar ShamtB = !mul(8, !sub(4, Idx));
1098  def : Pat<(or (shl GPR:$rk, (i32 ShamtA)), (srl GPR:$rj, (i32 ShamtB))),
1099            (BYTEPICK_W GPR:$rj, GPR:$rk, Idx)>;
1100}
1101} // Predicates = [IsLA32]
1102
1103let Predicates = [IsLA64] in {
1104def : PatGprGpr<add, ADD_D>;
1105def : PatGprGpr_32<add, ADD_W>;
1106def : PatGprImm<add, ADDI_D, simm12>;
1107def : PatGprImm_32<add, ADDI_W, simm12>;
1108def : PatGprGpr<sub, SUB_D>;
1109def : PatGprGpr_32<sub, SUB_W>;
1110def : PatGprGpr<sdiv, DIV_D>;
1111def : PatGprGpr<udiv, DIV_DU>;
1112def : PatGprGpr<srem, MOD_D>;
1113def : PatGprGpr<urem, MOD_DU>;
1114def : PatGprGpr<rotr, ROTR_D>;
1115def : PatGprGpr<loongarch_rotr_w, ROTR_W>;
1116def : PatGprImm<rotr, ROTRI_D, uimm6>;
1117def : PatGprImm_32<rotr, ROTRI_W, uimm5>;
1118def : Pat<(loongarch_rotl_w GPR:$rj, uimm5:$imm),
1119          (ROTRI_W GPR:$rj, (ImmSubFrom32 uimm5:$imm))>;
1120def : Pat<(sext_inreg (loongarch_rotl_w GPR:$rj, uimm5:$imm), i32),
1121          (ROTRI_W GPR:$rj, (ImmSubFrom32 uimm5:$imm))>;
1122// TODO: Select "_W[U]" instructions for i32xi32 if only lower 32 bits of the
1123// product are used.
1124def : PatGprGpr<mul, MUL_D>;
1125def : PatGprGpr<mulhs, MULH_D>;
1126def : PatGprGpr<mulhu, MULH_DU>;
1127// Select MULW_D_W for calculating the full 64 bits product of i32xi32 signed
1128// multiplication.
1129def : Pat<(i64 (mul (sext_inreg GPR:$rj, i32), (sext_inreg GPR:$rk, i32))),
1130          (MULW_D_W GPR:$rj, GPR:$rk)>;
1131// Select MULW_D_WU for calculating the full 64 bits product of i32xi32
1132// unsigned multiplication.
1133def : Pat<(i64 (mul (loongarch_bstrpick GPR:$rj, (i64 31), (i64 0)),
1134                    (loongarch_bstrpick GPR:$rk, (i64 31), (i64 0)))),
1135          (MULW_D_WU GPR:$rj, GPR:$rk)>;
1136
1137def : Pat<(add GPR:$rj, simm16_lsl16:$imm),
1138          (ADDU16I_D GPR:$rj, (HI16 $imm))>;
1139def : Pat<(add GPR:$rj, simm32_hi16_lo12:$imm),
1140          (ADDI_D (ADDU16I_D GPR:$rj, (HI16ForAddu16idAddiPair $imm)),
1141                  (LO12 $imm))>;
1142def : Pat<(sext_inreg (add GPR:$rj, simm32_hi16_lo12:$imm), i32),
1143          (ADDI_W (ADDU16I_D GPR:$rj, (HI16ForAddu16idAddiPair $imm)),
1144                  (LO12 $imm))>;
1145
1146let Predicates = [IsLA32] in {
1147def : Pat<(add GPR:$rj, (AddiPair:$im)),
1148          (ADDI_W (ADDI_W GPR:$rj, (AddiPairImmLarge AddiPair:$im)),
1149                  (AddiPairImmSmall AddiPair:$im))>;
1150} // Predicates = [IsLA32]
1151
1152let Predicates = [IsLA64] in {
1153def : Pat<(add GPR:$rj, (AddiPair:$im)),
1154          (ADDI_D (ADDI_D GPR:$rj, (AddiPairImmLarge AddiPair:$im)),
1155                  (AddiPairImmSmall AddiPair:$im))>;
1156def : Pat<(sext_inreg (add GPR:$rj, (AddiPair:$im)), i32),
1157          (ADDI_W (ADDI_W GPR:$rj, (AddiPairImmLarge AddiPair:$im)),
1158                  (AddiPairImmSmall AddiPair:$im))>;
1159} // Predicates = [IsLA64]
1160
1161let Predicates = [IsLA32] in {
1162foreach Idx0 = 1...4 in {
1163  foreach Idx1 = 1...4 in {
1164    defvar CImm = !add(1, !shl(!add(1, !shl(1, Idx0)), Idx1));
1165    def : Pat<(mul_const_oneuse GPR:$r, (i32 CImm)),
1166              (ALSL_W (ALSL_W GPR:$r, GPR:$r, (i32 Idx0)),
1167                      GPR:$r, (i32 Idx1))>;
1168  }
1169}
1170foreach Idx0 = 1...4 in {
1171  foreach Idx1 = 1...4 in {
1172    defvar Cb = !add(1, !shl(1, Idx0));
1173    defvar CImm = !add(Cb, !shl(Cb, Idx1));
1174    def : Pat<(mul_const_oneuse GPR:$r, (i32 CImm)),
1175              (ALSL_W (ALSL_W GPR:$r, GPR:$r, (i32 Idx0)),
1176                      (ALSL_W GPR:$r, GPR:$r, (i32 Idx0)), (i32 Idx1))>;
1177  }
1178}
1179} // Predicates = [IsLA32]
1180
1181let Predicates = [IsLA64] in {
1182foreach Idx0 = 1...4 in {
1183  foreach Idx1 = 1...4 in {
1184    defvar CImm = !add(1, !shl(!add(1, !shl(1, Idx0)), Idx1));
1185    def : Pat<(sext_inreg (mul_const_oneuse GPR:$r, (i64 CImm)), i32),
1186              (ALSL_W (ALSL_W GPR:$r, GPR:$r, (i64 Idx0)),
1187                      GPR:$r, (i64 Idx1))>;
1188    def : Pat<(mul_const_oneuse GPR:$r, (i64 CImm)),
1189              (ALSL_D (ALSL_D GPR:$r, GPR:$r, (i64 Idx0)),
1190                      GPR:$r, (i64 Idx1))>;
1191  }
1192}
1193foreach Idx0 = 1...4 in {
1194  foreach Idx1 = 1...4 in {
1195    defvar Cb = !add(1, !shl(1, Idx0));
1196    defvar CImm = !add(Cb, !shl(Cb, Idx1));
1197    def : Pat<(sext_inreg (mul_const_oneuse GPR:$r, (i64 CImm)), i32),
1198              (ALSL_W (ALSL_W GPR:$r, GPR:$r, (i64 Idx0)),
1199                      (ALSL_W GPR:$r, GPR:$r, (i64 Idx0)), (i64 Idx1))>;
1200    def : Pat<(mul_const_oneuse GPR:$r, (i64 CImm)),
1201              (ALSL_D (ALSL_D GPR:$r, GPR:$r, (i64 Idx0)),
1202                      (ALSL_D GPR:$r, GPR:$r, (i64 Idx0)), (i64 Idx1))>;
1203  }
1204}
1205} // Predicates = [IsLA64]
1206
1207let Predicates = [IsLA32] in {
1208def : Pat<(mul GPR:$rj, (AlslSlliImm:$im)),
1209          (SLLI_W (ALSL_W GPR:$rj, GPR:$rj, (AlslSlliImmI0 AlslSlliImm:$im)),
1210                  (AlslSlliImmI1 AlslSlliImm:$im))>;
1211} // Predicates = [IsLA32]
1212
1213let Predicates = [IsLA64] in {
1214def : Pat<(sext_inreg (mul GPR:$rj, (AlslSlliImm:$im)), i32),
1215          (SLLI_W (ALSL_W GPR:$rj, GPR:$rj, (AlslSlliImmI0 AlslSlliImm:$im)),
1216                  (AlslSlliImmI1 AlslSlliImm:$im))>;
1217def : Pat<(mul GPR:$rj, (AlslSlliImm:$im)),
1218          (SLLI_D (ALSL_D GPR:$rj, GPR:$rj, (AlslSlliImmI0 AlslSlliImm:$im)),
1219                  (AlslSlliImmI1 AlslSlliImm:$im))>;
1220} // Predicates = [IsLA64]
1221
1222foreach Idx = 1...7 in {
1223  defvar ShamtA = !mul(8, Idx);
1224  defvar ShamtB = !mul(8, !sub(8, Idx));
1225  def : Pat<(or (shl GPR:$rk, (i64 ShamtA)), (srl GPR:$rj, (i64 ShamtB))),
1226            (BYTEPICK_D GPR:$rj, GPR:$rk, Idx)>;
1227}
1228
1229foreach Idx = 1...3 in {
1230  defvar ShamtA = !mul(8, Idx);
1231  defvar ShamtB = !mul(8, !sub(4, Idx));
1232  // NOTE: the srl node would already be transformed into a loongarch_bstrpick
1233  // by the time this pattern gets to execute, hence the weird construction.
1234  def : Pat<(sext_inreg (or (shl GPR:$rk, (i64 ShamtA)),
1235                            (loongarch_bstrpick GPR:$rj, (i64 31),
1236                                                         (i64 ShamtB))), i32),
1237            (BYTEPICK_W GPR:$rj, GPR:$rk, Idx)>;
1238}
1239} // Predicates = [IsLA64]
1240
1241def : PatGprGpr<and, AND>;
1242def : PatGprImm<and, ANDI, uimm12>;
1243def : PatGprGpr<or, OR>;
1244def : PatGprImm<or, ORI, uimm12>;
1245def : PatGprGpr<xor, XOR>;
1246def : PatGprImm<xor, XORI, uimm12>;
1247def : Pat<(not GPR:$rj), (NOR GPR:$rj, R0)>;
1248def : Pat<(not (or GPR:$rj, GPR:$rk)), (NOR GPR:$rj, GPR:$rk)>;
1249def : Pat<(or GPR:$rj, (not GPR:$rk)), (ORN GPR:$rj, GPR:$rk)>;
1250def : Pat<(and GPR:$rj, (not GPR:$rk)), (ANDN GPR:$rj, GPR:$rk)>;
1251
1252let Predicates = [IsLA32] in {
1253def : Pat<(and GPR:$rj, BstrinsImm:$imm),
1254          (BSTRINS_W GPR:$rj, R0, (BstrinsMsb BstrinsImm:$imm),
1255                     (BstrinsLsb BstrinsImm:$imm))>;
1256} // Predicates = [IsLA32]
1257
1258let Predicates = [IsLA64] in {
1259def : Pat<(and GPR:$rj, BstrinsImm:$imm),
1260          (BSTRINS_D GPR:$rj, R0, (BstrinsMsb BstrinsImm:$imm),
1261                     (BstrinsLsb BstrinsImm:$imm))>;
1262} // Predicates = [IsLA64]
1263
1264/// Traps
1265
1266// We lower `trap` to `amswap.w rd:$r0, rk:$r1, rj:$r0`, as this is guaranteed
1267// to trap with an INE (non-existent on LA32, explicitly documented to INE on
1268// LA64). And the resulting signal is different from `debugtrap` like on some
1269// other existing ports so programs/porters might have an easier time.
1270def PseudoUNIMP : Pseudo<(outs), (ins), [(trap)]>,
1271                  PseudoInstExpansion<(AMSWAP_W R0, R1, R0)>;
1272
1273// We lower `debugtrap` to `break 0`, as this is guaranteed to exist and work,
1274// even for LA32 Primary. Also, because so far the ISA does not provide a
1275// specific trap instruction/kind exclusively for alerting the debugger,
1276// every other project uses the generic immediate of 0 for this.
1277def : Pat<(debugtrap), (BREAK 0)>;
1278
1279/// Bit counting operations
1280
1281let Predicates = [IsLA64] in {
1282def : PatGpr<ctlz, CLZ_D>;
1283def : PatGpr<cttz, CTZ_D>;
1284def : Pat<(ctlz (not GPR:$rj)), (CLO_D GPR:$rj)>;
1285def : Pat<(cttz (not GPR:$rj)), (CTO_D GPR:$rj)>;
1286def : PatGpr<loongarch_clzw, CLZ_W>;
1287def : PatGpr<loongarch_ctzw, CTZ_W>;
1288def : Pat<(loongarch_clzw (not GPR:$rj)), (CLO_W GPR:$rj)>;
1289def : Pat<(loongarch_ctzw (not GPR:$rj)), (CTO_W GPR:$rj)>;
1290} // Predicates = [IsLA64]
1291
1292let Predicates = [IsLA32] in {
1293def : PatGpr<ctlz, CLZ_W>;
1294def : PatGpr<cttz, CTZ_W>;
1295def : Pat<(ctlz (not GPR:$rj)), (CLO_W GPR:$rj)>;
1296def : Pat<(cttz (not GPR:$rj)), (CTO_W GPR:$rj)>;
1297} // Predicates = [IsLA32]
1298
1299/// FrameIndex calculations
1300let Predicates = [IsLA32] in {
1301def : Pat<(AddLike (i32 BaseAddr:$rj), simm12:$imm12),
1302          (ADDI_W (i32 BaseAddr:$rj), simm12:$imm12)>;
1303} // Predicates = [IsLA32]
1304let Predicates = [IsLA64] in {
1305def : Pat<(AddLike (i64 BaseAddr:$rj), simm12:$imm12),
1306          (ADDI_D (i64 BaseAddr:$rj), simm12:$imm12)>;
1307} // Predicates = [IsLA64]
1308
1309/// Shifted addition
1310let Predicates = [IsLA32] in {
1311def : Pat<(add GPR:$rk, (shl GPR:$rj, uimm2_plus1:$imm2)),
1312          (ALSL_W GPR:$rj, GPR:$rk, uimm2_plus1:$imm2)>;
1313} // Predicates = [IsLA32]
1314let Predicates = [IsLA64] in {
1315def : Pat<(add GPR:$rk, (shl GPR:$rj, uimm2_plus1:$imm2)),
1316          (ALSL_D GPR:$rj, GPR:$rk, uimm2_plus1:$imm2)>;
1317def : Pat<(sext_inreg (add GPR:$rk, (shl GPR:$rj, uimm2_plus1:$imm2)), i32),
1318          (ALSL_W GPR:$rj, GPR:$rk, uimm2_plus1:$imm2)>;
1319def : Pat<(loongarch_bstrpick (add GPR:$rk, (shl GPR:$rj, uimm2_plus1:$imm2)),
1320                              (i64 31), (i64 0)),
1321          (ALSL_WU GPR:$rj, GPR:$rk, uimm2_plus1:$imm2)>;
1322} // Predicates = [IsLA64]
1323
1324/// Shift
1325
1326let Predicates = [IsLA32] in {
1327def : PatGprGpr<shiftop<shl>, SLL_W>;
1328def : PatGprGpr<shiftop<sra>, SRA_W>;
1329def : PatGprGpr<shiftop<srl>, SRL_W>;
1330def : PatGprImm<shl, SLLI_W, uimm5>;
1331def : PatGprImm<sra, SRAI_W, uimm5>;
1332def : PatGprImm<srl, SRLI_W, uimm5>;
1333} // Predicates = [IsLA32]
1334
1335let Predicates = [IsLA64] in {
1336def : PatGprGpr<shiftopw<loongarch_sll_w>, SLL_W>;
1337def : PatGprGpr<shiftopw<loongarch_sra_w>, SRA_W>;
1338def : PatGprGpr<shiftopw<loongarch_srl_w>, SRL_W>;
1339def : PatGprGpr<shiftop<shl>, SLL_D>;
1340def : PatGprGpr<shiftop<sra>, SRA_D>;
1341def : PatGprGpr<shiftop<srl>, SRL_D>;
1342def : PatGprImm<shl, SLLI_D, uimm6>;
1343def : PatGprImm<sra, SRAI_D, uimm6>;
1344def : PatGprImm<srl, SRLI_D, uimm6>;
1345} // Predicates = [IsLA64]
1346
1347/// sext and zext
1348
1349def : Pat<(sext_inreg GPR:$rj, i8), (EXT_W_B GPR:$rj)>;
1350def : Pat<(sext_inreg GPR:$rj, i16), (EXT_W_H GPR:$rj)>;
1351
1352let Predicates = [IsLA64] in {
1353def : Pat<(sext_inreg GPR:$rj, i32), (ADDI_W GPR:$rj, 0)>;
1354} // Predicates = [IsLA64]
1355
1356/// Setcc
1357
1358def : PatGprGpr<setlt, SLT>;
1359def : PatGprImm<setlt, SLTI, simm12>;
1360def : PatGprGpr<setult, SLTU>;
1361def : PatGprImm<setult, SLTUI, simm12>;
1362
1363// Define pattern expansions for setcc operations that aren't directly
1364// handled by a LoongArch instruction.
1365def : Pat<(seteq GPR:$rj, 0), (SLTUI GPR:$rj, 1)>;
1366def : Pat<(seteq GPR:$rj, GPR:$rk), (SLTUI (XOR GPR:$rj, GPR:$rk), 1)>;
1367let Predicates = [IsLA32] in {
1368def : Pat<(seteq GPR:$rj, simm12_plus1:$imm12),
1369          (SLTUI (ADDI_W GPR:$rj, (NegImm simm12_plus1:$imm12)), 1)>;
1370} // Predicates = [IsLA32]
1371let Predicates = [IsLA64] in {
1372def : Pat<(seteq GPR:$rj, simm12_plus1:$imm12),
1373          (SLTUI (ADDI_D GPR:$rj, (NegImm simm12_plus1:$imm12)), 1)>;
1374} // Predicates = [IsLA64]
1375def : Pat<(setne GPR:$rj, 0), (SLTU R0, GPR:$rj)>;
1376def : Pat<(setne GPR:$rj, GPR:$rk), (SLTU R0, (XOR GPR:$rj, GPR:$rk))>;
1377let Predicates = [IsLA32] in {
1378def : Pat<(setne GPR:$rj, simm12_plus1:$imm12),
1379          (SLTU R0, (ADDI_W GPR:$rj, (NegImm simm12_plus1:$imm12)))>;
1380} // Predicates = [IsLA32]
1381let Predicates = [IsLA64] in {
1382def : Pat<(setne GPR:$rj, simm12_plus1:$imm12),
1383          (SLTU R0, (ADDI_D GPR:$rj, (NegImm simm12_plus1:$imm12)))>;
1384} // Predicates = [IsLA64]
1385def : Pat<(setugt GPR:$rj, GPR:$rk), (SLTU GPR:$rk, GPR:$rj)>;
1386def : Pat<(setuge GPR:$rj, GPR:$rk), (XORI (SLTU GPR:$rj, GPR:$rk), 1)>;
1387def : Pat<(setule GPR:$rj, GPR:$rk), (XORI (SLTU GPR:$rk, GPR:$rj), 1)>;
1388def : Pat<(setgt GPR:$rj, GPR:$rk), (SLT GPR:$rk, GPR:$rj)>;
1389def : Pat<(setge GPR:$rj, GPR:$rk), (XORI (SLT GPR:$rj, GPR:$rk), 1)>;
1390def : Pat<(setle GPR:$rj, GPR:$rk), (XORI (SLT GPR:$rk, GPR:$rj), 1)>;
1391
1392/// Select
1393
1394def : Pat<(select GPR:$cond, GPR:$t, 0), (MASKEQZ GPR:$t, GPR:$cond)>;
1395def : Pat<(select GPR:$cond, 0, GPR:$f), (MASKNEZ GPR:$f, GPR:$cond)>;
1396def : Pat<(select GPR:$cond, GPR:$t, GPR:$f),
1397          (OR (MASKEQZ GPR:$t, GPR:$cond), (MASKNEZ GPR:$f, GPR:$cond))>;
1398
1399/// Branches and jumps
1400
1401class BccPat<PatFrag CondOp, LAInst Inst>
1402    : Pat<(brcond (GRLenVT (CondOp GPR:$rj, GPR:$rd)), bb:$imm16),
1403          (Inst GPR:$rj, GPR:$rd, bb:$imm16)>;
1404
1405def : BccPat<seteq, BEQ>;
1406def : BccPat<setne, BNE>;
1407def : BccPat<setlt, BLT>;
1408def : BccPat<setge, BGE>;
1409def : BccPat<setult, BLTU>;
1410def : BccPat<setuge, BGEU>;
1411
1412class BccSwapPat<PatFrag CondOp, LAInst InstBcc>
1413    : Pat<(brcond (GRLenVT (CondOp GPR:$rd, GPR:$rj)), bb:$imm16),
1414          (InstBcc GPR:$rj, GPR:$rd, bb:$imm16)>;
1415
1416// Condition codes that don't have matching LoongArch branch instructions, but
1417// are trivially supported by swapping the two input operands.
1418def : BccSwapPat<setgt, BLT>;
1419def : BccSwapPat<setle, BGE>;
1420def : BccSwapPat<setugt, BLTU>;
1421def : BccSwapPat<setule, BGEU>;
1422
1423// An extra pattern is needed for a brcond without a setcc (i.e. where the
1424// condition was calculated elsewhere).
1425def : Pat<(brcond GPR:$rj, bb:$imm21), (BNEZ GPR:$rj, bb:$imm21)>;
1426
1427def : Pat<(brcond (GRLenVT (seteq GPR:$rj, 0)), bb:$imm21),
1428          (BEQZ GPR:$rj, bb:$imm21)>;
1429def : Pat<(brcond (GRLenVT (setne GPR:$rj, 0)), bb:$imm21),
1430          (BNEZ GPR:$rj, bb:$imm21)>;
1431
1432let isBarrier = 1, isBranch = 1, isTerminator = 1 in
1433def PseudoBR : Pseudo<(outs), (ins simm26_b:$imm26), [(br bb:$imm26)]>,
1434               PseudoInstExpansion<(B simm26_b:$imm26)>;
1435
1436let isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in
1437def PseudoBRIND : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
1438                  PseudoInstExpansion<(JIRL R0, GPR:$rj, simm16_lsl2:$imm16)>;
1439
1440def : Pat<(brind GPR:$rj), (PseudoBRIND GPR:$rj, 0)>;
1441def : Pat<(brind (add GPR:$rj, simm16_lsl2:$imm16)),
1442          (PseudoBRIND GPR:$rj, simm16_lsl2:$imm16)>;
1443
1444// Function call with 'Small' code model.
1445let isCall = 1, Defs = [R1] in
1446def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$func)>;
1447
1448def : Pat<(loongarch_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>;
1449def : Pat<(loongarch_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;
1450
1451// Function call with 'Medium' code model.
1452let isCall = 1, Defs = [R1, R20], Size = 8 in
1453def PseudoCALL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$func)>;
1454
1455let Predicates = [IsLA64] in {
1456def : Pat<(loongarch_call_medium tglobaladdr:$func),
1457          (PseudoCALL_MEDIUM tglobaladdr:$func)>;
1458def : Pat<(loongarch_call_medium texternalsym:$func),
1459          (PseudoCALL_MEDIUM texternalsym:$func)>;
1460} // Predicates = [IsLA64]
1461
1462// Function call with 'Large' code model.
1463let isCall = 1, Defs = [R1, R20], Size = 24 in
1464def PseudoCALL_LARGE: Pseudo<(outs), (ins bare_symbol:$func)>;
1465
1466let Predicates = [IsLA64] in {
1467def : Pat<(loongarch_call_large tglobaladdr:$func),
1468          (PseudoCALL_LARGE tglobaladdr:$func)>;
1469def : Pat<(loongarch_call_large texternalsym:$func),
1470          (PseudoCALL_LARGE texternalsym:$func)>;
1471} // Predicates = [IsLA64]
1472
1473let isCall = 1, Defs = [R1] in
1474def PseudoCALLIndirect : Pseudo<(outs), (ins GPR:$rj),
1475                                [(loongarch_call GPR:$rj)]>,
1476                         PseudoInstExpansion<(JIRL R1, GPR:$rj, 0)>;
1477let Predicates = [IsLA64] in {
1478def : Pat<(loongarch_call_medium GPR:$rj), (PseudoCALLIndirect GPR:$rj)>;
1479def : Pat<(loongarch_call_large GPR:$rj), (PseudoCALLIndirect GPR:$rj)>;
1480}
1481
1482let isCall = 1, hasSideEffects = 0, mayStore = 0, mayLoad = 0, Defs = [R1] in
1483def PseudoJIRL_CALL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
1484                      PseudoInstExpansion<(JIRL R1, GPR:$rj,
1485                                           simm16_lsl2:$imm16)>;
1486
1487let isBarrier = 1, isReturn = 1, isTerminator = 1 in
1488def PseudoRET : Pseudo<(outs), (ins), [(loongarch_ret)]>,
1489                PseudoInstExpansion<(JIRL R0, R1, 0)>;
1490
1491// Tail call with 'Small' code model.
1492let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
1493def PseudoTAIL : Pseudo<(outs), (ins bare_symbol:$dst)>;
1494
1495def : Pat<(loongarch_tail (iPTR tglobaladdr:$dst)),
1496          (PseudoTAIL tglobaladdr:$dst)>;
1497def : Pat<(loongarch_tail (iPTR texternalsym:$dst)),
1498          (PseudoTAIL texternalsym:$dst)>;
1499
1500// Tail call with 'Medium' code model.
1501let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
1502    Uses = [R3], Defs = [R20], Size = 8 in
1503def PseudoTAIL_MEDIUM : Pseudo<(outs), (ins bare_symbol:$dst)>;
1504
1505let Predicates = [IsLA64] in {
1506def : Pat<(loongarch_tail_medium (iPTR tglobaladdr:$dst)),
1507          (PseudoTAIL_MEDIUM tglobaladdr:$dst)>;
1508def : Pat<(loongarch_tail_medium (iPTR texternalsym:$dst)),
1509          (PseudoTAIL_MEDIUM texternalsym:$dst)>;
1510} // Predicates = [IsLA64]
1511
1512// Tail call with 'Large' code model.
1513let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
1514    Uses = [R3], Defs = [R19, R20], Size = 24 in
1515def PseudoTAIL_LARGE : Pseudo<(outs), (ins bare_symbol:$dst)>;
1516
1517let Predicates = [IsLA64] in {
1518def : Pat<(loongarch_tail_large (iPTR tglobaladdr:$dst)),
1519          (PseudoTAIL_LARGE tglobaladdr:$dst)>;
1520def : Pat<(loongarch_tail_large (iPTR texternalsym:$dst)),
1521          (PseudoTAIL_LARGE texternalsym:$dst)>;
1522} // Predicates = [IsLA64]
1523
1524let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3] in
1525def PseudoTAILIndirect : Pseudo<(outs), (ins GPRT:$rj),
1526                                [(loongarch_tail GPRT:$rj)]>,
1527                         PseudoInstExpansion<(JIRL R0, GPR:$rj, 0)>;
1528let Predicates = [IsLA64] in {
1529def : Pat<(loongarch_tail_medium GPR:$rj), (PseudoTAILIndirect GPR:$rj)>;
1530def : Pat<(loongarch_tail_large GPR:$rj), (PseudoTAILIndirect GPR:$rj)>;
1531}
1532
1533let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
1534    hasSideEffects = 0, mayStore = 0, mayLoad = 0, Uses = [R3] in
1535def PseudoB_TAIL : Pseudo<(outs), (ins simm26_b:$imm26)>,
1536                   PseudoInstExpansion<(B simm26_b:$imm26)>;
1537
1538let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
1539    hasSideEffects = 0, mayStore = 0, mayLoad = 0, Uses = [R3] in
1540def PseudoJIRL_TAIL : Pseudo<(outs), (ins GPR:$rj, simm16_lsl2:$imm16)>,
1541                      PseudoInstExpansion<(JIRL R0, GPR:$rj,
1542                                           simm16_lsl2:$imm16)>;
1543
1544/// call36/taill36 macro instructions
1545let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, isAsmParserOnly = 1,
1546    Defs = [R1], Size = 8, hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
1547def PseudoCALL36 : Pseudo<(outs), (ins bare_symbol:$dst), [],
1548                          "call36", "$dst">,
1549                   Requires<[IsLA64]>;
1550let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [R3],
1551    isCodeGenOnly = 0, isAsmParserOnly = 1, Size = 8, hasSideEffects = 0,
1552    mayStore = 0, mayLoad = 0 in
1553def PseudoTAIL36 : Pseudo<(outs), (ins GPR:$tmp, bare_symbol:$dst), [],
1554                          "tail36", "$tmp, $dst">,
1555                   Requires<[IsLA64]>;
1556
1557/// Load address (la*) macro instructions.
1558
1559// Define isCodeGenOnly = 0 to expose them to tablegened assembly parser.
1560let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0,
1561    isAsmParserOnly = 1 in {
1562def PseudoLA_ABS : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
1563                          "la.abs", "$dst, $src">;
1564def PseudoLA_ABS_LARGE : Pseudo<(outs GPR:$dst),
1565                                (ins GPR:$tmp, bare_symbol:$src), [],
1566                                "la.abs", "$dst, $src">;
1567def PseudoLA_PCREL : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
1568                            "la.pcrel", "$dst, $src">;
1569let Defs = [R20], Size = 20 in
1570def PseudoLA_PCREL_LARGE : Pseudo<(outs GPR:$dst),
1571                                  (ins GPR:$tmp, bare_symbol:$src), [],
1572                                  "la.pcrel", "$dst, $tmp, $src">,
1573                           Requires<[IsLA64]>;
1574def PseudoLA_TLS_LE : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
1575                             "la.tls.le", "$dst, $src">;
1576}
1577let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0,
1578    isAsmParserOnly = 1 in {
1579def PseudoLA_GOT : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
1580                          "la.got", "$dst, $src">;
1581def PseudoLA_TLS_IE : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
1582                             "la.tls.ie", "$dst, $src">;
1583def PseudoLA_TLS_LD : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
1584                             "la.tls.ld", "$dst, $src">;
1585def PseudoLA_TLS_GD : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
1586                             "la.tls.gd", "$dst, $src">;
1587let Defs = [R20], Size = 20 in {
1588def PseudoLA_GOT_LARGE : Pseudo<(outs GPR:$dst),
1589                                (ins GPR:$tmp, bare_symbol:$src), [],
1590                                "la.got", "$dst, $tmp, $src">,
1591                         Requires<[IsLA64]>;
1592def PseudoLA_TLS_IE_LARGE : Pseudo<(outs GPR:$dst),
1593                                   (ins GPR:$tmp, bare_symbol:$src), [],
1594                                   "la.tls.ie", "$dst, $tmp, $src">,
1595                            Requires<[IsLA64]>;
1596def PseudoLA_TLS_LD_LARGE : Pseudo<(outs GPR:$dst),
1597                                   (ins GPR:$tmp, bare_symbol:$src), [],
1598                                   "la.tls.ld", "$dst, $tmp, $src">,
1599                            Requires<[IsLA64]>;
1600def PseudoLA_TLS_GD_LARGE : Pseudo<(outs GPR:$dst),
1601                                   (ins GPR:$tmp, bare_symbol:$src), [],
1602                                   "la.tls.gd", "$dst, $tmp, $src">,
1603                            Requires<[IsLA64]>;
1604} // Defs = [R20], Size = 20
1605}
1606
1607// Load address inst alias: "la", "la.global" and "la.local".
1608// Default:
1609//     la = la.global = la.got
1610//     la.local = la.pcrel
1611// With feature "+la-global-with-pcrel":
1612//     la = la.global = la.pcrel
1613// With feature "+la-global-with-abs":
1614//     la = la.global = la.abs
1615// With feature "+la-local-with-abs":
1616//     la.local = la.abs
1617// With features "+la-global-with-pcrel,+la-global-with-abs"(disorder):
1618//     la = la.global = la.pcrel
1619// Note: To keep consistent with gnu-as behavior, the "la" can only have one
1620//       register operand.
1621def : InstAlias<"la $dst, $src", (PseudoLA_GOT GPR:$dst, bare_symbol:$src)>;
1622def : InstAlias<"la.global $dst, $src",
1623                (PseudoLA_GOT GPR:$dst, bare_symbol:$src)>;
1624def : InstAlias<"la.global $dst, $tmp, $src",
1625                (PseudoLA_GOT_LARGE GPR:$dst, GPR:$tmp, bare_symbol:$src)>;
1626def : InstAlias<"la.local $dst, $src",
1627                (PseudoLA_PCREL GPR:$dst, bare_symbol:$src)>;
1628def : InstAlias<"la.local $dst, $tmp, $src",
1629                (PseudoLA_PCREL_LARGE GPR:$dst, GPR:$tmp, bare_symbol:$src)>;
1630
1631// Note: Keep HasLaGlobalWithPcrel before HasLaGlobalWithAbs to ensure
1632// "la-global-with-pcrel" takes effect when bose "la-global-with-pcrel" and
1633// "la-global-with-abs" are enabled.
1634let Predicates = [HasLaGlobalWithPcrel] in {
1635def : InstAlias<"la $dst, $src", (PseudoLA_PCREL GPR:$dst, bare_symbol:$src)>;
1636def : InstAlias<"la.global $dst, $src",
1637                (PseudoLA_PCREL GPR:$dst, bare_symbol:$src)>;
1638def : InstAlias<"la.global $dst, $tmp, $src",
1639                (PseudoLA_PCREL_LARGE GPR:$dst, GPR:$tmp, bare_symbol:$src)>;
1640} // Predicates = [HasLaGlobalWithPcrel]
1641
1642let Predicates = [HasLaGlobalWithAbs] in {
1643def : InstAlias<"la $dst, $src", (PseudoLA_ABS GPR:$dst, bare_symbol:$src)>;
1644def : InstAlias<"la.global $dst, $src",
1645                (PseudoLA_ABS GPR:$dst, bare_symbol:$src)>;
1646def : InstAlias<"la.global $dst, $tmp, $src",
1647                (PseudoLA_ABS_LARGE GPR:$dst, GPR:$tmp, bare_symbol:$src)>;
1648} // Predicates = [HasLaGlobalWithAbs]
1649
1650let Predicates = [HasLaLocalWithAbs] in {
1651def : InstAlias<"la.local $dst, $src",
1652                (PseudoLA_ABS GPR:$dst, bare_symbol:$src)>;
1653def : InstAlias<"la.local $dst, $tmp, $src",
1654                (PseudoLA_ABS_LARGE GPR:$dst, GPR:$tmp, bare_symbol:$src)>;
1655} // Predicates = [HasLaLocalWithAbs]
1656
1657/// BSTRINS and BSTRPICK
1658
1659let Predicates = [IsLA32] in {
1660def : Pat<(loongarch_bstrins GPR:$rd, GPR:$rj, uimm5:$msbd, uimm5:$lsbd),
1661          (BSTRINS_W GPR:$rd, GPR:$rj, uimm5:$msbd, uimm5:$lsbd)>;
1662def : Pat<(loongarch_bstrpick GPR:$rj, uimm5:$msbd, uimm5:$lsbd),
1663          (BSTRPICK_W GPR:$rj, uimm5:$msbd, uimm5:$lsbd)>;
1664} // Predicates = [IsLA32]
1665
1666let Predicates = [IsLA64] in {
1667def : Pat<(loongarch_bstrins GPR:$rd, GPR:$rj, uimm6:$msbd, uimm6:$lsbd),
1668          (BSTRINS_D GPR:$rd, GPR:$rj, uimm6:$msbd, uimm6:$lsbd)>;
1669def : Pat<(loongarch_bstrpick GPR:$rj, uimm6:$msbd, uimm6:$lsbd),
1670          (BSTRPICK_D GPR:$rj, uimm6:$msbd, uimm6:$lsbd)>;
1671} // Predicates = [IsLA64]
1672
1673/// Byte-swapping and bit-reversal
1674
1675def : Pat<(loongarch_revb_2h GPR:$rj), (REVB_2H GPR:$rj)>;
1676def : Pat<(loongarch_bitrev_4b GPR:$rj), (BITREV_4B GPR:$rj)>;
1677
1678let Predicates = [IsLA32] in {
1679def : Pat<(bswap GPR:$rj), (ROTRI_W (REVB_2H GPR:$rj), 16)>;
1680def : Pat<(bitreverse GPR:$rj), (BITREV_W GPR:$rj)>;
1681def : Pat<(bswap (bitreverse GPR:$rj)), (BITREV_4B GPR:$rj)>;
1682def : Pat<(bitreverse (bswap GPR:$rj)), (BITREV_4B GPR:$rj)>;
1683} // Predicates = [IsLA32]
1684
1685let Predicates = [IsLA64] in {
1686def : Pat<(loongarch_revb_2w GPR:$rj), (REVB_2W GPR:$rj)>;
1687def : Pat<(bswap GPR:$rj), (REVB_D GPR:$rj)>;
1688def : Pat<(loongarch_bitrev_w GPR:$rj), (BITREV_W GPR:$rj)>;
1689def : Pat<(bitreverse GPR:$rj), (BITREV_D GPR:$rj)>;
1690def : Pat<(bswap (bitreverse GPR:$rj)), (BITREV_8B GPR:$rj)>;
1691def : Pat<(bitreverse (bswap GPR:$rj)), (BITREV_8B GPR:$rj)>;
1692} // Predicates = [IsLA64]
1693
1694/// Loads
1695
1696multiclass LdPat<PatFrag LoadOp, LAInst Inst, ValueType vt = GRLenVT> {
1697  def : Pat<(vt (LoadOp BaseAddr:$rj)), (Inst BaseAddr:$rj, 0)>;
1698  def : Pat<(vt (LoadOp (AddrConstant GPR:$rj, simm12:$imm12))),
1699            (Inst GPR:$rj, simm12:$imm12)>;
1700  def : Pat<(vt (LoadOp (AddLike BaseAddr:$rj, simm12:$imm12))),
1701            (Inst BaseAddr:$rj, simm12:$imm12)>;
1702}
1703
1704defm : LdPat<sextloadi8, LD_B>;
1705defm : LdPat<extloadi8, LD_B>;
1706defm : LdPat<sextloadi16, LD_H>;
1707defm : LdPat<extloadi16, LD_H>;
1708defm : LdPat<load, LD_W>, Requires<[IsLA32]>;
1709defm : LdPat<zextloadi8, LD_BU>;
1710defm : LdPat<zextloadi16, LD_HU>;
1711let Predicates = [IsLA64] in {
1712defm : LdPat<sextloadi32, LD_W, i64>;
1713defm : LdPat<extloadi32, LD_W, i64>;
1714defm : LdPat<zextloadi32, LD_WU, i64>;
1715defm : LdPat<load, LD_D, i64>;
1716} // Predicates = [IsLA64]
1717
1718// LA64 register-register-addressed loads
1719let Predicates = [IsLA64] in {
1720class RegRegLdPat<PatFrag LoadOp, LAInst Inst, ValueType vt>
1721  : Pat<(vt (LoadOp (add NonFIBaseAddr:$rj, GPR:$rk))),
1722        (Inst NonFIBaseAddr:$rj, GPR:$rk)>;
1723
1724def : RegRegLdPat<extloadi8, LDX_B, i64>;
1725def : RegRegLdPat<sextloadi8, LDX_B, i64>;
1726def : RegRegLdPat<zextloadi8, LDX_BU, i64>;
1727def : RegRegLdPat<extloadi16, LDX_H, i64>;
1728def : RegRegLdPat<sextloadi16, LDX_H, i64>;
1729def : RegRegLdPat<zextloadi16, LDX_HU, i64>;
1730def : RegRegLdPat<extloadi32, LDX_W, i64>;
1731def : RegRegLdPat<sextloadi32, LDX_W, i64>;
1732def : RegRegLdPat<zextloadi32, LDX_WU, i64>;
1733def : RegRegLdPat<load, LDX_D, i64>;
1734} // Predicates = [IsLA64]
1735
1736/// Stores
1737
1738multiclass StPat<PatFrag StoreOp, LAInst Inst, RegisterClass StTy,
1739                 ValueType vt> {
1740  def : Pat<(StoreOp (vt StTy:$rd), BaseAddr:$rj),
1741            (Inst StTy:$rd, BaseAddr:$rj, 0)>;
1742  def : Pat<(StoreOp (vt StTy:$rs2), (AddrConstant GPR:$rj, simm12:$imm12)),
1743            (Inst StTy:$rs2, GPR:$rj, simm12:$imm12)>;
1744  def : Pat<(StoreOp (vt StTy:$rd), (AddLike BaseAddr:$rj, simm12:$imm12)),
1745            (Inst StTy:$rd, BaseAddr:$rj, simm12:$imm12)>;
1746}
1747
1748defm : StPat<truncstorei8, ST_B, GPR, GRLenVT>;
1749defm : StPat<truncstorei16, ST_H, GPR, GRLenVT>;
1750defm : StPat<store, ST_W, GPR, i32>, Requires<[IsLA32]>;
1751let Predicates = [IsLA64] in {
1752defm : StPat<truncstorei32, ST_W, GPR, i64>;
1753defm : StPat<store, ST_D, GPR, i64>;
1754} // Predicates = [IsLA64]
1755
1756let Predicates = [IsLA64] in {
1757def : Pat<(i64 (sextloadi32 (AddLike BaseAddr:$rj, simm14_lsl2:$imm14))),
1758          (LDPTR_W BaseAddr:$rj, simm14_lsl2:$imm14)>;
1759def : Pat<(i64 (load (AddLike BaseAddr:$rj, simm14_lsl2:$imm14))),
1760          (LDPTR_D BaseAddr:$rj, simm14_lsl2:$imm14)>;
1761def : Pat<(truncstorei32 (i64 GPR:$rd),
1762                         (AddLike BaseAddr:$rj, simm14_lsl2:$imm14)),
1763          (STPTR_W GPR:$rd, BaseAddr:$rj, simm14_lsl2:$imm14)>;
1764def : Pat<(store (i64 GPR:$rd), (AddLike BaseAddr:$rj, simm14_lsl2:$imm14)),
1765          (STPTR_D GPR:$rd, BaseAddr:$rj, simm14_lsl2:$imm14)>;
1766} // Predicates = [IsLA64]
1767
1768// LA64 register-register-addressed stores
1769let Predicates = [IsLA64] in {
1770class RegRegStPat<PatFrag StoreOp, LAInst Inst, RegisterClass StTy,
1771                  ValueType vt>
1772  : Pat<(StoreOp (vt StTy:$rd), (add NonFIBaseAddr:$rj, GPR:$rk)),
1773        (Inst StTy:$rd, NonFIBaseAddr:$rj, GPR:$rk)>;
1774
1775def : RegRegStPat<truncstorei8, STX_B, GPR, i64>;
1776def : RegRegStPat<truncstorei16, STX_H, GPR, i64>;
1777def : RegRegStPat<truncstorei32, STX_W, GPR, i64>;
1778def : RegRegStPat<store, STX_D, GPR, i64>;
1779} // Predicates = [IsLA64]
1780
1781/// Atomic loads and stores
1782
1783// DBAR hint encoding for LA664 and later micro-architectures, paraphrased from
1784// the Linux patch revealing it [1]:
1785//
1786// - Bit 4: kind of constraint (0: completion, 1: ordering)
1787// - Bit 3: barrier for previous read (0: true, 1: false)
1788// - Bit 2: barrier for previous write (0: true, 1: false)
1789// - Bit 1: barrier for succeeding read (0: true, 1: false)
1790// - Bit 0: barrier for succeeding write (0: true, 1: false)
1791//
1792// Hint 0x700: barrier for "read after read" from the same address, which is
1793// e.g. needed by LL-SC loops on older models. (DBAR 0x700 behaves the same as
1794// nop if such reordering is disabled on supporting newer models.)
1795//
1796// [1]: https://lore.kernel.org/loongarch/20230516124536.535343-1-chenhuacai@loongson.cn/
1797//
1798// Implementations without support for the finer-granularity hints simply treat
1799// all as the full barrier (DBAR 0), so we can unconditionally start emiting the
1800// more precise hints right away.
1801
1802def : Pat<(atomic_fence 4, timm), (DBAR 0b10100)>; // acquire
1803def : Pat<(atomic_fence 5, timm), (DBAR 0b10010)>; // release
1804def : Pat<(atomic_fence 6, timm), (DBAR 0b10000)>; // acqrel
1805def : Pat<(atomic_fence 7, timm), (DBAR 0b10000)>; // seqcst
1806
1807defm : LdPat<atomic_load_8, LD_B>;
1808defm : LdPat<atomic_load_16, LD_H>;
1809defm : LdPat<atomic_load_32, LD_W>;
1810
1811class release_seqcst_store<PatFrag base>
1812    : PatFrag<(ops node:$val, node:$ptr), (base node:$val, node:$ptr), [{
1813  AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getSuccessOrdering();
1814  return isReleaseOrStronger(Ordering);
1815}]>;
1816
1817class unordered_monotonic_store<PatFrag base>
1818    : PatFrag<(ops node:$val, node:$ptr), (base node:$val, node:$ptr), [{
1819  AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getSuccessOrdering();
1820  return !isReleaseOrStronger(Ordering);
1821}]>;
1822
1823def atomic_store_release_seqcst_32 : release_seqcst_store<atomic_store_32>;
1824def atomic_store_release_seqcst_64 : release_seqcst_store<atomic_store_64>;
1825def atomic_store_unordered_monotonic_32
1826    : unordered_monotonic_store<atomic_store_32>;
1827def atomic_store_unordered_monotonic_64
1828    : unordered_monotonic_store<atomic_store_64>;
1829
1830defm : StPat<atomic_store_8, ST_B, GPR, GRLenVT>;
1831defm : StPat<atomic_store_16, ST_H, GPR, GRLenVT>;
1832defm : StPat<atomic_store_unordered_monotonic_32, ST_W, GPR, i32>,
1833                   Requires<[IsLA32]>;
1834
1835def PseudoAtomicStoreW
1836  : Pseudo<(outs GPR:$dst), (ins GPR:$rk, GPR:$rj)>,
1837           PseudoInstExpansion<(AMSWAP__DB_W R0, GPR:$rk, GPRMemAtomic:$rj)>;
1838
1839def : Pat<(atomic_store_release_seqcst_32 GPR:$rj, GPR:$rk),
1840          (PseudoAtomicStoreW GPR:$rj, GPR:$rk)>;
1841
1842let Predicates = [IsLA64] in {
1843def PseudoAtomicStoreD
1844  : Pseudo<(outs GPR:$dst), (ins GPR:$rk, GPR:$rj)>,
1845           PseudoInstExpansion<(AMSWAP__DB_D R0, GPR:$rk, GPRMemAtomic:$rj)>;
1846
1847def : Pat<(atomic_store_release_seqcst_64 GPR:$rj, GPR:$rk),
1848          (PseudoAtomicStoreD GPR:$rj, GPR:$rk)>;
1849
1850defm : LdPat<atomic_load_64, LD_D>;
1851defm : StPat<atomic_store_unordered_monotonic_32, ST_W, GPR, i64>;
1852defm : StPat<atomic_store_unordered_monotonic_64, ST_D, GPR, i64>;
1853} // Predicates = [IsLA64]
1854
1855/// Atomic Ops
1856
1857class PseudoMaskedAM
1858    : Pseudo<(outs GPR:$res, GPR:$scratch),
1859             (ins GPR:$addr, GPR:$incr, GPR:$mask, grlenimm:$ordering)> {
1860  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
1861  let mayLoad = 1;
1862  let mayStore = 1;
1863  let hasSideEffects = 0;
1864  let Size = 36;
1865}
1866
1867def PseudoMaskedAtomicSwap32 : PseudoMaskedAM;
1868def PseudoMaskedAtomicLoadAdd32 : PseudoMaskedAM;
1869def PseudoMaskedAtomicLoadSub32 : PseudoMaskedAM;
1870def PseudoMaskedAtomicLoadNand32 : PseudoMaskedAM;
1871
1872class PseudoAM : Pseudo<(outs GPR:$res, GPR:$scratch),
1873                        (ins GPR:$addr, GPR:$incr, grlenimm:$ordering)> {
1874  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
1875  let mayLoad = 1;
1876  let mayStore = 1;
1877  let hasSideEffects = 0;
1878  let Size = 24;
1879}
1880
1881def PseudoAtomicSwap32 : PseudoAM;
1882def PseudoAtomicLoadNand32 : PseudoAM;
1883def PseudoAtomicLoadNand64 : PseudoAM;
1884def PseudoAtomicLoadAdd32 : PseudoAM;
1885def PseudoAtomicLoadSub32 : PseudoAM;
1886def PseudoAtomicLoadAnd32 : PseudoAM;
1887def PseudoAtomicLoadOr32 : PseudoAM;
1888def PseudoAtomicLoadXor32 : PseudoAM;
1889
1890multiclass PseudoBinPat<string Op, Pseudo BinInst> {
1891  def : Pat<(!cast<PatFrag>(Op#"_monotonic") GPR:$addr, GPR:$incr),
1892            (BinInst GPR:$addr, GPR:$incr, 2)>;
1893  def : Pat<(!cast<PatFrag>(Op#"_acquire") GPR:$addr, GPR:$incr),
1894            (BinInst GPR:$addr, GPR:$incr, 4)>;
1895  def : Pat<(!cast<PatFrag>(Op#"_release") GPR:$addr, GPR:$incr),
1896            (BinInst GPR:$addr, GPR:$incr, 5)>;
1897  def : Pat<(!cast<PatFrag>(Op#"_acq_rel") GPR:$addr, GPR:$incr),
1898            (BinInst GPR:$addr, GPR:$incr, 6)>;
1899  def : Pat<(!cast<PatFrag>(Op#"_seq_cst") GPR:$addr, GPR:$incr),
1900            (BinInst GPR:$addr, GPR:$incr, 7)>;
1901}
1902
1903class PseudoMaskedAMUMinUMax
1904    : Pseudo<(outs GPR:$res, GPR:$scratch1, GPR:$scratch2),
1905             (ins GPR:$addr, GPR:$incr, GPR:$mask, grlenimm:$ordering)> {
1906  let Constraints = "@earlyclobber $res,@earlyclobber $scratch1,"
1907                    "@earlyclobber $scratch2";
1908  let mayLoad = 1;
1909  let mayStore = 1;
1910  let hasSideEffects = 0;
1911  let Size = 48;
1912}
1913
1914def PseudoMaskedAtomicLoadUMax32 : PseudoMaskedAMUMinUMax;
1915def PseudoMaskedAtomicLoadUMin32 : PseudoMaskedAMUMinUMax;
1916
1917class PseudoMaskedAMMinMax
1918    : Pseudo<(outs GPR:$res, GPR:$scratch1, GPR:$scratch2),
1919             (ins GPR:$addr, GPR:$incr, GPR:$mask, grlenimm:$sextshamt,
1920              grlenimm:$ordering)> {
1921  let Constraints = "@earlyclobber $res,@earlyclobber $scratch1,"
1922                    "@earlyclobber $scratch2";
1923  let mayLoad = 1;
1924  let mayStore = 1;
1925  let hasSideEffects = 0;
1926  let Size = 56;
1927}
1928
1929def PseudoMaskedAtomicLoadMax32 : PseudoMaskedAMMinMax;
1930def PseudoMaskedAtomicLoadMin32 : PseudoMaskedAMMinMax;
1931
1932/// Compare and exchange
1933
1934class PseudoCmpXchg
1935    : Pseudo<(outs GPR:$res, GPR:$scratch),
1936             (ins GPR:$addr, GPR:$cmpval, GPR:$newval, grlenimm:$fail_order)> {
1937  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
1938  let mayLoad = 1;
1939  let mayStore = 1;
1940  let hasSideEffects = 0;
1941  let Size = 36;
1942}
1943
1944def PseudoCmpXchg32 : PseudoCmpXchg;
1945def PseudoCmpXchg64 : PseudoCmpXchg;
1946
1947def PseudoMaskedCmpXchg32
1948    : Pseudo<(outs GPR:$res, GPR:$scratch),
1949             (ins GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask,
1950              grlenimm:$fail_order)> {
1951  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
1952  let mayLoad = 1;
1953  let mayStore = 1;
1954  let hasSideEffects = 0;
1955  let Size = 44;
1956}
1957
1958class PseudoMaskedAMMinMaxPat<Intrinsic intrin, Pseudo AMInst>
1959    : Pat<(intrin GPR:$addr, GPR:$incr, GPR:$mask, GPR:$shiftamt,
1960           timm:$ordering),
1961          (AMInst GPR:$addr, GPR:$incr, GPR:$mask, GPR:$shiftamt,
1962           timm:$ordering)>;
1963
1964class AtomicPat<Intrinsic intrin, Pseudo AMInst>
1965    : Pat<(intrin GPR:$addr, GPR:$incr, GPR:$mask, timm:$ordering),
1966          (AMInst GPR:$addr, GPR:$incr, GPR:$mask, timm:$ordering)>;
1967
1968// These atomic cmpxchg PatFrags only care about the failure ordering.
1969// The PatFrags defined by multiclass `ternary_atomic_op_ord` in
1970// TargetSelectionDAG.td care about the merged memory ordering that is the
1971// stronger one between success and failure. But for LoongArch LL-SC we only
1972// need to care about the failure ordering as explained in PR #67391. So we
1973// define these PatFrags that will be used to define cmpxchg pats below.
1974multiclass ternary_atomic_op_failure_ord {
1975  def NAME#_failure_monotonic : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
1976      (!cast<SDPatternOperator>(NAME) node:$ptr, node:$cmp, node:$val), [{
1977    AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getFailureOrdering();
1978    return Ordering == AtomicOrdering::Monotonic;
1979  }]>;
1980  def NAME#_failure_acquire : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
1981      (!cast<SDPatternOperator>(NAME) node:$ptr, node:$cmp, node:$val), [{
1982    AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getFailureOrdering();
1983    return Ordering == AtomicOrdering::Acquire;
1984  }]>;
1985  def NAME#_failure_release : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
1986      (!cast<SDPatternOperator>(NAME) node:$ptr, node:$cmp, node:$val), [{
1987    AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getFailureOrdering();
1988    return Ordering == AtomicOrdering::Release;
1989  }]>;
1990  def NAME#_failure_acq_rel : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
1991      (!cast<SDPatternOperator>(NAME) node:$ptr, node:$cmp, node:$val), [{
1992    AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getFailureOrdering();
1993    return Ordering == AtomicOrdering::AcquireRelease;
1994  }]>;
1995  def NAME#_failure_seq_cst : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
1996      (!cast<SDPatternOperator>(NAME) node:$ptr, node:$cmp, node:$val), [{
1997    AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getFailureOrdering();
1998    return Ordering == AtomicOrdering::SequentiallyConsistent;
1999  }]>;
2000}
2001
2002defm atomic_cmp_swap_32 : ternary_atomic_op_failure_ord;
2003defm atomic_cmp_swap_64 : ternary_atomic_op_failure_ord;
2004
2005let Predicates = [IsLA64] in {
2006def : AtomicPat<int_loongarch_masked_atomicrmw_xchg_i64,
2007                PseudoMaskedAtomicSwap32>;
2008def : Pat<(atomic_swap_32 GPR:$addr, GPR:$incr),
2009          (AMSWAP__DB_W GPR:$incr, GPR:$addr)>;
2010def : Pat<(atomic_swap_64 GPR:$addr, GPR:$incr),
2011          (AMSWAP__DB_D GPR:$incr, GPR:$addr)>;
2012def : Pat<(atomic_load_add_64 GPR:$rj, GPR:$rk),
2013          (AMADD__DB_D GPR:$rk, GPR:$rj)>;
2014def : AtomicPat<int_loongarch_masked_atomicrmw_add_i64,
2015                PseudoMaskedAtomicLoadAdd32>;
2016def : Pat<(atomic_load_sub_32 GPR:$rj, GPR:$rk),
2017          (AMADD__DB_W (SUB_W R0, GPR:$rk), GPR:$rj)>;
2018def : Pat<(atomic_load_sub_64 GPR:$rj, GPR:$rk),
2019          (AMADD__DB_D (SUB_D R0, GPR:$rk), GPR:$rj)>;
2020def : AtomicPat<int_loongarch_masked_atomicrmw_sub_i64,
2021                PseudoMaskedAtomicLoadSub32>;
2022defm : PseudoBinPat<"atomic_load_nand_64", PseudoAtomicLoadNand64>;
2023def : AtomicPat<int_loongarch_masked_atomicrmw_nand_i64,
2024                PseudoMaskedAtomicLoadNand32>;
2025def : Pat<(atomic_load_add_32 GPR:$rj, GPR:$rk),
2026          (AMADD__DB_W GPR:$rk, GPR:$rj)>;
2027def : Pat<(atomic_load_and_32 GPR:$rj, GPR:$rk),
2028          (AMAND__DB_W GPR:$rk, GPR:$rj)>;
2029def : Pat<(atomic_load_and_64 GPR:$rj, GPR:$rk),
2030          (AMAND__DB_D GPR:$rk, GPR:$rj)>;
2031def : Pat<(atomic_load_or_32 GPR:$rj, GPR:$rk),
2032          (AMOR__DB_W GPR:$rk, GPR:$rj)>;
2033def : Pat<(atomic_load_or_64 GPR:$rj, GPR:$rk),
2034          (AMOR__DB_D GPR:$rk, GPR:$rj)>;
2035def : Pat<(atomic_load_xor_32 GPR:$rj, GPR:$rk),
2036          (AMXOR__DB_W GPR:$rk, GPR:$rj)>;
2037def : Pat<(atomic_load_xor_64 GPR:$rj, GPR:$rk),
2038          (AMXOR__DB_D GPR:$rk, GPR:$rj)>;
2039
2040def : Pat<(atomic_load_umin_32 GPR:$rj, GPR:$rk),
2041          (AMMIN__DB_WU GPR:$rk, GPR:$rj)>;
2042def : Pat<(atomic_load_umin_64 GPR:$rj, GPR:$rk),
2043          (AMMIN__DB_DU GPR:$rk, GPR:$rj)>;
2044def : Pat<(atomic_load_umax_32 GPR:$rj, GPR:$rk),
2045          (AMMAX__DB_WU GPR:$rk, GPR:$rj)>;
2046def : Pat<(atomic_load_umax_64 GPR:$rj, GPR:$rk),
2047          (AMMAX__DB_DU GPR:$rk, GPR:$rj)>;
2048
2049def : Pat<(atomic_load_min_32 GPR:$rj, GPR:$rk),
2050          (AMMIN__DB_W GPR:$rk, GPR:$rj)>;
2051def : Pat<(atomic_load_min_64 GPR:$rj, GPR:$rk),
2052          (AMMIN__DB_D GPR:$rk, GPR:$rj)>;
2053def : Pat<(atomic_load_max_32 GPR:$rj, GPR:$rk),
2054          (AMMAX__DB_W GPR:$rk, GPR:$rj)>;
2055def : Pat<(atomic_load_max_64 GPR:$rj, GPR:$rk),
2056          (AMMAX__DB_D GPR:$rk, GPR:$rj)>;
2057
2058def : AtomicPat<int_loongarch_masked_atomicrmw_umax_i64,
2059                PseudoMaskedAtomicLoadUMax32>;
2060def : AtomicPat<int_loongarch_masked_atomicrmw_umin_i64,
2061                PseudoMaskedAtomicLoadUMin32>;
2062
2063// Ordering constants must be kept in sync with the AtomicOrdering enum in
2064// AtomicOrdering.h.
2065multiclass PseudoCmpXchgPat<string Op, Pseudo CmpXchgInst,
2066                            ValueType vt = GRLenVT> {
2067  def : Pat<(vt (!cast<PatFrag>(Op#"_failure_monotonic") GPR:$addr, GPR:$cmp, GPR:$new)),
2068            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 2)>;
2069  def : Pat<(vt (!cast<PatFrag>(Op#"_failure_acquire") GPR:$addr, GPR:$cmp, GPR:$new)),
2070            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 4)>;
2071  def : Pat<(vt (!cast<PatFrag>(Op#"_failure_release") GPR:$addr, GPR:$cmp, GPR:$new)),
2072            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 5)>;
2073  def : Pat<(vt (!cast<PatFrag>(Op#"_failure_acq_rel") GPR:$addr, GPR:$cmp, GPR:$new)),
2074            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 6)>;
2075  def : Pat<(vt (!cast<PatFrag>(Op#"_failure_seq_cst") GPR:$addr, GPR:$cmp, GPR:$new)),
2076            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 7)>;
2077}
2078
2079defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32>;
2080defm : PseudoCmpXchgPat<"atomic_cmp_swap_64", PseudoCmpXchg64, i64>;
2081def : Pat<(int_loongarch_masked_cmpxchg_i64
2082            GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$fail_order),
2083          (PseudoMaskedCmpXchg32
2084            GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$fail_order)>;
2085
2086def : PseudoMaskedAMMinMaxPat<int_loongarch_masked_atomicrmw_max_i64,
2087                              PseudoMaskedAtomicLoadMax32>;
2088def : PseudoMaskedAMMinMaxPat<int_loongarch_masked_atomicrmw_min_i64,
2089                              PseudoMaskedAtomicLoadMin32>;
2090} // Predicates = [IsLA64]
2091
2092defm : PseudoBinPat<"atomic_load_nand_32", PseudoAtomicLoadNand32>;
2093
2094let Predicates = [IsLA32] in {
2095def : AtomicPat<int_loongarch_masked_atomicrmw_xchg_i32,
2096                PseudoMaskedAtomicSwap32>;
2097defm : PseudoBinPat<"atomic_swap_32", PseudoAtomicSwap32>;
2098def : AtomicPat<int_loongarch_masked_atomicrmw_add_i32,
2099                PseudoMaskedAtomicLoadAdd32>;
2100def : AtomicPat<int_loongarch_masked_atomicrmw_sub_i32,
2101                PseudoMaskedAtomicLoadSub32>;
2102def : AtomicPat<int_loongarch_masked_atomicrmw_nand_i32,
2103                PseudoMaskedAtomicLoadNand32>;
2104defm : PseudoBinPat<"atomic_load_add_32", PseudoAtomicLoadAdd32>;
2105defm : PseudoBinPat<"atomic_load_sub_32", PseudoAtomicLoadSub32>;
2106defm : PseudoBinPat<"atomic_load_and_32", PseudoAtomicLoadAnd32>;
2107defm : PseudoBinPat<"atomic_load_or_32", PseudoAtomicLoadOr32>;
2108defm : PseudoBinPat<"atomic_load_xor_32", PseudoAtomicLoadXor32>;
2109} // Predicates = [IsLA32]
2110
2111/// Intrinsics
2112
2113def : Pat<(int_loongarch_cacop_d timm:$op, i64:$rj, timm:$imm12),
2114          (CACOP timm:$op, GPR:$rj, timm:$imm12)>;
2115def : Pat<(int_loongarch_cacop_w i32:$op, i32:$rj, i32:$imm12),
2116          (CACOP timm:$op, GPR:$rj, timm:$imm12)>;
2117def : Pat<(loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>;
2118def : Pat<(loongarch_ibar uimm15:$imm15), (IBAR uimm15:$imm15)>;
2119def : Pat<(loongarch_break uimm15:$imm15), (BREAK uimm15:$imm15)>;
2120def : Pat<(loongarch_syscall uimm15:$imm15), (SYSCALL uimm15:$imm15)>;
2121
2122let Predicates = [IsLA64] in {
2123// CRC Check Instructions
2124def : PatGprGpr<loongarch_crc_w_b_w, CRC_W_B_W>;
2125def : PatGprGpr<loongarch_crc_w_h_w, CRC_W_H_W>;
2126def : PatGprGpr<loongarch_crc_w_w_w, CRC_W_W_W>;
2127def : PatGprGpr<loongarch_crc_w_d_w, CRC_W_D_W>;
2128def : PatGprGpr<loongarch_crcc_w_b_w, CRCC_W_B_W>;
2129def : PatGprGpr<loongarch_crcc_w_h_w, CRCC_W_H_W>;
2130def : PatGprGpr<loongarch_crcc_w_w_w, CRCC_W_W_W>;
2131def : PatGprGpr<loongarch_crcc_w_d_w, CRCC_W_D_W>;
2132} // Predicates = [IsLA64]
2133
2134/// Other pseudo-instructions
2135
2136// Pessimistically assume the stack pointer will be clobbered
2137let Defs = [R3], Uses = [R3] in {
2138def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
2139                              [(callseq_start timm:$amt1, timm:$amt2)]>;
2140def ADJCALLSTACKUP   : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
2141                              [(callseq_end timm:$amt1, timm:$amt2)]>;
2142} // Defs = [R3], Uses = [R3]
2143
2144//===----------------------------------------------------------------------===//
2145// Assembler Pseudo Instructions
2146//===----------------------------------------------------------------------===//
2147
2148def : InstAlias<"nop", (ANDI R0, R0, 0)>;
2149def : InstAlias<"move $dst, $src", (OR GPR:$dst, GPR:$src, R0)>;
2150// `ret` is supported since binutils commit 20f2e2686c79a5ac (version 2.40 and
2151// later).
2152def : InstAlias<"ret", (JIRL R0, R1, 0)>;
2153def : InstAlias<"jr $rj", (JIRL R0, GPR:$rj, 0)>;
2154
2155// Branches implemented with alias.
2156// Always output the canonical mnemonic for the pseudo branch instructions.
2157// The GNU tools emit the canonical mnemonic for the branch pseudo instructions
2158// as well (e.g. "bgt" will be recognised by the assembler but never printed by
2159// objdump). Match this behaviour by setting a zero weight.
2160def : InstAlias<"bgt $rj, $rd, $imm16",
2161                (BLT GPR:$rd, GPR:$rj, simm16_lsl2_br:$imm16), 0>;
2162def : InstAlias<"bgtu $rj, $rd, $imm16",
2163                (BLTU GPR:$rd, GPR:$rj, simm16_lsl2_br:$imm16), 0>;
2164def : InstAlias<"ble $rj, $rd, $imm16",
2165                (BGE GPR:$rd, GPR:$rj, simm16_lsl2_br:$imm16), 0>;
2166def : InstAlias<"bleu $rj, $rd, $imm16",
2167                (BGEU GPR:$rd, GPR:$rj, simm16_lsl2_br:$imm16), 0>;
2168def : InstAlias<"bltz $rd, $imm16",
2169                (BLT GPR:$rd, R0, simm16_lsl2_br:$imm16), 0>;
2170def : InstAlias<"bgtz $rj, $imm16",
2171                (BLT R0, GPR:$rj, simm16_lsl2_br:$imm16), 0>;
2172def : InstAlias<"blez $rj, $imm16",
2173                (BGE R0, GPR:$rj, simm16_lsl2_br:$imm16), 0>;
2174def : InstAlias<"bgez $rd, $imm16",
2175                (BGE GPR:$rd, R0, simm16_lsl2_br:$imm16), 0>;
2176
2177// Load immediate.
2178let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0,
2179    isAsmParserOnly = 1 in {
2180def PseudoLI_W : Pseudo<(outs GPR:$rd), (ins imm32:$imm), [],
2181                        "li.w", "$rd, $imm">;
2182def PseudoLI_D : Pseudo<(outs GPR:$rd), (ins grlenimm:$imm), [],
2183                        "li.d", "$rd, $imm">, Requires<[IsLA64]>;
2184}
2185
2186//===----------------------------------------------------------------------===//
2187// Basic Floating-Point Instructions
2188//===----------------------------------------------------------------------===//
2189
2190include "LoongArchFloat32InstrInfo.td"
2191include "LoongArchFloat64InstrInfo.td"
2192
2193let Predicates = [HasBasicF], usesCustomInserter = 1 in {
2194  def WRFCSR : Pseudo<(outs), (ins uimm2:$fcsr, GPR:$src),
2195               [(loongarch_movgr2fcsr uimm2:$fcsr, GRLenVT:$src)]>;
2196  def RDFCSR : Pseudo<(outs GPR:$rd), (ins uimm2:$fcsr),
2197               [(set GPR:$rd, (loongarch_movfcsr2gr uimm2:$fcsr))]>;
2198}
2199
2200//===----------------------------------------------------------------------===//
2201// Privilege Instructions
2202//===----------------------------------------------------------------------===//
2203
2204// CSR Access Instructions
2205let hasSideEffects = 1 in
2206def CSRRD : FmtCSR<0x04000000, (outs GPR:$rd), (ins uimm14:$csr_num),
2207                   "$rd, $csr_num">;
2208let hasSideEffects = 1, Constraints = "$rd = $dst" in {
2209def CSRWR : FmtCSR<0x04000020, (outs GPR:$dst),
2210                   (ins GPR:$rd, uimm14:$csr_num), "$rd, $csr_num">;
2211def CSRXCHG : FmtCSRXCHG<0x04000000, (outs GPR:$dst),
2212                         (ins GPR:$rd, GPR:$rj, uimm14:$csr_num),
2213                         "$rd, $rj, $csr_num">;
2214} // hasSideEffects = 1, Constraints = "$rd = $dst"
2215
2216// IOCSR Access Instructions
2217def IOCSRRD_B : IOCSRRD<0x06480000>;
2218def IOCSRRD_H : IOCSRRD<0x06480400>;
2219def IOCSRRD_W : IOCSRRD<0x06480800>;
2220def IOCSRWR_B : IOCSRWR<0x06481000>;
2221def IOCSRWR_H : IOCSRWR<0x06481400>;
2222def IOCSRWR_W : IOCSRWR<0x06481800>;
2223let Predicates = [IsLA64] in {
2224def IOCSRRD_D : IOCSRRD<0x06480c00>;
2225def IOCSRWR_D : IOCSRWR<0x06481c00>;
2226} // Predicates = [IsLA64]
2227
2228// TLB Maintenance Instructions
2229let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in {
2230def TLBSRCH  : FmtI32<0x06482800>;
2231def TLBRD    : FmtI32<0x06482c00>;
2232def TLBWR    : FmtI32<0x06483000>;
2233def TLBFILL  : FmtI32<0x06483400>;
2234def TLBCLR   : FmtI32<0x06482000>;
2235def TLBFLUSH : FmtI32<0x06482400>;
2236def INVTLB : FmtINVTLB<(outs), (ins GPR:$rk, GPR:$rj, uimm5:$op),
2237                       "$op, $rj, $rk">;
2238} // hasSideEffects = 1, mayLoad = 0, mayStore = 0
2239
2240// Software Page Walking Instructions
2241def LDDIR : Fmt2RI8<0x06400000, (outs GPR:$rd),
2242                    (ins GPR:$rj, uimm8:$imm8), "$rd, $rj, $imm8">;
2243def LDPTE : FmtLDPTE<(outs), (ins GPR:$rj, uimm8:$seq), "$rj, $seq">;
2244
2245
2246// Other Miscellaneous Instructions
2247let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
2248def ERTN : FmtI32<0x06483800>;
2249def DBCL : MISC_I15<0x002a8000>;
2250def IDLE : MISC_I15<0x06488000>;
2251
2252//===----------------------------------------------------------------------===//
2253// Privilege Intrinsics
2254//===----------------------------------------------------------------------===//
2255
2256def : Pat<(loongarch_csrrd uimm14:$imm14), (CSRRD uimm14:$imm14)>;
2257def : Pat<(loongarch_csrwr GPR:$rd, uimm14:$imm14),
2258          (CSRWR GPR:$rd, uimm14:$imm14)>;
2259def : Pat<(loongarch_csrxchg GPR:$rd, GPR:$rj, uimm14:$imm14),
2260          (CSRXCHG GPR:$rd, GPR:$rj, uimm14:$imm14)>;
2261
2262def : Pat<(loongarch_iocsrrd_b GPR:$rj), (IOCSRRD_B GPR:$rj)>;
2263def : Pat<(loongarch_iocsrrd_h GPR:$rj), (IOCSRRD_H GPR:$rj)>;
2264def : Pat<(loongarch_iocsrrd_w GPR:$rj), (IOCSRRD_W GPR:$rj)>;
2265
2266def : Pat<(loongarch_iocsrwr_b GPR:$rd, GPR:$rj), (IOCSRWR_B GPR:$rd, GPR:$rj)>;
2267def : Pat<(loongarch_iocsrwr_h GPR:$rd, GPR:$rj), (IOCSRWR_H GPR:$rd, GPR:$rj)>;
2268def : Pat<(loongarch_iocsrwr_w GPR:$rd, GPR:$rj), (IOCSRWR_W GPR:$rd, GPR:$rj)>;
2269
2270def : Pat<(loongarch_cpucfg GPR:$rj), (CPUCFG GPR:$rj)>;
2271
2272let Predicates = [IsLA64] in {
2273def : Pat<(loongarch_iocsrrd_d GPR:$rj), (IOCSRRD_D GPR:$rj)>;
2274def : Pat<(loongarch_iocsrwr_d GPR:$rd, GPR:$rj), (IOCSRWR_D GPR:$rd, GPR:$rj)>;
2275def : Pat<(int_loongarch_asrtle_d GPR:$rj, GPR:$rk),
2276          (ASRTLE_D GPR:$rj, GPR:$rk)>;
2277def : Pat<(int_loongarch_asrtgt_d GPR:$rj, GPR:$rk),
2278          (ASRTGT_D GPR:$rj, GPR:$rk)>;
2279def : Pat<(int_loongarch_lddir_d GPR:$rj, timm:$imm8),
2280          (LDDIR GPR:$rj, timm:$imm8)>;
2281def : Pat<(int_loongarch_ldpte_d GPR:$rj, timm:$imm8),
2282          (LDPTE GPR:$rj, timm:$imm8)>;
2283} // Predicates = [IsLA64]
2284
2285//===----------------------------------------------------------------------===//
2286// LSX Instructions
2287//===----------------------------------------------------------------------===//
2288include "LoongArchLSXInstrInfo.td"
2289
2290//===----------------------------------------------------------------------===//
2291// LASX Instructions
2292//===----------------------------------------------------------------------===//
2293include "LoongArchLASXInstrInfo.td"
2294
2295//===----------------------------------------------------------------------===//
2296// LVZ Instructions
2297//===----------------------------------------------------------------------===//
2298include "LoongArchLVZInstrInfo.td"
2299
2300//===----------------------------------------------------------------------===//
2301// LBT Instructions
2302//===----------------------------------------------------------------------===//
2303include "LoongArchLBTInstrInfo.td"
2304