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