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