xref: /openbmc/qemu/tcg/tcg-op-ldst.c (revision 3860a2a8de56fad71db42f4ad120eb7eff03b51f)
1a1429ca2SRichard Henderson /*
2a1429ca2SRichard Henderson  * Tiny Code Generator for QEMU
3a1429ca2SRichard Henderson  *
4a1429ca2SRichard Henderson  * Copyright (c) 2008 Fabrice Bellard
5a1429ca2SRichard Henderson  *
6a1429ca2SRichard Henderson  * Permission is hereby granted, free of charge, to any person obtaining a copy
7a1429ca2SRichard Henderson  * of this software and associated documentation files (the "Software"), to deal
8a1429ca2SRichard Henderson  * in the Software without restriction, including without limitation the rights
9a1429ca2SRichard Henderson  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10a1429ca2SRichard Henderson  * copies of the Software, and to permit persons to whom the Software is
11a1429ca2SRichard Henderson  * furnished to do so, subject to the following conditions:
12a1429ca2SRichard Henderson  *
13a1429ca2SRichard Henderson  * The above copyright notice and this permission notice shall be included in
14a1429ca2SRichard Henderson  * all copies or substantial portions of the Software.
15a1429ca2SRichard Henderson  *
16a1429ca2SRichard Henderson  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17a1429ca2SRichard Henderson  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18a1429ca2SRichard Henderson  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19a1429ca2SRichard Henderson  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20a1429ca2SRichard Henderson  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21a1429ca2SRichard Henderson  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22a1429ca2SRichard Henderson  * THE SOFTWARE.
23a1429ca2SRichard Henderson  */
24a1429ca2SRichard Henderson 
25a1429ca2SRichard Henderson #include "qemu/osdep.h"
26a1429ca2SRichard Henderson #include "tcg/tcg.h"
27a1429ca2SRichard Henderson #include "tcg/tcg-temp-internal.h"
28ad3d0e4dSRichard Henderson #include "tcg/tcg-op-common.h"
29a1429ca2SRichard Henderson #include "tcg/tcg-mo.h"
30bdbb9d69SRichard Henderson #include "exec/translation-block.h"
31a1429ca2SRichard Henderson #include "exec/plugin-gen.h"
32a1429ca2SRichard Henderson #include "tcg-internal.h"
33a1429ca2SRichard Henderson 
34a1429ca2SRichard Henderson 
check_max_alignment(unsigned a_bits)353a80bde3SRichard Henderson static void check_max_alignment(unsigned a_bits)
36a1429ca2SRichard Henderson {
373a80bde3SRichard Henderson     /*
383a80bde3SRichard Henderson      * The requested alignment cannot overlap the TLB flags.
393a80bde3SRichard Henderson      * FIXME: Must keep the count up-to-date with "exec/cpu-all.h".
403a80bde3SRichard Henderson      */
41397cabaaSRichard Henderson     if (tcg_use_softmmu) {
42a0eaae08SRichard Henderson         tcg_debug_assert(a_bits + 5 <= tcg_ctx->page_bits);
43397cabaaSRichard Henderson     }
443a80bde3SRichard Henderson }
453a80bde3SRichard Henderson 
tcg_canonicalize_memop(MemOp op,bool is64,bool st)463a80bde3SRichard Henderson static MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st)
473a80bde3SRichard Henderson {
48*c5809eeeSRichard Henderson     unsigned a_bits = memop_alignment_bits(op);
49a1429ca2SRichard Henderson 
503a80bde3SRichard Henderson     check_max_alignment(a_bits);
513a80bde3SRichard Henderson 
52a1429ca2SRichard Henderson     /* Prefer MO_ALIGN+MO_XX over MO_ALIGN_XX+MO_XX */
53a1429ca2SRichard Henderson     if (a_bits == (op & MO_SIZE)) {
54a1429ca2SRichard Henderson         op = (op & ~MO_AMASK) | MO_ALIGN;
55a1429ca2SRichard Henderson     }
56a1429ca2SRichard Henderson 
57a1429ca2SRichard Henderson     switch (op & MO_SIZE) {
58a1429ca2SRichard Henderson     case MO_8:
59a1429ca2SRichard Henderson         op &= ~MO_BSWAP;
60a1429ca2SRichard Henderson         break;
61a1429ca2SRichard Henderson     case MO_16:
62a1429ca2SRichard Henderson         break;
63a1429ca2SRichard Henderson     case MO_32:
64a1429ca2SRichard Henderson         if (!is64) {
65a1429ca2SRichard Henderson             op &= ~MO_SIGN;
66a1429ca2SRichard Henderson         }
67a1429ca2SRichard Henderson         break;
68a1429ca2SRichard Henderson     case MO_64:
69a1429ca2SRichard Henderson         if (is64) {
70a1429ca2SRichard Henderson             op &= ~MO_SIGN;
71a1429ca2SRichard Henderson             break;
72a1429ca2SRichard Henderson         }
73a1429ca2SRichard Henderson         /* fall through */
74a1429ca2SRichard Henderson     default:
75a1429ca2SRichard Henderson         g_assert_not_reached();
76a1429ca2SRichard Henderson     }
77a1429ca2SRichard Henderson     if (st) {
78a1429ca2SRichard Henderson         op &= ~MO_SIGN;
79a1429ca2SRichard Henderson     }
80cbb14556SRichard Henderson 
81cbb14556SRichard Henderson     /* In serial mode, reduce atomicity. */
82cbb14556SRichard Henderson     if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
83cbb14556SRichard Henderson         op &= ~MO_ATOM_MASK;
84cbb14556SRichard Henderson         op |= MO_ATOM_NONE;
85cbb14556SRichard Henderson     }
86cbb14556SRichard Henderson 
87a1429ca2SRichard Henderson     return op;
88a1429ca2SRichard Henderson }
89a1429ca2SRichard Henderson 
gen_ldst(TCGOpcode opc,TCGTemp * vl,TCGTemp * vh,TCGTemp * addr,MemOpIdx oi)90d5920b72SRichard Henderson static void gen_ldst(TCGOpcode opc, TCGTemp *vl, TCGTemp *vh,
91d5920b72SRichard Henderson                      TCGTemp *addr, MemOpIdx oi)
92a1429ca2SRichard Henderson {
93d5920b72SRichard Henderson     if (TCG_TARGET_REG_BITS == 64 || tcg_ctx->addr_type == TCG_TYPE_I32) {
94d5920b72SRichard Henderson         if (vh) {
95d5920b72SRichard Henderson             tcg_gen_op4(opc, temp_arg(vl), temp_arg(vh), temp_arg(addr), oi);
96a1429ca2SRichard Henderson         } else {
97d5920b72SRichard Henderson             tcg_gen_op3(opc, temp_arg(vl), temp_arg(addr), oi);
98a1429ca2SRichard Henderson         }
99d5920b72SRichard Henderson     } else {
100d5920b72SRichard Henderson         /* See TCGV_LOW/HIGH. */
101d5920b72SRichard Henderson         TCGTemp *al = addr + HOST_BIG_ENDIAN;
102d5920b72SRichard Henderson         TCGTemp *ah = addr + !HOST_BIG_ENDIAN;
103d5920b72SRichard Henderson 
104d5920b72SRichard Henderson         if (vh) {
105d5920b72SRichard Henderson             tcg_gen_op5(opc, temp_arg(vl), temp_arg(vh),
106d5920b72SRichard Henderson                         temp_arg(al), temp_arg(ah), oi);
107d5920b72SRichard Henderson         } else {
108d5920b72SRichard Henderson             tcg_gen_op4(opc, temp_arg(vl), temp_arg(al), temp_arg(ah), oi);
109d5920b72SRichard Henderson         }
110d5920b72SRichard Henderson     }
111a1429ca2SRichard Henderson }
112a1429ca2SRichard Henderson 
gen_ldst_i64(TCGOpcode opc,TCGv_i64 v,TCGTemp * addr,MemOpIdx oi)113d5920b72SRichard Henderson static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 v, TCGTemp *addr, MemOpIdx oi)
114a1429ca2SRichard Henderson {
115a1429ca2SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
116d5920b72SRichard Henderson         TCGTemp *vl = tcgv_i32_temp(TCGV_LOW(v));
117d5920b72SRichard Henderson         TCGTemp *vh = tcgv_i32_temp(TCGV_HIGH(v));
118d5920b72SRichard Henderson         gen_ldst(opc, vl, vh, addr, oi);
119a1429ca2SRichard Henderson     } else {
120d5920b72SRichard Henderson         gen_ldst(opc, tcgv_i64_temp(v), NULL, addr, oi);
121a1429ca2SRichard Henderson     }
122a1429ca2SRichard Henderson }
123a1429ca2SRichard Henderson 
tcg_gen_req_mo(TCGBar type)124a1429ca2SRichard Henderson static void tcg_gen_req_mo(TCGBar type)
125a1429ca2SRichard Henderson {
12628ea568aSRichard Henderson     type &= tcg_ctx->guest_mo;
127a1429ca2SRichard Henderson     type &= ~TCG_TARGET_DEFAULT_MO;
128a1429ca2SRichard Henderson     if (type) {
129a1429ca2SRichard Henderson         tcg_gen_mb(type | TCG_BAR_SC);
130a1429ca2SRichard Henderson     }
131a1429ca2SRichard Henderson }
132a1429ca2SRichard Henderson 
133eb9d02f2SRichard Henderson /* Only required for loads, where value might overlap addr. */
plugin_maybe_preserve_addr(TCGTemp * addr)134d5920b72SRichard Henderson static TCGv_i64 plugin_maybe_preserve_addr(TCGTemp *addr)
135a1429ca2SRichard Henderson {
136a1429ca2SRichard Henderson #ifdef CONFIG_PLUGIN
137a1429ca2SRichard Henderson     if (tcg_ctx->plugin_insn != NULL) {
138a1429ca2SRichard Henderson         /* Save a copy of the vaddr for use after a load.  */
139fcdab382SRichard Henderson         TCGv_i64 temp = tcg_temp_ebb_new_i64();
140d5920b72SRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
141d5920b72SRichard Henderson             tcg_gen_extu_i32_i64(temp, temp_tcgv_i32(addr));
142d5920b72SRichard Henderson         } else {
143d5920b72SRichard Henderson             tcg_gen_mov_i64(temp, temp_tcgv_i64(addr));
144d5920b72SRichard Henderson         }
145a1429ca2SRichard Henderson         return temp;
146a1429ca2SRichard Henderson     }
147a1429ca2SRichard Henderson #endif
148eb9d02f2SRichard Henderson     return NULL;
149a1429ca2SRichard Henderson }
150a1429ca2SRichard Henderson 
151b709da5dSPierrick Bouvier #ifdef CONFIG_PLUGIN
152eb9d02f2SRichard Henderson static void
plugin_gen_mem_callbacks(TCGv_i64 copy_addr,TCGTemp * orig_addr,MemOpIdx oi,enum qemu_plugin_mem_rw rw)153d5920b72SRichard Henderson plugin_gen_mem_callbacks(TCGv_i64 copy_addr, TCGTemp *orig_addr, MemOpIdx oi,
154a1429ca2SRichard Henderson                          enum qemu_plugin_mem_rw rw)
155a1429ca2SRichard Henderson {
156a1429ca2SRichard Henderson     if (tcg_ctx->plugin_insn != NULL) {
157a1429ca2SRichard Henderson         qemu_plugin_meminfo_t info = make_plugin_meminfo(oi, rw);
158fcdab382SRichard Henderson 
159d5920b72SRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
160d5920b72SRichard Henderson             if (!copy_addr) {
161d5920b72SRichard Henderson                 copy_addr = tcg_temp_ebb_new_i64();
162d5920b72SRichard Henderson                 tcg_gen_extu_i32_i64(copy_addr, temp_tcgv_i32(orig_addr));
163d5920b72SRichard Henderson             }
1648a2927f2SRichard Henderson             tcg_gen_plugin_mem_cb(copy_addr, info);
165d5920b72SRichard Henderson             tcg_temp_free_i64(copy_addr);
166d5920b72SRichard Henderson         } else {
167eb9d02f2SRichard Henderson             if (copy_addr) {
1688a2927f2SRichard Henderson                 tcg_gen_plugin_mem_cb(copy_addr, info);
169fcdab382SRichard Henderson                 tcg_temp_free_i64(copy_addr);
170fcdab382SRichard Henderson             } else {
1718a2927f2SRichard Henderson                 tcg_gen_plugin_mem_cb(temp_tcgv_i64(orig_addr), info);
172eb9d02f2SRichard Henderson             }
173fcdab382SRichard Henderson         }
174a1429ca2SRichard Henderson     }
175b709da5dSPierrick Bouvier }
176b709da5dSPierrick Bouvier #endif
177b709da5dSPierrick Bouvier 
178b709da5dSPierrick Bouvier static void
plugin_gen_mem_callbacks_i32(TCGv_i32 val,TCGv_i64 copy_addr,TCGTemp * orig_addr,MemOpIdx oi,enum qemu_plugin_mem_rw rw)179b709da5dSPierrick Bouvier plugin_gen_mem_callbacks_i32(TCGv_i32 val,
180b709da5dSPierrick Bouvier                              TCGv_i64 copy_addr, TCGTemp *orig_addr,
181b709da5dSPierrick Bouvier                              MemOpIdx oi, enum qemu_plugin_mem_rw rw)
182b709da5dSPierrick Bouvier {
183b709da5dSPierrick Bouvier #ifdef CONFIG_PLUGIN
184b709da5dSPierrick Bouvier     if (tcg_ctx->plugin_insn != NULL) {
185b709da5dSPierrick Bouvier         tcg_gen_st_i32(val, tcg_env,
186b709da5dSPierrick Bouvier                        offsetof(CPUState, neg.plugin_mem_value_low) -
187b709da5dSPierrick Bouvier                        sizeof(CPUState) + (HOST_BIG_ENDIAN * 4));
188b709da5dSPierrick Bouvier         plugin_gen_mem_callbacks(copy_addr, orig_addr, oi, rw);
189b709da5dSPierrick Bouvier     }
190b709da5dSPierrick Bouvier #endif
191b709da5dSPierrick Bouvier }
192b709da5dSPierrick Bouvier 
193b709da5dSPierrick Bouvier static void
plugin_gen_mem_callbacks_i64(TCGv_i64 val,TCGv_i64 copy_addr,TCGTemp * orig_addr,MemOpIdx oi,enum qemu_plugin_mem_rw rw)194b709da5dSPierrick Bouvier plugin_gen_mem_callbacks_i64(TCGv_i64 val,
195b709da5dSPierrick Bouvier                              TCGv_i64 copy_addr, TCGTemp *orig_addr,
196b709da5dSPierrick Bouvier                              MemOpIdx oi, enum qemu_plugin_mem_rw rw)
197b709da5dSPierrick Bouvier {
198b709da5dSPierrick Bouvier #ifdef CONFIG_PLUGIN
199b709da5dSPierrick Bouvier     if (tcg_ctx->plugin_insn != NULL) {
200b709da5dSPierrick Bouvier         tcg_gen_st_i64(val, tcg_env,
201b709da5dSPierrick Bouvier                        offsetof(CPUState, neg.plugin_mem_value_low) -
202b709da5dSPierrick Bouvier                        sizeof(CPUState));
203b709da5dSPierrick Bouvier         plugin_gen_mem_callbacks(copy_addr, orig_addr, oi, rw);
204b709da5dSPierrick Bouvier     }
205b709da5dSPierrick Bouvier #endif
206b709da5dSPierrick Bouvier }
207b709da5dSPierrick Bouvier 
208b709da5dSPierrick Bouvier static void
plugin_gen_mem_callbacks_i128(TCGv_i128 val,TCGv_i64 copy_addr,TCGTemp * orig_addr,MemOpIdx oi,enum qemu_plugin_mem_rw rw)209b709da5dSPierrick Bouvier plugin_gen_mem_callbacks_i128(TCGv_i128 val,
210b709da5dSPierrick Bouvier                              TCGv_i64 copy_addr, TCGTemp *orig_addr,
211b709da5dSPierrick Bouvier                              MemOpIdx oi, enum qemu_plugin_mem_rw rw)
212b709da5dSPierrick Bouvier {
213b709da5dSPierrick Bouvier #ifdef CONFIG_PLUGIN
214b709da5dSPierrick Bouvier     if (tcg_ctx->plugin_insn != NULL) {
215b709da5dSPierrick Bouvier         tcg_gen_st_i64(TCGV128_LOW(val), tcg_env,
216b709da5dSPierrick Bouvier                        offsetof(CPUState, neg.plugin_mem_value_low) -
217b709da5dSPierrick Bouvier                        sizeof(CPUState));
218b709da5dSPierrick Bouvier         tcg_gen_st_i64(TCGV128_HIGH(val), tcg_env,
219b709da5dSPierrick Bouvier                        offsetof(CPUState, neg.plugin_mem_value_high) -
220b709da5dSPierrick Bouvier                        sizeof(CPUState));
221b709da5dSPierrick Bouvier         plugin_gen_mem_callbacks(copy_addr, orig_addr, oi, rw);
222b709da5dSPierrick Bouvier     }
223a1429ca2SRichard Henderson #endif
224a1429ca2SRichard Henderson }
225a1429ca2SRichard Henderson 
tcg_gen_qemu_ld_i32_int(TCGv_i32 val,TCGTemp * addr,TCGArg idx,MemOp memop)226d5920b72SRichard Henderson static void tcg_gen_qemu_ld_i32_int(TCGv_i32 val, TCGTemp *addr,
227d5920b72SRichard Henderson                                     TCGArg idx, MemOp memop)
228a1429ca2SRichard Henderson {
229a1429ca2SRichard Henderson     MemOp orig_memop;
230d5920b72SRichard Henderson     MemOpIdx orig_oi, oi;
231fcdab382SRichard Henderson     TCGv_i64 copy_addr;
232fecccfccSRichard Henderson     TCGOpcode opc;
233a1429ca2SRichard Henderson 
234a1429ca2SRichard Henderson     tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
235d5920b72SRichard Henderson     orig_memop = memop = tcg_canonicalize_memop(memop, 0, 0);
236d5920b72SRichard Henderson     orig_oi = oi = make_memop_idx(memop, idx);
237a1429ca2SRichard Henderson 
238a1429ca2SRichard Henderson     if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
239a1429ca2SRichard Henderson         memop &= ~MO_BSWAP;
240a1429ca2SRichard Henderson         /* The bswap primitive benefits from zero-extended input.  */
241a1429ca2SRichard Henderson         if ((memop & MO_SSIZE) == MO_SW) {
242a1429ca2SRichard Henderson             memop &= ~MO_SIGN;
243a1429ca2SRichard Henderson         }
244d5920b72SRichard Henderson         oi = make_memop_idx(memop, idx);
245a1429ca2SRichard Henderson     }
246a1429ca2SRichard Henderson 
247eb9d02f2SRichard Henderson     copy_addr = plugin_maybe_preserve_addr(addr);
248fecccfccSRichard Henderson     if (tcg_ctx->addr_type == TCG_TYPE_I32) {
249fecccfccSRichard Henderson         opc = INDEX_op_qemu_ld_a32_i32;
250fecccfccSRichard Henderson     } else {
251fecccfccSRichard Henderson         opc = INDEX_op_qemu_ld_a64_i32;
252fecccfccSRichard Henderson     }
253fecccfccSRichard Henderson     gen_ldst(opc, tcgv_i32_temp(val), NULL, addr, oi);
254b709da5dSPierrick Bouvier     plugin_gen_mem_callbacks_i32(val, copy_addr, addr, orig_oi,
255b709da5dSPierrick Bouvier                                  QEMU_PLUGIN_MEM_R);
256a1429ca2SRichard Henderson 
257a1429ca2SRichard Henderson     if ((orig_memop ^ memop) & MO_BSWAP) {
258a1429ca2SRichard Henderson         switch (orig_memop & MO_SIZE) {
259a1429ca2SRichard Henderson         case MO_16:
260a1429ca2SRichard Henderson             tcg_gen_bswap16_i32(val, val, (orig_memop & MO_SIGN
261a1429ca2SRichard Henderson                                            ? TCG_BSWAP_IZ | TCG_BSWAP_OS
262a1429ca2SRichard Henderson                                            : TCG_BSWAP_IZ | TCG_BSWAP_OZ));
263a1429ca2SRichard Henderson             break;
264a1429ca2SRichard Henderson         case MO_32:
265a1429ca2SRichard Henderson             tcg_gen_bswap32_i32(val, val);
266a1429ca2SRichard Henderson             break;
267a1429ca2SRichard Henderson         default:
268a1429ca2SRichard Henderson             g_assert_not_reached();
269a1429ca2SRichard Henderson         }
270a1429ca2SRichard Henderson     }
271a1429ca2SRichard Henderson }
272a1429ca2SRichard Henderson 
tcg_gen_qemu_ld_i32_chk(TCGv_i32 val,TCGTemp * addr,TCGArg idx,MemOp memop,TCGType addr_type)273d5920b72SRichard Henderson void tcg_gen_qemu_ld_i32_chk(TCGv_i32 val, TCGTemp *addr, TCGArg idx,
274d5920b72SRichard Henderson                              MemOp memop, TCGType addr_type)
275d5920b72SRichard Henderson {
276d5920b72SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
277d5920b72SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_32);
278d5920b72SRichard Henderson     tcg_gen_qemu_ld_i32_int(val, addr, idx, memop);
279d5920b72SRichard Henderson }
280d5920b72SRichard Henderson 
tcg_gen_qemu_st_i32_int(TCGv_i32 val,TCGTemp * addr,TCGArg idx,MemOp memop)281d5920b72SRichard Henderson static void tcg_gen_qemu_st_i32_int(TCGv_i32 val, TCGTemp *addr,
282d5920b72SRichard Henderson                                     TCGArg idx, MemOp memop)
283a1429ca2SRichard Henderson {
284a1429ca2SRichard Henderson     TCGv_i32 swap = NULL;
285d5920b72SRichard Henderson     MemOpIdx orig_oi, oi;
286d5920b72SRichard Henderson     TCGOpcode opc;
287a1429ca2SRichard Henderson 
288a1429ca2SRichard Henderson     tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
289a1429ca2SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 1);
290d5920b72SRichard Henderson     orig_oi = oi = make_memop_idx(memop, idx);
291a1429ca2SRichard Henderson 
292a1429ca2SRichard Henderson     if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
293a1429ca2SRichard Henderson         swap = tcg_temp_ebb_new_i32();
294a1429ca2SRichard Henderson         switch (memop & MO_SIZE) {
295a1429ca2SRichard Henderson         case MO_16:
296a1429ca2SRichard Henderson             tcg_gen_bswap16_i32(swap, val, 0);
297a1429ca2SRichard Henderson             break;
298a1429ca2SRichard Henderson         case MO_32:
299a1429ca2SRichard Henderson             tcg_gen_bswap32_i32(swap, val);
300a1429ca2SRichard Henderson             break;
301a1429ca2SRichard Henderson         default:
302a1429ca2SRichard Henderson             g_assert_not_reached();
303a1429ca2SRichard Henderson         }
304a1429ca2SRichard Henderson         val = swap;
305a1429ca2SRichard Henderson         memop &= ~MO_BSWAP;
306d5920b72SRichard Henderson         oi = make_memop_idx(memop, idx);
307a1429ca2SRichard Henderson     }
308a1429ca2SRichard Henderson 
309a1429ca2SRichard Henderson     if (TCG_TARGET_HAS_qemu_st8_i32 && (memop & MO_SIZE) == MO_8) {
310fecccfccSRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
311fecccfccSRichard Henderson             opc = INDEX_op_qemu_st8_a32_i32;
312a1429ca2SRichard Henderson         } else {
313fecccfccSRichard Henderson             opc = INDEX_op_qemu_st8_a64_i32;
314fecccfccSRichard Henderson         }
315fecccfccSRichard Henderson     } else {
316fecccfccSRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
317fecccfccSRichard Henderson             opc = INDEX_op_qemu_st_a32_i32;
318fecccfccSRichard Henderson         } else {
319fecccfccSRichard Henderson             opc = INDEX_op_qemu_st_a64_i32;
320fecccfccSRichard Henderson         }
321a1429ca2SRichard Henderson     }
322d5920b72SRichard Henderson     gen_ldst(opc, tcgv_i32_temp(val), NULL, addr, oi);
323b709da5dSPierrick Bouvier     plugin_gen_mem_callbacks_i32(val, NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W);
324a1429ca2SRichard Henderson 
325a1429ca2SRichard Henderson     if (swap) {
326a1429ca2SRichard Henderson         tcg_temp_free_i32(swap);
327a1429ca2SRichard Henderson     }
328a1429ca2SRichard Henderson }
329a1429ca2SRichard Henderson 
tcg_gen_qemu_st_i32_chk(TCGv_i32 val,TCGTemp * addr,TCGArg idx,MemOp memop,TCGType addr_type)330d5920b72SRichard Henderson void tcg_gen_qemu_st_i32_chk(TCGv_i32 val, TCGTemp *addr, TCGArg idx,
331d5920b72SRichard Henderson                              MemOp memop, TCGType addr_type)
332d5920b72SRichard Henderson {
333d5920b72SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
334d5920b72SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_32);
335d5920b72SRichard Henderson     tcg_gen_qemu_st_i32_int(val, addr, idx, memop);
336d5920b72SRichard Henderson }
337d5920b72SRichard Henderson 
tcg_gen_qemu_ld_i64_int(TCGv_i64 val,TCGTemp * addr,TCGArg idx,MemOp memop)338d5920b72SRichard Henderson static void tcg_gen_qemu_ld_i64_int(TCGv_i64 val, TCGTemp *addr,
339d5920b72SRichard Henderson                                     TCGArg idx, MemOp memop)
340a1429ca2SRichard Henderson {
341a1429ca2SRichard Henderson     MemOp orig_memop;
342d5920b72SRichard Henderson     MemOpIdx orig_oi, oi;
343fcdab382SRichard Henderson     TCGv_i64 copy_addr;
344fecccfccSRichard Henderson     TCGOpcode opc;
345a1429ca2SRichard Henderson 
346a1429ca2SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
347d5920b72SRichard Henderson         tcg_gen_qemu_ld_i32_int(TCGV_LOW(val), addr, idx, memop);
348a1429ca2SRichard Henderson         if (memop & MO_SIGN) {
349a1429ca2SRichard Henderson             tcg_gen_sari_i32(TCGV_HIGH(val), TCGV_LOW(val), 31);
350a1429ca2SRichard Henderson         } else {
351a1429ca2SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(val), 0);
352a1429ca2SRichard Henderson         }
353a1429ca2SRichard Henderson         return;
354a1429ca2SRichard Henderson     }
355a1429ca2SRichard Henderson 
356a1429ca2SRichard Henderson     tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
357d5920b72SRichard Henderson     orig_memop = memop = tcg_canonicalize_memop(memop, 1, 0);
358d5920b72SRichard Henderson     orig_oi = oi = make_memop_idx(memop, idx);
359a1429ca2SRichard Henderson 
360a1429ca2SRichard Henderson     if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
361a1429ca2SRichard Henderson         memop &= ~MO_BSWAP;
362a1429ca2SRichard Henderson         /* The bswap primitive benefits from zero-extended input.  */
363a1429ca2SRichard Henderson         if ((memop & MO_SIGN) && (memop & MO_SIZE) < MO_64) {
364a1429ca2SRichard Henderson             memop &= ~MO_SIGN;
365a1429ca2SRichard Henderson         }
366d5920b72SRichard Henderson         oi = make_memop_idx(memop, idx);
367a1429ca2SRichard Henderson     }
368a1429ca2SRichard Henderson 
369eb9d02f2SRichard Henderson     copy_addr = plugin_maybe_preserve_addr(addr);
370fecccfccSRichard Henderson     if (tcg_ctx->addr_type == TCG_TYPE_I32) {
371fecccfccSRichard Henderson         opc = INDEX_op_qemu_ld_a32_i64;
372fecccfccSRichard Henderson     } else {
373fecccfccSRichard Henderson         opc = INDEX_op_qemu_ld_a64_i64;
374fecccfccSRichard Henderson     }
375fecccfccSRichard Henderson     gen_ldst_i64(opc, val, addr, oi);
376b709da5dSPierrick Bouvier     plugin_gen_mem_callbacks_i64(val, copy_addr, addr, orig_oi,
377b709da5dSPierrick Bouvier                                  QEMU_PLUGIN_MEM_R);
378a1429ca2SRichard Henderson 
379a1429ca2SRichard Henderson     if ((orig_memop ^ memop) & MO_BSWAP) {
380a1429ca2SRichard Henderson         int flags = (orig_memop & MO_SIGN
381a1429ca2SRichard Henderson                      ? TCG_BSWAP_IZ | TCG_BSWAP_OS
382a1429ca2SRichard Henderson                      : TCG_BSWAP_IZ | TCG_BSWAP_OZ);
383a1429ca2SRichard Henderson         switch (orig_memop & MO_SIZE) {
384a1429ca2SRichard Henderson         case MO_16:
385a1429ca2SRichard Henderson             tcg_gen_bswap16_i64(val, val, flags);
386a1429ca2SRichard Henderson             break;
387a1429ca2SRichard Henderson         case MO_32:
388a1429ca2SRichard Henderson             tcg_gen_bswap32_i64(val, val, flags);
389a1429ca2SRichard Henderson             break;
390a1429ca2SRichard Henderson         case MO_64:
391a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(val, val);
392a1429ca2SRichard Henderson             break;
393a1429ca2SRichard Henderson         default:
394a1429ca2SRichard Henderson             g_assert_not_reached();
395a1429ca2SRichard Henderson         }
396a1429ca2SRichard Henderson     }
397a1429ca2SRichard Henderson }
398a1429ca2SRichard Henderson 
tcg_gen_qemu_ld_i64_chk(TCGv_i64 val,TCGTemp * addr,TCGArg idx,MemOp memop,TCGType addr_type)399d5920b72SRichard Henderson void tcg_gen_qemu_ld_i64_chk(TCGv_i64 val, TCGTemp *addr, TCGArg idx,
400d5920b72SRichard Henderson                              MemOp memop, TCGType addr_type)
401d5920b72SRichard Henderson {
402d5920b72SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
403d5920b72SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_64);
404d5920b72SRichard Henderson     tcg_gen_qemu_ld_i64_int(val, addr, idx, memop);
405d5920b72SRichard Henderson }
406d5920b72SRichard Henderson 
tcg_gen_qemu_st_i64_int(TCGv_i64 val,TCGTemp * addr,TCGArg idx,MemOp memop)407d5920b72SRichard Henderson static void tcg_gen_qemu_st_i64_int(TCGv_i64 val, TCGTemp *addr,
408d5920b72SRichard Henderson                                     TCGArg idx, MemOp memop)
409a1429ca2SRichard Henderson {
410a1429ca2SRichard Henderson     TCGv_i64 swap = NULL;
411d5920b72SRichard Henderson     MemOpIdx orig_oi, oi;
412fecccfccSRichard Henderson     TCGOpcode opc;
413a1429ca2SRichard Henderson 
414a1429ca2SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
415d5920b72SRichard Henderson         tcg_gen_qemu_st_i32_int(TCGV_LOW(val), addr, idx, memop);
416a1429ca2SRichard Henderson         return;
417a1429ca2SRichard Henderson     }
418a1429ca2SRichard Henderson 
419a1429ca2SRichard Henderson     tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
420a1429ca2SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 1);
421d5920b72SRichard Henderson     orig_oi = oi = make_memop_idx(memop, idx);
422a1429ca2SRichard Henderson 
423a1429ca2SRichard Henderson     if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
424a1429ca2SRichard Henderson         swap = tcg_temp_ebb_new_i64();
425a1429ca2SRichard Henderson         switch (memop & MO_SIZE) {
426a1429ca2SRichard Henderson         case MO_16:
427a1429ca2SRichard Henderson             tcg_gen_bswap16_i64(swap, val, 0);
428a1429ca2SRichard Henderson             break;
429a1429ca2SRichard Henderson         case MO_32:
430a1429ca2SRichard Henderson             tcg_gen_bswap32_i64(swap, val, 0);
431a1429ca2SRichard Henderson             break;
432a1429ca2SRichard Henderson         case MO_64:
433a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(swap, val);
434a1429ca2SRichard Henderson             break;
435a1429ca2SRichard Henderson         default:
436a1429ca2SRichard Henderson             g_assert_not_reached();
437a1429ca2SRichard Henderson         }
438a1429ca2SRichard Henderson         val = swap;
439a1429ca2SRichard Henderson         memop &= ~MO_BSWAP;
440d5920b72SRichard Henderson         oi = make_memop_idx(memop, idx);
441a1429ca2SRichard Henderson     }
442a1429ca2SRichard Henderson 
443fecccfccSRichard Henderson     if (tcg_ctx->addr_type == TCG_TYPE_I32) {
444fecccfccSRichard Henderson         opc = INDEX_op_qemu_st_a32_i64;
445fecccfccSRichard Henderson     } else {
446fecccfccSRichard Henderson         opc = INDEX_op_qemu_st_a64_i64;
447fecccfccSRichard Henderson     }
448fecccfccSRichard Henderson     gen_ldst_i64(opc, val, addr, oi);
449b709da5dSPierrick Bouvier     plugin_gen_mem_callbacks_i64(val, NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W);
450a1429ca2SRichard Henderson 
451a1429ca2SRichard Henderson     if (swap) {
452a1429ca2SRichard Henderson         tcg_temp_free_i64(swap);
453a1429ca2SRichard Henderson     }
454a1429ca2SRichard Henderson }
455a1429ca2SRichard Henderson 
tcg_gen_qemu_st_i64_chk(TCGv_i64 val,TCGTemp * addr,TCGArg idx,MemOp memop,TCGType addr_type)456d5920b72SRichard Henderson void tcg_gen_qemu_st_i64_chk(TCGv_i64 val, TCGTemp *addr, TCGArg idx,
457d5920b72SRichard Henderson                              MemOp memop, TCGType addr_type)
458d5920b72SRichard Henderson {
459d5920b72SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
460d5920b72SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_64);
461d5920b72SRichard Henderson     tcg_gen_qemu_st_i64_int(val, addr, idx, memop);
462d5920b72SRichard Henderson }
463d5920b72SRichard Henderson 
464a1429ca2SRichard Henderson /*
465a1429ca2SRichard Henderson  * Return true if @mop, without knowledge of the pointer alignment,
466a1429ca2SRichard Henderson  * does not require 16-byte atomicity, and it would be adventagous
467a1429ca2SRichard Henderson  * to avoid a call to a helper function.
468a1429ca2SRichard Henderson  */
use_two_i64_for_i128(MemOp mop)469a1429ca2SRichard Henderson static bool use_two_i64_for_i128(MemOp mop)
470a1429ca2SRichard Henderson {
471a1429ca2SRichard Henderson     /* Two softmmu tlb lookups is larger than one function call. */
472397cabaaSRichard Henderson     if (tcg_use_softmmu) {
473a1429ca2SRichard Henderson         return false;
474397cabaaSRichard Henderson     }
475397cabaaSRichard Henderson 
476a1429ca2SRichard Henderson     /*
477a1429ca2SRichard Henderson      * For user-only, two 64-bit operations may well be smaller than a call.
478a1429ca2SRichard Henderson      * Determine if that would be legal for the requested atomicity.
479a1429ca2SRichard Henderson      */
480a1429ca2SRichard Henderson     switch (mop & MO_ATOM_MASK) {
481a1429ca2SRichard Henderson     case MO_ATOM_NONE:
482a1429ca2SRichard Henderson     case MO_ATOM_IFALIGN_PAIR:
483a1429ca2SRichard Henderson         return true;
484a1429ca2SRichard Henderson     case MO_ATOM_IFALIGN:
485a1429ca2SRichard Henderson     case MO_ATOM_SUBALIGN:
486a1429ca2SRichard Henderson     case MO_ATOM_WITHIN16:
487a1429ca2SRichard Henderson     case MO_ATOM_WITHIN16_PAIR:
488cbb14556SRichard Henderson         return false;
489a1429ca2SRichard Henderson     default:
490a1429ca2SRichard Henderson         g_assert_not_reached();
491a1429ca2SRichard Henderson     }
492a1429ca2SRichard Henderson }
493a1429ca2SRichard Henderson 
canonicalize_memop_i128_as_i64(MemOp ret[2],MemOp orig)494a1429ca2SRichard Henderson static void canonicalize_memop_i128_as_i64(MemOp ret[2], MemOp orig)
495a1429ca2SRichard Henderson {
496a1429ca2SRichard Henderson     MemOp mop_1 = orig, mop_2;
497a1429ca2SRichard Henderson 
498a1429ca2SRichard Henderson     /* Reduce the size to 64-bit. */
499a1429ca2SRichard Henderson     mop_1 = (mop_1 & ~MO_SIZE) | MO_64;
500a1429ca2SRichard Henderson 
501a1429ca2SRichard Henderson     /* Retain the alignment constraints of the original. */
502a1429ca2SRichard Henderson     switch (orig & MO_AMASK) {
503a1429ca2SRichard Henderson     case MO_UNALN:
504a1429ca2SRichard Henderson     case MO_ALIGN_2:
505a1429ca2SRichard Henderson     case MO_ALIGN_4:
506a1429ca2SRichard Henderson         mop_2 = mop_1;
507a1429ca2SRichard Henderson         break;
508a1429ca2SRichard Henderson     case MO_ALIGN_8:
509a1429ca2SRichard Henderson         /* Prefer MO_ALIGN+MO_64 to MO_ALIGN_8+MO_64. */
510a1429ca2SRichard Henderson         mop_1 = (mop_1 & ~MO_AMASK) | MO_ALIGN;
511a1429ca2SRichard Henderson         mop_2 = mop_1;
512a1429ca2SRichard Henderson         break;
513a1429ca2SRichard Henderson     case MO_ALIGN:
514a1429ca2SRichard Henderson         /* Second has 8-byte alignment; first has 16-byte alignment. */
515a1429ca2SRichard Henderson         mop_2 = mop_1;
516a1429ca2SRichard Henderson         mop_1 = (mop_1 & ~MO_AMASK) | MO_ALIGN_16;
517a1429ca2SRichard Henderson         break;
518a1429ca2SRichard Henderson     case MO_ALIGN_16:
519a1429ca2SRichard Henderson     case MO_ALIGN_32:
520a1429ca2SRichard Henderson     case MO_ALIGN_64:
521a1429ca2SRichard Henderson         /* Second has 8-byte alignment; first retains original. */
522a1429ca2SRichard Henderson         mop_2 = (mop_1 & ~MO_AMASK) | MO_ALIGN;
523a1429ca2SRichard Henderson         break;
524a1429ca2SRichard Henderson     default:
525a1429ca2SRichard Henderson         g_assert_not_reached();
526a1429ca2SRichard Henderson     }
527a1429ca2SRichard Henderson 
528a1429ca2SRichard Henderson     /* Use a memory ordering implemented by the host. */
529a1429ca2SRichard Henderson     if ((orig & MO_BSWAP) && !tcg_target_has_memory_bswap(mop_1)) {
530a1429ca2SRichard Henderson         mop_1 &= ~MO_BSWAP;
531a1429ca2SRichard Henderson         mop_2 &= ~MO_BSWAP;
532a1429ca2SRichard Henderson     }
533a1429ca2SRichard Henderson 
534a1429ca2SRichard Henderson     ret[0] = mop_1;
535a1429ca2SRichard Henderson     ret[1] = mop_2;
536a1429ca2SRichard Henderson }
537a1429ca2SRichard Henderson 
maybe_extend_addr64(TCGTemp * addr)5380700ceb3SRichard Henderson static TCGv_i64 maybe_extend_addr64(TCGTemp *addr)
539e570597aSRichard Henderson {
5400700ceb3SRichard Henderson     if (tcg_ctx->addr_type == TCG_TYPE_I32) {
541e570597aSRichard Henderson         TCGv_i64 a64 = tcg_temp_ebb_new_i64();
5420700ceb3SRichard Henderson         tcg_gen_extu_i32_i64(a64, temp_tcgv_i32(addr));
543e570597aSRichard Henderson         return a64;
5440700ceb3SRichard Henderson     }
5450700ceb3SRichard Henderson     return temp_tcgv_i64(addr);
546e570597aSRichard Henderson }
547e570597aSRichard Henderson 
maybe_free_addr64(TCGv_i64 a64)548e570597aSRichard Henderson static void maybe_free_addr64(TCGv_i64 a64)
549e570597aSRichard Henderson {
5500700ceb3SRichard Henderson     if (tcg_ctx->addr_type == TCG_TYPE_I32) {
551e570597aSRichard Henderson         tcg_temp_free_i64(a64);
5520700ceb3SRichard Henderson     }
553e570597aSRichard Henderson }
554e570597aSRichard Henderson 
tcg_gen_qemu_ld_i128_int(TCGv_i128 val,TCGTemp * addr,TCGArg idx,MemOp memop)555d5920b72SRichard Henderson static void tcg_gen_qemu_ld_i128_int(TCGv_i128 val, TCGTemp *addr,
556d5920b72SRichard Henderson                                      TCGArg idx, MemOp memop)
557a1429ca2SRichard Henderson {
558cbb14556SRichard Henderson     MemOpIdx orig_oi;
559d5920b72SRichard Henderson     TCGv_i64 ext_addr = NULL;
560fecccfccSRichard Henderson     TCGOpcode opc;
561a1429ca2SRichard Henderson 
562*c5809eeeSRichard Henderson     check_max_alignment(memop_alignment_bits(memop));
563a1429ca2SRichard Henderson     tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
564a1429ca2SRichard Henderson 
565cbb14556SRichard Henderson     /* In serial mode, reduce atomicity. */
566cbb14556SRichard Henderson     if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
567cbb14556SRichard Henderson         memop &= ~MO_ATOM_MASK;
568cbb14556SRichard Henderson         memop |= MO_ATOM_NONE;
569cbb14556SRichard Henderson     }
570cbb14556SRichard Henderson     orig_oi = make_memop_idx(memop, idx);
571cbb14556SRichard Henderson 
572a1429ca2SRichard Henderson     /* TODO: For now, force 32-bit hosts to use the helper. */
573a1429ca2SRichard Henderson     if (TCG_TARGET_HAS_qemu_ldst_i128 && TCG_TARGET_REG_BITS == 64) {
574a1429ca2SRichard Henderson         TCGv_i64 lo, hi;
575a1429ca2SRichard Henderson         bool need_bswap = false;
576d5920b72SRichard Henderson         MemOpIdx oi = orig_oi;
577a1429ca2SRichard Henderson 
578a1429ca2SRichard Henderson         if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
579a1429ca2SRichard Henderson             lo = TCGV128_HIGH(val);
580a1429ca2SRichard Henderson             hi = TCGV128_LOW(val);
581d5920b72SRichard Henderson             oi = make_memop_idx(memop & ~MO_BSWAP, idx);
582a1429ca2SRichard Henderson             need_bswap = true;
583a1429ca2SRichard Henderson         } else {
584a1429ca2SRichard Henderson             lo = TCGV128_LOW(val);
585a1429ca2SRichard Henderson             hi = TCGV128_HIGH(val);
586a1429ca2SRichard Henderson         }
587a1429ca2SRichard Henderson 
588fecccfccSRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
589fecccfccSRichard Henderson             opc = INDEX_op_qemu_ld_a32_i128;
590fecccfccSRichard Henderson         } else {
591fecccfccSRichard Henderson             opc = INDEX_op_qemu_ld_a64_i128;
592fecccfccSRichard Henderson         }
593fecccfccSRichard Henderson         gen_ldst(opc, tcgv_i64_temp(lo), tcgv_i64_temp(hi), addr, oi);
594a1429ca2SRichard Henderson 
595a1429ca2SRichard Henderson         if (need_bswap) {
596a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(lo, lo);
597a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(hi, hi);
598a1429ca2SRichard Henderson         }
599a1429ca2SRichard Henderson     } else if (use_two_i64_for_i128(memop)) {
600a1429ca2SRichard Henderson         MemOp mop[2];
601d5920b72SRichard Henderson         TCGTemp *addr_p8;
602a1429ca2SRichard Henderson         TCGv_i64 x, y;
603d5920b72SRichard Henderson         bool need_bswap;
604a1429ca2SRichard Henderson 
605a1429ca2SRichard Henderson         canonicalize_memop_i128_as_i64(mop, memop);
606d5920b72SRichard Henderson         need_bswap = (mop[0] ^ memop) & MO_BSWAP;
607a1429ca2SRichard Henderson 
608fecccfccSRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
609fecccfccSRichard Henderson             opc = INDEX_op_qemu_ld_a32_i64;
610fecccfccSRichard Henderson         } else {
611fecccfccSRichard Henderson             opc = INDEX_op_qemu_ld_a64_i64;
612fecccfccSRichard Henderson         }
613fecccfccSRichard Henderson 
614a1429ca2SRichard Henderson         /*
615a1429ca2SRichard Henderson          * Since there are no global TCGv_i128, there is no visible state
616a1429ca2SRichard Henderson          * changed if the second load faults.  Load directly into the two
617a1429ca2SRichard Henderson          * subwords.
618a1429ca2SRichard Henderson          */
619a1429ca2SRichard Henderson         if ((memop & MO_BSWAP) == MO_LE) {
620a1429ca2SRichard Henderson             x = TCGV128_LOW(val);
621a1429ca2SRichard Henderson             y = TCGV128_HIGH(val);
622a1429ca2SRichard Henderson         } else {
623a1429ca2SRichard Henderson             x = TCGV128_HIGH(val);
624a1429ca2SRichard Henderson             y = TCGV128_LOW(val);
625a1429ca2SRichard Henderson         }
626a1429ca2SRichard Henderson 
627fecccfccSRichard Henderson         gen_ldst_i64(opc, x, addr, make_memop_idx(mop[0], idx));
628a1429ca2SRichard Henderson 
629d5920b72SRichard Henderson         if (need_bswap) {
630a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(x, x);
631a1429ca2SRichard Henderson         }
632a1429ca2SRichard Henderson 
633d5920b72SRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
634d5920b72SRichard Henderson             TCGv_i32 t = tcg_temp_ebb_new_i32();
635d5920b72SRichard Henderson             tcg_gen_addi_i32(t, temp_tcgv_i32(addr), 8);
636d5920b72SRichard Henderson             addr_p8 = tcgv_i32_temp(t);
637d5920b72SRichard Henderson         } else {
638d5920b72SRichard Henderson             TCGv_i64 t = tcg_temp_ebb_new_i64();
639d5920b72SRichard Henderson             tcg_gen_addi_i64(t, temp_tcgv_i64(addr), 8);
640d5920b72SRichard Henderson             addr_p8 = tcgv_i64_temp(t);
641d5920b72SRichard Henderson         }
642a1429ca2SRichard Henderson 
643fecccfccSRichard Henderson         gen_ldst_i64(opc, y, addr_p8, make_memop_idx(mop[1], idx));
644d5920b72SRichard Henderson         tcg_temp_free_internal(addr_p8);
645d5920b72SRichard Henderson 
646d5920b72SRichard Henderson         if (need_bswap) {
647a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(y, y);
648a1429ca2SRichard Henderson         }
649a1429ca2SRichard Henderson     } else {
650d5920b72SRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
651d5920b72SRichard Henderson             ext_addr = tcg_temp_ebb_new_i64();
652d5920b72SRichard Henderson             tcg_gen_extu_i32_i64(ext_addr, temp_tcgv_i32(addr));
653d5920b72SRichard Henderson             addr = tcgv_i64_temp(ext_addr);
654d5920b72SRichard Henderson         }
655ad75a51eSRichard Henderson         gen_helper_ld_i128(val, tcg_env, temp_tcgv_i64(addr),
656d5920b72SRichard Henderson                            tcg_constant_i32(orig_oi));
657a1429ca2SRichard Henderson     }
658a1429ca2SRichard Henderson 
659b709da5dSPierrick Bouvier     plugin_gen_mem_callbacks_i128(val, ext_addr, addr, orig_oi,
660b709da5dSPierrick Bouvier                                   QEMU_PLUGIN_MEM_R);
661a1429ca2SRichard Henderson }
662a1429ca2SRichard Henderson 
tcg_gen_qemu_ld_i128_chk(TCGv_i128 val,TCGTemp * addr,TCGArg idx,MemOp memop,TCGType addr_type)663d5920b72SRichard Henderson void tcg_gen_qemu_ld_i128_chk(TCGv_i128 val, TCGTemp *addr, TCGArg idx,
664d5920b72SRichard Henderson                               MemOp memop, TCGType addr_type)
665a1429ca2SRichard Henderson {
666d5920b72SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
667a1429ca2SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) == MO_128);
668a1429ca2SRichard Henderson     tcg_debug_assert((memop & MO_SIGN) == 0);
669d5920b72SRichard Henderson     tcg_gen_qemu_ld_i128_int(val, addr, idx, memop);
670d5920b72SRichard Henderson }
671d5920b72SRichard Henderson 
tcg_gen_qemu_st_i128_int(TCGv_i128 val,TCGTemp * addr,TCGArg idx,MemOp memop)672d5920b72SRichard Henderson static void tcg_gen_qemu_st_i128_int(TCGv_i128 val, TCGTemp *addr,
673d5920b72SRichard Henderson                                      TCGArg idx, MemOp memop)
674d5920b72SRichard Henderson {
675cbb14556SRichard Henderson     MemOpIdx orig_oi;
676d5920b72SRichard Henderson     TCGv_i64 ext_addr = NULL;
677fecccfccSRichard Henderson     TCGOpcode opc;
678a1429ca2SRichard Henderson 
679*c5809eeeSRichard Henderson     check_max_alignment(memop_alignment_bits(memop));
680a1429ca2SRichard Henderson     tcg_gen_req_mo(TCG_MO_ST_LD | TCG_MO_ST_ST);
681a1429ca2SRichard Henderson 
682cbb14556SRichard Henderson     /* In serial mode, reduce atomicity. */
683cbb14556SRichard Henderson     if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
684cbb14556SRichard Henderson         memop &= ~MO_ATOM_MASK;
685cbb14556SRichard Henderson         memop |= MO_ATOM_NONE;
686cbb14556SRichard Henderson     }
687cbb14556SRichard Henderson     orig_oi = make_memop_idx(memop, idx);
688cbb14556SRichard Henderson 
689a1429ca2SRichard Henderson     /* TODO: For now, force 32-bit hosts to use the helper. */
690a1429ca2SRichard Henderson 
691a1429ca2SRichard Henderson     if (TCG_TARGET_HAS_qemu_ldst_i128 && TCG_TARGET_REG_BITS == 64) {
692a1429ca2SRichard Henderson         TCGv_i64 lo, hi;
693d5920b72SRichard Henderson         MemOpIdx oi = orig_oi;
694a1429ca2SRichard Henderson         bool need_bswap = false;
695a1429ca2SRichard Henderson 
696a1429ca2SRichard Henderson         if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
697d5920b72SRichard Henderson             lo = tcg_temp_ebb_new_i64();
698d5920b72SRichard Henderson             hi = tcg_temp_ebb_new_i64();
699a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(lo, TCGV128_HIGH(val));
700a1429ca2SRichard Henderson             tcg_gen_bswap64_i64(hi, TCGV128_LOW(val));
701d5920b72SRichard Henderson             oi = make_memop_idx(memop & ~MO_BSWAP, idx);
702a1429ca2SRichard Henderson             need_bswap = true;
703a1429ca2SRichard Henderson         } else {
704a1429ca2SRichard Henderson             lo = TCGV128_LOW(val);
705a1429ca2SRichard Henderson             hi = TCGV128_HIGH(val);
706a1429ca2SRichard Henderson         }
707a1429ca2SRichard Henderson 
708fecccfccSRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
709fecccfccSRichard Henderson             opc = INDEX_op_qemu_st_a32_i128;
710fecccfccSRichard Henderson         } else {
711fecccfccSRichard Henderson             opc = INDEX_op_qemu_st_a64_i128;
712fecccfccSRichard Henderson         }
713fecccfccSRichard Henderson         gen_ldst(opc, tcgv_i64_temp(lo), tcgv_i64_temp(hi), addr, oi);
714a1429ca2SRichard Henderson 
715a1429ca2SRichard Henderson         if (need_bswap) {
716a1429ca2SRichard Henderson             tcg_temp_free_i64(lo);
717a1429ca2SRichard Henderson             tcg_temp_free_i64(hi);
718a1429ca2SRichard Henderson         }
719a1429ca2SRichard Henderson     } else if (use_two_i64_for_i128(memop)) {
720a1429ca2SRichard Henderson         MemOp mop[2];
721d5920b72SRichard Henderson         TCGTemp *addr_p8;
722d5920b72SRichard Henderson         TCGv_i64 x, y, b = NULL;
723a1429ca2SRichard Henderson 
724a1429ca2SRichard Henderson         canonicalize_memop_i128_as_i64(mop, memop);
725a1429ca2SRichard Henderson 
726fecccfccSRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
727fecccfccSRichard Henderson             opc = INDEX_op_qemu_st_a32_i64;
728fecccfccSRichard Henderson         } else {
729fecccfccSRichard Henderson             opc = INDEX_op_qemu_st_a64_i64;
730fecccfccSRichard Henderson         }
731fecccfccSRichard Henderson 
732a1429ca2SRichard Henderson         if ((memop & MO_BSWAP) == MO_LE) {
733a1429ca2SRichard Henderson             x = TCGV128_LOW(val);
734a1429ca2SRichard Henderson             y = TCGV128_HIGH(val);
735a1429ca2SRichard Henderson         } else {
736a1429ca2SRichard Henderson             x = TCGV128_HIGH(val);
737a1429ca2SRichard Henderson             y = TCGV128_LOW(val);
738a1429ca2SRichard Henderson         }
739a1429ca2SRichard Henderson 
740a1429ca2SRichard Henderson         if ((mop[0] ^ memop) & MO_BSWAP) {
741d5920b72SRichard Henderson             b = tcg_temp_ebb_new_i64();
742d5920b72SRichard Henderson             tcg_gen_bswap64_i64(b, x);
743d5920b72SRichard Henderson             x = b;
744d5920b72SRichard Henderson         }
745fecccfccSRichard Henderson 
746fecccfccSRichard Henderson         gen_ldst_i64(opc, x, addr, make_memop_idx(mop[0], idx));
747d5920b72SRichard Henderson 
748d5920b72SRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
749d5920b72SRichard Henderson             TCGv_i32 t = tcg_temp_ebb_new_i32();
750d5920b72SRichard Henderson             tcg_gen_addi_i32(t, temp_tcgv_i32(addr), 8);
751d5920b72SRichard Henderson             addr_p8 = tcgv_i32_temp(t);
752d5920b72SRichard Henderson         } else {
753a1429ca2SRichard Henderson             TCGv_i64 t = tcg_temp_ebb_new_i64();
754d5920b72SRichard Henderson             tcg_gen_addi_i64(t, temp_tcgv_i64(addr), 8);
755d5920b72SRichard Henderson             addr_p8 = tcgv_i64_temp(t);
756a1429ca2SRichard Henderson         }
757a1429ca2SRichard Henderson 
758d5920b72SRichard Henderson         if (b) {
759d5920b72SRichard Henderson             tcg_gen_bswap64_i64(b, y);
760fecccfccSRichard Henderson             gen_ldst_i64(opc, b, addr_p8, make_memop_idx(mop[1], idx));
761d5920b72SRichard Henderson             tcg_temp_free_i64(b);
762fecccfccSRichard Henderson         } else {
763fecccfccSRichard Henderson             gen_ldst_i64(opc, y, addr_p8, make_memop_idx(mop[1], idx));
764d5920b72SRichard Henderson         }
765d5920b72SRichard Henderson         tcg_temp_free_internal(addr_p8);
766d5920b72SRichard Henderson     } else {
767d5920b72SRichard Henderson         if (tcg_ctx->addr_type == TCG_TYPE_I32) {
768d5920b72SRichard Henderson             ext_addr = tcg_temp_ebb_new_i64();
769d5920b72SRichard Henderson             tcg_gen_extu_i32_i64(ext_addr, temp_tcgv_i32(addr));
770d5920b72SRichard Henderson             addr = tcgv_i64_temp(ext_addr);
771d5920b72SRichard Henderson         }
772ad75a51eSRichard Henderson         gen_helper_st_i128(tcg_env, temp_tcgv_i64(addr), val,
773d5920b72SRichard Henderson                            tcg_constant_i32(orig_oi));
774d5920b72SRichard Henderson     }
775d5920b72SRichard Henderson 
776b709da5dSPierrick Bouvier     plugin_gen_mem_callbacks_i128(val, ext_addr, addr, orig_oi,
777b709da5dSPierrick Bouvier                                   QEMU_PLUGIN_MEM_W);
778d5920b72SRichard Henderson }
779d5920b72SRichard Henderson 
tcg_gen_qemu_st_i128_chk(TCGv_i128 val,TCGTemp * addr,TCGArg idx,MemOp memop,TCGType addr_type)780d5920b72SRichard Henderson void tcg_gen_qemu_st_i128_chk(TCGv_i128 val, TCGTemp *addr, TCGArg idx,
781d5920b72SRichard Henderson                               MemOp memop, TCGType addr_type)
782d5920b72SRichard Henderson {
783d5920b72SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
784d5920b72SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) == MO_128);
785d5920b72SRichard Henderson     tcg_debug_assert((memop & MO_SIGN) == 0);
786d5920b72SRichard Henderson     tcg_gen_qemu_st_i128_int(val, addr, idx, memop);
787a1429ca2SRichard Henderson }
788a1429ca2SRichard Henderson 
tcg_gen_ext_i32(TCGv_i32 ret,TCGv_i32 val,MemOp opc)789f1c29532SRichard Henderson void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc)
790a1429ca2SRichard Henderson {
791a1429ca2SRichard Henderson     switch (opc & MO_SSIZE) {
792a1429ca2SRichard Henderson     case MO_SB:
793a1429ca2SRichard Henderson         tcg_gen_ext8s_i32(ret, val);
794a1429ca2SRichard Henderson         break;
795a1429ca2SRichard Henderson     case MO_UB:
796a1429ca2SRichard Henderson         tcg_gen_ext8u_i32(ret, val);
797a1429ca2SRichard Henderson         break;
798a1429ca2SRichard Henderson     case MO_SW:
799a1429ca2SRichard Henderson         tcg_gen_ext16s_i32(ret, val);
800a1429ca2SRichard Henderson         break;
801a1429ca2SRichard Henderson     case MO_UW:
802a1429ca2SRichard Henderson         tcg_gen_ext16u_i32(ret, val);
803a1429ca2SRichard Henderson         break;
804f1c29532SRichard Henderson     case MO_UL:
805f1c29532SRichard Henderson     case MO_SL:
806a1429ca2SRichard Henderson         tcg_gen_mov_i32(ret, val);
807a1429ca2SRichard Henderson         break;
808f1c29532SRichard Henderson     default:
809f1c29532SRichard Henderson         g_assert_not_reached();
810a1429ca2SRichard Henderson     }
811a1429ca2SRichard Henderson }
812a1429ca2SRichard Henderson 
tcg_gen_ext_i64(TCGv_i64 ret,TCGv_i64 val,MemOp opc)813f1c29532SRichard Henderson void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc)
814a1429ca2SRichard Henderson {
815a1429ca2SRichard Henderson     switch (opc & MO_SSIZE) {
816a1429ca2SRichard Henderson     case MO_SB:
817a1429ca2SRichard Henderson         tcg_gen_ext8s_i64(ret, val);
818a1429ca2SRichard Henderson         break;
819a1429ca2SRichard Henderson     case MO_UB:
820a1429ca2SRichard Henderson         tcg_gen_ext8u_i64(ret, val);
821a1429ca2SRichard Henderson         break;
822a1429ca2SRichard Henderson     case MO_SW:
823a1429ca2SRichard Henderson         tcg_gen_ext16s_i64(ret, val);
824a1429ca2SRichard Henderson         break;
825a1429ca2SRichard Henderson     case MO_UW:
826a1429ca2SRichard Henderson         tcg_gen_ext16u_i64(ret, val);
827a1429ca2SRichard Henderson         break;
828a1429ca2SRichard Henderson     case MO_SL:
829a1429ca2SRichard Henderson         tcg_gen_ext32s_i64(ret, val);
830a1429ca2SRichard Henderson         break;
831a1429ca2SRichard Henderson     case MO_UL:
832a1429ca2SRichard Henderson         tcg_gen_ext32u_i64(ret, val);
833a1429ca2SRichard Henderson         break;
834f1c29532SRichard Henderson     case MO_UQ:
835f1c29532SRichard Henderson     case MO_SQ:
836a1429ca2SRichard Henderson         tcg_gen_mov_i64(ret, val);
837a1429ca2SRichard Henderson         break;
838f1c29532SRichard Henderson     default:
839f1c29532SRichard Henderson         g_assert_not_reached();
840a1429ca2SRichard Henderson     }
841a1429ca2SRichard Henderson }
842a1429ca2SRichard Henderson 
843ddfdd417SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv_i64,
844a1429ca2SRichard Henderson                                   TCGv_i32, TCGv_i32, TCGv_i32);
845ddfdd417SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv_i64,
846a1429ca2SRichard Henderson                                   TCGv_i64, TCGv_i64, TCGv_i32);
847ddfdd417SRichard Henderson typedef void (*gen_atomic_cx_i128)(TCGv_i128, TCGv_env, TCGv_i64,
848a1429ca2SRichard Henderson                                    TCGv_i128, TCGv_i128, TCGv_i32);
849ddfdd417SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv_i64,
850a1429ca2SRichard Henderson                                   TCGv_i32, TCGv_i32);
851ddfdd417SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv_i64,
852a1429ca2SRichard Henderson                                   TCGv_i64, TCGv_i32);
853a1429ca2SRichard Henderson 
854a1429ca2SRichard Henderson #ifdef CONFIG_ATOMIC64
855a1429ca2SRichard Henderson # define WITH_ATOMIC64(X) X,
856a1429ca2SRichard Henderson #else
857a1429ca2SRichard Henderson # define WITH_ATOMIC64(X)
858a1429ca2SRichard Henderson #endif
85976f9d6adSRichard Henderson #if HAVE_CMPXCHG128
860a1429ca2SRichard Henderson # define WITH_ATOMIC128(X) X,
861a1429ca2SRichard Henderson #else
862a1429ca2SRichard Henderson # define WITH_ATOMIC128(X)
863a1429ca2SRichard Henderson #endif
864a1429ca2SRichard Henderson 
865a1429ca2SRichard Henderson static void * const table_cmpxchg[(MO_SIZE | MO_BSWAP) + 1] = {
866a1429ca2SRichard Henderson     [MO_8] = gen_helper_atomic_cmpxchgb,
867a1429ca2SRichard Henderson     [MO_16 | MO_LE] = gen_helper_atomic_cmpxchgw_le,
868a1429ca2SRichard Henderson     [MO_16 | MO_BE] = gen_helper_atomic_cmpxchgw_be,
869a1429ca2SRichard Henderson     [MO_32 | MO_LE] = gen_helper_atomic_cmpxchgl_le,
870a1429ca2SRichard Henderson     [MO_32 | MO_BE] = gen_helper_atomic_cmpxchgl_be,
871a1429ca2SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_cmpxchgq_le)
872a1429ca2SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_cmpxchgq_be)
873a1429ca2SRichard Henderson     WITH_ATOMIC128([MO_128 | MO_LE] = gen_helper_atomic_cmpxchgo_le)
874a1429ca2SRichard Henderson     WITH_ATOMIC128([MO_128 | MO_BE] = gen_helper_atomic_cmpxchgo_be)
875a1429ca2SRichard Henderson };
876a1429ca2SRichard Henderson 
tcg_gen_nonatomic_cmpxchg_i32_int(TCGv_i32 retv,TCGTemp * addr,TCGv_i32 cmpv,TCGv_i32 newv,TCGArg idx,MemOp memop)8770700ceb3SRichard Henderson static void tcg_gen_nonatomic_cmpxchg_i32_int(TCGv_i32 retv, TCGTemp *addr,
8780700ceb3SRichard Henderson                                               TCGv_i32 cmpv, TCGv_i32 newv,
8790700ceb3SRichard Henderson                                               TCGArg idx, MemOp memop)
880a1429ca2SRichard Henderson {
881a1429ca2SRichard Henderson     TCGv_i32 t1 = tcg_temp_ebb_new_i32();
882a1429ca2SRichard Henderson     TCGv_i32 t2 = tcg_temp_ebb_new_i32();
883a1429ca2SRichard Henderson 
884a1429ca2SRichard Henderson     tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE);
885a1429ca2SRichard Henderson 
8860700ceb3SRichard Henderson     tcg_gen_qemu_ld_i32_int(t1, addr, idx, memop & ~MO_SIGN);
887a1429ca2SRichard Henderson     tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1);
8880700ceb3SRichard Henderson     tcg_gen_qemu_st_i32_int(t2, addr, idx, memop);
889a1429ca2SRichard Henderson     tcg_temp_free_i32(t2);
890a1429ca2SRichard Henderson 
891a1429ca2SRichard Henderson     if (memop & MO_SIGN) {
892a1429ca2SRichard Henderson         tcg_gen_ext_i32(retv, t1, memop);
893a1429ca2SRichard Henderson     } else {
894a1429ca2SRichard Henderson         tcg_gen_mov_i32(retv, t1);
895a1429ca2SRichard Henderson     }
896a1429ca2SRichard Henderson     tcg_temp_free_i32(t1);
897a1429ca2SRichard Henderson }
898a1429ca2SRichard Henderson 
tcg_gen_nonatomic_cmpxchg_i32_chk(TCGv_i32 retv,TCGTemp * addr,TCGv_i32 cmpv,TCGv_i32 newv,TCGArg idx,MemOp memop,TCGType addr_type)8990700ceb3SRichard Henderson void tcg_gen_nonatomic_cmpxchg_i32_chk(TCGv_i32 retv, TCGTemp *addr,
9000700ceb3SRichard Henderson                                        TCGv_i32 cmpv, TCGv_i32 newv,
9010700ceb3SRichard Henderson                                        TCGArg idx, MemOp memop,
9020700ceb3SRichard Henderson                                        TCGType addr_type)
9030700ceb3SRichard Henderson {
9040700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
9050700ceb3SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_32);
9060700ceb3SRichard Henderson     tcg_gen_nonatomic_cmpxchg_i32_int(retv, addr, cmpv, newv, idx, memop);
9070700ceb3SRichard Henderson }
9080700ceb3SRichard Henderson 
tcg_gen_atomic_cmpxchg_i32_int(TCGv_i32 retv,TCGTemp * addr,TCGv_i32 cmpv,TCGv_i32 newv,TCGArg idx,MemOp memop)9090700ceb3SRichard Henderson static void tcg_gen_atomic_cmpxchg_i32_int(TCGv_i32 retv, TCGTemp *addr,
9100700ceb3SRichard Henderson                                            TCGv_i32 cmpv, TCGv_i32 newv,
9110700ceb3SRichard Henderson                                            TCGArg idx, MemOp memop)
912a1429ca2SRichard Henderson {
913a1429ca2SRichard Henderson     gen_atomic_cx_i32 gen;
914ddfdd417SRichard Henderson     TCGv_i64 a64;
915a1429ca2SRichard Henderson     MemOpIdx oi;
916a1429ca2SRichard Henderson 
917a1429ca2SRichard Henderson     if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
9180700ceb3SRichard Henderson         tcg_gen_nonatomic_cmpxchg_i32_int(retv, addr, cmpv, newv, idx, memop);
919a1429ca2SRichard Henderson         return;
920a1429ca2SRichard Henderson     }
921a1429ca2SRichard Henderson 
922a1429ca2SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
923a1429ca2SRichard Henderson     gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)];
924a1429ca2SRichard Henderson     tcg_debug_assert(gen != NULL);
925a1429ca2SRichard Henderson 
926a1429ca2SRichard Henderson     oi = make_memop_idx(memop & ~MO_SIGN, idx);
927ddfdd417SRichard Henderson     a64 = maybe_extend_addr64(addr);
928ad75a51eSRichard Henderson     gen(retv, tcg_env, a64, cmpv, newv, tcg_constant_i32(oi));
929ddfdd417SRichard Henderson     maybe_free_addr64(a64);
930a1429ca2SRichard Henderson 
931a1429ca2SRichard Henderson     if (memop & MO_SIGN) {
932a1429ca2SRichard Henderson         tcg_gen_ext_i32(retv, retv, memop);
933a1429ca2SRichard Henderson     }
934a1429ca2SRichard Henderson }
935a1429ca2SRichard Henderson 
tcg_gen_atomic_cmpxchg_i32_chk(TCGv_i32 retv,TCGTemp * addr,TCGv_i32 cmpv,TCGv_i32 newv,TCGArg idx,MemOp memop,TCGType addr_type)9360700ceb3SRichard Henderson void tcg_gen_atomic_cmpxchg_i32_chk(TCGv_i32 retv, TCGTemp *addr,
9370700ceb3SRichard Henderson                                     TCGv_i32 cmpv, TCGv_i32 newv,
9380700ceb3SRichard Henderson                                     TCGArg idx, MemOp memop,
9390700ceb3SRichard Henderson                                     TCGType addr_type)
9400700ceb3SRichard Henderson {
9410700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
9420700ceb3SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_32);
9430700ceb3SRichard Henderson     tcg_gen_atomic_cmpxchg_i32_int(retv, addr, cmpv, newv, idx, memop);
9440700ceb3SRichard Henderson }
9450700ceb3SRichard Henderson 
tcg_gen_nonatomic_cmpxchg_i64_int(TCGv_i64 retv,TCGTemp * addr,TCGv_i64 cmpv,TCGv_i64 newv,TCGArg idx,MemOp memop)9460700ceb3SRichard Henderson static void tcg_gen_nonatomic_cmpxchg_i64_int(TCGv_i64 retv, TCGTemp *addr,
9470700ceb3SRichard Henderson                                               TCGv_i64 cmpv, TCGv_i64 newv,
9480700ceb3SRichard Henderson                                               TCGArg idx, MemOp memop)
949a1429ca2SRichard Henderson {
950a1429ca2SRichard Henderson     TCGv_i64 t1, t2;
951a1429ca2SRichard Henderson 
952a1429ca2SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
9530700ceb3SRichard Henderson         tcg_gen_nonatomic_cmpxchg_i32_int(TCGV_LOW(retv), addr, TCGV_LOW(cmpv),
954a1429ca2SRichard Henderson                                           TCGV_LOW(newv), idx, memop);
955a1429ca2SRichard Henderson         if (memop & MO_SIGN) {
956a1429ca2SRichard Henderson             tcg_gen_sari_i32(TCGV_HIGH(retv), TCGV_LOW(retv), 31);
957a1429ca2SRichard Henderson         } else {
958a1429ca2SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(retv), 0);
959a1429ca2SRichard Henderson         }
960a1429ca2SRichard Henderson         return;
961a1429ca2SRichard Henderson     }
962a1429ca2SRichard Henderson 
963a1429ca2SRichard Henderson     t1 = tcg_temp_ebb_new_i64();
964a1429ca2SRichard Henderson     t2 = tcg_temp_ebb_new_i64();
965a1429ca2SRichard Henderson 
966a1429ca2SRichard Henderson     tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE);
967a1429ca2SRichard Henderson 
9680700ceb3SRichard Henderson     tcg_gen_qemu_ld_i64_int(t1, addr, idx, memop & ~MO_SIGN);
969a1429ca2SRichard Henderson     tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1);
9700700ceb3SRichard Henderson     tcg_gen_qemu_st_i64_int(t2, addr, idx, memop);
971a1429ca2SRichard Henderson     tcg_temp_free_i64(t2);
972a1429ca2SRichard Henderson 
973a1429ca2SRichard Henderson     if (memop & MO_SIGN) {
974a1429ca2SRichard Henderson         tcg_gen_ext_i64(retv, t1, memop);
975a1429ca2SRichard Henderson     } else {
976a1429ca2SRichard Henderson         tcg_gen_mov_i64(retv, t1);
977a1429ca2SRichard Henderson     }
978a1429ca2SRichard Henderson     tcg_temp_free_i64(t1);
979a1429ca2SRichard Henderson }
980a1429ca2SRichard Henderson 
tcg_gen_nonatomic_cmpxchg_i64_chk(TCGv_i64 retv,TCGTemp * addr,TCGv_i64 cmpv,TCGv_i64 newv,TCGArg idx,MemOp memop,TCGType addr_type)9810700ceb3SRichard Henderson void tcg_gen_nonatomic_cmpxchg_i64_chk(TCGv_i64 retv, TCGTemp *addr,
9820700ceb3SRichard Henderson                                        TCGv_i64 cmpv, TCGv_i64 newv,
9830700ceb3SRichard Henderson                                        TCGArg idx, MemOp memop,
9840700ceb3SRichard Henderson                                        TCGType addr_type)
9850700ceb3SRichard Henderson {
9860700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
9870700ceb3SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_64);
9880700ceb3SRichard Henderson     tcg_gen_nonatomic_cmpxchg_i64_int(retv, addr, cmpv, newv, idx, memop);
9890700ceb3SRichard Henderson }
9900700ceb3SRichard Henderson 
tcg_gen_atomic_cmpxchg_i64_int(TCGv_i64 retv,TCGTemp * addr,TCGv_i64 cmpv,TCGv_i64 newv,TCGArg idx,MemOp memop)9910700ceb3SRichard Henderson static void tcg_gen_atomic_cmpxchg_i64_int(TCGv_i64 retv, TCGTemp *addr,
9920700ceb3SRichard Henderson                                            TCGv_i64 cmpv, TCGv_i64 newv,
9930700ceb3SRichard Henderson                                            TCGArg idx, MemOp memop)
994a1429ca2SRichard Henderson {
995a1429ca2SRichard Henderson     if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
9960700ceb3SRichard Henderson         tcg_gen_nonatomic_cmpxchg_i64_int(retv, addr, cmpv, newv, idx, memop);
997a1429ca2SRichard Henderson         return;
998a1429ca2SRichard Henderson     }
999a1429ca2SRichard Henderson 
1000a1429ca2SRichard Henderson     if ((memop & MO_SIZE) == MO_64) {
1001a1429ca2SRichard Henderson         gen_atomic_cx_i64 gen;
1002a1429ca2SRichard Henderson 
1003a1429ca2SRichard Henderson         memop = tcg_canonicalize_memop(memop, 1, 0);
1004a1429ca2SRichard Henderson         gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)];
1005a1429ca2SRichard Henderson         if (gen) {
1006a1429ca2SRichard Henderson             MemOpIdx oi = make_memop_idx(memop, idx);
1007ddfdd417SRichard Henderson             TCGv_i64 a64 = maybe_extend_addr64(addr);
1008ad75a51eSRichard Henderson             gen(retv, tcg_env, a64, cmpv, newv, tcg_constant_i32(oi));
1009ddfdd417SRichard Henderson             maybe_free_addr64(a64);
1010a1429ca2SRichard Henderson             return;
1011a1429ca2SRichard Henderson         }
1012a1429ca2SRichard Henderson 
1013ad75a51eSRichard Henderson         gen_helper_exit_atomic(tcg_env);
1014a1429ca2SRichard Henderson 
1015a1429ca2SRichard Henderson         /*
1016a1429ca2SRichard Henderson          * Produce a result for a well-formed opcode stream.  This satisfies
1017a1429ca2SRichard Henderson          * liveness for set before used, which happens before this dead code
1018a1429ca2SRichard Henderson          * is removed.
1019a1429ca2SRichard Henderson          */
1020a1429ca2SRichard Henderson         tcg_gen_movi_i64(retv, 0);
1021a1429ca2SRichard Henderson         return;
1022a1429ca2SRichard Henderson     }
1023a1429ca2SRichard Henderson 
1024a1429ca2SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
10250700ceb3SRichard Henderson         tcg_gen_atomic_cmpxchg_i32_int(TCGV_LOW(retv), addr, TCGV_LOW(cmpv),
1026a1429ca2SRichard Henderson                                        TCGV_LOW(newv), idx, memop);
1027a1429ca2SRichard Henderson         if (memop & MO_SIGN) {
1028a1429ca2SRichard Henderson             tcg_gen_sari_i32(TCGV_HIGH(retv), TCGV_LOW(retv), 31);
1029a1429ca2SRichard Henderson         } else {
1030a1429ca2SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(retv), 0);
1031a1429ca2SRichard Henderson         }
1032a1429ca2SRichard Henderson     } else {
1033a1429ca2SRichard Henderson         TCGv_i32 c32 = tcg_temp_ebb_new_i32();
1034a1429ca2SRichard Henderson         TCGv_i32 n32 = tcg_temp_ebb_new_i32();
1035a1429ca2SRichard Henderson         TCGv_i32 r32 = tcg_temp_ebb_new_i32();
1036a1429ca2SRichard Henderson 
1037a1429ca2SRichard Henderson         tcg_gen_extrl_i64_i32(c32, cmpv);
1038a1429ca2SRichard Henderson         tcg_gen_extrl_i64_i32(n32, newv);
10390700ceb3SRichard Henderson         tcg_gen_atomic_cmpxchg_i32_int(r32, addr, c32, n32,
10400700ceb3SRichard Henderson                                        idx, memop & ~MO_SIGN);
1041a1429ca2SRichard Henderson         tcg_temp_free_i32(c32);
1042a1429ca2SRichard Henderson         tcg_temp_free_i32(n32);
1043a1429ca2SRichard Henderson 
1044a1429ca2SRichard Henderson         tcg_gen_extu_i32_i64(retv, r32);
1045a1429ca2SRichard Henderson         tcg_temp_free_i32(r32);
1046a1429ca2SRichard Henderson 
1047a1429ca2SRichard Henderson         if (memop & MO_SIGN) {
1048a1429ca2SRichard Henderson             tcg_gen_ext_i64(retv, retv, memop);
1049a1429ca2SRichard Henderson         }
1050a1429ca2SRichard Henderson     }
1051a1429ca2SRichard Henderson }
1052a1429ca2SRichard Henderson 
tcg_gen_atomic_cmpxchg_i64_chk(TCGv_i64 retv,TCGTemp * addr,TCGv_i64 cmpv,TCGv_i64 newv,TCGArg idx,MemOp memop,TCGType addr_type)10530700ceb3SRichard Henderson void tcg_gen_atomic_cmpxchg_i64_chk(TCGv_i64 retv, TCGTemp *addr,
10540700ceb3SRichard Henderson                                     TCGv_i64 cmpv, TCGv_i64 newv,
10550700ceb3SRichard Henderson                                     TCGArg idx, MemOp memop, TCGType addr_type)
10560700ceb3SRichard Henderson {
10570700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
10580700ceb3SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_64);
10590700ceb3SRichard Henderson     tcg_gen_atomic_cmpxchg_i64_int(retv, addr, cmpv, newv, idx, memop);
10600700ceb3SRichard Henderson }
10610700ceb3SRichard Henderson 
tcg_gen_nonatomic_cmpxchg_i128_int(TCGv_i128 retv,TCGTemp * addr,TCGv_i128 cmpv,TCGv_i128 newv,TCGArg idx,MemOp memop)10620700ceb3SRichard Henderson static void tcg_gen_nonatomic_cmpxchg_i128_int(TCGv_i128 retv, TCGTemp *addr,
10630700ceb3SRichard Henderson                                                TCGv_i128 cmpv, TCGv_i128 newv,
10640700ceb3SRichard Henderson                                                TCGArg idx, MemOp memop)
1065a1429ca2SRichard Henderson {
1066a1429ca2SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1067a1429ca2SRichard Henderson         /* Inline expansion below is simply too large for 32-bit hosts. */
1068a1429ca2SRichard Henderson         MemOpIdx oi = make_memop_idx(memop, idx);
10690700ceb3SRichard Henderson         TCGv_i64 a64 = maybe_extend_addr64(addr);
1070a1429ca2SRichard Henderson 
1071ad75a51eSRichard Henderson         gen_helper_nonatomic_cmpxchgo(retv, tcg_env, a64, cmpv, newv,
1072fbea7a40SRichard Henderson                                       tcg_constant_i32(oi));
1073ddfdd417SRichard Henderson         maybe_free_addr64(a64);
1074a1429ca2SRichard Henderson     } else {
1075a1429ca2SRichard Henderson         TCGv_i128 oldv = tcg_temp_ebb_new_i128();
1076a1429ca2SRichard Henderson         TCGv_i128 tmpv = tcg_temp_ebb_new_i128();
1077a1429ca2SRichard Henderson         TCGv_i64 t0 = tcg_temp_ebb_new_i64();
1078a1429ca2SRichard Henderson         TCGv_i64 t1 = tcg_temp_ebb_new_i64();
1079a1429ca2SRichard Henderson         TCGv_i64 z = tcg_constant_i64(0);
1080a1429ca2SRichard Henderson 
10810700ceb3SRichard Henderson         tcg_gen_qemu_ld_i128_int(oldv, addr, idx, memop);
1082a1429ca2SRichard Henderson 
1083a1429ca2SRichard Henderson         /* Compare i128 */
1084a1429ca2SRichard Henderson         tcg_gen_xor_i64(t0, TCGV128_LOW(oldv), TCGV128_LOW(cmpv));
1085a1429ca2SRichard Henderson         tcg_gen_xor_i64(t1, TCGV128_HIGH(oldv), TCGV128_HIGH(cmpv));
1086a1429ca2SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1087a1429ca2SRichard Henderson 
1088a1429ca2SRichard Henderson         /* tmpv = equal ? newv : oldv */
1089a1429ca2SRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, TCGV128_LOW(tmpv), t0, z,
1090a1429ca2SRichard Henderson                             TCGV128_LOW(newv), TCGV128_LOW(oldv));
1091a1429ca2SRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, TCGV128_HIGH(tmpv), t0, z,
1092a1429ca2SRichard Henderson                             TCGV128_HIGH(newv), TCGV128_HIGH(oldv));
1093a1429ca2SRichard Henderson 
1094a1429ca2SRichard Henderson         /* Unconditional writeback. */
10950700ceb3SRichard Henderson         tcg_gen_qemu_st_i128_int(tmpv, addr, idx, memop);
1096a1429ca2SRichard Henderson         tcg_gen_mov_i128(retv, oldv);
1097a1429ca2SRichard Henderson 
1098a1429ca2SRichard Henderson         tcg_temp_free_i64(t0);
1099a1429ca2SRichard Henderson         tcg_temp_free_i64(t1);
1100a1429ca2SRichard Henderson         tcg_temp_free_i128(tmpv);
1101a1429ca2SRichard Henderson         tcg_temp_free_i128(oldv);
1102a1429ca2SRichard Henderson     }
1103a1429ca2SRichard Henderson }
1104a1429ca2SRichard Henderson 
tcg_gen_nonatomic_cmpxchg_i128_chk(TCGv_i128 retv,TCGTemp * addr,TCGv_i128 cmpv,TCGv_i128 newv,TCGArg idx,MemOp memop,TCGType addr_type)11050700ceb3SRichard Henderson void tcg_gen_nonatomic_cmpxchg_i128_chk(TCGv_i128 retv, TCGTemp *addr,
11060700ceb3SRichard Henderson                                         TCGv_i128 cmpv, TCGv_i128 newv,
11070700ceb3SRichard Henderson                                         TCGArg idx, MemOp memop,
11080700ceb3SRichard Henderson                                         TCGType addr_type)
11090700ceb3SRichard Henderson {
11100700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
11110700ceb3SRichard Henderson     tcg_debug_assert((memop & (MO_SIZE | MO_SIGN)) == MO_128);
11120700ceb3SRichard Henderson     tcg_gen_nonatomic_cmpxchg_i128_int(retv, addr, cmpv, newv, idx, memop);
11130700ceb3SRichard Henderson }
11140700ceb3SRichard Henderson 
tcg_gen_atomic_cmpxchg_i128_int(TCGv_i128 retv,TCGTemp * addr,TCGv_i128 cmpv,TCGv_i128 newv,TCGArg idx,MemOp memop)11150700ceb3SRichard Henderson static void tcg_gen_atomic_cmpxchg_i128_int(TCGv_i128 retv, TCGTemp *addr,
11160700ceb3SRichard Henderson                                             TCGv_i128 cmpv, TCGv_i128 newv,
11170700ceb3SRichard Henderson                                             TCGArg idx, MemOp memop)
1118a1429ca2SRichard Henderson {
1119a1429ca2SRichard Henderson     gen_atomic_cx_i128 gen;
1120a1429ca2SRichard Henderson 
1121a1429ca2SRichard Henderson     if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
11220700ceb3SRichard Henderson         tcg_gen_nonatomic_cmpxchg_i128_int(retv, addr, cmpv, newv, idx, memop);
1123a1429ca2SRichard Henderson         return;
1124a1429ca2SRichard Henderson     }
1125a1429ca2SRichard Henderson 
1126a1429ca2SRichard Henderson     gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)];
1127a1429ca2SRichard Henderson     if (gen) {
1128a1429ca2SRichard Henderson         MemOpIdx oi = make_memop_idx(memop, idx);
1129ddfdd417SRichard Henderson         TCGv_i64 a64 = maybe_extend_addr64(addr);
1130ad75a51eSRichard Henderson         gen(retv, tcg_env, a64, cmpv, newv, tcg_constant_i32(oi));
1131ddfdd417SRichard Henderson         maybe_free_addr64(a64);
1132a1429ca2SRichard Henderson         return;
1133a1429ca2SRichard Henderson     }
1134a1429ca2SRichard Henderson 
1135ad75a51eSRichard Henderson     gen_helper_exit_atomic(tcg_env);
1136a1429ca2SRichard Henderson 
1137a1429ca2SRichard Henderson     /*
1138a1429ca2SRichard Henderson      * Produce a result for a well-formed opcode stream.  This satisfies
1139a1429ca2SRichard Henderson      * liveness for set before used, which happens before this dead code
1140a1429ca2SRichard Henderson      * is removed.
1141a1429ca2SRichard Henderson      */
1142a1429ca2SRichard Henderson     tcg_gen_movi_i64(TCGV128_LOW(retv), 0);
1143a1429ca2SRichard Henderson     tcg_gen_movi_i64(TCGV128_HIGH(retv), 0);
1144a1429ca2SRichard Henderson }
1145a1429ca2SRichard Henderson 
tcg_gen_atomic_cmpxchg_i128_chk(TCGv_i128 retv,TCGTemp * addr,TCGv_i128 cmpv,TCGv_i128 newv,TCGArg idx,MemOp memop,TCGType addr_type)11460700ceb3SRichard Henderson void tcg_gen_atomic_cmpxchg_i128_chk(TCGv_i128 retv, TCGTemp *addr,
11470700ceb3SRichard Henderson                                      TCGv_i128 cmpv, TCGv_i128 newv,
11480700ceb3SRichard Henderson                                      TCGArg idx, MemOp memop,
11490700ceb3SRichard Henderson                                      TCGType addr_type)
11500700ceb3SRichard Henderson {
11510700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);
11520700ceb3SRichard Henderson     tcg_debug_assert((memop & (MO_SIZE | MO_SIGN)) == MO_128);
11530700ceb3SRichard Henderson     tcg_gen_atomic_cmpxchg_i128_int(retv, addr, cmpv, newv, idx, memop);
11540700ceb3SRichard Henderson }
11550700ceb3SRichard Henderson 
do_nonatomic_op_i32(TCGv_i32 ret,TCGTemp * addr,TCGv_i32 val,TCGArg idx,MemOp memop,bool new_val,void (* gen)(TCGv_i32,TCGv_i32,TCGv_i32))11560700ceb3SRichard Henderson static void do_nonatomic_op_i32(TCGv_i32 ret, TCGTemp *addr, TCGv_i32 val,
1157a1429ca2SRichard Henderson                                 TCGArg idx, MemOp memop, bool new_val,
1158a1429ca2SRichard Henderson                                 void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
1159a1429ca2SRichard Henderson {
1160a1429ca2SRichard Henderson     TCGv_i32 t1 = tcg_temp_ebb_new_i32();
1161a1429ca2SRichard Henderson     TCGv_i32 t2 = tcg_temp_ebb_new_i32();
1162a1429ca2SRichard Henderson 
1163a1429ca2SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
1164a1429ca2SRichard Henderson 
11650700ceb3SRichard Henderson     tcg_gen_qemu_ld_i32_int(t1, addr, idx, memop);
1166a1429ca2SRichard Henderson     tcg_gen_ext_i32(t2, val, memop);
1167a1429ca2SRichard Henderson     gen(t2, t1, t2);
11680700ceb3SRichard Henderson     tcg_gen_qemu_st_i32_int(t2, addr, idx, memop);
1169a1429ca2SRichard Henderson 
1170a1429ca2SRichard Henderson     tcg_gen_ext_i32(ret, (new_val ? t2 : t1), memop);
1171a1429ca2SRichard Henderson     tcg_temp_free_i32(t1);
1172a1429ca2SRichard Henderson     tcg_temp_free_i32(t2);
1173a1429ca2SRichard Henderson }
1174a1429ca2SRichard Henderson 
do_atomic_op_i32(TCGv_i32 ret,TCGTemp * addr,TCGv_i32 val,TCGArg idx,MemOp memop,void * const table[])11750700ceb3SRichard Henderson static void do_atomic_op_i32(TCGv_i32 ret, TCGTemp *addr, TCGv_i32 val,
1176a1429ca2SRichard Henderson                              TCGArg idx, MemOp memop, void * const table[])
1177a1429ca2SRichard Henderson {
1178a1429ca2SRichard Henderson     gen_atomic_op_i32 gen;
1179ddfdd417SRichard Henderson     TCGv_i64 a64;
1180a1429ca2SRichard Henderson     MemOpIdx oi;
1181a1429ca2SRichard Henderson 
1182a1429ca2SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
1183a1429ca2SRichard Henderson 
1184a1429ca2SRichard Henderson     gen = table[memop & (MO_SIZE | MO_BSWAP)];
1185a1429ca2SRichard Henderson     tcg_debug_assert(gen != NULL);
1186a1429ca2SRichard Henderson 
1187a1429ca2SRichard Henderson     oi = make_memop_idx(memop & ~MO_SIGN, idx);
1188ddfdd417SRichard Henderson     a64 = maybe_extend_addr64(addr);
1189ad75a51eSRichard Henderson     gen(ret, tcg_env, a64, val, tcg_constant_i32(oi));
1190ddfdd417SRichard Henderson     maybe_free_addr64(a64);
1191a1429ca2SRichard Henderson 
1192a1429ca2SRichard Henderson     if (memop & MO_SIGN) {
1193a1429ca2SRichard Henderson         tcg_gen_ext_i32(ret, ret, memop);
1194a1429ca2SRichard Henderson     }
1195a1429ca2SRichard Henderson }
1196a1429ca2SRichard Henderson 
do_nonatomic_op_i64(TCGv_i64 ret,TCGTemp * addr,TCGv_i64 val,TCGArg idx,MemOp memop,bool new_val,void (* gen)(TCGv_i64,TCGv_i64,TCGv_i64))11970700ceb3SRichard Henderson static void do_nonatomic_op_i64(TCGv_i64 ret, TCGTemp *addr, TCGv_i64 val,
1198a1429ca2SRichard Henderson                                 TCGArg idx, MemOp memop, bool new_val,
1199a1429ca2SRichard Henderson                                 void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
1200a1429ca2SRichard Henderson {
1201a1429ca2SRichard Henderson     TCGv_i64 t1 = tcg_temp_ebb_new_i64();
1202a1429ca2SRichard Henderson     TCGv_i64 t2 = tcg_temp_ebb_new_i64();
1203a1429ca2SRichard Henderson 
1204a1429ca2SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
1205a1429ca2SRichard Henderson 
12060700ceb3SRichard Henderson     tcg_gen_qemu_ld_i64_int(t1, addr, idx, memop);
1207a1429ca2SRichard Henderson     tcg_gen_ext_i64(t2, val, memop);
1208a1429ca2SRichard Henderson     gen(t2, t1, t2);
12090700ceb3SRichard Henderson     tcg_gen_qemu_st_i64_int(t2, addr, idx, memop);
1210a1429ca2SRichard Henderson 
1211a1429ca2SRichard Henderson     tcg_gen_ext_i64(ret, (new_val ? t2 : t1), memop);
1212a1429ca2SRichard Henderson     tcg_temp_free_i64(t1);
1213a1429ca2SRichard Henderson     tcg_temp_free_i64(t2);
1214a1429ca2SRichard Henderson }
1215a1429ca2SRichard Henderson 
do_atomic_op_i64(TCGv_i64 ret,TCGTemp * addr,TCGv_i64 val,TCGArg idx,MemOp memop,void * const table[])12160700ceb3SRichard Henderson static void do_atomic_op_i64(TCGv_i64 ret, TCGTemp *addr, TCGv_i64 val,
1217a1429ca2SRichard Henderson                              TCGArg idx, MemOp memop, void * const table[])
1218a1429ca2SRichard Henderson {
1219a1429ca2SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
1220a1429ca2SRichard Henderson 
1221a1429ca2SRichard Henderson     if ((memop & MO_SIZE) == MO_64) {
12220700ceb3SRichard Henderson         gen_atomic_op_i64 gen = table[memop & (MO_SIZE | MO_BSWAP)];
1223a1429ca2SRichard Henderson 
12240700ceb3SRichard Henderson         if (gen) {
12250700ceb3SRichard Henderson             MemOpIdx oi = make_memop_idx(memop & ~MO_SIGN, idx);
12260700ceb3SRichard Henderson             TCGv_i64 a64 = maybe_extend_addr64(addr);
1227ad75a51eSRichard Henderson             gen(ret, tcg_env, a64, val, tcg_constant_i32(oi));
1228ddfdd417SRichard Henderson             maybe_free_addr64(a64);
12290700ceb3SRichard Henderson             return;
12300700ceb3SRichard Henderson         }
12310700ceb3SRichard Henderson 
1232ad75a51eSRichard Henderson         gen_helper_exit_atomic(tcg_env);
1233a1429ca2SRichard Henderson         /* Produce a result, so that we have a well-formed opcode stream
1234a1429ca2SRichard Henderson            with respect to uses of the result in the (dead) code following.  */
1235a1429ca2SRichard Henderson         tcg_gen_movi_i64(ret, 0);
1236a1429ca2SRichard Henderson     } else {
1237a1429ca2SRichard Henderson         TCGv_i32 v32 = tcg_temp_ebb_new_i32();
1238a1429ca2SRichard Henderson         TCGv_i32 r32 = tcg_temp_ebb_new_i32();
1239a1429ca2SRichard Henderson 
1240a1429ca2SRichard Henderson         tcg_gen_extrl_i64_i32(v32, val);
1241a1429ca2SRichard Henderson         do_atomic_op_i32(r32, addr, v32, idx, memop & ~MO_SIGN, table);
1242a1429ca2SRichard Henderson         tcg_temp_free_i32(v32);
1243a1429ca2SRichard Henderson 
1244a1429ca2SRichard Henderson         tcg_gen_extu_i32_i64(ret, r32);
1245a1429ca2SRichard Henderson         tcg_temp_free_i32(r32);
1246a1429ca2SRichard Henderson 
1247a1429ca2SRichard Henderson         if (memop & MO_SIGN) {
1248a1429ca2SRichard Henderson             tcg_gen_ext_i64(ret, ret, memop);
1249a1429ca2SRichard Henderson         }
1250a1429ca2SRichard Henderson     }
1251a1429ca2SRichard Henderson }
1252a1429ca2SRichard Henderson 
1253a1429ca2SRichard Henderson #define GEN_ATOMIC_HELPER(NAME, OP, NEW)                                \
1254a1429ca2SRichard Henderson static void * const table_##NAME[(MO_SIZE | MO_BSWAP) + 1] = {          \
1255a1429ca2SRichard Henderson     [MO_8] = gen_helper_atomic_##NAME##b,                               \
1256a1429ca2SRichard Henderson     [MO_16 | MO_LE] = gen_helper_atomic_##NAME##w_le,                   \
1257a1429ca2SRichard Henderson     [MO_16 | MO_BE] = gen_helper_atomic_##NAME##w_be,                   \
1258a1429ca2SRichard Henderson     [MO_32 | MO_LE] = gen_helper_atomic_##NAME##l_le,                   \
1259a1429ca2SRichard Henderson     [MO_32 | MO_BE] = gen_helper_atomic_##NAME##l_be,                   \
1260a1429ca2SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_##NAME##q_le)     \
1261a1429ca2SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be)     \
1262a1429ca2SRichard Henderson };                                                                      \
12630700ceb3SRichard Henderson void tcg_gen_atomic_##NAME##_i32_chk(TCGv_i32 ret, TCGTemp *addr,       \
12640700ceb3SRichard Henderson                                      TCGv_i32 val, TCGArg idx,          \
12650700ceb3SRichard Henderson                                      MemOp memop, TCGType addr_type)    \
1266a1429ca2SRichard Henderson {                                                                       \
12670700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);                  \
12680700ceb3SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_32);                       \
1269a1429ca2SRichard Henderson     if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) {                        \
1270a1429ca2SRichard Henderson         do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME);     \
1271a1429ca2SRichard Henderson     } else {                                                            \
1272a1429ca2SRichard Henderson         do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW,            \
1273a1429ca2SRichard Henderson                             tcg_gen_##OP##_i32);                        \
1274a1429ca2SRichard Henderson     }                                                                   \
1275a1429ca2SRichard Henderson }                                                                       \
12760700ceb3SRichard Henderson void tcg_gen_atomic_##NAME##_i64_chk(TCGv_i64 ret, TCGTemp *addr,       \
12770700ceb3SRichard Henderson                                      TCGv_i64 val, TCGArg idx,          \
12780700ceb3SRichard Henderson                                      MemOp memop, TCGType addr_type)    \
1279a1429ca2SRichard Henderson {                                                                       \
12800700ceb3SRichard Henderson     tcg_debug_assert(addr_type == tcg_ctx->addr_type);                  \
12810700ceb3SRichard Henderson     tcg_debug_assert((memop & MO_SIZE) <= MO_64);                       \
1282a1429ca2SRichard Henderson     if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) {                        \
1283a1429ca2SRichard Henderson         do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME);     \
1284a1429ca2SRichard Henderson     } else {                                                            \
1285a1429ca2SRichard Henderson         do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW,            \
1286a1429ca2SRichard Henderson                             tcg_gen_##OP##_i64);                        \
1287a1429ca2SRichard Henderson     }                                                                   \
1288a1429ca2SRichard Henderson }
1289a1429ca2SRichard Henderson 
1290a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_add, add, 0)
1291a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_and, and, 0)
1292a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_or, or, 0)
1293a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor, xor, 0)
1294a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_smin, smin, 0)
1295a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_umin, umin, 0)
1296a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_smax, smax, 0)
1297a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(fetch_umax, umax, 0)
1298a1429ca2SRichard Henderson 
1299a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(add_fetch, add, 1)
1300a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(and_fetch, and, 1)
1301a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(or_fetch, or, 1)
1302a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch, xor, 1)
1303a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(smin_fetch, smin, 1)
1304a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(umin_fetch, umin, 1)
1305a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(smax_fetch, smax, 1)
1306a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(umax_fetch, umax, 1)
1307a1429ca2SRichard Henderson 
tcg_gen_mov2_i32(TCGv_i32 r,TCGv_i32 a,TCGv_i32 b)1308a1429ca2SRichard Henderson static void tcg_gen_mov2_i32(TCGv_i32 r, TCGv_i32 a, TCGv_i32 b)
1309a1429ca2SRichard Henderson {
1310a1429ca2SRichard Henderson     tcg_gen_mov_i32(r, b);
1311a1429ca2SRichard Henderson }
1312a1429ca2SRichard Henderson 
tcg_gen_mov2_i64(TCGv_i64 r,TCGv_i64 a,TCGv_i64 b)1313a1429ca2SRichard Henderson static void tcg_gen_mov2_i64(TCGv_i64 r, TCGv_i64 a, TCGv_i64 b)
1314a1429ca2SRichard Henderson {
1315a1429ca2SRichard Henderson     tcg_gen_mov_i64(r, b);
1316a1429ca2SRichard Henderson }
1317a1429ca2SRichard Henderson 
1318a1429ca2SRichard Henderson GEN_ATOMIC_HELPER(xchg, mov2, 0)
1319a1429ca2SRichard Henderson 
1320a1429ca2SRichard Henderson #undef GEN_ATOMIC_HELPER
1321