xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfoA.td (revision a90b9d0159070121c221b966469c3e36d912bf82)
1//===-- RISCVInstrInfoA.td - RISC-V 'A' instructions -------*- 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 RISC-V instructions from the standard 'A', Atomic
10// Instructions extension.
11//
12//===----------------------------------------------------------------------===//
13
14//===----------------------------------------------------------------------===//
15// Instruction class templates
16//===----------------------------------------------------------------------===//
17
18let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
19class LR_r<bit aq, bit rl, bits<3> funct3, string opcodestr>
20    : RVInstRAtomic<0b00010, aq, rl, funct3, OPC_AMO,
21                    (outs GPR:$rd), (ins GPRMemZeroOffset:$rs1),
22                    opcodestr, "$rd, $rs1"> {
23  let rs2 = 0;
24}
25
26multiclass LR_r_aq_rl<bits<3> funct3, string opcodestr> {
27  def ""     : LR_r<0, 0, funct3, opcodestr>;
28  def _AQ    : LR_r<1, 0, funct3, opcodestr # ".aq">;
29  def _RL    : LR_r<0, 1, funct3, opcodestr # ".rl">;
30  def _AQ_RL : LR_r<1, 1, funct3, opcodestr # ".aqrl">;
31}
32
33let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in
34class AMO_rr<bits<5> funct5, bit aq, bit rl, bits<3> funct3, string opcodestr>
35    : RVInstRAtomic<funct5, aq, rl, funct3, OPC_AMO,
36                    (outs GPR:$rd), (ins GPRMemZeroOffset:$rs1, GPR:$rs2),
37                    opcodestr, "$rd, $rs2, $rs1">;
38
39multiclass AMO_rr_aq_rl<bits<5> funct5, bits<3> funct3, string opcodestr> {
40  def ""     : AMO_rr<funct5, 0, 0, funct3, opcodestr>;
41  def _AQ    : AMO_rr<funct5, 1, 0, funct3, opcodestr # ".aq">;
42  def _RL    : AMO_rr<funct5, 0, 1, funct3, opcodestr # ".rl">;
43  def _AQ_RL : AMO_rr<funct5, 1, 1, funct3, opcodestr # ".aqrl">;
44}
45
46//===----------------------------------------------------------------------===//
47// Instructions
48//===----------------------------------------------------------------------===//
49
50let Predicates = [HasStdExtA], IsSignExtendingOpW = 1 in {
51defm LR_W       : LR_r_aq_rl<0b010, "lr.w">, Sched<[WriteAtomicLDW, ReadAtomicLDW]>;
52defm SC_W       : AMO_rr_aq_rl<0b00011, 0b010, "sc.w">,
53                  Sched<[WriteAtomicSTW, ReadAtomicSTW, ReadAtomicSTW]>;
54defm AMOSWAP_W  : AMO_rr_aq_rl<0b00001, 0b010, "amoswap.w">,
55                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
56defm AMOADD_W   : AMO_rr_aq_rl<0b00000, 0b010, "amoadd.w">,
57                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
58defm AMOXOR_W   : AMO_rr_aq_rl<0b00100, 0b010, "amoxor.w">,
59                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
60defm AMOAND_W   : AMO_rr_aq_rl<0b01100, 0b010, "amoand.w">,
61                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
62defm AMOOR_W    : AMO_rr_aq_rl<0b01000, 0b010, "amoor.w">,
63                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
64defm AMOMIN_W   : AMO_rr_aq_rl<0b10000, 0b010, "amomin.w">,
65                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
66defm AMOMAX_W   : AMO_rr_aq_rl<0b10100, 0b010, "amomax.w">,
67                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
68defm AMOMINU_W  : AMO_rr_aq_rl<0b11000, 0b010, "amominu.w">,
69                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
70defm AMOMAXU_W  : AMO_rr_aq_rl<0b11100, 0b010, "amomaxu.w">,
71                  Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>;
72} // Predicates = [HasStdExtA]
73
74let Predicates = [HasStdExtA, IsRV64] in {
75defm LR_D       : LR_r_aq_rl<0b011, "lr.d">, Sched<[WriteAtomicLDD, ReadAtomicLDD]>;
76defm SC_D       : AMO_rr_aq_rl<0b00011, 0b011, "sc.d">,
77                  Sched<[WriteAtomicSTD, ReadAtomicSTD, ReadAtomicSTD]>;
78defm AMOSWAP_D  : AMO_rr_aq_rl<0b00001, 0b011, "amoswap.d">,
79                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
80defm AMOADD_D   : AMO_rr_aq_rl<0b00000, 0b011, "amoadd.d">,
81                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
82defm AMOXOR_D   : AMO_rr_aq_rl<0b00100, 0b011, "amoxor.d">,
83                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
84defm AMOAND_D   : AMO_rr_aq_rl<0b01100, 0b011, "amoand.d">,
85                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
86defm AMOOR_D    : AMO_rr_aq_rl<0b01000, 0b011, "amoor.d">,
87                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
88defm AMOMIN_D   : AMO_rr_aq_rl<0b10000, 0b011, "amomin.d">,
89                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
90defm AMOMAX_D   : AMO_rr_aq_rl<0b10100, 0b011, "amomax.d">,
91                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
92defm AMOMINU_D  : AMO_rr_aq_rl<0b11000, 0b011, "amominu.d">,
93                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
94defm AMOMAXU_D  : AMO_rr_aq_rl<0b11100, 0b011, "amomaxu.d">,
95                  Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>;
96} // Predicates = [HasStdExtA, IsRV64]
97
98//===----------------------------------------------------------------------===//
99// Pseudo-instructions and codegen patterns
100//===----------------------------------------------------------------------===//
101
102// Atomic load/store are available under both +a and +force-atomics.
103// Fences will be inserted for atomic load/stores according to the logic in
104// RISCVTargetLowering::{emitLeadingFence,emitTrailingFence}.
105let Predicates = [HasAtomicLdSt] in {
106  def : LdPat<atomic_load_8,  LB>;
107  def : LdPat<atomic_load_16, LH>;
108  def : LdPat<atomic_load_32, LW>;
109
110  def : StPat<atomic_store_8,  SB, GPR, XLenVT>;
111  def : StPat<atomic_store_16, SH, GPR, XLenVT>;
112  def : StPat<atomic_store_32, SW, GPR, XLenVT>;
113}
114
115let Predicates = [HasAtomicLdSt, IsRV64] in {
116  def : LdPat<atomic_load_64, LD, i64>;
117  def : StPat<atomic_store_64, SD, GPR, i64>;
118}
119
120/// AMOs
121
122multiclass AMOPat<string AtomicOp, string BaseInst, ValueType vt = XLenVT,
123                  list<Predicate> ExtraPreds = []> {
124let Predicates = !listconcat([HasStdExtA, NotHasStdExtZtso], ExtraPreds) in {
125  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_monotonic"),
126                  !cast<RVInst>(BaseInst), vt>;
127  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_acquire"),
128                  !cast<RVInst>(BaseInst#"_AQ"), vt>;
129  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_release"),
130                  !cast<RVInst>(BaseInst#"_RL"), vt>;
131  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_acq_rel"),
132                  !cast<RVInst>(BaseInst#"_AQ_RL"), vt>;
133  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_seq_cst"),
134                  !cast<RVInst>(BaseInst#"_AQ_RL"), vt>;
135}
136let Predicates = !listconcat([HasStdExtA, HasStdExtZtso], ExtraPreds) in {
137  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_monotonic"),
138                  !cast<RVInst>(BaseInst), vt>;
139  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_acquire"),
140                  !cast<RVInst>(BaseInst), vt>;
141  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_release"),
142                  !cast<RVInst>(BaseInst), vt>;
143  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_acq_rel"),
144                  !cast<RVInst>(BaseInst), vt>;
145  def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_seq_cst"),
146                  !cast<RVInst>(BaseInst), vt>;
147}
148}
149
150defm : AMOPat<"atomic_swap_32", "AMOSWAP_W">;
151defm : AMOPat<"atomic_load_add_32", "AMOADD_W">;
152defm : AMOPat<"atomic_load_and_32", "AMOAND_W">;
153defm : AMOPat<"atomic_load_or_32", "AMOOR_W">;
154defm : AMOPat<"atomic_load_xor_32", "AMOXOR_W">;
155defm : AMOPat<"atomic_load_max_32", "AMOMAX_W">;
156defm : AMOPat<"atomic_load_min_32", "AMOMIN_W">;
157defm : AMOPat<"atomic_load_umax_32", "AMOMAXU_W">;
158defm : AMOPat<"atomic_load_umin_32", "AMOMINU_W">;
159
160defm : AMOPat<"atomic_swap_64", "AMOSWAP_D", i64, [IsRV64]>;
161defm : AMOPat<"atomic_load_add_64", "AMOADD_D", i64, [IsRV64]>;
162defm : AMOPat<"atomic_load_and_64", "AMOAND_D", i64, [IsRV64]>;
163defm : AMOPat<"atomic_load_or_64", "AMOOR_D", i64, [IsRV64]>;
164defm : AMOPat<"atomic_load_xor_64", "AMOXOR_D", i64, [IsRV64]>;
165defm : AMOPat<"atomic_load_max_64", "AMOMAX_D", i64, [IsRV64]>;
166defm : AMOPat<"atomic_load_min_64", "AMOMIN_D", i64, [IsRV64]>;
167defm : AMOPat<"atomic_load_umax_64", "AMOMAXU_D", i64, [IsRV64]>;
168defm : AMOPat<"atomic_load_umin_64", "AMOMINU_D", i64, [IsRV64]>;
169
170
171/// Pseudo AMOs
172
173class PseudoAMO : Pseudo<(outs GPR:$res, GPR:$scratch),
174                         (ins GPR:$addr, GPR:$incr, ixlenimm:$ordering), []> {
175  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
176  let mayLoad = 1;
177  let mayStore = 1;
178  let hasSideEffects = 0;
179}
180
181class PseudoMaskedAMO
182    : Pseudo<(outs GPR:$res, GPR:$scratch),
183             (ins GPR:$addr, GPR:$incr, GPR:$mask, ixlenimm:$ordering), []> {
184  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
185  let mayLoad = 1;
186  let mayStore = 1;
187  let hasSideEffects = 0;
188}
189
190class PseudoMaskedAMOMinMax
191    : Pseudo<(outs GPR:$res, GPR:$scratch1, GPR:$scratch2),
192             (ins GPR:$addr, GPR:$incr, GPR:$mask, ixlenimm:$sextshamt,
193              ixlenimm:$ordering), []> {
194  let Constraints = "@earlyclobber $res,@earlyclobber $scratch1,"
195                    "@earlyclobber $scratch2";
196  let mayLoad = 1;
197  let mayStore = 1;
198  let hasSideEffects = 0;
199}
200
201class PseudoMaskedAMOUMinUMax
202    : Pseudo<(outs GPR:$res, GPR:$scratch1, GPR:$scratch2),
203             (ins GPR:$addr, GPR:$incr, GPR:$mask, ixlenimm:$ordering), []> {
204  let Constraints = "@earlyclobber $res,@earlyclobber $scratch1,"
205                    "@earlyclobber $scratch2";
206  let mayLoad = 1;
207  let mayStore = 1;
208  let hasSideEffects = 0;
209}
210
211class PseudoMaskedAMOPat<Intrinsic intrin, Pseudo AMOInst>
212    : Pat<(intrin GPR:$addr, GPR:$incr, GPR:$mask, timm:$ordering),
213          (AMOInst GPR:$addr, GPR:$incr, GPR:$mask, timm:$ordering)>;
214
215class PseudoMaskedAMOMinMaxPat<Intrinsic intrin, Pseudo AMOInst>
216    : Pat<(intrin GPR:$addr, GPR:$incr, GPR:$mask, GPR:$shiftamt,
217           timm:$ordering),
218          (AMOInst GPR:$addr, GPR:$incr, GPR:$mask, GPR:$shiftamt,
219           timm:$ordering)>;
220
221let Predicates = [HasStdExtA] in {
222
223let Size = 20 in
224def PseudoAtomicLoadNand32 : PseudoAMO;
225// Ordering constants must be kept in sync with the AtomicOrdering enum in
226// AtomicOrdering.h.
227def : Pat<(XLenVT (atomic_load_nand_32_monotonic GPR:$addr, GPR:$incr)),
228          (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 2)>;
229def : Pat<(XLenVT (atomic_load_nand_32_acquire GPR:$addr, GPR:$incr)),
230          (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 4)>;
231def : Pat<(XLenVT (atomic_load_nand_32_release GPR:$addr, GPR:$incr)),
232          (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 5)>;
233def : Pat<(XLenVT (atomic_load_nand_32_acq_rel GPR:$addr, GPR:$incr)),
234          (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 6)>;
235def : Pat<(XLenVT (atomic_load_nand_32_seq_cst GPR:$addr, GPR:$incr)),
236          (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 7)>;
237
238let Size = 28 in
239def PseudoMaskedAtomicSwap32 : PseudoMaskedAMO;
240def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_xchg_i32,
241                         PseudoMaskedAtomicSwap32>;
242let Size = 28 in
243def PseudoMaskedAtomicLoadAdd32 : PseudoMaskedAMO;
244def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_add_i32,
245                         PseudoMaskedAtomicLoadAdd32>;
246let Size = 28 in
247def PseudoMaskedAtomicLoadSub32 : PseudoMaskedAMO;
248def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_sub_i32,
249                         PseudoMaskedAtomicLoadSub32>;
250let Size = 32 in
251def PseudoMaskedAtomicLoadNand32 : PseudoMaskedAMO;
252def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_nand_i32,
253                         PseudoMaskedAtomicLoadNand32>;
254let Size = 44 in
255def PseudoMaskedAtomicLoadMax32 : PseudoMaskedAMOMinMax;
256def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_max_i32,
257                               PseudoMaskedAtomicLoadMax32>;
258let Size = 44 in
259def PseudoMaskedAtomicLoadMin32 : PseudoMaskedAMOMinMax;
260def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_min_i32,
261                               PseudoMaskedAtomicLoadMin32>;
262let Size = 36 in
263def PseudoMaskedAtomicLoadUMax32 : PseudoMaskedAMOUMinUMax;
264def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umax_i32,
265                         PseudoMaskedAtomicLoadUMax32>;
266let Size = 36 in
267def PseudoMaskedAtomicLoadUMin32 : PseudoMaskedAMOUMinUMax;
268def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umin_i32,
269                         PseudoMaskedAtomicLoadUMin32>;
270} // Predicates = [HasStdExtA]
271
272let Predicates = [HasStdExtA, IsRV64] in {
273
274let Size = 20 in
275def PseudoAtomicLoadNand64 : PseudoAMO;
276// Ordering constants must be kept in sync with the AtomicOrdering enum in
277// AtomicOrdering.h.
278def : Pat<(i64 (atomic_load_nand_64_monotonic GPR:$addr, GPR:$incr)),
279          (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 2)>;
280def : Pat<(i64 (atomic_load_nand_64_acquire GPR:$addr, GPR:$incr)),
281          (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 4)>;
282def : Pat<(i64 (atomic_load_nand_64_release GPR:$addr, GPR:$incr)),
283          (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 5)>;
284def : Pat<(i64 (atomic_load_nand_64_acq_rel GPR:$addr, GPR:$incr)),
285          (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 6)>;
286def : Pat<(i64 (atomic_load_nand_64_seq_cst GPR:$addr, GPR:$incr)),
287          (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 7)>;
288
289def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_xchg_i64,
290                         PseudoMaskedAtomicSwap32>;
291def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_add_i64,
292                         PseudoMaskedAtomicLoadAdd32>;
293def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_sub_i64,
294                         PseudoMaskedAtomicLoadSub32>;
295def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_nand_i64,
296                         PseudoMaskedAtomicLoadNand32>;
297def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_max_i64,
298                               PseudoMaskedAtomicLoadMax32>;
299def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_min_i64,
300                               PseudoMaskedAtomicLoadMin32>;
301def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umax_i64,
302                         PseudoMaskedAtomicLoadUMax32>;
303def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umin_i64,
304                         PseudoMaskedAtomicLoadUMin32>;
305} // Predicates = [HasStdExtA, IsRV64]
306
307
308/// Compare and exchange
309
310class PseudoCmpXchg
311    : Pseudo<(outs GPR:$res, GPR:$scratch),
312             (ins GPR:$addr, GPR:$cmpval, GPR:$newval, ixlenimm:$ordering), []> {
313  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
314  let mayLoad = 1;
315  let mayStore = 1;
316  let hasSideEffects = 0;
317  let Size = 16;
318}
319
320// Ordering constants must be kept in sync with the AtomicOrdering enum in
321// AtomicOrdering.h.
322multiclass PseudoCmpXchgPat<string Op, Pseudo CmpXchgInst,
323                            ValueType vt = XLenVT> {
324  def : Pat<(vt (!cast<PatFrag>(Op#"_monotonic") GPR:$addr, GPR:$cmp, GPR:$new)),
325            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 2)>;
326  def : Pat<(vt (!cast<PatFrag>(Op#"_acquire") GPR:$addr, GPR:$cmp, GPR:$new)),
327            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 4)>;
328  def : Pat<(vt (!cast<PatFrag>(Op#"_release") GPR:$addr, GPR:$cmp, GPR:$new)),
329            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 5)>;
330  def : Pat<(vt (!cast<PatFrag>(Op#"_acq_rel") GPR:$addr, GPR:$cmp, GPR:$new)),
331            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 6)>;
332  def : Pat<(vt (!cast<PatFrag>(Op#"_seq_cst") GPR:$addr, GPR:$cmp, GPR:$new)),
333            (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 7)>;
334}
335
336let Predicates = [HasStdExtA, NoStdExtZacas] in {
337def PseudoCmpXchg32 : PseudoCmpXchg;
338defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32>;
339}
340
341let Predicates = [HasStdExtA, NoStdExtZacas, IsRV64] in {
342def PseudoCmpXchg64 : PseudoCmpXchg;
343defm : PseudoCmpXchgPat<"atomic_cmp_swap_64", PseudoCmpXchg64, i64>;
344}
345
346let Predicates = [HasStdExtA] in {
347def PseudoMaskedCmpXchg32
348    : Pseudo<(outs GPR:$res, GPR:$scratch),
349             (ins GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask,
350              ixlenimm:$ordering), []> {
351  let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
352  let mayLoad = 1;
353  let mayStore = 1;
354  let hasSideEffects = 0;
355  let Size = 32;
356}
357
358def : Pat<(int_riscv_masked_cmpxchg_i32
359            GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering),
360          (PseudoMaskedCmpXchg32
361            GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering)>;
362} // Predicates = [HasStdExtA]
363
364let Predicates = [HasStdExtA, IsRV64] in {
365def : Pat<(int_riscv_masked_cmpxchg_i64
366            GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering),
367          (PseudoMaskedCmpXchg32
368            GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering)>;
369} // Predicates = [HasStdExtA, IsRV64]
370
371//===----------------------------------------------------------------------===//
372// Experimental RV64 i32 legalization patterns.
373//===----------------------------------------------------------------------===//
374
375class PatGprGprA<SDPatternOperator OpNode, RVInst Inst, ValueType vt>
376    : Pat<(vt (OpNode (XLenVT GPR:$rs1), (vt GPR:$rs2))), (Inst GPR:$rs1, GPR:$rs2)>;
377
378multiclass AMOPat2<string AtomicOp, string BaseInst, ValueType vt = XLenVT,
379                   list<Predicate> ExtraPreds = []> {
380let Predicates = !listconcat([HasStdExtA, NotHasStdExtZtso], ExtraPreds) in {
381  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_monotonic"),
382                   !cast<RVInst>(BaseInst), vt>;
383  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_acquire"),
384                   !cast<RVInst>(BaseInst#"_AQ"), vt>;
385  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_release"),
386                   !cast<RVInst>(BaseInst#"_RL"), vt>;
387  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_acq_rel"),
388                   !cast<RVInst>(BaseInst#"_AQ_RL"), vt>;
389  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_seq_cst"),
390                   !cast<RVInst>(BaseInst#"_AQ_RL"), vt>;
391}
392let Predicates = !listconcat([HasStdExtA, HasStdExtZtso], ExtraPreds) in {
393  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_monotonic"),
394                   !cast<RVInst>(BaseInst), vt>;
395  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_acquire"),
396                   !cast<RVInst>(BaseInst), vt>;
397  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_release"),
398                   !cast<RVInst>(BaseInst), vt>;
399  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_acq_rel"),
400                   !cast<RVInst>(BaseInst), vt>;
401  def : PatGprGprA<!cast<PatFrag>(AtomicOp#"_seq_cst"),
402                   !cast<RVInst>(BaseInst), vt>;
403}
404}
405
406defm : AMOPat2<"atomic_swap_32", "AMOSWAP_W", i32>;
407defm : AMOPat2<"atomic_load_add_32", "AMOADD_W", i32>;
408defm : AMOPat2<"atomic_load_and_32", "AMOAND_W", i32>;
409defm : AMOPat2<"atomic_load_or_32", "AMOOR_W", i32>;
410defm : AMOPat2<"atomic_load_xor_32", "AMOXOR_W", i32>;
411defm : AMOPat2<"atomic_load_max_32", "AMOMAX_W", i32>;
412defm : AMOPat2<"atomic_load_min_32", "AMOMIN_W", i32>;
413defm : AMOPat2<"atomic_load_umax_32", "AMOMAXU_W", i32>;
414defm : AMOPat2<"atomic_load_umin_32", "AMOMINU_W", i32>;
415
416let Predicates = [HasStdExtA, IsRV64] in
417defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32, i32>;
418
419let Predicates = [HasAtomicLdSt] in {
420  def : LdPat<atomic_load_8,  LB, i32>;
421  def : LdPat<atomic_load_16, LH, i32>;
422  def : LdPat<atomic_load_32, LW, i32>;
423
424  def : StPat<atomic_store_8,  SB, GPR, i32>;
425  def : StPat<atomic_store_16, SH, GPR, i32>;
426  def : StPat<atomic_store_32, SW, GPR, i32>;
427}
428
429