blob: 152335cfe144c7f7767e2b924c9941198311f2f5 [file] [log] [blame]
blueswir18289b272008-02-27 17:53:27 +00001/*
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
Richard Henderson3cf246f2013-10-03 14:04:46 -050025#include "tcg-be-null.h"
26
blueswir1d4a9eb12008-10-05 09:59:14 +000027#ifndef NDEBUG
blueswir18289b272008-02-27 17:53:27 +000028static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
29 "%g0",
30 "%g1",
31 "%g2",
32 "%g3",
33 "%g4",
34 "%g5",
35 "%g6",
36 "%g7",
37 "%o0",
38 "%o1",
39 "%o2",
40 "%o3",
41 "%o4",
42 "%o5",
43 "%o6",
44 "%o7",
45 "%l0",
46 "%l1",
47 "%l2",
48 "%l3",
49 "%l4",
50 "%l5",
51 "%l6",
52 "%l7",
53 "%i0",
54 "%i1",
55 "%i2",
56 "%i3",
57 "%i4",
58 "%i5",
59 "%i6",
60 "%i7",
61};
blueswir1d4a9eb12008-10-05 09:59:14 +000062#endif
blueswir18289b272008-02-27 17:53:27 +000063
Richard Henderson375816f2012-03-25 22:04:59 +020064/* Define some temporary registers. T2 is used for constant generation. */
65#define TCG_REG_T1 TCG_REG_G1
66#define TCG_REG_T2 TCG_REG_O7
67
Richard Hendersonc6f7e4f2012-03-24 22:11:25 +010068#ifdef CONFIG_USE_GUEST_BASE
Richard Henderson375816f2012-03-25 22:04:59 +020069# define TCG_GUEST_BASE_REG TCG_REG_I5
Richard Hendersonc6f7e4f2012-03-24 22:11:25 +010070#else
71# define TCG_GUEST_BASE_REG TCG_REG_G0
72#endif
Blue Swirle141ab52011-09-18 14:55:46 +000073
blueswir10954d0d2008-03-11 21:01:02 +000074static const int tcg_target_reg_alloc_order[] = {
blueswir18289b272008-02-27 17:53:27 +000075 TCG_REG_L0,
76 TCG_REG_L1,
77 TCG_REG_L2,
78 TCG_REG_L3,
79 TCG_REG_L4,
80 TCG_REG_L5,
81 TCG_REG_L6,
82 TCG_REG_L7,
Richard Henderson26adfb72012-03-25 22:43:17 +020083
blueswir18289b272008-02-27 17:53:27 +000084 TCG_REG_I0,
85 TCG_REG_I1,
86 TCG_REG_I2,
87 TCG_REG_I3,
88 TCG_REG_I4,
Richard Henderson375816f2012-03-25 22:04:59 +020089 TCG_REG_I5,
Richard Henderson26adfb72012-03-25 22:43:17 +020090
91 TCG_REG_G2,
92 TCG_REG_G3,
93 TCG_REG_G4,
94 TCG_REG_G5,
95
96 TCG_REG_O0,
97 TCG_REG_O1,
98 TCG_REG_O2,
99 TCG_REG_O3,
100 TCG_REG_O4,
101 TCG_REG_O5,
blueswir18289b272008-02-27 17:53:27 +0000102};
103
104static const int tcg_target_call_iarg_regs[6] = {
105 TCG_REG_O0,
106 TCG_REG_O1,
107 TCG_REG_O2,
108 TCG_REG_O3,
109 TCG_REG_O4,
110 TCG_REG_O5,
111};
112
Stefan Weil26a74ae2011-09-05 11:07:01 +0200113static const int tcg_target_call_oarg_regs[] = {
blueswir18289b272008-02-27 17:53:27 +0000114 TCG_REG_O0,
Blue Swirle141ab52011-09-18 14:55:46 +0000115 TCG_REG_O1,
116 TCG_REG_O2,
117 TCG_REG_O3,
blueswir18289b272008-02-27 17:53:27 +0000118};
119
blueswir18289b272008-02-27 17:53:27 +0000120#define INSN_OP(x) ((x) << 30)
121#define INSN_OP2(x) ((x) << 22)
122#define INSN_OP3(x) ((x) << 19)
123#define INSN_OPF(x) ((x) << 5)
124#define INSN_RD(x) ((x) << 25)
125#define INSN_RS1(x) ((x) << 14)
126#define INSN_RS2(x) (x)
blueswir18384dd62008-05-25 11:19:24 +0000127#define INSN_ASI(x) ((x) << 5)
blueswir18289b272008-02-27 17:53:27 +0000128
Richard Henderson203342d2012-10-10 09:02:47 -0700129#define INSN_IMM10(x) ((1 << 13) | ((x) & 0x3ff))
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800130#define INSN_IMM11(x) ((1 << 13) | ((x) & 0x7ff))
blueswir18289b272008-02-27 17:53:27 +0000131#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff))
Richard Hendersonab1339b2012-10-10 09:02:46 -0700132#define INSN_OFF16(x) ((((x) >> 2) & 0x3fff) | ((((x) >> 16) & 3) << 20))
blueswir11da92db2009-04-04 19:10:26 +0000133#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff)
Richard Hendersona115f3e2012-10-10 09:02:44 -0700134#define INSN_COND(x) ((x) << 25)
blueswir18289b272008-02-27 17:53:27 +0000135
blueswir1cf7c2ca2008-05-15 19:44:09 +0000136#define COND_N 0x0
137#define COND_E 0x1
138#define COND_LE 0x2
139#define COND_L 0x3
140#define COND_LEU 0x4
141#define COND_CS 0x5
142#define COND_NEG 0x6
143#define COND_VS 0x7
blueswir1b3db8752008-03-08 13:33:42 +0000144#define COND_A 0x8
blueswir1cf7c2ca2008-05-15 19:44:09 +0000145#define COND_NE 0x9
146#define COND_G 0xa
147#define COND_GE 0xb
148#define COND_GU 0xc
149#define COND_CC 0xd
150#define COND_POS 0xe
151#define COND_VC 0xf
Richard Hendersona115f3e2012-10-10 09:02:44 -0700152#define BA (INSN_OP(0) | INSN_COND(COND_A) | INSN_OP2(0x2))
blueswir18289b272008-02-27 17:53:27 +0000153
Richard Hendersonab1339b2012-10-10 09:02:46 -0700154#define RCOND_Z 1
155#define RCOND_LEZ 2
156#define RCOND_LZ 3
157#define RCOND_NZ 5
158#define RCOND_GZ 6
159#define RCOND_GEZ 7
160
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800161#define MOVCC_ICC (1 << 18)
162#define MOVCC_XCC (1 << 18 | 1 << 12)
163
Richard Hendersona115f3e2012-10-10 09:02:44 -0700164#define BPCC_ICC 0
165#define BPCC_XCC (2 << 20)
166#define BPCC_PT (1 << 19)
167#define BPCC_PN 0
168#define BPCC_A (1 << 29)
169
Richard Hendersonab1339b2012-10-10 09:02:46 -0700170#define BPR_PT BPCC_PT
171
blueswir18289b272008-02-27 17:53:27 +0000172#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00))
Richard Henderson7a3766f2010-01-12 19:59:31 +0000173#define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10))
blueswir18289b272008-02-27 17:53:27 +0000174#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01))
Richard Hendersondc699602010-02-16 14:21:19 -0800175#define ARITH_ANDN (INSN_OP(2) | INSN_OP3(0x05))
blueswir18289b272008-02-27 17:53:27 +0000176#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02))
blueswir19a7f3222008-05-17 09:41:14 +0000177#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12))
Richard Hendersonbe6551b2010-02-16 14:02:04 -0800178#define ARITH_ORN (INSN_OP(2) | INSN_OP3(0x06))
blueswir18289b272008-02-27 17:53:27 +0000179#define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03))
blueswir1f5ef6aa2008-05-16 20:15:58 +0000180#define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04))
181#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14))
Richard Hendersona221ae32012-03-23 23:57:12 +0100182#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x08))
blueswir18289b272008-02-27 17:53:27 +0000183#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c))
184#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a))
185#define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e))
186#define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f))
187#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09))
188#define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d))
189#define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d))
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800190#define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c))
Richard Henderson203342d2012-10-10 09:02:47 -0700191#define ARITH_MOVR (INSN_OP(2) | INSN_OP3(0x2f))
blueswir18289b272008-02-27 17:53:27 +0000192
193#define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25))
194#define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26))
195#define SHIFT_SRA (INSN_OP(2) | INSN_OP3(0x27))
196
197#define SHIFT_SLLX (INSN_OP(2) | INSN_OP3(0x25) | (1 << 12))
198#define SHIFT_SRLX (INSN_OP(2) | INSN_OP3(0x26) | (1 << 12))
199#define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12))
200
Richard Henderson7a3766f2010-01-12 19:59:31 +0000201#define RDY (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0))
Richard Henderson583d1212010-01-12 19:59:33 +0000202#define WRY (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0))
blueswir18289b272008-02-27 17:53:27 +0000203#define JMPL (INSN_OP(2) | INSN_OP3(0x38))
204#define SAVE (INSN_OP(2) | INSN_OP3(0x3c))
205#define RESTORE (INSN_OP(2) | INSN_OP3(0x3d))
206#define SETHI (INSN_OP(0) | INSN_OP2(0x4))
207#define CALL INSN_OP(1)
208#define LDUB (INSN_OP(3) | INSN_OP3(0x01))
209#define LDSB (INSN_OP(3) | INSN_OP3(0x09))
210#define LDUH (INSN_OP(3) | INSN_OP3(0x02))
211#define LDSH (INSN_OP(3) | INSN_OP3(0x0a))
212#define LDUW (INSN_OP(3) | INSN_OP3(0x00))
213#define LDSW (INSN_OP(3) | INSN_OP3(0x08))
214#define LDX (INSN_OP(3) | INSN_OP3(0x0b))
215#define STB (INSN_OP(3) | INSN_OP3(0x05))
216#define STH (INSN_OP(3) | INSN_OP3(0x06))
217#define STW (INSN_OP(3) | INSN_OP3(0x04))
218#define STX (INSN_OP(3) | INSN_OP3(0x0e))
blueswir18384dd62008-05-25 11:19:24 +0000219#define LDUBA (INSN_OP(3) | INSN_OP3(0x11))
220#define LDSBA (INSN_OP(3) | INSN_OP3(0x19))
221#define LDUHA (INSN_OP(3) | INSN_OP3(0x12))
222#define LDSHA (INSN_OP(3) | INSN_OP3(0x1a))
223#define LDUWA (INSN_OP(3) | INSN_OP3(0x10))
224#define LDSWA (INSN_OP(3) | INSN_OP3(0x18))
225#define LDXA (INSN_OP(3) | INSN_OP3(0x1b))
226#define STBA (INSN_OP(3) | INSN_OP3(0x15))
227#define STHA (INSN_OP(3) | INSN_OP3(0x16))
228#define STWA (INSN_OP(3) | INSN_OP3(0x14))
229#define STXA (INSN_OP(3) | INSN_OP3(0x1e))
230
231#ifndef ASI_PRIMARY_LITTLE
232#define ASI_PRIMARY_LITTLE 0x88
233#endif
blueswir18289b272008-02-27 17:53:27 +0000234
Richard Hendersona0ce3412012-03-23 23:27:39 +0100235#define LDUH_LE (LDUHA | INSN_ASI(ASI_PRIMARY_LITTLE))
236#define LDSH_LE (LDSHA | INSN_ASI(ASI_PRIMARY_LITTLE))
237#define LDUW_LE (LDUWA | INSN_ASI(ASI_PRIMARY_LITTLE))
238#define LDSW_LE (LDSWA | INSN_ASI(ASI_PRIMARY_LITTLE))
239#define LDX_LE (LDXA | INSN_ASI(ASI_PRIMARY_LITTLE))
240
241#define STH_LE (STHA | INSN_ASI(ASI_PRIMARY_LITTLE))
242#define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE))
243#define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE))
244
Richard Hendersona115f3e2012-10-10 09:02:44 -0700245static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
246{
247 return (val << ((sizeof(tcg_target_long) * 8 - bits))
248 >> (sizeof(tcg_target_long) * 8 - bits)) == val;
249}
250
251static inline int check_fit_i32(uint32_t val, unsigned int bits)
252{
253 return ((val << (32 - bits)) >> (32 - bits)) == val;
254}
255
256static void patch_reloc(uint8_t *code_ptr, int type,
Richard Henderson2ba7fae22013-08-20 15:30:10 -0700257 intptr_t value, intptr_t addend)
Richard Hendersona115f3e2012-10-10 09:02:44 -0700258{
259 uint32_t insn;
260 value += addend;
261 switch (type) {
262 case R_SPARC_32:
263 if (value != (uint32_t)value) {
264 tcg_abort();
265 }
266 *(uint32_t *)code_ptr = value;
267 break;
Richard Hendersonab1339b2012-10-10 09:02:46 -0700268 case R_SPARC_WDISP16:
Richard Henderson2ba7fae22013-08-20 15:30:10 -0700269 value -= (intptr_t)code_ptr;
Richard Hendersonab1339b2012-10-10 09:02:46 -0700270 if (!check_fit_tl(value >> 2, 16)) {
271 tcg_abort();
272 }
273 insn = *(uint32_t *)code_ptr;
274 insn &= ~INSN_OFF16(-1);
275 insn |= INSN_OFF16(value);
276 *(uint32_t *)code_ptr = insn;
277 break;
Richard Hendersona115f3e2012-10-10 09:02:44 -0700278 case R_SPARC_WDISP19:
Richard Henderson2ba7fae22013-08-20 15:30:10 -0700279 value -= (intptr_t)code_ptr;
Richard Hendersona115f3e2012-10-10 09:02:44 -0700280 if (!check_fit_tl(value >> 2, 19)) {
281 tcg_abort();
282 }
283 insn = *(uint32_t *)code_ptr;
284 insn &= ~INSN_OFF19(-1);
285 insn |= INSN_OFF19(value);
286 *(uint32_t *)code_ptr = insn;
287 break;
288 default:
289 tcg_abort();
290 }
291}
292
293/* parse target specific constraints */
294static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
295{
296 const char *ct_str;
297
298 ct_str = *pct_str;
299 switch (ct_str[0]) {
300 case 'r':
301 ct->ct |= TCG_CT_REG;
302 tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
303 break;
304 case 'L': /* qemu_ld/st constraint */
305 ct->ct |= TCG_CT_REG;
306 tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
307 // Helper args
308 tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0);
309 tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1);
310 tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2);
311 break;
312 case 'I':
313 ct->ct |= TCG_CT_CONST_S11;
314 break;
315 case 'J':
316 ct->ct |= TCG_CT_CONST_S13;
317 break;
318 case 'Z':
319 ct->ct |= TCG_CT_CONST_ZERO;
320 break;
321 default:
322 return -1;
323 }
324 ct_str++;
325 *pct_str = ct_str;
326 return 0;
327}
328
329/* test if a constant matches the constraint */
330static inline int tcg_target_const_match(tcg_target_long val,
331 const TCGArgConstraint *arg_ct)
332{
333 int ct = arg_ct->ct;
334
335 if (ct & TCG_CT_CONST) {
336 return 1;
337 } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
338 return 1;
339 } else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) {
340 return 1;
341 } else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13)) {
342 return 1;
343 } else {
344 return 0;
345 }
346}
347
blueswir126cc9152008-05-24 18:06:35 +0000348static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2,
349 int op)
350{
351 tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
352 INSN_RS2(rs2));
353}
354
blueswir16f41b772008-08-17 20:14:16 +0000355static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1,
356 uint32_t offset, int op)
blueswir126cc9152008-05-24 18:06:35 +0000357{
358 tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
359 INSN_IMM13(offset));
360}
361
Richard Hendersonba225192010-01-12 19:59:29 +0000362static void tcg_out_arithc(TCGContext *s, int rd, int rs1,
363 int val2, int val2const, int op)
364{
365 tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1)
366 | (val2const ? INSN_IMM13(val2) : INSN_RS2(val2)));
367}
368
Richard Henderson2a534af2011-11-09 08:03:34 +0000369static inline void tcg_out_mov(TCGContext *s, TCGType type,
370 TCGReg ret, TCGReg arg)
blueswir18289b272008-02-27 17:53:27 +0000371{
Richard Hendersondda73c72012-10-10 09:02:38 -0700372 if (ret != arg) {
373 tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR);
374 }
blueswir126cc9152008-05-24 18:06:35 +0000375}
376
377static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg)
378{
379 tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10));
blueswir18289b272008-02-27 17:53:27 +0000380}
381
blueswir1b1012342008-05-24 18:09:50 +0000382static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg)
383{
384 tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR);
385}
386
Richard Hendersona9c7d272013-09-09 21:07:09 -0700387static void tcg_out_movi(TCGContext *s, TCGType type,
388 TCGReg ret, tcg_target_long arg)
blueswir1b1012342008-05-24 18:09:50 +0000389{
Richard Hendersona9c7d272013-09-09 21:07:09 -0700390 tcg_target_long hi, lo;
blueswir1b1012342008-05-24 18:09:50 +0000391
Richard Hendersona9c7d272013-09-09 21:07:09 -0700392 /* A 13-bit constant sign-extended to 64-bits. */
393 if (check_fit_tl(arg, 13)) {
394 tcg_out_movi_imm13(s, ret, arg);
395 return;
396 }
397
398 /* A 32-bit constant, or 32-bit zero-extended to 64-bits. */
Richard Henderson43172202009-12-19 19:45:27 -0800399 if (TCG_TARGET_REG_BITS == 32
400 || type == TCG_TYPE_I32
Richard Hendersona9c7d272013-09-09 21:07:09 -0700401 || (arg & ~0xffffffffu) == 0) {
402 tcg_out_sethi(s, ret, arg);
403 if (arg & 0x3ff) {
404 tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR);
405 }
406 return;
407 }
408
409 /* A 32-bit constant sign-extended to 64-bits. */
410 if (check_fit_tl(arg, 32)) {
Richard Henderson43172202009-12-19 19:45:27 -0800411 tcg_out_sethi(s, ret, ~arg);
412 tcg_out_arithi(s, ret, ret, (arg & 0x3ff) | -0x400, ARITH_XOR);
Richard Hendersona9c7d272013-09-09 21:07:09 -0700413 return;
414 }
415
416 /* A 64-bit constant decomposed into 2 32-bit pieces. */
417 lo = (int32_t)arg;
418 if (check_fit_tl(lo, 13)) {
419 hi = (arg - lo) >> 31 >> 1;
420 tcg_out_movi(s, TCG_TYPE_I32, ret, hi);
Richard Henderson375816f2012-03-25 22:04:59 +0200421 tcg_out_arithi(s, ret, ret, 32, SHIFT_SLLX);
Richard Hendersona9c7d272013-09-09 21:07:09 -0700422 tcg_out_arithi(s, ret, ret, lo, ARITH_ADD);
423 } else {
424 hi = arg >> 31 >> 1;
425 tcg_out_movi(s, TCG_TYPE_I32, ret, hi);
426 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T2, lo);
427 tcg_out_arithi(s, ret, ret, 32, SHIFT_SLLX);
Richard Henderson375816f2012-03-25 22:04:59 +0200428 tcg_out_arith(s, ret, ret, TCG_REG_T2, ARITH_OR);
blueswir16f41b772008-08-17 20:14:16 +0000429 }
blueswir18289b272008-02-27 17:53:27 +0000430}
431
Richard Hendersona0ce3412012-03-23 23:27:39 +0100432static inline void tcg_out_ldst_rr(TCGContext *s, int data, int a1,
433 int a2, int op)
blueswir18289b272008-02-27 17:53:27 +0000434{
Richard Hendersona0ce3412012-03-23 23:27:39 +0100435 tcg_out32(s, op | INSN_RD(data) | INSN_RS1(a1) | INSN_RS2(a2));
blueswir18289b272008-02-27 17:53:27 +0000436}
437
Richard Hendersona0ce3412012-03-23 23:27:39 +0100438static inline void tcg_out_ldst(TCGContext *s, int ret, int addr,
439 int offset, int op)
blueswir1b3db8752008-03-08 13:33:42 +0000440{
Richard Hendersona0ce3412012-03-23 23:27:39 +0100441 if (check_fit_tl(offset, 13)) {
blueswir18289b272008-02-27 17:53:27 +0000442 tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) |
443 INSN_IMM13(offset));
Richard Hendersona0ce3412012-03-23 23:27:39 +0100444 } else {
Richard Henderson375816f2012-03-25 22:04:59 +0200445 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, offset);
446 tcg_out_ldst_rr(s, ret, addr, TCG_REG_T1, op);
blueswir1cf7c2ca2008-05-15 19:44:09 +0000447 }
blueswir18289b272008-02-27 17:53:27 +0000448}
449
Richard Henderson2a534af2011-11-09 08:03:34 +0000450static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
Richard Hendersona05b5b92013-08-20 17:07:26 -0700451 TCGReg arg1, intptr_t arg2)
blueswir18289b272008-02-27 17:53:27 +0000452{
Richard Hendersona0ce3412012-03-23 23:27:39 +0100453 tcg_out_ldst(s, ret, arg1, arg2, (type == TCG_TYPE_I32 ? LDUW : LDX));
blueswir18289b272008-02-27 17:53:27 +0000454}
455
Richard Henderson2a534af2011-11-09 08:03:34 +0000456static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
Richard Hendersona05b5b92013-08-20 17:07:26 -0700457 TCGReg arg1, intptr_t arg2)
blueswir18289b272008-02-27 17:53:27 +0000458{
Richard Hendersona0ce3412012-03-23 23:27:39 +0100459 tcg_out_ldst(s, arg, arg1, arg2, (type == TCG_TYPE_I32 ? STW : STX));
460}
461
Richard Hendersonc8fc56c2013-08-20 18:31:45 -0700462static inline void tcg_out_ld_ptr(TCGContext *s, TCGReg ret, uintptr_t arg)
Richard Hendersona0ce3412012-03-23 23:27:39 +0100463{
Richard Hendersonc8fc56c2013-08-20 18:31:45 -0700464 TCGReg base = TCG_REG_G0;
Richard Hendersona0ce3412012-03-23 23:27:39 +0100465 if (!check_fit_tl(arg, 10)) {
466 tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ff);
Richard Hendersonc8fc56c2013-08-20 18:31:45 -0700467 base = ret;
Richard Hendersona0ce3412012-03-23 23:27:39 +0100468 }
Richard Hendersonc8fc56c2013-08-20 18:31:45 -0700469 tcg_out_ld(s, TCG_TYPE_PTR, ret, base, arg & 0x3ff);
blueswir18289b272008-02-27 17:53:27 +0000470}
471
Richard Henderson583d1212010-01-12 19:59:33 +0000472static inline void tcg_out_sety(TCGContext *s, int rs)
blueswir18289b272008-02-27 17:53:27 +0000473{
Richard Henderson583d1212010-01-12 19:59:33 +0000474 tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs));
blueswir18289b272008-02-27 17:53:27 +0000475}
476
Richard Henderson7a3766f2010-01-12 19:59:31 +0000477static inline void tcg_out_rdy(TCGContext *s, int rd)
478{
479 tcg_out32(s, RDY | INSN_RD(rd));
480}
481
blueswir18289b272008-02-27 17:53:27 +0000482static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
483{
484 if (val != 0) {
blueswir157e49b42008-05-18 08:11:14 +0000485 if (check_fit_tl(val, 13))
blueswir18289b272008-02-27 17:53:27 +0000486 tcg_out_arithi(s, reg, reg, val, ARITH_ADD);
blueswir1f5ef6aa2008-05-16 20:15:58 +0000487 else {
Richard Henderson375816f2012-03-25 22:04:59 +0200488 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, val);
489 tcg_out_arith(s, reg, reg, TCG_REG_T1, ARITH_ADD);
blueswir1f5ef6aa2008-05-16 20:15:58 +0000490 }
blueswir18289b272008-02-27 17:53:27 +0000491 }
492}
493
Richard Henderson583d1212010-01-12 19:59:33 +0000494static void tcg_out_div32(TCGContext *s, int rd, int rs1,
495 int val2, int val2const, int uns)
496{
497 /* Load Y with the sign/zero extension of RS1 to 64-bits. */
498 if (uns) {
499 tcg_out_sety(s, TCG_REG_G0);
500 } else {
Richard Henderson375816f2012-03-25 22:04:59 +0200501 tcg_out_arithi(s, TCG_REG_T1, rs1, 31, SHIFT_SRA);
502 tcg_out_sety(s, TCG_REG_T1);
Richard Henderson583d1212010-01-12 19:59:33 +0000503 }
504
505 tcg_out_arithc(s, rd, rs1, val2, val2const,
506 uns ? ARITH_UDIV : ARITH_SDIV);
507}
508
blueswir18289b272008-02-27 17:53:27 +0000509static inline void tcg_out_nop(TCGContext *s)
510{
blueswir126cc9152008-05-24 18:06:35 +0000511 tcg_out_sethi(s, TCG_REG_G0, 0);
blueswir18289b272008-02-27 17:53:27 +0000512}
513
Richard Henderson0aed2572012-09-24 14:21:40 -0700514static const uint8_t tcg_cond_to_bcond[] = {
blueswir1cf7c2ca2008-05-15 19:44:09 +0000515 [TCG_COND_EQ] = COND_E,
516 [TCG_COND_NE] = COND_NE,
517 [TCG_COND_LT] = COND_L,
518 [TCG_COND_GE] = COND_GE,
519 [TCG_COND_LE] = COND_LE,
520 [TCG_COND_GT] = COND_G,
521 [TCG_COND_LTU] = COND_CS,
522 [TCG_COND_GEU] = COND_CC,
523 [TCG_COND_LEU] = COND_LEU,
524 [TCG_COND_GTU] = COND_GU,
525};
526
Richard Hendersonab1339b2012-10-10 09:02:46 -0700527static const uint8_t tcg_cond_to_rcond[] = {
528 [TCG_COND_EQ] = RCOND_Z,
529 [TCG_COND_NE] = RCOND_NZ,
530 [TCG_COND_LT] = RCOND_LZ,
531 [TCG_COND_GT] = RCOND_GZ,
532 [TCG_COND_LE] = RCOND_LEZ,
533 [TCG_COND_GE] = RCOND_GEZ
534};
535
Richard Hendersona115f3e2012-10-10 09:02:44 -0700536static void tcg_out_bpcc0(TCGContext *s, int scond, int flags, int off19)
537{
538 tcg_out32(s, INSN_OP(0) | INSN_OP2(1) | INSN_COND(scond) | flags | off19);
539}
540
541static void tcg_out_bpcc(TCGContext *s, int scond, int flags, int label)
542{
543 TCGLabel *l = &s->labels[label];
544 int off19;
545
546 if (l->has_value) {
547 off19 = INSN_OFF19(l->u.value - (unsigned long)s->code_ptr);
548 } else {
549 /* Make sure to preserve destinations during retranslation. */
550 off19 = *(uint32_t *)s->code_ptr & INSN_OFF19(-1);
551 tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label, 0);
552 }
553 tcg_out_bpcc0(s, scond, flags, off19);
554}
555
Richard Henderson56f49272009-12-19 20:23:19 -0800556static void tcg_out_cmp(TCGContext *s, TCGArg c1, TCGArg c2, int c2const)
557{
Richard Hendersonba225192010-01-12 19:59:29 +0000558 tcg_out_arithc(s, TCG_REG_G0, c1, c2, c2const, ARITH_SUBCC);
Richard Henderson56f49272009-12-19 20:23:19 -0800559}
560
Richard Hendersona115f3e2012-10-10 09:02:44 -0700561static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond, TCGArg arg1,
562 TCGArg arg2, int const_arg2, int label)
blueswir1cf7c2ca2008-05-15 19:44:09 +0000563{
Richard Henderson56f49272009-12-19 20:23:19 -0800564 tcg_out_cmp(s, arg1, arg2, const_arg2);
Richard Hendersona115f3e2012-10-10 09:02:44 -0700565 tcg_out_bpcc(s, tcg_cond_to_bcond[cond], BPCC_ICC | BPCC_PT, label);
blueswir1cf7c2ca2008-05-15 19:44:09 +0000566 tcg_out_nop(s);
567}
568
Richard Hendersonded37f02012-10-10 09:02:37 -0700569static void tcg_out_movcc(TCGContext *s, TCGCond cond, int cc, TCGArg ret,
570 TCGArg v1, int v1const)
571{
572 tcg_out32(s, ARITH_MOVCC | cc | INSN_RD(ret)
573 | INSN_RS1(tcg_cond_to_bcond[cond])
574 | (v1const ? INSN_IMM11(v1) : INSN_RS2(v1)));
575}
576
577static void tcg_out_movcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
578 TCGArg c1, TCGArg c2, int c2const,
579 TCGArg v1, int v1const)
580{
581 tcg_out_cmp(s, c1, c2, c2const);
582 tcg_out_movcc(s, cond, MOVCC_ICC, ret, v1, v1const);
583}
584
Richard Hendersona212ea72009-12-17 23:47:54 -0800585#if TCG_TARGET_REG_BITS == 64
Richard Hendersona115f3e2012-10-10 09:02:44 -0700586static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGArg arg1,
587 TCGArg arg2, int const_arg2, int label)
blueswir11da92db2009-04-04 19:10:26 +0000588{
Richard Hendersonab1339b2012-10-10 09:02:46 -0700589 /* For 64-bit signed comparisons vs zero, we can avoid the compare. */
590 if (arg2 == 0 && !is_unsigned_cond(cond)) {
591 TCGLabel *l = &s->labels[label];
592 int off16;
593
594 if (l->has_value) {
595 off16 = INSN_OFF16(l->u.value - (unsigned long)s->code_ptr);
596 } else {
597 /* Make sure to preserve destinations during retranslation. */
598 off16 = *(uint32_t *)s->code_ptr & INSN_OFF16(-1);
599 tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP16, label, 0);
600 }
601 tcg_out32(s, INSN_OP(0) | INSN_OP2(3) | BPR_PT | INSN_RS1(arg1)
602 | INSN_COND(tcg_cond_to_rcond[cond]) | off16);
603 } else {
604 tcg_out_cmp(s, arg1, arg2, const_arg2);
605 tcg_out_bpcc(s, tcg_cond_to_bcond[cond], BPCC_XCC | BPCC_PT, label);
606 }
blueswir11da92db2009-04-04 19:10:26 +0000607 tcg_out_nop(s);
608}
Richard Hendersonded37f02012-10-10 09:02:37 -0700609
Richard Henderson203342d2012-10-10 09:02:47 -0700610static void tcg_out_movr(TCGContext *s, TCGCond cond, TCGArg ret, TCGArg c1,
611 TCGArg v1, int v1const)
612{
613 tcg_out32(s, ARITH_MOVR | INSN_RD(ret) | INSN_RS1(c1)
614 | (tcg_cond_to_rcond[cond] << 10)
615 | (v1const ? INSN_IMM10(v1) : INSN_RS2(v1)));
616}
617
Richard Hendersonded37f02012-10-10 09:02:37 -0700618static void tcg_out_movcond_i64(TCGContext *s, TCGCond cond, TCGArg ret,
619 TCGArg c1, TCGArg c2, int c2const,
620 TCGArg v1, int v1const)
621{
Richard Henderson203342d2012-10-10 09:02:47 -0700622 /* For 64-bit signed comparisons vs zero, we can avoid the compare.
623 Note that the immediate range is one bit smaller, so we must check
624 for that as well. */
625 if (c2 == 0 && !is_unsigned_cond(cond)
626 && (!v1const || check_fit_tl(v1, 10))) {
627 tcg_out_movr(s, cond, ret, c1, v1, v1const);
628 } else {
629 tcg_out_cmp(s, c1, c2, c2const);
630 tcg_out_movcc(s, cond, MOVCC_XCC, ret, v1, v1const);
631 }
Richard Hendersonded37f02012-10-10 09:02:37 -0700632}
Richard Henderson56f49272009-12-19 20:23:19 -0800633#else
Richard Henderson8a56e842010-03-19 11:26:05 -0700634static void tcg_out_brcond2_i32(TCGContext *s, TCGCond cond,
Richard Henderson56f49272009-12-19 20:23:19 -0800635 TCGArg al, TCGArg ah,
636 TCGArg bl, int blconst,
637 TCGArg bh, int bhconst, int label_dest)
638{
Richard Hendersona115f3e2012-10-10 09:02:44 -0700639 int scond, label_next = gen_new_label();
Richard Henderson56f49272009-12-19 20:23:19 -0800640
641 tcg_out_cmp(s, ah, bh, bhconst);
642
643 /* Note that we fill one of the delay slots with the second compare. */
644 switch (cond) {
645 case TCG_COND_EQ:
Richard Hendersona115f3e2012-10-10 09:02:44 -0700646 tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_next);
Richard Henderson56f49272009-12-19 20:23:19 -0800647 tcg_out_cmp(s, al, bl, blconst);
Richard Hendersona115f3e2012-10-10 09:02:44 -0700648 tcg_out_bpcc(s, COND_E, BPCC_ICC | BPCC_PT, label_dest);
Richard Henderson56f49272009-12-19 20:23:19 -0800649 break;
650
651 case TCG_COND_NE:
Richard Hendersona115f3e2012-10-10 09:02:44 -0700652 tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_dest);
Richard Henderson56f49272009-12-19 20:23:19 -0800653 tcg_out_cmp(s, al, bl, blconst);
Richard Hendersona115f3e2012-10-10 09:02:44 -0700654 tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_dest);
Richard Henderson56f49272009-12-19 20:23:19 -0800655 break;
656
657 default:
Richard Hendersona115f3e2012-10-10 09:02:44 -0700658 scond = tcg_cond_to_bcond[tcg_high_cond(cond)];
659 tcg_out_bpcc(s, scond, BPCC_ICC | BPCC_PT, label_dest);
Richard Henderson56f49272009-12-19 20:23:19 -0800660 tcg_out_nop(s);
Richard Hendersona115f3e2012-10-10 09:02:44 -0700661 tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_next);
Richard Henderson56f49272009-12-19 20:23:19 -0800662 tcg_out_cmp(s, al, bl, blconst);
Richard Hendersona115f3e2012-10-10 09:02:44 -0700663 scond = tcg_cond_to_bcond[tcg_unsigned_cond(cond)];
664 tcg_out_bpcc(s, scond, BPCC_ICC | BPCC_PT, label_dest);
Richard Henderson56f49272009-12-19 20:23:19 -0800665 break;
666 }
667 tcg_out_nop(s);
668
Stefan Weil9d6fca72012-03-10 19:59:04 +0100669 tcg_out_label(s, label_next, s->code_ptr);
Richard Henderson56f49272009-12-19 20:23:19 -0800670}
blueswir11da92db2009-04-04 19:10:26 +0000671#endif
672
Richard Henderson8a56e842010-03-19 11:26:05 -0700673static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800674 TCGArg c1, TCGArg c2, int c2const)
675{
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800676 /* For 32-bit comparisons, we can play games with ADDX/SUBX. */
677 switch (cond) {
Richard Henderson7d458a72012-10-10 09:02:40 -0700678 case TCG_COND_LTU:
679 case TCG_COND_GEU:
680 /* The result of the comparison is in the carry bit. */
681 break;
682
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800683 case TCG_COND_EQ:
684 case TCG_COND_NE:
Richard Henderson7d458a72012-10-10 09:02:40 -0700685 /* For equality, we can transform to inequality vs zero. */
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800686 if (c2 != 0) {
687 tcg_out_arithc(s, ret, c1, c2, c2const, ARITH_XOR);
688 }
689 c1 = TCG_REG_G0, c2 = ret, c2const = 0;
Richard Henderson7d458a72012-10-10 09:02:40 -0700690 cond = (cond == TCG_COND_EQ ? TCG_COND_GEU : TCG_COND_LTU);
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800691 break;
692
693 case TCG_COND_GTU:
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800694 case TCG_COND_LEU:
Richard Henderson7d458a72012-10-10 09:02:40 -0700695 /* If we don't need to load a constant into a register, we can
696 swap the operands on GTU/LEU. There's no benefit to loading
697 the constant into a temporary register. */
698 if (!c2const || c2 == 0) {
699 TCGArg t = c1;
700 c1 = c2;
701 c2 = t;
702 c2const = 0;
703 cond = tcg_swap_cond(cond);
704 break;
705 }
706 /* FALLTHRU */
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800707
708 default:
709 tcg_out_cmp(s, c1, c2, c2const);
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800710 tcg_out_movi_imm13(s, ret, 0);
Richard Hendersonded37f02012-10-10 09:02:37 -0700711 tcg_out_movcc(s, cond, MOVCC_ICC, ret, 1, 1);
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800712 return;
713 }
714
715 tcg_out_cmp(s, c1, c2, c2const);
716 if (cond == TCG_COND_LTU) {
717 tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_ADDX);
718 } else {
719 tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_SUBX);
720 }
721}
722
723#if TCG_TARGET_REG_BITS == 64
Richard Henderson8a56e842010-03-19 11:26:05 -0700724static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGArg ret,
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800725 TCGArg c1, TCGArg c2, int c2const)
726{
Richard Henderson203342d2012-10-10 09:02:47 -0700727 /* For 64-bit signed comparisons vs zero, we can avoid the compare
728 if the input does not overlap the output. */
729 if (c2 == 0 && !is_unsigned_cond(cond) && c1 != ret) {
730 tcg_out_movi_imm13(s, ret, 0);
731 tcg_out_movr(s, cond, ret, c1, 1, 1);
732 } else {
733 tcg_out_cmp(s, c1, c2, c2const);
734 tcg_out_movi_imm13(s, ret, 0);
735 tcg_out_movcc(s, cond, MOVCC_XCC, ret, 1, 1);
736 }
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800737}
738#else
Richard Henderson8a56e842010-03-19 11:26:05 -0700739static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret,
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800740 TCGArg al, TCGArg ah,
741 TCGArg bl, int blconst,
742 TCGArg bh, int bhconst)
743{
Richard Hendersondda73c72012-10-10 09:02:38 -0700744 int tmp = TCG_REG_T1;
745
746 /* Note that the low parts are fully consumed before tmp is set. */
747 if (ret != ah && (bhconst || ret != bh)) {
748 tmp = ret;
749 }
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800750
751 switch (cond) {
752 case TCG_COND_EQ:
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800753 case TCG_COND_NE:
Richard Hendersonfd84ea22012-10-10 09:02:43 -0700754 if (bl == 0 && bh == 0) {
755 if (cond == TCG_COND_EQ) {
756 tcg_out_arith(s, TCG_REG_G0, al, ah, ARITH_ORCC);
757 tcg_out_movi(s, TCG_TYPE_I32, ret, 1);
758 } else {
759 tcg_out_arith(s, ret, al, ah, ARITH_ORCC);
760 }
761 } else {
762 tcg_out_setcond_i32(s, cond, tmp, al, bl, blconst);
763 tcg_out_cmp(s, ah, bh, bhconst);
764 tcg_out_mov(s, TCG_TYPE_I32, ret, tmp);
765 }
Richard Hendersondda73c72012-10-10 09:02:38 -0700766 tcg_out_movcc(s, TCG_COND_NE, MOVCC_ICC, ret, cond == TCG_COND_NE, 1);
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800767 break;
768
769 default:
Richard Hendersondda73c72012-10-10 09:02:38 -0700770 /* <= : ah < bh | (ah == bh && al <= bl) */
771 tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), tmp, al, bl, blconst);
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800772 tcg_out_cmp(s, ah, bh, bhconst);
Richard Hendersondda73c72012-10-10 09:02:38 -0700773 tcg_out_mov(s, TCG_TYPE_I32, ret, tmp);
774 tcg_out_movcc(s, TCG_COND_NE, MOVCC_ICC, ret, 0, 1);
775 tcg_out_movcc(s, tcg_high_cond(cond), MOVCC_ICC, ret, 1, 1);
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800776 break;
777 }
778}
Blue Swirl07ca08b2013-02-27 16:09:38 +0000779#endif
Richard Henderson4ec28e22012-10-10 09:02:41 -0700780
781static void tcg_out_addsub2(TCGContext *s, TCGArg rl, TCGArg rh,
782 TCGArg al, TCGArg ah, TCGArg bl, int blconst,
783 TCGArg bh, int bhconst, int opl, int oph)
784{
785 TCGArg tmp = TCG_REG_T1;
786
787 /* Note that the low parts are fully consumed before tmp is set. */
788 if (rl != ah && (bhconst || rl != bh)) {
789 tmp = rl;
790 }
791
792 tcg_out_arithc(s, tmp, al, bl, blconst, opl);
793 tcg_out_arithc(s, rh, ah, bh, bhconst, oph);
794 tcg_out_mov(s, TCG_TYPE_I32, rl, tmp);
795}
Richard Hendersondbfe80e2010-02-15 21:22:59 -0800796
Richard Hendersonaad2f062013-08-20 18:25:38 -0700797static inline void tcg_out_calli(TCGContext *s, uintptr_t dest)
798{
799 intptr_t disp = dest - (uintptr_t)s->code_ptr;
800
801 if (disp == (int32_t)disp) {
802 tcg_out32(s, CALL | (uint32_t)disp >> 2);
803 } else {
804 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, dest & ~0xfff);
805 tcg_out_arithi(s, TCG_REG_O7, TCG_REG_T1, dest & 0xfff, JMPL);
806 }
807}
808
Richard Henderson7ea5d722014-03-05 09:42:08 -0800809#ifdef CONFIG_SOFTMMU
810static uintptr_t qemu_ld_trampoline[16];
811static uintptr_t qemu_st_trampoline[16];
812
813static void build_trampolines(TCGContext *s)
814{
815 static uintptr_t const qemu_ld_helpers[16] = {
816 [MO_UB] = (uintptr_t)helper_ret_ldub_mmu,
817 [MO_SB] = (uintptr_t)helper_ret_ldsb_mmu,
818 [MO_LEUW] = (uintptr_t)helper_le_lduw_mmu,
819 [MO_LESW] = (uintptr_t)helper_le_ldsw_mmu,
820 [MO_LEUL] = (uintptr_t)helper_le_ldul_mmu,
821 [MO_LEQ] = (uintptr_t)helper_le_ldq_mmu,
822 [MO_BEUW] = (uintptr_t)helper_be_lduw_mmu,
823 [MO_BESW] = (uintptr_t)helper_be_ldsw_mmu,
824 [MO_BEUL] = (uintptr_t)helper_be_ldul_mmu,
825 [MO_BEQ] = (uintptr_t)helper_be_ldq_mmu,
826 };
827 static uintptr_t const qemu_st_helpers[16] = {
828 [MO_UB] = (uintptr_t)helper_ret_stb_mmu,
829 [MO_LEUW] = (uintptr_t)helper_le_stw_mmu,
830 [MO_LEUL] = (uintptr_t)helper_le_stl_mmu,
831 [MO_LEQ] = (uintptr_t)helper_le_stq_mmu,
832 [MO_BEUW] = (uintptr_t)helper_be_stw_mmu,
833 [MO_BEUL] = (uintptr_t)helper_be_stl_mmu,
834 [MO_BEQ] = (uintptr_t)helper_be_stq_mmu,
835 };
836
837 int i;
838 TCGReg ra;
839 uintptr_t tramp;
840
841 for (i = 0; i < 16; ++i) {
842 if (qemu_ld_helpers[i] == 0) {
843 continue;
844 }
845
846 /* May as well align the trampoline. */
847 tramp = (uintptr_t)s->code_ptr;
848 while (tramp & 15) {
849 tcg_out_nop(s);
850 tramp += 4;
851 }
852 qemu_ld_trampoline[i] = tramp;
853
854 /* Find the retaddr argument register. */
855 ra = TCG_REG_O3 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS);
856
857 /* Set the retaddr operand. */
858 tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
859 /* Set the env operand. */
860 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0);
861 /* Tail call. */
862 tcg_out_calli(s, qemu_ld_helpers[i]);
863 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra);
864 }
865
866 for (i = 0; i < 16; ++i) {
867 if (qemu_st_helpers[i] == 0) {
868 continue;
869 }
870
871 /* May as well align the trampoline. */
872 tramp = (uintptr_t)s->code_ptr;
873 while (tramp & 15) {
874 tcg_out_nop(s);
875 tramp += 4;
876 }
877 qemu_st_trampoline[i] = tramp;
878
879 /* Find the retaddr argument. For 32-bit, this may be past the
880 last argument register, and need passing on the stack. */
881 ra = (TCG_REG_O4
882 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)
883 + (TCG_TARGET_REG_BITS == 32 && (i & MO_SIZE) == MO_64));
884
885 /* Set the retaddr operand. */
886 if (ra >= TCG_REG_O6) {
887 tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_O7, TCG_REG_CALL_STACK,
888 TCG_TARGET_CALL_STACK_OFFSET);
889 ra = TCG_REG_G1;
890 }
891 tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
892 /* Set the env operand. */
893 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0);
894 /* Tail call. */
895 tcg_out_calli(s, qemu_st_helpers[i]);
896 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra);
897 }
898}
899#endif
900
blueswir17d551702008-05-14 19:22:05 +0000901/* Generate global QEMU prologue and epilogue code */
Richard Hendersone4d58b42010-06-02 17:26:56 -0700902static void tcg_target_qemu_prologue(TCGContext *s)
blueswir1b3db8752008-03-08 13:33:42 +0000903{
Richard Henderson4c3204c2012-03-25 21:21:46 +0200904 int tmp_buf_size, frame_size;
905
906 /* The TCG temp buffer is at the top of the frame, immediately
907 below the frame pointer. */
908 tmp_buf_size = CPU_TEMP_BUF_NLONGS * (int)sizeof(long);
909 tcg_set_frame(s, TCG_REG_I6, TCG_TARGET_STACK_BIAS - tmp_buf_size,
910 tmp_buf_size);
911
912 /* TCG_TARGET_CALL_STACK_OFFSET includes the stack bias, but is
913 otherwise the minimal frame usable by callees. */
914 frame_size = TCG_TARGET_CALL_STACK_OFFSET - TCG_TARGET_STACK_BIAS;
915 frame_size += TCG_STATIC_CALL_ARGS_SIZE + tmp_buf_size;
916 frame_size += TCG_TARGET_STACK_ALIGN - 1;
917 frame_size &= -TCG_TARGET_STACK_ALIGN;
blueswir1b3db8752008-03-08 13:33:42 +0000918 tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) |
Richard Henderson4c3204c2012-03-25 21:21:46 +0200919 INSN_IMM13(-frame_size));
Richard Hendersonc6f7e4f2012-03-24 22:11:25 +0100920
921#ifdef CONFIG_USE_GUEST_BASE
922 if (GUEST_BASE != 0) {
923 tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE);
924 tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
925 }
926#endif
927
Richard Hendersonaad2f062013-08-20 18:25:38 -0700928 tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I1, 0, JMPL);
Richard Henderson0c554162012-03-25 19:52:11 +0200929 /* delay slot */
930 tcg_out_nop(s);
Richard Henderson4c3204c2012-03-25 21:21:46 +0200931
932 /* No epilogue required. We issue ret + restore directly in the TB. */
Richard Henderson7ea5d722014-03-05 09:42:08 -0800933
934#ifdef CONFIG_SOFTMMU
935 build_trampolines(s);
936#endif
blueswir1b3db8752008-03-08 13:33:42 +0000937}
938
blueswir1f5ef6aa2008-05-16 20:15:58 +0000939#if defined(CONFIG_SOFTMMU)
Richard Hendersona0ce3412012-03-23 23:27:39 +0100940/* Perform the TLB load and compare.
blueswir1bffe1432008-08-17 14:34:27 +0000941
Richard Hendersona0ce3412012-03-23 23:27:39 +0100942 Inputs:
Richard Hendersona8b12c12013-09-06 15:01:14 -0700943 ADDRLO and ADDRHI contain the possible two parts of the address.
blueswir19d0efc82008-09-13 20:07:53 +0000944
Richard Hendersona0ce3412012-03-23 23:27:39 +0100945 MEM_INDEX and S_BITS are the memory context and log2 size of the load.
blueswir1bffe1432008-08-17 14:34:27 +0000946
Richard Hendersona0ce3412012-03-23 23:27:39 +0100947 WHICH is the offset into the CPUTLBEntry structure of the slot to read.
948 This should be offsetof addr_read or addr_write.
949
950 The result of the TLB comparison is in %[ix]cc. The sanitized address
951 is in the returned register, maybe %o0. The TLB addend is in %o1. */
952
Richard Hendersona8b12c12013-09-06 15:01:14 -0700953static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
954 int mem_index, TCGMemOp s_bits, int which)
blueswir1f5ef6aa2008-05-16 20:15:58 +0000955{
Richard Hendersona8b12c12013-09-06 15:01:14 -0700956 const TCGReg r0 = TCG_REG_O0;
957 const TCGReg r1 = TCG_REG_O1;
958 const TCGReg r2 = TCG_REG_O2;
959 TCGReg addr = addrlo;
Richard Hendersona0ce3412012-03-23 23:27:39 +0100960 int tlb_ofs;
blueswir1f5ef6aa2008-05-16 20:15:58 +0000961
Richard Hendersona0ce3412012-03-23 23:27:39 +0100962 if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) {
963 /* Assemble the 64-bit address in R0. */
964 tcg_out_arithi(s, r0, addrlo, 0, SHIFT_SRL);
Richard Hendersona8b12c12013-09-06 15:01:14 -0700965 tcg_out_arithi(s, r1, addrhi, 32, SHIFT_SLLX);
Richard Hendersona0ce3412012-03-23 23:27:39 +0100966 tcg_out_arith(s, r0, r0, r1, ARITH_OR);
Richard Hendersond801a8f2013-09-06 17:19:12 -0700967 addr = r0;
Richard Hendersona0ce3412012-03-23 23:27:39 +0100968 }
blueswir1f5ef6aa2008-05-16 20:15:58 +0000969
Richard Hendersond801a8f2013-09-06 17:19:12 -0700970 /* Shift the page number down. */
971 tcg_out_arithi(s, r1, addrlo, TARGET_PAGE_BITS, SHIFT_SRL);
blueswir1f5ef6aa2008-05-16 20:15:58 +0000972
Richard Hendersona0ce3412012-03-23 23:27:39 +0100973 /* Mask out the page offset, except for the required alignment. */
Richard Hendersond801a8f2013-09-06 17:19:12 -0700974 tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_T1,
975 TARGET_PAGE_MASK | ((1 << s_bits) - 1));
blueswir1f5ef6aa2008-05-16 20:15:58 +0000976
Richard Hendersond801a8f2013-09-06 17:19:12 -0700977 /* Mask the tlb index. */
978 tcg_out_arithi(s, r1, r1, CPU_TLB_SIZE - 1, ARITH_AND);
979
980 /* Mask page, part 2. */
981 tcg_out_arith(s, r0, addr, TCG_REG_T1, ARITH_AND);
982
983 /* Shift the tlb index into place. */
984 tcg_out_arithi(s, r1, r1, CPU_TLB_ENTRY_BITS, SHIFT_SLL);
blueswir1f5ef6aa2008-05-16 20:15:58 +0000985
Richard Hendersona0ce3412012-03-23 23:27:39 +0100986 /* Relative to the current ENV. */
987 tcg_out_arith(s, r1, TCG_AREG0, r1, ARITH_ADD);
blueswir1f5ef6aa2008-05-16 20:15:58 +0000988
Richard Hendersona0ce3412012-03-23 23:27:39 +0100989 /* Find a base address that can load both tlb comparator and addend. */
990 tlb_ofs = offsetof(CPUArchState, tlb_table[mem_index][0]);
991 if (!check_fit_tl(tlb_ofs + sizeof(CPUTLBEntry), 13)) {
Richard Hendersond801a8f2013-09-06 17:19:12 -0700992 tcg_out_addi(s, r1, tlb_ofs & ~0x3ff);
993 tlb_ofs &= 0x3ff;
Richard Hendersona0ce3412012-03-23 23:27:39 +0100994 }
blueswir1f5ef6aa2008-05-16 20:15:58 +0000995
Richard Hendersona0ce3412012-03-23 23:27:39 +0100996 /* Load the tlb comparator and the addend. */
997 tcg_out_ld(s, TCG_TYPE_TL, r2, r1, tlb_ofs + which);
998 tcg_out_ld(s, TCG_TYPE_PTR, r1, r1, tlb_ofs+offsetof(CPUTLBEntry, addend));
blueswir153c37482008-08-15 18:14:44 +0000999
blueswir156fc64d2008-08-16 19:54:01 +00001000 /* subcc arg0, arg2, %g0 */
Richard Hendersona0ce3412012-03-23 23:27:39 +01001001 tcg_out_cmp(s, r0, r2, 0);
blueswir1f5ef6aa2008-05-16 20:15:58 +00001002
Richard Hendersona0ce3412012-03-23 23:27:39 +01001003 /* If the guest address must be zero-extended, do so now. */
1004 if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) {
1005 tcg_out_arithi(s, r0, addrlo, 0, SHIFT_SRL);
1006 return r0;
1007 }
1008 return addrlo;
1009}
1010#endif /* CONFIG_SOFTMMU */
blueswir1f5ef6aa2008-05-16 20:15:58 +00001011
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001012static const int qemu_ld_opc[16] = {
1013 [MO_UB] = LDUB,
1014 [MO_SB] = LDSB,
1015
1016 [MO_BEUW] = LDUH,
1017 [MO_BESW] = LDSH,
1018 [MO_BEUL] = LDUW,
1019 [MO_BESL] = LDSW,
1020 [MO_BEQ] = LDX,
1021
1022 [MO_LEUW] = LDUH_LE,
1023 [MO_LESW] = LDSH_LE,
1024 [MO_LEUL] = LDUW_LE,
1025 [MO_LESL] = LDSW_LE,
1026 [MO_LEQ] = LDX_LE,
Richard Hendersona0ce3412012-03-23 23:27:39 +01001027};
blueswir1f5ef6aa2008-05-16 20:15:58 +00001028
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001029static const int qemu_st_opc[16] = {
1030 [MO_UB] = STB,
1031
1032 [MO_BEUW] = STH,
1033 [MO_BEUL] = STW,
1034 [MO_BEQ] = STX,
1035
1036 [MO_LEUW] = STH_LE,
1037 [MO_LEUL] = STW_LE,
1038 [MO_LEQ] = STX_LE,
Richard Hendersona0ce3412012-03-23 23:27:39 +01001039};
blueswir1bffe1432008-08-17 14:34:27 +00001040
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001041static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
Richard Hendersona0ce3412012-03-23 23:27:39 +01001042{
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001043 TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
1044 TCGMemOp memop, s_bits;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001045#if defined(CONFIG_SOFTMMU)
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001046 TCGReg addrz, param;
Richard Henderson7ea5d722014-03-05 09:42:08 -08001047 uintptr_t func;
1048 int memi;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001049 uint32_t *label_ptr[2];
1050#endif
1051
Richard Hendersona8b12c12013-09-06 15:01:14 -07001052 datalo = *args++;
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001053 datahi = (TCG_TARGET_REG_BITS == 32 && is64 ? *args++ : 0);
1054 addrlo = *args++;
1055 addrhi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS ? *args++ : 0);
1056 memop = *args++;
1057 s_bits = memop & MO_SIZE;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001058
1059#if defined(CONFIG_SOFTMMU)
Richard Hendersona8b12c12013-09-06 15:01:14 -07001060 memi = *args++;
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001061 addrz = tcg_out_tlb_load(s, addrlo, addrhi, memi, s_bits,
1062 offsetof(CPUTLBEntry, addr_read));
Richard Hendersona0ce3412012-03-23 23:27:39 +01001063
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001064 if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
Richard Hendersona0ce3412012-03-23 23:27:39 +01001065 int reg64;
1066
1067 /* bne,pn %[xi]cc, label0 */
1068 label_ptr[0] = (uint32_t *)s->code_ptr;
Richard Hendersona115f3e2012-10-10 09:02:44 -07001069 tcg_out_bpcc0(s, COND_NE, BPCC_PN
1070 | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0);
Richard Hendersone7bc9002013-09-06 14:20:00 -07001071 tcg_out_nop(s);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001072
1073 /* TLB Hit. */
1074 /* Load all 64-bits into an O/G register. */
1075 reg64 = (datalo < 16 ? datalo : TCG_REG_O0);
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001076 tcg_out_ldst_rr(s, reg64, addrz, TCG_REG_O1, qemu_ld_opc[memop]);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001077
1078 /* Move the two 32-bit pieces into the destination registers. */
1079 tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX);
1080 if (reg64 != datalo) {
1081 tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64);
1082 }
1083
1084 /* b,a,pt label1 */
1085 label_ptr[1] = (uint32_t *)s->code_ptr;
Richard Hendersona115f3e2012-10-10 09:02:44 -07001086 tcg_out_bpcc0(s, COND_A, BPCC_A | BPCC_PT, 0);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001087 } else {
1088 /* The fast path is exactly one insn. Thus we can perform the
1089 entire TLB Hit in the (annulled) delay slot of the branch
1090 over the TLB Miss case. */
1091
1092 /* beq,a,pt %[xi]cc, label0 */
1093 label_ptr[0] = NULL;
1094 label_ptr[1] = (uint32_t *)s->code_ptr;
Richard Hendersona115f3e2012-10-10 09:02:44 -07001095 tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT
1096 | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001097 /* delay slot */
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001098 tcg_out_ldst_rr(s, datalo, addrz, TCG_REG_O1, qemu_ld_opc[memop]);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001099 }
1100
1101 /* TLB Miss. */
1102
1103 if (label_ptr[0]) {
1104 *label_ptr[0] |= INSN_OFF19((unsigned long)s->code_ptr -
1105 (unsigned long)label_ptr[0]);
1106 }
Richard Henderson7ea5d722014-03-05 09:42:08 -08001107
1108 param = TCG_REG_O1;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001109 if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
Richard Henderson7ea5d722014-03-05 09:42:08 -08001110 tcg_out_mov(s, TCG_TYPE_REG, param++, addrhi);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001111 }
Richard Henderson7ea5d722014-03-05 09:42:08 -08001112 tcg_out_mov(s, TCG_TYPE_REG, param++, addrlo);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001113
Richard Henderson7ea5d722014-03-05 09:42:08 -08001114 /* We use the helpers to extend SB and SW data, leaving the case
1115 of SL needing explicit extending below. */
1116 if ((memop & ~MO_BSWAP) == MO_SL) {
1117 func = qemu_ld_trampoline[memop & ~MO_SIGN];
1118 } else {
1119 func = qemu_ld_trampoline[memop];
1120 }
1121 assert(func != 0);
1122 tcg_out_calli(s, func);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001123 /* delay slot */
Richard Henderson7ea5d722014-03-05 09:42:08 -08001124 tcg_out_movi(s, TCG_TYPE_I32, param, memi);
blueswir1f5ef6aa2008-05-16 20:15:58 +00001125
Richard Henderson7ea5d722014-03-05 09:42:08 -08001126 switch (memop & ~MO_BSWAP) {
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001127 case MO_SL:
Richard Henderson7ea5d722014-03-05 09:42:08 -08001128 tcg_out_arithi(s, datalo, TCG_REG_O0, 0, SHIFT_SRA);
blueswir1f5ef6aa2008-05-16 20:15:58 +00001129 break;
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001130 case MO_Q:
Richard Hendersona0ce3412012-03-23 23:27:39 +01001131 if (TCG_TARGET_REG_BITS == 32) {
Richard Henderson7ea5d722014-03-05 09:42:08 -08001132 tcg_out_mov(s, TCG_TYPE_REG, datahi, TCG_REG_O0);
1133 tcg_out_mov(s, TCG_TYPE_REG, datalo, TCG_REG_O1);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001134 break;
1135 }
1136 /* FALLTHRU */
blueswir1f5ef6aa2008-05-16 20:15:58 +00001137 default:
1138 /* mov */
Richard Henderson7ea5d722014-03-05 09:42:08 -08001139 tcg_out_mov(s, TCG_TYPE_REG, datalo, TCG_REG_O0);
blueswir1f5ef6aa2008-05-16 20:15:58 +00001140 break;
1141 }
1142
Richard Hendersona0ce3412012-03-23 23:27:39 +01001143 *label_ptr[1] |= INSN_OFF19((unsigned long)s->code_ptr -
1144 (unsigned long)label_ptr[1]);
blueswir11da92db2009-04-04 19:10:26 +00001145#else
Richard Hendersona0ce3412012-03-23 23:27:39 +01001146 if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) {
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001147 tcg_out_arithi(s, TCG_REG_T1, addrlo, 0, SHIFT_SRL);
1148 addrlo = TCG_REG_T1;
blueswir1f5ef6aa2008-05-16 20:15:58 +00001149 }
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001150 if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
Richard Hendersona0ce3412012-03-23 23:27:39 +01001151 int reg64 = (datalo < 16 ? datalo : TCG_REG_O0);
blueswir1f5ef6aa2008-05-16 20:15:58 +00001152
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001153 tcg_out_ldst_rr(s, reg64, addrlo,
Richard Hendersonc6f7e4f2012-03-24 22:11:25 +01001154 (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0),
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001155 qemu_ld_opc[memop]);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001156
1157 tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX);
1158 if (reg64 != datalo) {
1159 tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64);
1160 }
1161 } else {
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001162 tcg_out_ldst_rr(s, datalo, addrlo,
Richard Hendersonc6f7e4f2012-03-24 22:11:25 +01001163 (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0),
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001164 qemu_ld_opc[memop]);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001165 }
1166#endif /* CONFIG_SOFTMMU */
blueswir1f5ef6aa2008-05-16 20:15:58 +00001167}
1168
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001169static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
blueswir1f5ef6aa2008-05-16 20:15:58 +00001170{
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001171 TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
1172 TCGMemOp memop, s_bits;
blueswir1f5ef6aa2008-05-16 20:15:58 +00001173#if defined(CONFIG_SOFTMMU)
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001174 TCGReg addrz, datafull, param;
Richard Henderson7ea5d722014-03-05 09:42:08 -08001175 uintptr_t func;
1176 int memi;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001177 uint32_t *label_ptr;
blueswir1f5ef6aa2008-05-16 20:15:58 +00001178#endif
1179
Richard Hendersona8b12c12013-09-06 15:01:14 -07001180 datalo = *args++;
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001181 datahi = (TCG_TARGET_REG_BITS == 32 && is64 ? *args++ : 0);
1182 addrlo = *args++;
1183 addrhi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS ? *args++ : 0);
1184 memop = *args++;
1185 s_bits = memop & MO_SIZE;
blueswir1f5ef6aa2008-05-16 20:15:58 +00001186
1187#if defined(CONFIG_SOFTMMU)
Richard Hendersona8b12c12013-09-06 15:01:14 -07001188 memi = *args++;
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001189 addrz = tcg_out_tlb_load(s, addrlo, addrhi, memi, s_bits,
1190 offsetof(CPUTLBEntry, addr_write));
Richard Hendersona0ce3412012-03-23 23:27:39 +01001191
Richard Hendersona7a49842012-10-10 09:02:39 -07001192 datafull = datalo;
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001193 if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
Richard Henderson375816f2012-03-25 22:04:59 +02001194 /* Reconstruct the full 64-bit value. */
1195 tcg_out_arithi(s, TCG_REG_T1, datalo, 0, SHIFT_SRL);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001196 tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX);
Richard Henderson375816f2012-03-25 22:04:59 +02001197 tcg_out_arith(s, TCG_REG_O2, TCG_REG_T1, TCG_REG_O2, ARITH_OR);
Richard Hendersona7a49842012-10-10 09:02:39 -07001198 datafull = TCG_REG_O2;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001199 }
1200
1201 /* The fast path is exactly one insn. Thus we can perform the entire
1202 TLB Hit in the (annulled) delay slot of the branch over TLB Miss. */
1203 /* beq,a,pt %[xi]cc, label0 */
1204 label_ptr = (uint32_t *)s->code_ptr;
Richard Hendersona115f3e2012-10-10 09:02:44 -07001205 tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT
1206 | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001207 /* delay slot */
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001208 tcg_out_ldst_rr(s, datafull, addrz, TCG_REG_O1, qemu_st_opc[memop]);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001209
1210 /* TLB Miss. */
1211
Richard Henderson7ea5d722014-03-05 09:42:08 -08001212 param = TCG_REG_O1;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001213 if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
Richard Henderson7ea5d722014-03-05 09:42:08 -08001214 tcg_out_mov(s, TCG_TYPE_REG, param++, addrhi);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001215 }
Richard Henderson7ea5d722014-03-05 09:42:08 -08001216 tcg_out_mov(s, TCG_TYPE_REG, param++, addrlo);
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001217 if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
Richard Henderson7ea5d722014-03-05 09:42:08 -08001218 tcg_out_mov(s, TCG_TYPE_REG, param++, datahi);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001219 }
Richard Henderson7ea5d722014-03-05 09:42:08 -08001220 tcg_out_mov(s, TCG_TYPE_REG, param++, datalo);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001221
Richard Henderson7ea5d722014-03-05 09:42:08 -08001222 func = qemu_st_trampoline[memop];
1223 assert(func != 0);
1224 tcg_out_calli(s, func);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001225 /* delay slot */
Richard Henderson7ea5d722014-03-05 09:42:08 -08001226 tcg_out_movi(s, TCG_TYPE_REG, param, memi);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001227
Richard Hendersona0ce3412012-03-23 23:27:39 +01001228 *label_ptr |= INSN_OFF19((unsigned long)s->code_ptr -
1229 (unsigned long)label_ptr);
1230#else
Richard Hendersona0ce3412012-03-23 23:27:39 +01001231 if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) {
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001232 tcg_out_arithi(s, TCG_REG_T1, addrlo, 0, SHIFT_SRL);
1233 addrlo = TCG_REG_T1;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001234 }
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001235 if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
Richard Henderson375816f2012-03-25 22:04:59 +02001236 tcg_out_arithi(s, TCG_REG_T1, datalo, 0, SHIFT_SRL);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001237 tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX);
Richard Henderson375816f2012-03-25 22:04:59 +02001238 tcg_out_arith(s, TCG_REG_O2, TCG_REG_T1, TCG_REG_O2, ARITH_OR);
1239 datalo = TCG_REG_O2;
Richard Hendersona0ce3412012-03-23 23:27:39 +01001240 }
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001241 tcg_out_ldst_rr(s, datalo, addrlo,
Richard Hendersonc6f7e4f2012-03-24 22:11:25 +01001242 (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0),
Richard Hendersoneef0d9e2013-09-03 20:12:01 -07001243 qemu_st_opc[memop]);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001244#endif /* CONFIG_SOFTMMU */
blueswir1f5ef6aa2008-05-16 20:15:58 +00001245}
1246
Richard Hendersona9751602010-03-19 11:12:29 -07001247static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
blueswir18289b272008-02-27 17:53:27 +00001248 const int *const_args)
1249{
1250 int c;
1251
1252 switch (opc) {
1253 case INDEX_op_exit_tb:
blueswir1b3db8752008-03-08 13:33:42 +00001254 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]);
Richard Hendersonaad2f062013-08-20 18:25:38 -07001255 tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, JMPL);
blueswir1b3db8752008-03-08 13:33:42 +00001256 tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) |
1257 INSN_RS2(TCG_REG_G0));
blueswir18289b272008-02-27 17:53:27 +00001258 break;
1259 case INDEX_op_goto_tb:
1260 if (s->tb_jmp_offset) {
1261 /* direct jump method */
Richard Henderson5bbd2ca2012-09-21 10:48:51 -07001262 uint32_t old_insn = *(uint32_t *)s->code_ptr;
blueswir18289b272008-02-27 17:53:27 +00001263 s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
Richard Henderson5bbd2ca2012-09-21 10:48:51 -07001264 /* Make sure to preserve links during retranslation. */
1265 tcg_out32(s, CALL | (old_insn & ~INSN_OP(-1)));
blueswir18289b272008-02-27 17:53:27 +00001266 } else {
1267 /* indirect jump method */
Richard Hendersonc8fc56c2013-08-20 18:31:45 -07001268 tcg_out_ld_ptr(s, TCG_REG_T1, (uintptr_t)(s->tb_next + args[0]));
Richard Hendersonaad2f062013-08-20 18:25:38 -07001269 tcg_out_arithi(s, TCG_REG_G0, TCG_REG_T1, 0, JMPL);
blueswir18289b272008-02-27 17:53:27 +00001270 }
blueswir153cd9272008-03-07 18:21:39 +00001271 tcg_out_nop(s);
blueswir18289b272008-02-27 17:53:27 +00001272 s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
1273 break;
1274 case INDEX_op_call:
Richard Henderson375816f2012-03-25 22:04:59 +02001275 if (const_args[0]) {
Richard Hendersonaad2f062013-08-20 18:25:38 -07001276 tcg_out_calli(s, args[0]);
Richard Henderson375816f2012-03-25 22:04:59 +02001277 } else {
Richard Hendersonaad2f062013-08-20 18:25:38 -07001278 tcg_out_arithi(s, TCG_REG_O7, args[0], 0, JMPL);
blueswir18289b272008-02-27 17:53:27 +00001279 }
Richard Henderson4c3204c2012-03-25 21:21:46 +02001280 /* delay slot */
1281 tcg_out_nop(s);
blueswir18289b272008-02-27 17:53:27 +00001282 break;
blueswir18289b272008-02-27 17:53:27 +00001283 case INDEX_op_br:
Richard Hendersona115f3e2012-10-10 09:02:44 -07001284 tcg_out_bpcc(s, COND_A, BPCC_PT, args[0]);
blueswir1f5ef6aa2008-05-16 20:15:58 +00001285 tcg_out_nop(s);
blueswir18289b272008-02-27 17:53:27 +00001286 break;
1287 case INDEX_op_movi_i32:
1288 tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
1289 break;
1290
Richard Hendersona212ea72009-12-17 23:47:54 -08001291#if TCG_TARGET_REG_BITS == 64
blueswir18289b272008-02-27 17:53:27 +00001292#define OP_32_64(x) \
Richard Hendersonba225192010-01-12 19:59:29 +00001293 glue(glue(case INDEX_op_, x), _i32): \
1294 glue(glue(case INDEX_op_, x), _i64)
blueswir18289b272008-02-27 17:53:27 +00001295#else
1296#define OP_32_64(x) \
Richard Hendersonba225192010-01-12 19:59:29 +00001297 glue(glue(case INDEX_op_, x), _i32)
blueswir18289b272008-02-27 17:53:27 +00001298#endif
Richard Hendersonba225192010-01-12 19:59:29 +00001299 OP_32_64(ld8u):
blueswir18289b272008-02-27 17:53:27 +00001300 tcg_out_ldst(s, args[0], args[1], args[2], LDUB);
1301 break;
Richard Hendersonba225192010-01-12 19:59:29 +00001302 OP_32_64(ld8s):
blueswir18289b272008-02-27 17:53:27 +00001303 tcg_out_ldst(s, args[0], args[1], args[2], LDSB);
1304 break;
Richard Hendersonba225192010-01-12 19:59:29 +00001305 OP_32_64(ld16u):
blueswir18289b272008-02-27 17:53:27 +00001306 tcg_out_ldst(s, args[0], args[1], args[2], LDUH);
1307 break;
Richard Hendersonba225192010-01-12 19:59:29 +00001308 OP_32_64(ld16s):
blueswir18289b272008-02-27 17:53:27 +00001309 tcg_out_ldst(s, args[0], args[1], args[2], LDSH);
1310 break;
1311 case INDEX_op_ld_i32:
Richard Hendersona212ea72009-12-17 23:47:54 -08001312#if TCG_TARGET_REG_BITS == 64
blueswir153cd9272008-03-07 18:21:39 +00001313 case INDEX_op_ld32u_i64:
blueswir18289b272008-02-27 17:53:27 +00001314#endif
1315 tcg_out_ldst(s, args[0], args[1], args[2], LDUW);
1316 break;
Richard Hendersonba225192010-01-12 19:59:29 +00001317 OP_32_64(st8):
blueswir18289b272008-02-27 17:53:27 +00001318 tcg_out_ldst(s, args[0], args[1], args[2], STB);
1319 break;
Richard Hendersonba225192010-01-12 19:59:29 +00001320 OP_32_64(st16):
blueswir18289b272008-02-27 17:53:27 +00001321 tcg_out_ldst(s, args[0], args[1], args[2], STH);
1322 break;
1323 case INDEX_op_st_i32:
Richard Hendersona212ea72009-12-17 23:47:54 -08001324#if TCG_TARGET_REG_BITS == 64
blueswir153cd9272008-03-07 18:21:39 +00001325 case INDEX_op_st32_i64:
blueswir18289b272008-02-27 17:53:27 +00001326#endif
1327 tcg_out_ldst(s, args[0], args[1], args[2], STW);
1328 break;
Richard Hendersonba225192010-01-12 19:59:29 +00001329 OP_32_64(add):
blueswir153cd9272008-03-07 18:21:39 +00001330 c = ARITH_ADD;
Richard Hendersonba225192010-01-12 19:59:29 +00001331 goto gen_arith;
1332 OP_32_64(sub):
blueswir18289b272008-02-27 17:53:27 +00001333 c = ARITH_SUB;
Richard Hendersonba225192010-01-12 19:59:29 +00001334 goto gen_arith;
1335 OP_32_64(and):
blueswir18289b272008-02-27 17:53:27 +00001336 c = ARITH_AND;
Richard Hendersonba225192010-01-12 19:59:29 +00001337 goto gen_arith;
Richard Hendersondc699602010-02-16 14:21:19 -08001338 OP_32_64(andc):
1339 c = ARITH_ANDN;
1340 goto gen_arith;
Richard Hendersonba225192010-01-12 19:59:29 +00001341 OP_32_64(or):
blueswir18289b272008-02-27 17:53:27 +00001342 c = ARITH_OR;
Richard Hendersonba225192010-01-12 19:59:29 +00001343 goto gen_arith;
Richard Henderson18c8f7a2010-02-16 14:23:39 -08001344 OP_32_64(orc):
1345 c = ARITH_ORN;
1346 goto gen_arith;
Richard Hendersonba225192010-01-12 19:59:29 +00001347 OP_32_64(xor):
blueswir18289b272008-02-27 17:53:27 +00001348 c = ARITH_XOR;
Richard Hendersonba225192010-01-12 19:59:29 +00001349 goto gen_arith;
blueswir18289b272008-02-27 17:53:27 +00001350 case INDEX_op_shl_i32:
1351 c = SHIFT_SLL;
Richard Henderson1fd95942012-03-25 21:36:28 +02001352 do_shift32:
1353 /* Limit immediate shift count lest we create an illegal insn. */
1354 tcg_out_arithc(s, args[0], args[1], args[2] & 31, const_args[2], c);
1355 break;
blueswir18289b272008-02-27 17:53:27 +00001356 case INDEX_op_shr_i32:
1357 c = SHIFT_SRL;
Richard Henderson1fd95942012-03-25 21:36:28 +02001358 goto do_shift32;
blueswir18289b272008-02-27 17:53:27 +00001359 case INDEX_op_sar_i32:
1360 c = SHIFT_SRA;
Richard Henderson1fd95942012-03-25 21:36:28 +02001361 goto do_shift32;
blueswir18289b272008-02-27 17:53:27 +00001362 case INDEX_op_mul_i32:
1363 c = ARITH_UMUL;
Richard Hendersonba225192010-01-12 19:59:29 +00001364 goto gen_arith;
Richard Henderson583d1212010-01-12 19:59:33 +00001365
Richard Henderson4b5a85c2010-02-16 13:55:15 -08001366 OP_32_64(neg):
1367 c = ARITH_SUB;
1368 goto gen_arith1;
Richard Hendersonbe6551b2010-02-16 14:02:04 -08001369 OP_32_64(not):
1370 c = ARITH_ORN;
1371 goto gen_arith1;
Richard Henderson4b5a85c2010-02-16 13:55:15 -08001372
Richard Henderson583d1212010-01-12 19:59:33 +00001373 case INDEX_op_div_i32:
1374 tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0);
1375 break;
1376 case INDEX_op_divu_i32:
1377 tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 1);
1378 break;
1379
blueswir18289b272008-02-27 17:53:27 +00001380 case INDEX_op_brcond_i32:
blueswir11da92db2009-04-04 19:10:26 +00001381 tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
1382 args[3]);
blueswir18289b272008-02-27 17:53:27 +00001383 break;
Richard Hendersondbfe80e2010-02-15 21:22:59 -08001384 case INDEX_op_setcond_i32:
1385 tcg_out_setcond_i32(s, args[3], args[0], args[1],
1386 args[2], const_args[2]);
1387 break;
Richard Hendersonded37f02012-10-10 09:02:37 -07001388 case INDEX_op_movcond_i32:
1389 tcg_out_movcond_i32(s, args[5], args[0], args[1],
1390 args[2], const_args[2], args[3], const_args[3]);
1391 break;
Richard Hendersondbfe80e2010-02-15 21:22:59 -08001392
Richard Henderson56f49272009-12-19 20:23:19 -08001393#if TCG_TARGET_REG_BITS == 32
1394 case INDEX_op_brcond2_i32:
1395 tcg_out_brcond2_i32(s, args[4], args[0], args[1],
1396 args[2], const_args[2],
1397 args[3], const_args[3], args[5]);
1398 break;
Richard Hendersondbfe80e2010-02-15 21:22:59 -08001399 case INDEX_op_setcond2_i32:
1400 tcg_out_setcond2_i32(s, args[5], args[0], args[1], args[2],
1401 args[3], const_args[3],
1402 args[4], const_args[4]);
1403 break;
Richard Henderson803d8052013-02-19 23:51:51 -08001404#endif
1405
Richard Henderson7a3766f2010-01-12 19:59:31 +00001406 case INDEX_op_add2_i32:
Richard Henderson4ec28e22012-10-10 09:02:41 -07001407 tcg_out_addsub2(s, args[0], args[1], args[2], args[3],
1408 args[4], const_args[4], args[5], const_args[5],
1409 ARITH_ADDCC, ARITH_ADDX);
Richard Henderson7a3766f2010-01-12 19:59:31 +00001410 break;
1411 case INDEX_op_sub2_i32:
Richard Henderson4ec28e22012-10-10 09:02:41 -07001412 tcg_out_addsub2(s, args[0], args[1], args[2], args[3],
1413 args[4], const_args[4], args[5], const_args[5],
1414 ARITH_SUBCC, ARITH_SUBX);
Richard Henderson7a3766f2010-01-12 19:59:31 +00001415 break;
1416 case INDEX_op_mulu2_i32:
1417 tcg_out_arithc(s, args[0], args[2], args[3], const_args[3],
1418 ARITH_UMUL);
1419 tcg_out_rdy(s, args[1]);
1420 break;
blueswir18289b272008-02-27 17:53:27 +00001421
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001422 case INDEX_op_qemu_ld_i32:
1423 tcg_out_qemu_ld(s, args, 0);
blueswir18289b272008-02-27 17:53:27 +00001424 break;
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001425 case INDEX_op_qemu_ld_i64:
1426 tcg_out_qemu_ld(s, args, 1);
blueswir18289b272008-02-27 17:53:27 +00001427 break;
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001428 case INDEX_op_qemu_st_i32:
1429 tcg_out_qemu_st(s, args, 0);
blueswir18289b272008-02-27 17:53:27 +00001430 break;
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001431 case INDEX_op_qemu_st_i64:
1432 tcg_out_qemu_st(s, args, 1);
Richard Hendersona0ce3412012-03-23 23:27:39 +01001433 break;
blueswir18289b272008-02-27 17:53:27 +00001434
Richard Hendersona212ea72009-12-17 23:47:54 -08001435#if TCG_TARGET_REG_BITS == 64
blueswir18289b272008-02-27 17:53:27 +00001436 case INDEX_op_movi_i64:
1437 tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
1438 break;
blueswir153cd9272008-03-07 18:21:39 +00001439 case INDEX_op_ld32s_i64:
1440 tcg_out_ldst(s, args[0], args[1], args[2], LDSW);
1441 break;
blueswir18289b272008-02-27 17:53:27 +00001442 case INDEX_op_ld_i64:
1443 tcg_out_ldst(s, args[0], args[1], args[2], LDX);
1444 break;
1445 case INDEX_op_st_i64:
1446 tcg_out_ldst(s, args[0], args[1], args[2], STX);
1447 break;
1448 case INDEX_op_shl_i64:
1449 c = SHIFT_SLLX;
Richard Henderson1fd95942012-03-25 21:36:28 +02001450 do_shift64:
1451 /* Limit immediate shift count lest we create an illegal insn. */
1452 tcg_out_arithc(s, args[0], args[1], args[2] & 63, const_args[2], c);
1453 break;
blueswir18289b272008-02-27 17:53:27 +00001454 case INDEX_op_shr_i64:
1455 c = SHIFT_SRLX;
Richard Henderson1fd95942012-03-25 21:36:28 +02001456 goto do_shift64;
blueswir18289b272008-02-27 17:53:27 +00001457 case INDEX_op_sar_i64:
1458 c = SHIFT_SRAX;
Richard Henderson1fd95942012-03-25 21:36:28 +02001459 goto do_shift64;
blueswir18289b272008-02-27 17:53:27 +00001460 case INDEX_op_mul_i64:
1461 c = ARITH_MULX;
Richard Hendersonba225192010-01-12 19:59:29 +00001462 goto gen_arith;
Richard Henderson583d1212010-01-12 19:59:33 +00001463 case INDEX_op_div_i64:
blueswir153cd9272008-03-07 18:21:39 +00001464 c = ARITH_SDIVX;
Richard Hendersonba225192010-01-12 19:59:29 +00001465 goto gen_arith;
Richard Henderson583d1212010-01-12 19:59:33 +00001466 case INDEX_op_divu_i64:
blueswir18289b272008-02-27 17:53:27 +00001467 c = ARITH_UDIVX;
Richard Hendersonba225192010-01-12 19:59:29 +00001468 goto gen_arith;
Richard Hendersoncc6dfec2010-01-12 19:59:34 +00001469 case INDEX_op_ext32s_i64:
Richard Henderson1d0a6062014-03-04 15:24:04 -08001470 tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRA);
Richard Hendersoncc6dfec2010-01-12 19:59:34 +00001471 break;
1472 case INDEX_op_ext32u_i64:
Richard Henderson1d0a6062014-03-04 15:24:04 -08001473 tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRL);
Richard Hendersoncc6dfec2010-01-12 19:59:34 +00001474 break;
blueswir18289b272008-02-27 17:53:27 +00001475
1476 case INDEX_op_brcond_i64:
blueswir11da92db2009-04-04 19:10:26 +00001477 tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
1478 args[3]);
blueswir18289b272008-02-27 17:53:27 +00001479 break;
Richard Hendersondbfe80e2010-02-15 21:22:59 -08001480 case INDEX_op_setcond_i64:
1481 tcg_out_setcond_i64(s, args[3], args[0], args[1],
1482 args[2], const_args[2]);
1483 break;
Richard Hendersonded37f02012-10-10 09:02:37 -07001484 case INDEX_op_movcond_i64:
1485 tcg_out_movcond_i64(s, args[5], args[0], args[1],
1486 args[2], const_args[2], args[3], const_args[3]);
1487 break;
blueswir18289b272008-02-27 17:53:27 +00001488#endif
Richard Hendersonba225192010-01-12 19:59:29 +00001489 gen_arith:
1490 tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c);
blueswir153cd9272008-03-07 18:21:39 +00001491 break;
1492
Richard Henderson4b5a85c2010-02-16 13:55:15 -08001493 gen_arith1:
1494 tcg_out_arithc(s, args[0], TCG_REG_G0, args[1], const_args[1], c);
1495 break;
1496
blueswir18289b272008-02-27 17:53:27 +00001497 default:
1498 fprintf(stderr, "unknown opcode 0x%x\n", opc);
1499 tcg_abort();
1500 }
1501}
1502
1503static const TCGTargetOpDef sparc_op_defs[] = {
1504 { INDEX_op_exit_tb, { } },
blueswir1b3db8752008-03-08 13:33:42 +00001505 { INDEX_op_goto_tb, { } },
blueswir18289b272008-02-27 17:53:27 +00001506 { INDEX_op_call, { "ri" } },
blueswir18289b272008-02-27 17:53:27 +00001507 { INDEX_op_br, { } },
1508
1509 { INDEX_op_mov_i32, { "r", "r" } },
1510 { INDEX_op_movi_i32, { "r" } },
1511 { INDEX_op_ld8u_i32, { "r", "r" } },
1512 { INDEX_op_ld8s_i32, { "r", "r" } },
1513 { INDEX_op_ld16u_i32, { "r", "r" } },
1514 { INDEX_op_ld16s_i32, { "r", "r" } },
1515 { INDEX_op_ld_i32, { "r", "r" } },
Richard Henderson89269f62012-10-10 09:02:42 -07001516 { INDEX_op_st8_i32, { "rZ", "r" } },
1517 { INDEX_op_st16_i32, { "rZ", "r" } },
1518 { INDEX_op_st_i32, { "rZ", "r" } },
blueswir18289b272008-02-27 17:53:27 +00001519
Richard Henderson89269f62012-10-10 09:02:42 -07001520 { INDEX_op_add_i32, { "r", "rZ", "rJ" } },
1521 { INDEX_op_mul_i32, { "r", "rZ", "rJ" } },
1522 { INDEX_op_div_i32, { "r", "rZ", "rJ" } },
1523 { INDEX_op_divu_i32, { "r", "rZ", "rJ" } },
Richard Henderson89269f62012-10-10 09:02:42 -07001524 { INDEX_op_sub_i32, { "r", "rZ", "rJ" } },
1525 { INDEX_op_and_i32, { "r", "rZ", "rJ" } },
1526 { INDEX_op_andc_i32, { "r", "rZ", "rJ" } },
1527 { INDEX_op_or_i32, { "r", "rZ", "rJ" } },
1528 { INDEX_op_orc_i32, { "r", "rZ", "rJ" } },
1529 { INDEX_op_xor_i32, { "r", "rZ", "rJ" } },
blueswir18289b272008-02-27 17:53:27 +00001530
Richard Henderson89269f62012-10-10 09:02:42 -07001531 { INDEX_op_shl_i32, { "r", "rZ", "rJ" } },
1532 { INDEX_op_shr_i32, { "r", "rZ", "rJ" } },
1533 { INDEX_op_sar_i32, { "r", "rZ", "rJ" } },
blueswir18289b272008-02-27 17:53:27 +00001534
Richard Henderson4b5a85c2010-02-16 13:55:15 -08001535 { INDEX_op_neg_i32, { "r", "rJ" } },
Richard Hendersonbe6551b2010-02-16 14:02:04 -08001536 { INDEX_op_not_i32, { "r", "rJ" } },
Richard Henderson4b5a85c2010-02-16 13:55:15 -08001537
Richard Henderson89269f62012-10-10 09:02:42 -07001538 { INDEX_op_brcond_i32, { "rZ", "rJ" } },
1539 { INDEX_op_setcond_i32, { "r", "rZ", "rJ" } },
1540 { INDEX_op_movcond_i32, { "r", "rZ", "rJ", "rI", "0" } },
Richard Hendersondbfe80e2010-02-15 21:22:59 -08001541
Richard Henderson56f49272009-12-19 20:23:19 -08001542#if TCG_TARGET_REG_BITS == 32
Richard Henderson89269f62012-10-10 09:02:42 -07001543 { INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } },
1544 { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rJ", "rJ" } },
Richard Henderson803d8052013-02-19 23:51:51 -08001545#endif
1546
Richard Henderson89269f62012-10-10 09:02:42 -07001547 { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
1548 { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
1549 { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rJ" } },
blueswir18289b272008-02-27 17:53:27 +00001550
Richard Hendersona212ea72009-12-17 23:47:54 -08001551#if TCG_TARGET_REG_BITS == 64
blueswir18289b272008-02-27 17:53:27 +00001552 { INDEX_op_mov_i64, { "r", "r" } },
1553 { INDEX_op_movi_i64, { "r" } },
1554 { INDEX_op_ld8u_i64, { "r", "r" } },
1555 { INDEX_op_ld8s_i64, { "r", "r" } },
1556 { INDEX_op_ld16u_i64, { "r", "r" } },
1557 { INDEX_op_ld16s_i64, { "r", "r" } },
1558 { INDEX_op_ld32u_i64, { "r", "r" } },
1559 { INDEX_op_ld32s_i64, { "r", "r" } },
1560 { INDEX_op_ld_i64, { "r", "r" } },
Richard Henderson89269f62012-10-10 09:02:42 -07001561 { INDEX_op_st8_i64, { "rZ", "r" } },
1562 { INDEX_op_st16_i64, { "rZ", "r" } },
1563 { INDEX_op_st32_i64, { "rZ", "r" } },
1564 { INDEX_op_st_i64, { "rZ", "r" } },
blueswir18289b272008-02-27 17:53:27 +00001565
Richard Henderson89269f62012-10-10 09:02:42 -07001566 { INDEX_op_add_i64, { "r", "rZ", "rJ" } },
1567 { INDEX_op_mul_i64, { "r", "rZ", "rJ" } },
1568 { INDEX_op_div_i64, { "r", "rZ", "rJ" } },
1569 { INDEX_op_divu_i64, { "r", "rZ", "rJ" } },
Richard Henderson89269f62012-10-10 09:02:42 -07001570 { INDEX_op_sub_i64, { "r", "rZ", "rJ" } },
1571 { INDEX_op_and_i64, { "r", "rZ", "rJ" } },
1572 { INDEX_op_andc_i64, { "r", "rZ", "rJ" } },
1573 { INDEX_op_or_i64, { "r", "rZ", "rJ" } },
1574 { INDEX_op_orc_i64, { "r", "rZ", "rJ" } },
1575 { INDEX_op_xor_i64, { "r", "rZ", "rJ" } },
blueswir18289b272008-02-27 17:53:27 +00001576
Richard Henderson89269f62012-10-10 09:02:42 -07001577 { INDEX_op_shl_i64, { "r", "rZ", "rJ" } },
1578 { INDEX_op_shr_i64, { "r", "rZ", "rJ" } },
1579 { INDEX_op_sar_i64, { "r", "rZ", "rJ" } },
Richard Henderson4b5a85c2010-02-16 13:55:15 -08001580
1581 { INDEX_op_neg_i64, { "r", "rJ" } },
Richard Hendersonbe6551b2010-02-16 14:02:04 -08001582 { INDEX_op_not_i64, { "r", "rJ" } },
Richard Henderson4b5a85c2010-02-16 13:55:15 -08001583
Richard Henderson1d0a6062014-03-04 15:24:04 -08001584 { INDEX_op_ext32s_i64, { "r", "r" } },
1585 { INDEX_op_ext32u_i64, { "r", "r" } },
blueswir18289b272008-02-27 17:53:27 +00001586
Richard Henderson89269f62012-10-10 09:02:42 -07001587 { INDEX_op_brcond_i64, { "rZ", "rJ" } },
1588 { INDEX_op_setcond_i64, { "r", "rZ", "rJ" } },
1589 { INDEX_op_movcond_i64, { "r", "rZ", "rJ", "rI", "0" } },
blueswir18289b272008-02-27 17:53:27 +00001590#endif
Richard Hendersona0ce3412012-03-23 23:27:39 +01001591
1592#if TCG_TARGET_REG_BITS == 64
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001593 { INDEX_op_qemu_ld_i32, { "r", "L" } },
1594 { INDEX_op_qemu_ld_i64, { "r", "L" } },
1595 { INDEX_op_qemu_st_i32, { "L", "L" } },
1596 { INDEX_op_qemu_st_i64, { "L", "L" } },
Richard Hendersona0ce3412012-03-23 23:27:39 +01001597#elif TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001598 { INDEX_op_qemu_ld_i32, { "r", "L" } },
1599 { INDEX_op_qemu_ld_i64, { "r", "r", "L" } },
1600 { INDEX_op_qemu_st_i32, { "L", "L" } },
1601 { INDEX_op_qemu_st_i64, { "L", "L", "L" } },
Richard Hendersona0ce3412012-03-23 23:27:39 +01001602#else
Richard Hendersoncab0a7e2013-09-09 19:51:21 -07001603 { INDEX_op_qemu_ld_i32, { "r", "L", "L" } },
1604 { INDEX_op_qemu_ld_i64, { "L", "L", "L", "L" } },
1605 { INDEX_op_qemu_st_i32, { "L", "L", "L" } },
1606 { INDEX_op_qemu_st_i64, { "L", "L", "L", "L" } },
Richard Hendersona0ce3412012-03-23 23:27:39 +01001607#endif
1608
blueswir18289b272008-02-27 17:53:27 +00001609 { -1 },
1610};
1611
Richard Hendersone4d58b42010-06-02 17:26:56 -07001612static void tcg_target_init(TCGContext *s)
blueswir18289b272008-02-27 17:53:27 +00001613{
1614 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
Richard Hendersona212ea72009-12-17 23:47:54 -08001615#if TCG_TARGET_REG_BITS == 64
blueswir18289b272008-02-27 17:53:27 +00001616 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
1617#endif
1618 tcg_regset_set32(tcg_target_call_clobber_regs, 0,
blueswir1b3db8752008-03-08 13:33:42 +00001619 (1 << TCG_REG_G1) |
1620 (1 << TCG_REG_G2) |
1621 (1 << TCG_REG_G3) |
1622 (1 << TCG_REG_G4) |
1623 (1 << TCG_REG_G5) |
1624 (1 << TCG_REG_G6) |
1625 (1 << TCG_REG_G7) |
blueswir18289b272008-02-27 17:53:27 +00001626 (1 << TCG_REG_O0) |
1627 (1 << TCG_REG_O1) |
1628 (1 << TCG_REG_O2) |
1629 (1 << TCG_REG_O3) |
1630 (1 << TCG_REG_O4) |
1631 (1 << TCG_REG_O5) |
blueswir18289b272008-02-27 17:53:27 +00001632 (1 << TCG_REG_O7));
1633
1634 tcg_regset_clear(s->reserved_regs);
Richard Henderson375816f2012-03-25 22:04:59 +02001635 tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0); /* zero */
1636 tcg_regset_set_reg(s->reserved_regs, TCG_REG_G6); /* reserved for os */
1637 tcg_regset_set_reg(s->reserved_regs, TCG_REG_G7); /* thread pointer */
1638 tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6); /* frame pointer */
1639 tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7); /* return address */
1640 tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); /* stack pointer */
1641 tcg_regset_set_reg(s->reserved_regs, TCG_REG_T1); /* for internal use */
1642 tcg_regset_set_reg(s->reserved_regs, TCG_REG_T2); /* for internal use */
1643
blueswir18289b272008-02-27 17:53:27 +00001644 tcg_add_target_add_op_defs(sparc_op_defs);
blueswir18289b272008-02-27 17:53:27 +00001645}
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001646
1647#if TCG_TARGET_REG_BITS == 64
1648# define ELF_HOST_MACHINE EM_SPARCV9
Richard Henderson9b9c37c2012-09-21 10:34:21 -07001649#else
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001650# define ELF_HOST_MACHINE EM_SPARC32PLUS
1651# define ELF_HOST_FLAGS EF_SPARC_32PLUS
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001652#endif
1653
1654typedef struct {
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001655 DebugFrameCIE cie;
Richard Henderson497a22e2013-06-05 07:39:57 -07001656 DebugFrameFDEHeader fde;
1657 uint8_t fde_def_cfa[TCG_TARGET_REG_BITS == 64 ? 4 : 2];
1658 uint8_t fde_win_save;
1659 uint8_t fde_ret_save[3];
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001660} DebugFrame;
1661
1662static DebugFrame debug_frame = {
1663 .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
1664 .cie.id = -1,
1665 .cie.version = 1,
1666 .cie.code_align = 1,
1667 .cie.data_align = -sizeof(void *) & 0x7f,
1668 .cie.return_column = 15, /* o7 */
1669
Richard Henderson497a22e2013-06-05 07:39:57 -07001670 /* Total FDE size does not include the "len" member. */
1671 .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
1672
1673 .fde_def_cfa = {
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001674#if TCG_TARGET_REG_BITS == 64
1675 12, 30, /* DW_CFA_def_cfa i6, 2047 */
1676 (2047 & 0x7f) | 0x80, (2047 >> 7)
1677#else
1678 13, 30 /* DW_CFA_def_cfa_register i6 */
1679#endif
1680 },
Richard Henderson497a22e2013-06-05 07:39:57 -07001681 .fde_win_save = 0x2d, /* DW_CFA_GNU_window_save */
1682 .fde_ret_save = { 9, 15, 31 }, /* DW_CFA_register o7, i7 */
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001683};
1684
1685void tcg_register_jit(void *buf, size_t buf_size)
1686{
Richard Hendersonc8fc56c2013-08-20 18:31:45 -07001687 debug_frame.fde.func_start = (uintptr_t)buf;
Richard Hendersoncb1977d2012-03-24 10:47:39 -07001688 debug_frame.fde.func_len = buf_size;
1689
1690 tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
1691}
Richard Henderson5bbd2ca2012-09-21 10:48:51 -07001692
1693void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
1694{
1695 uint32_t *ptr = (uint32_t *)jmp_addr;
Richard Hendersonc8fc56c2013-08-20 18:31:45 -07001696 uintptr_t disp = addr - jmp_addr;
Richard Henderson5bbd2ca2012-09-21 10:48:51 -07001697
1698 /* We can reach the entire address space for 32-bit. For 64-bit
1699 the code_gen_buffer can't be larger than 2GB. */
Richard Hendersonc8fc56c2013-08-20 18:31:45 -07001700 assert(disp == (int32_t)disp);
Richard Henderson5bbd2ca2012-09-21 10:48:51 -07001701
Richard Hendersonc8fc56c2013-08-20 18:31:45 -07001702 *ptr = CALL | (uint32_t)disp >> 2;
Richard Henderson5bbd2ca2012-09-21 10:48:51 -07001703 flush_icache_range(jmp_addr, jmp_addr + 4);
1704}