Add hppa*-*-hpux* to targets which do not support split DWARF
[official-gcc.git] / gcc / config / riscv / sync.md
blob54bb0a66518ae353fa4ed640339213bf5da6682c
1 ;; Machine description for RISC-V atomic operations.
2 ;; Copyright (C) 2011-2024 Free Software Foundation, Inc.
3 ;; Contributed by Andrew Waterman (andrew@sifive.com).
4 ;; Based on MIPS target for GNU compiler.
6 ;; This file is part of GCC.
8 ;; GCC is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 3, or (at your option)
11 ;; any later version.
13 ;; GCC is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GCC; see the file COPYING3.  If not see
20 ;; <http://www.gnu.org/licenses/>.
22 (define_c_enum "unspec" [
23   UNSPEC_COMPARE_AND_SWAP
24   UNSPEC_COMPARE_AND_SWAP_SUBWORD
25   UNSPEC_SYNC_OLD_OP
26   UNSPEC_SYNC_OLD_OP_SUBWORD
27   UNSPEC_SYNC_EXCHANGE
28   UNSPEC_SYNC_EXCHANGE_SUBWORD
29   UNSPEC_ATOMIC_LOAD
30   UNSPEC_ATOMIC_STORE
31   UNSPEC_MEMORY_BARRIER
34 ;; Memory barriers.
36 (define_expand "mem_thread_fence"
37   [(match_operand:SI 0 "const_int_operand" "")] ;; model
38   ""
39   {
40     enum memmodel model = memmodel_base (INTVAL (operands[0]));
42     if (TARGET_ZTSO && model == MEMMODEL_SEQ_CST)
43       {
44         rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
45         MEM_VOLATILE_P (mem) = 1;
46         emit_insn (gen_mem_thread_fence_ztso (mem, operands[0]));
47       }
48     else if (!TARGET_ZTSO && model != MEMMODEL_RELAXED)
49       {
50         rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
51         MEM_VOLATILE_P (mem) = 1;
52         emit_insn (gen_mem_thread_fence_rvwmo (mem, operands[0]));
53       }
54     DONE;
55   })
57 ;; Atomic memory operations.
59 (define_expand "atomic_load<mode>"
60   [(match_operand:GPR 0 "register_operand")
61    (match_operand:GPR 1 "memory_operand")
62    (match_operand:SI 2 "const_int_operand")] ;; model
63   ""
64   {
65     if (TARGET_ZTSO)
66       emit_insn (gen_atomic_load_ztso<mode> (operands[0], operands[1],
67                                              operands[2]));
68     else
69       emit_insn (gen_atomic_load_rvwmo<mode> (operands[0], operands[1],
70                                               operands[2]));
71     DONE;
72   })
74 (define_expand "atomic_store<mode>"
75   [(match_operand:GPR 0 "memory_operand")
76    (match_operand:GPR 1 "reg_or_0_operand")
77    (match_operand:SI 2 "const_int_operand")] ;; model
78   ""
79   {
80     if (TARGET_ZTSO)
81       emit_insn (gen_atomic_store_ztso<mode> (operands[0], operands[1],
82                                               operands[2]));
83     else
84       emit_insn (gen_atomic_store_rvwmo<mode> (operands[0], operands[1],
85                                                operands[2]));
86     DONE;
87   })
89 (define_insn "atomic_<atomic_optab><mode>"
90   [(set (match_operand:GPR 0 "memory_operand" "+A")
91         (unspec_volatile:GPR
92           [(any_atomic:GPR (match_dup 0)
93                      (match_operand:GPR 1 "reg_or_0_operand" "rJ"))
94            (match_operand:SI 2 "const_int_operand")] ;; model
95          UNSPEC_SYNC_OLD_OP))]
96   "TARGET_ATOMIC"
97   "amo<insn>.<amo>%A2\tzero,%z1,%0"
98   [(set_attr "type" "atomic")
99    (set (attr "length") (const_int 4))])
101 (define_insn "atomic_fetch_<atomic_optab><mode>"
102   [(set (match_operand:GPR 0 "register_operand" "=&r")
103         (match_operand:GPR 1 "memory_operand" "+A"))
104    (set (match_dup 1)
105         (unspec_volatile:GPR
106           [(any_atomic:GPR (match_dup 1)
107                      (match_operand:GPR 2 "reg_or_0_operand" "rJ"))
108            (match_operand:SI 3 "const_int_operand")] ;; model
109          UNSPEC_SYNC_OLD_OP))]
110   "TARGET_ATOMIC"
111   "amo<insn>.<amo>%A3\t%0,%z2,%1"
112   [(set_attr "type" "atomic")
113    (set (attr "length") (const_int 4))])
115 (define_insn "subword_atomic_fetch_strong_<atomic_optab>"
116   [(set (match_operand:SI 0 "register_operand" "=&r")              ;; old value at mem
117         (match_operand:SI 1 "memory_operand" "+A"))                ;; mem location
118    (set (match_dup 1)
119         (unspec_volatile:SI
120           [(any_atomic:SI (match_dup 1)
121                      (match_operand:SI 2 "register_operand" "rI")) ;; value for op
122            (match_operand:SI 3 "const_int_operand")]               ;; model
123          UNSPEC_SYNC_OLD_OP_SUBWORD))
124     (match_operand:SI 4 "register_operand" "rI")                   ;; mask
125     (match_operand:SI 5 "register_operand" "rI")                   ;; not_mask
126     (clobber (match_scratch:SI 6 "=&r"))                           ;; tmp_1
127     (clobber (match_scratch:SI 7 "=&r"))]                          ;; tmp_2
128   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
129   {
130     return "1:\;"
131            "lr.w%I3\t%0, %1\;"
132            "<insn>\t%6, %0, %2\;"
133            "and\t%6, %6, %4\;"
134            "and\t%7, %0, %5\;"
135            "or\t%7, %7, %6\;"
136            "sc.w%J3\t%6, %7, %1\;"
137            "bnez\t%6, 1b";
138   }
139   [(set_attr "type" "multi")
140    (set (attr "length") (const_int 28))])
142 (define_expand "atomic_fetch_nand<mode>"
143   [(match_operand:SHORT 0 "register_operand")                         ;; old value at mem
144    (not:SHORT (and:SHORT (match_operand:SHORT 1 "memory_operand")     ;; mem location
145                          (match_operand:SHORT 2 "reg_or_0_operand"))) ;; value for op
146    (match_operand:SI 3 "const_int_operand")]                          ;; model
147   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
149   /* We have no QImode/HImode atomics, so form a mask, then use
150      subword_atomic_fetch_strong_nand to implement a LR/SC version of the
151      operation.  */
153   /* Logic duplicated in gcc/libgcc/config/riscv/atomic.c for use when inlining
154      is disabled.  */
156   rtx old = gen_reg_rtx (SImode);
157   rtx mem = operands[1];
158   rtx value = operands[2];
159   rtx model = operands[3];
160   rtx aligned_mem = gen_reg_rtx (SImode);
161   rtx shift = gen_reg_rtx (SImode);
162   rtx mask = gen_reg_rtx (SImode);
163   rtx not_mask = gen_reg_rtx (SImode);
165   riscv_subword_address (mem, &aligned_mem, &shift, &mask, &not_mask);
167   rtx shifted_value = gen_reg_rtx (SImode);
168   riscv_lshift_subword (<MODE>mode, value, shift, &shifted_value);
170   emit_insn (gen_subword_atomic_fetch_strong_nand (old, aligned_mem,
171                                                    shifted_value, model,
172                                                    mask, not_mask));
174   emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old,
175                                          gen_lowpart (QImode, shift)));
177   emit_move_insn (operands[0], gen_lowpart (<MODE>mode, old));
179   DONE;
182 (define_insn "subword_atomic_fetch_strong_nand"
183   [(set (match_operand:SI 0 "register_operand" "=&r")                     ;; old value at mem
184         (match_operand:SI 1 "memory_operand" "+A"))                       ;; mem location
185    (set (match_dup 1)
186         (unspec_volatile:SI
187           [(not:SI (and:SI (match_dup 1)
188                            (match_operand:SI 2 "register_operand" "rI"))) ;; value for op
189            (match_operand:SI 3 "const_int_operand")]                      ;; mask
190          UNSPEC_SYNC_OLD_OP_SUBWORD))
191     (match_operand:SI 4 "register_operand" "rI")                          ;; mask
192     (match_operand:SI 5 "register_operand" "rI")                          ;; not_mask
193     (clobber (match_scratch:SI 6 "=&r"))                                  ;; tmp_1
194     (clobber (match_scratch:SI 7 "=&r"))]                                 ;; tmp_2
195   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
196   {
197     return "1:\;"
198            "lr.w%I3\t%0, %1\;"
199            "and\t%6, %0, %2\;"
200            "not\t%6, %6\;"
201            "and\t%6, %6, %4\;"
202            "and\t%7, %0, %5\;"
203            "or\t%7, %7, %6\;"
204            "sc.w%J3\t%6, %7, %1\;"
205            "bnez\t%6, 1b";
206   }
207   [(set_attr "type" "multi")
208    (set (attr "length") (const_int 32))])
210 (define_expand "atomic_fetch_<atomic_optab><mode>"
211   [(match_operand:SHORT 0 "register_operand")                    ;; old value at mem
212    (any_atomic:SHORT (match_operand:SHORT 1 "memory_operand")    ;; mem location
213                      (match_operand:SHORT 2 "reg_or_0_operand")) ;; value for op
214    (match_operand:SI 3 "const_int_operand")]                     ;; model
215   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
217   /* We have no QImode/HImode atomics, so form a mask, then use
218      subword_atomic_fetch_strong_<mode> to implement a LR/SC version of the
219      operation.  */
221   /* Logic duplicated in gcc/libgcc/config/riscv/atomic.c for use when inlining
222      is disabled.  */
224   rtx old = gen_reg_rtx (SImode);
225   rtx mem = operands[1];
226   rtx value = operands[2];
227   rtx model = operands[3];
228   rtx aligned_mem = gen_reg_rtx (SImode);
229   rtx shift = gen_reg_rtx (SImode);
230   rtx mask = gen_reg_rtx (SImode);
231   rtx not_mask = gen_reg_rtx (SImode);
233   riscv_subword_address (mem, &aligned_mem, &shift, &mask, &not_mask);
235   rtx shifted_value = gen_reg_rtx (SImode);
236   riscv_lshift_subword (<MODE>mode, value, shift, &shifted_value);
238   emit_insn (gen_subword_atomic_fetch_strong_<atomic_optab> (old, aligned_mem,
239                                                              shifted_value,
240                                                              model, mask,
241                                                              not_mask));
243   emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old,
244                                          gen_lowpart (QImode, shift)));
246   emit_move_insn (operands[0], gen_lowpart (<MODE>mode, old));
248   DONE;
251 (define_insn "atomic_exchange<mode>"
252   [(set (match_operand:GPR 0 "register_operand" "=&r")
253         (unspec_volatile:GPR
254           [(match_operand:GPR 1 "memory_operand" "+A")
255            (match_operand:SI 3 "const_int_operand")] ;; model
256           UNSPEC_SYNC_EXCHANGE))
257    (set (match_dup 1)
258         (match_operand:GPR 2 "register_operand" "0"))]
259   "TARGET_ATOMIC"
260   "amoswap.<amo>%A3\t%0,%z2,%1"
261   [(set_attr "type" "atomic")
262    (set (attr "length") (const_int 4))])
264 (define_expand "atomic_exchange<mode>"
265   [(match_operand:SHORT 0 "register_operand") ;; old value at mem
266    (match_operand:SHORT 1 "memory_operand")   ;; mem location
267    (match_operand:SHORT 2 "register_operand") ;; value
268    (match_operand:SI 3 "const_int_operand")]  ;; model
269   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
271   rtx old = gen_reg_rtx (SImode);
272   rtx mem = operands[1];
273   rtx value = operands[2];
274   rtx model = operands[3];
275   rtx aligned_mem = gen_reg_rtx (SImode);
276   rtx shift = gen_reg_rtx (SImode);
277   rtx mask = gen_reg_rtx (SImode);
278   rtx not_mask = gen_reg_rtx (SImode);
280   riscv_subword_address (mem, &aligned_mem, &shift, &mask, &not_mask);
282   rtx shifted_value = gen_reg_rtx (SImode);
283   riscv_lshift_subword (<MODE>mode, value, shift, &shifted_value);
285   emit_insn (gen_subword_atomic_exchange_strong (old, aligned_mem,
286                                                  shifted_value, model,
287                                                  not_mask));
289   emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old,
290                                          gen_lowpart (QImode, shift)));
292   emit_move_insn (operands[0], gen_lowpart (<MODE>mode, old));
293   DONE;
296 (define_insn "subword_atomic_exchange_strong"
297   [(set (match_operand:SI 0 "register_operand" "=&r")    ;; old value at mem
298         (match_operand:SI 1 "memory_operand" "+A"))      ;; mem location
299    (set (match_dup 1)
300         (unspec_volatile:SI
301           [(match_operand:SI 2 "reg_or_0_operand" "rI")  ;; value
302            (match_operand:SI 3 "const_int_operand")]     ;; model
303       UNSPEC_SYNC_EXCHANGE_SUBWORD))
304     (match_operand:SI 4 "reg_or_0_operand" "rI")         ;; not_mask
305     (clobber (match_scratch:SI 5 "=&r"))]                ;; tmp_1
306   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
307   {
308     return "1:\;"
309            "lr.w%I3\t%0, %1\;"
310            "and\t%5, %0, %4\;"
311            "or\t%5, %5, %2\;"
312            "sc.w%J3\t%5, %5, %1\;"
313            "bnez\t%5, 1b";
314   }
315   [(set_attr "type" "multi")
316    (set (attr "length") (const_int 20))])
318 (define_insn "atomic_cas_value_strong<mode>"
319   [(set (match_operand:GPR 0 "register_operand" "=&r")
320         (match_operand:GPR 1 "memory_operand" "+A"))
321    (set (match_dup 1)
322         (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
323                               (match_operand:GPR 3 "reg_or_0_operand" "rJ")
324                               (match_operand:SI 4 "const_int_operand")  ;; mod_s
325                               (match_operand:SI 5 "const_int_operand")] ;; mod_f
326          UNSPEC_COMPARE_AND_SWAP))
327    (clobber (match_scratch:GPR 6 "=&r"))]
328   "TARGET_ATOMIC"
329   {
330     enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
331     enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
332     /* Find the union of the two memory models so we can satisfy both success
333        and failure memory models.  */
334     operands[5] = GEN_INT (riscv_union_memmodels (model_success, model_failure));
335     return "1:\;"
336            "lr.<amo>%I5\t%0,%1\;"
337            "bne\t%0,%z2,1f\;"
338            "sc.<amo>%J5\t%6,%z3,%1\;"
339            "bnez\t%6,1b\;"
340            "1:";
341   }
342   [(set_attr "type" "multi")
343    (set (attr "length") (const_int 16))])
345 (define_expand "atomic_compare_and_swap<mode>"
346   [(match_operand:SI 0 "register_operand" "")   ;; bool output
347    (match_operand:GPR 1 "register_operand" "")  ;; val output
348    (match_operand:GPR 2 "memory_operand" "")    ;; memory
349    (match_operand:GPR 3 "reg_or_0_operand" "")  ;; expected value
350    (match_operand:GPR 4 "reg_or_0_operand" "")  ;; desired value
351    (match_operand:SI 5 "const_int_operand" "")  ;; is_weak
352    (match_operand:SI 6 "const_int_operand" "")  ;; mod_s
353    (match_operand:SI 7 "const_int_operand" "")] ;; mod_f
354   "TARGET_ATOMIC"
356   emit_insn (gen_atomic_cas_value_strong<mode> (operands[1], operands[2],
357                                                 operands[3], operands[4],
358                                                 operands[6], operands[7]));
360   rtx compare = operands[1];
361   if (operands[3] != const0_rtx)
362     {
363       rtx difference = gen_rtx_MINUS (<MODE>mode, operands[1], operands[3]);
364       compare = gen_reg_rtx (<MODE>mode);
365       emit_insn (gen_rtx_SET (compare, difference));
366     }
368   if (word_mode != <MODE>mode)
369     {
370       rtx reg = gen_reg_rtx (word_mode);
371       emit_insn (gen_rtx_SET (reg, gen_rtx_SIGN_EXTEND (word_mode, compare)));
372       compare = reg;
373     }
375   emit_insn (gen_rtx_SET (operands[0], gen_rtx_EQ (SImode, compare, const0_rtx)));
376   DONE;
379 (define_expand "atomic_compare_and_swap<mode>"
380   [(match_operand:SI 0 "register_operand")    ;; bool output
381    (match_operand:SHORT 1 "register_operand") ;; val output
382    (match_operand:SHORT 2 "memory_operand")   ;; memory
383    (match_operand:SHORT 3 "reg_or_0_operand") ;; expected value
384    (match_operand:SHORT 4 "reg_or_0_operand") ;; desired value
385    (match_operand:SI 5 "const_int_operand")   ;; is_weak
386    (match_operand:SI 6 "const_int_operand")   ;; mod_s
387    (match_operand:SI 7 "const_int_operand")]  ;; mod_f
388   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
390   emit_insn (gen_atomic_cas_value_strong<mode> (operands[1], operands[2],
391                                                 operands[3], operands[4],
392                                                 operands[6], operands[7]));
394   rtx val = gen_reg_rtx (SImode);
395   if (operands[1] != const0_rtx)
396     emit_move_insn (val, gen_rtx_SIGN_EXTEND (SImode, operands[1]));
397   else
398     emit_move_insn (val, const0_rtx);
400   rtx exp = gen_reg_rtx (SImode);
401   if (operands[3] != const0_rtx)
402     emit_move_insn (exp, gen_rtx_SIGN_EXTEND (SImode, operands[3]));
403   else
404     emit_move_insn (exp, const0_rtx);
406   rtx compare = val;
407   if (exp != const0_rtx)
408     {
409       rtx difference = gen_rtx_MINUS (SImode, val, exp);
410       compare = gen_reg_rtx (SImode);
411       emit_move_insn (compare, difference);
412     }
414   if (word_mode != SImode)
415     {
416       rtx reg = gen_reg_rtx (word_mode);
417       emit_move_insn (reg, gen_rtx_SIGN_EXTEND (word_mode, compare));
418       compare = reg;
419     }
421   emit_move_insn (operands[0], gen_rtx_EQ (SImode, compare, const0_rtx));
422   DONE;
425 (define_expand "atomic_cas_value_strong<mode>"
426   [(match_operand:SHORT 0 "register_operand") ;; val output
427    (match_operand:SHORT 1 "memory_operand")   ;; memory
428    (match_operand:SHORT 2 "reg_or_0_operand") ;; expected value
429    (match_operand:SHORT 3 "reg_or_0_operand") ;; desired value
430    (match_operand:SI 4 "const_int_operand")   ;; mod_s
431    (match_operand:SI 5 "const_int_operand")   ;; mod_f
432    (match_scratch:SHORT 6)]
433   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
435   /* We have no QImode/HImode atomics, so form a mask, then use
436      subword_atomic_cas_strong<mode> to implement a LR/SC version of the
437      operation.  */
439   /* Logic duplicated in gcc/libgcc/config/riscv/atomic.c for use when inlining
440      is disabled.  */
442   rtx old = gen_reg_rtx (SImode);
443   rtx mem = operands[1];
444   rtx aligned_mem = gen_reg_rtx (SImode);
445   rtx shift = gen_reg_rtx (SImode);
446   rtx mask = gen_reg_rtx (SImode);
447   rtx not_mask = gen_reg_rtx (SImode);
449   riscv_subword_address (mem, &aligned_mem, &shift, &mask, &not_mask);
451   rtx o = operands[2];
452   rtx n = operands[3];
453   rtx shifted_o = gen_reg_rtx (SImode);
454   rtx shifted_n = gen_reg_rtx (SImode);
456   riscv_lshift_subword (<MODE>mode, o, shift, &shifted_o);
457   riscv_lshift_subword (<MODE>mode, n, shift, &shifted_n);
459   emit_move_insn (shifted_o, gen_rtx_AND (SImode, shifted_o, mask));
460   emit_move_insn (shifted_n, gen_rtx_AND (SImode, shifted_n, mask));
462   enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
463   enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
464   /* Find the union of the two memory models so we can satisfy both success
465      and failure memory models.  */
466   rtx model = GEN_INT (riscv_union_memmodels (model_success, model_failure));
468   emit_insn (gen_subword_atomic_cas_strong (old, aligned_mem,
469                                             shifted_o, shifted_n,
470                                             model, mask, not_mask));
472   emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old,
473                                          gen_lowpart (QImode, shift)));
475   emit_move_insn (operands[0], gen_lowpart (<MODE>mode, old));
477   DONE;
480 (define_insn "subword_atomic_cas_strong"
481   [(set (match_operand:SI 0 "register_operand" "=&r")                      ;; old value at mem
482         (match_operand:SI 1 "memory_operand" "+A"))                        ;; mem location
483    (set (match_dup 1)
484         (unspec_volatile:SI [(match_operand:SI 2 "reg_or_0_operand" "rJ")  ;; expected value
485                              (match_operand:SI 3 "reg_or_0_operand" "rJ")] ;; desired value
486          UNSPEC_COMPARE_AND_SWAP_SUBWORD))
487         (match_operand:SI 4 "const_int_operand")                           ;; model
488         (match_operand:SI 5 "register_operand" "rI")                       ;; mask
489         (match_operand:SI 6 "register_operand" "rI")                       ;; not_mask
490         (clobber (match_scratch:SI 7 "=&r"))]                              ;; tmp_1
491   "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC"
492   {
493     return "1:\;"
494            "lr.w%I4\t%0, %1\;"
495            "and\t%7, %0, %5\;"
496            "bne\t%7, %z2, 1f\;"
497            "and\t%7, %0, %6\;"
498            "or\t%7, %7, %3\;"
499            "sc.w%J4\t%7, %7, %1\;"
500            "bnez\t%7, 1b\;"
501            "1:";
502   }
503   [(set_attr "type" "multi")
504    (set (attr "length") (const_int 28))])
506 (define_expand "atomic_test_and_set"
507   [(match_operand:QI 0 "register_operand" "")    ;; bool output
508    (match_operand:QI 1 "memory_operand" "+A")    ;; memory
509    (match_operand:SI 2 "const_int_operand" "")]  ;; model
510   "TARGET_ATOMIC"
512   /* We have no QImode atomics, so use the address LSBs to form a mask,
513      then use an aligned SImode atomic.  */
514   rtx old = gen_reg_rtx (SImode);
515   rtx mem = operands[1];
516   rtx model = operands[2];
517   rtx set = gen_reg_rtx (QImode);
518   rtx aligned_mem = gen_reg_rtx (SImode);
519   rtx shift = gen_reg_rtx (SImode);
521   /* Unused.  */
522   rtx _mask = gen_reg_rtx (SImode);
523   rtx _not_mask = gen_reg_rtx (SImode);
525   riscv_subword_address (mem, &aligned_mem, &shift, &_mask, &_not_mask);
527   emit_move_insn (set, GEN_INT (1));
528   rtx shifted_set = gen_reg_rtx (SImode);
529   riscv_lshift_subword (QImode, set, shift, &shifted_set);
531   emit_insn (gen_atomic_fetch_orsi (old, aligned_mem, shifted_set, model));
533   emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old,
534                                          gen_lowpart (QImode, shift)));
536   emit_move_insn (operands[0], gen_lowpart (QImode, old));
538   DONE;