1 /*
2 * Tiny Code Generator for QEMU
3 *
4 * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard@rtp-net.org>
5 * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
6 * Based on i386/tcg-target.c - Copyright (c) 2008 Fabrice Bellard
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27 #include "tcg-be-ldst.h"
28
29 #ifdef HOST_WORDS_BIGENDIAN
30 # define MIPS_BE 1
31 #else
32 # define MIPS_BE 0
33 #endif
34
35 #define LO_OFF (MIPS_BE * 4)
36 #define HI_OFF (4 - LO_OFF)
37
38 #ifndef NDEBUG
39 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
40 "zero",
41 "at",
42 "v0",
43 "v1",
44 "a0",
45 "a1",
46 "a2",
47 "a3",
48 "t0",
49 "t1",
50 "t2",
51 "t3",
52 "t4",
53 "t5",
54 "t6",
55 "t7",
56 "s0",
57 "s1",
58 "s2",
59 "s3",
60 "s4",
61 "s5",
62 "s6",
63 "s7",
64 "t8",
65 "t9",
66 "k0",
67 "k1",
68 "gp",
69 "sp",
70 "s8",
71 "ra",
72 };
73 #endif
74
75 #define TCG_TMP0 TCG_REG_AT
76 #define TCG_TMP1 TCG_REG_T9
77
78 /* check if we really need so many registers :P */
79 static const TCGReg tcg_target_reg_alloc_order[] = {
80 /* Call saved registers. */
81 TCG_REG_S0,
82 TCG_REG_S1,
83 TCG_REG_S2,
84 TCG_REG_S3,
85 TCG_REG_S4,
86 TCG_REG_S5,
87 TCG_REG_S6,
88 TCG_REG_S7,
89 TCG_REG_S8,
90
91 /* Call clobbered registers. */
92 TCG_REG_T0,
93 TCG_REG_T1,
94 TCG_REG_T2,
95 TCG_REG_T3,
96 TCG_REG_T4,
97 TCG_REG_T5,
98 TCG_REG_T6,
99 TCG_REG_T7,
100 TCG_REG_T8,
101 TCG_REG_T9,
102 TCG_REG_V1,
103 TCG_REG_V0,
104
105 /* Argument registers, opposite order of allocation. */
106 TCG_REG_A3,
107 TCG_REG_A2,
108 TCG_REG_A1,
109 TCG_REG_A0,
110 };
111
112 static const TCGReg tcg_target_call_iarg_regs[4] = {
113 TCG_REG_A0,
114 TCG_REG_A1,
115 TCG_REG_A2,
116 TCG_REG_A3
117 };
118
119 static const TCGReg tcg_target_call_oarg_regs[2] = {
120 TCG_REG_V0,
121 TCG_REG_V1
122 };
123
124 static tcg_insn_unit *tb_ret_addr;
125
reloc_pc16_val(tcg_insn_unit * pc,tcg_insn_unit * target)126 static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
127 {
128 /* Let the compiler perform the right-shift as part of the arithmetic. */
129 ptrdiff_t disp = target - (pc + 1);
130 assert(disp == (int16_t)disp);
131 return disp & 0xffff;
132 }
133
reloc_pc16(tcg_insn_unit * pc,tcg_insn_unit * target)134 static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target)
135 {
136 *pc = deposit32(*pc, 0, 16, reloc_pc16_val(pc, target));
137 }
138
reloc_26_val(tcg_insn_unit * pc,tcg_insn_unit * target)139 static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
140 {
141 assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
142 return ((uintptr_t)target >> 2) & 0x3ffffff;
143 }
144
reloc_26(tcg_insn_unit * pc,tcg_insn_unit * target)145 static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
146 {
147 *pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target));
148 }
149
patch_reloc(tcg_insn_unit * code_ptr,int type,intptr_t value,intptr_t addend)150 static void patch_reloc(tcg_insn_unit *code_ptr, int type,
151 intptr_t value, intptr_t addend)
152 {
153 assert(type == R_MIPS_PC16);
154 assert(addend == 0);
155 reloc_pc16(code_ptr, (tcg_insn_unit *)value);
156 }
157
158 #define TCG_CT_CONST_ZERO 0x100
159 #define TCG_CT_CONST_U16 0x200 /* Unsigned 16-bit: 0 - 0xffff. */
160 #define TCG_CT_CONST_S16 0x400 /* Signed 16-bit: -32768 - 32767 */
161 #define TCG_CT_CONST_P2M1 0x800 /* Power of 2 minus 1. */
162 #define TCG_CT_CONST_N16 0x1000 /* "Negatable" 16-bit: -32767 - 32767 */
163
is_p2m1(tcg_target_long val)164 static inline bool is_p2m1(tcg_target_long val)
165 {
166 return val && ((val + 1) & val) == 0;
167 }
168
169 /* parse target specific constraints */
target_parse_constraint(TCGArgConstraint * ct,const char ** pct_str)170 static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
171 {
172 const char *ct_str;
173
174 ct_str = *pct_str;
175 switch(ct_str[0]) {
176 case 'r':
177 ct->ct |= TCG_CT_REG;
178 tcg_regset_set(ct->u.regs, 0xffffffff);
179 break;
180 case 'L': /* qemu_ld output arg constraint */
181 ct->ct |= TCG_CT_REG;
182 tcg_regset_set(ct->u.regs, 0xffffffff);
183 tcg_regset_reset_reg(ct->u.regs, TCG_REG_V0);
184 break;
185 case 'l': /* qemu_ld input arg constraint */
186 ct->ct |= TCG_CT_REG;
187 tcg_regset_set(ct->u.regs, 0xffffffff);
188 tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
189 #if defined(CONFIG_SOFTMMU)
190 if (TARGET_LONG_BITS == 64) {
191 tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
192 }
193 #endif
194 break;
195 case 'S': /* qemu_st constraint */
196 ct->ct |= TCG_CT_REG;
197 tcg_regset_set(ct->u.regs, 0xffffffff);
198 tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
199 #if defined(CONFIG_SOFTMMU)
200 if (TARGET_LONG_BITS == 32) {
201 tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
202 } else {
203 tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
204 tcg_regset_reset_reg(ct->u.regs, TCG_REG_A3);
205 }
206 #endif
207 break;
208 case 'I':
209 ct->ct |= TCG_CT_CONST_U16;
210 break;
211 case 'J':
212 ct->ct |= TCG_CT_CONST_S16;
213 break;
214 case 'K':
215 ct->ct |= TCG_CT_CONST_P2M1;
216 break;
217 case 'N':
218 ct->ct |= TCG_CT_CONST_N16;
219 break;
220 case 'Z':
221 /* We are cheating a bit here, using the fact that the register
222 ZERO is also the register number 0. Hence there is no need
223 to check for const_args in each instruction. */
224 ct->ct |= TCG_CT_CONST_ZERO;
225 break;
226 default:
227 return -1;
228 }
229 ct_str++;
230 *pct_str = ct_str;
231 return 0;
232 }
233
234 /* test if a constant matches the constraint */
tcg_target_const_match(tcg_target_long val,TCGType type,const TCGArgConstraint * arg_ct)235 static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
236 const TCGArgConstraint *arg_ct)
237 {
238 int ct;
239 ct = arg_ct->ct;
240 if (ct & TCG_CT_CONST) {
241 return 1;
242 } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
243 return 1;
244 } else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) {
245 return 1;
246 } else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) {
247 return 1;
248 } else if ((ct & TCG_CT_CONST_N16) && val >= -32767 && val <= 32767) {
249 return 1;
250 } else if ((ct & TCG_CT_CONST_P2M1)
251 && use_mips32r2_instructions && is_p2m1(val)) {
252 return 1;
253 }
254 return 0;
255 }
256
257 /* instruction opcodes */
258 typedef enum {
259 OPC_J = 0x02 << 26,
260 OPC_JAL = 0x03 << 26,
261 OPC_BEQ = 0x04 << 26,
262 OPC_BNE = 0x05 << 26,
263 OPC_BLEZ = 0x06 << 26,
264 OPC_BGTZ = 0x07 << 26,
265 OPC_ADDIU = 0x09 << 26,
266 OPC_SLTI = 0x0A << 26,
267 OPC_SLTIU = 0x0B << 26,
268 OPC_ANDI = 0x0C << 26,
269 OPC_ORI = 0x0D << 26,
270 OPC_XORI = 0x0E << 26,
271 OPC_LUI = 0x0F << 26,
272 OPC_LB = 0x20 << 26,
273 OPC_LH = 0x21 << 26,
274 OPC_LW = 0x23 << 26,
275 OPC_LBU = 0x24 << 26,
276 OPC_LHU = 0x25 << 26,
277 OPC_LWU = 0x27 << 26,
278 OPC_SB = 0x28 << 26,
279 OPC_SH = 0x29 << 26,
280 OPC_SW = 0x2B << 26,
281
282 OPC_SPECIAL = 0x00 << 26,
283 OPC_SLL = OPC_SPECIAL | 0x00,
284 OPC_SRL = OPC_SPECIAL | 0x02,
285 OPC_ROTR = OPC_SPECIAL | (0x01 << 21) | 0x02,
286 OPC_SRA = OPC_SPECIAL | 0x03,
287 OPC_SLLV = OPC_SPECIAL | 0x04,
288 OPC_SRLV = OPC_SPECIAL | 0x06,
289 OPC_ROTRV = OPC_SPECIAL | (0x01 << 6) | 0x06,
290 OPC_SRAV = OPC_SPECIAL | 0x07,
291 OPC_JR = OPC_SPECIAL | 0x08,
292 OPC_JALR = OPC_SPECIAL | 0x09,
293 OPC_MOVZ = OPC_SPECIAL | 0x0A,
294 OPC_MOVN = OPC_SPECIAL | 0x0B,
295 OPC_MFHI = OPC_SPECIAL | 0x10,
296 OPC_MFLO = OPC_SPECIAL | 0x12,
297 OPC_MULT = OPC_SPECIAL | 0x18,
298 OPC_MULTU = OPC_SPECIAL | 0x19,
299 OPC_DIV = OPC_SPECIAL | 0x1A,
300 OPC_DIVU = OPC_SPECIAL | 0x1B,
301 OPC_ADDU = OPC_SPECIAL | 0x21,
302 OPC_SUBU = OPC_SPECIAL | 0x23,
303 OPC_AND = OPC_SPECIAL | 0x24,
304 OPC_OR = OPC_SPECIAL | 0x25,
305 OPC_XOR = OPC_SPECIAL | 0x26,
306 OPC_NOR = OPC_SPECIAL | 0x27,
307 OPC_SLT = OPC_SPECIAL | 0x2A,
308 OPC_SLTU = OPC_SPECIAL | 0x2B,
309
310 OPC_REGIMM = 0x01 << 26,
311 OPC_BLTZ = OPC_REGIMM | (0x00 << 16),
312 OPC_BGEZ = OPC_REGIMM | (0x01 << 16),
313
314 OPC_SPECIAL2 = 0x1c << 26,
315 OPC_MUL = OPC_SPECIAL2 | 0x002,
316
317 OPC_SPECIAL3 = 0x1f << 26,
318 OPC_EXT = OPC_SPECIAL3 | 0x000,
319 OPC_INS = OPC_SPECIAL3 | 0x004,
320 OPC_WSBH = OPC_SPECIAL3 | 0x0a0,
321 OPC_SEB = OPC_SPECIAL3 | 0x420,
322 OPC_SEH = OPC_SPECIAL3 | 0x620,
323 } MIPSInsn;
324
325 /*
326 * Type reg
327 */
tcg_out_opc_reg(TCGContext * s,MIPSInsn opc,TCGReg rd,TCGReg rs,TCGReg rt)328 static inline void tcg_out_opc_reg(TCGContext *s, MIPSInsn opc,
329 TCGReg rd, TCGReg rs, TCGReg rt)
330 {
331 int32_t inst;
332
333 inst = opc;
334 inst |= (rs & 0x1F) << 21;
335 inst |= (rt & 0x1F) << 16;
336 inst |= (rd & 0x1F) << 11;
337 tcg_out32(s, inst);
338 }
339
340 /*
341 * Type immediate
342 */
tcg_out_opc_imm(TCGContext * s,MIPSInsn opc,TCGReg rt,TCGReg rs,TCGArg imm)343 static inline void tcg_out_opc_imm(TCGContext *s, MIPSInsn opc,
344 TCGReg rt, TCGReg rs, TCGArg imm)
345 {
346 int32_t inst;
347
348 inst = opc;
349 inst |= (rs & 0x1F) << 21;
350 inst |= (rt & 0x1F) << 16;
351 inst |= (imm & 0xffff);
352 tcg_out32(s, inst);
353 }
354
355 /*
356 * Type bitfield
357 */
tcg_out_opc_bf(TCGContext * s,MIPSInsn opc,TCGReg rt,TCGReg rs,int msb,int lsb)358 static inline void tcg_out_opc_bf(TCGContext *s, MIPSInsn opc, TCGReg rt,
359 TCGReg rs, int msb, int lsb)
360 {
361 int32_t inst;
362
363 inst = opc;
364 inst |= (rs & 0x1F) << 21;
365 inst |= (rt & 0x1F) << 16;
366 inst |= (msb & 0x1F) << 11;
367 inst |= (lsb & 0x1F) << 6;
368 tcg_out32(s, inst);
369 }
370
371 /*
372 * Type branch
373 */
tcg_out_opc_br(TCGContext * s,MIPSInsn opc,TCGReg rt,TCGReg rs)374 static inline void tcg_out_opc_br(TCGContext *s, MIPSInsn opc,
375 TCGReg rt, TCGReg rs)
376 {
377 /* We pay attention here to not modify the branch target by reading
378 the existing value and using it again. This ensure that caches and
379 memory are kept coherent during retranslation. */
380 uint16_t offset = (uint16_t)*s->code_ptr;
381
382 tcg_out_opc_imm(s, opc, rt, rs, offset);
383 }
384
385 /*
386 * Type sa
387 */
tcg_out_opc_sa(TCGContext * s,MIPSInsn opc,TCGReg rd,TCGReg rt,TCGArg sa)388 static inline void tcg_out_opc_sa(TCGContext *s, MIPSInsn opc,
389 TCGReg rd, TCGReg rt, TCGArg sa)
390 {
391 int32_t inst;
392
393 inst = opc;
394 inst |= (rt & 0x1F) << 16;
395 inst |= (rd & 0x1F) << 11;
396 inst |= (sa & 0x1F) << 6;
397 tcg_out32(s, inst);
398
399 }
400
401 /*
402 * Type jump.
403 * Returns true if the branch was in range and the insn was emitted.
404 */
tcg_out_opc_jmp(TCGContext * s,MIPSInsn opc,void * target)405 static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
406 {
407 uintptr_t dest = (uintptr_t)target;
408 uintptr_t from = (uintptr_t)s->code_ptr + 4;
409 int32_t inst;
410
411 /* The pc-region branch happens within the 256MB region of
412 the delay slot (thus the +4). */
413 if ((from ^ dest) & -(1 << 28)) {
414 return false;
415 }
416 assert((dest & 3) == 0);
417
418 inst = opc;
419 inst |= (dest >> 2) & 0x3ffffff;
420 tcg_out32(s, inst);
421 return true;
422 }
423
tcg_out_nop(TCGContext * s)424 static inline void tcg_out_nop(TCGContext *s)
425 {
426 tcg_out32(s, 0);
427 }
428
tcg_out_mov(TCGContext * s,TCGType type,TCGReg ret,TCGReg arg)429 static inline void tcg_out_mov(TCGContext *s, TCGType type,
430 TCGReg ret, TCGReg arg)
431 {
432 /* Simple reg-reg move, optimising out the 'do nothing' case */
433 if (ret != arg) {
434 tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
435 }
436 }
437
tcg_out_movi(TCGContext * s,TCGType type,TCGReg reg,tcg_target_long arg)438 static inline void tcg_out_movi(TCGContext *s, TCGType type,
439 TCGReg reg, tcg_target_long arg)
440 {
441 if (arg == (int16_t)arg) {
442 tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg);
443 } else if (arg == (uint16_t)arg) {
444 tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg);
445 } else {
446 tcg_out_opc_imm(s, OPC_LUI, reg, TCG_REG_ZERO, arg >> 16);
447 if (arg & 0xffff) {
448 tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff);
449 }
450 }
451 }
452
tcg_out_bswap16(TCGContext * s,TCGReg ret,TCGReg arg)453 static inline void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg)
454 {
455 if (use_mips32r2_instructions) {
456 tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
457 } else {
458 /* ret and arg can't be register at */
459 if (ret == TCG_TMP0 || arg == TCG_TMP0) {
460 tcg_abort();
461 }
462
463 tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8);
464 tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8);
465 tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00);
466 tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
467 }
468 }
469
tcg_out_bswap16s(TCGContext * s,TCGReg ret,TCGReg arg)470 static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
471 {
472 if (use_mips32r2_instructions) {
473 tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
474 tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret);
475 } else {
476 /* ret and arg can't be register at */
477 if (ret == TCG_TMP0 || arg == TCG_TMP0) {
478 tcg_abort();
479 }
480
481 tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8);
482 tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
483 tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
484 tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
485 }
486 }
487
tcg_out_bswap32(TCGContext * s,TCGReg ret,TCGReg arg)488 static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg)
489 {
490 if (use_mips32r2_instructions) {
491 tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
492 tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16);
493 } else {
494 /* ret and arg must be different and can't be register at */
495 if (ret == arg || ret == TCG_TMP0 || arg == TCG_TMP0) {
496 tcg_abort();
497 }
498
499 tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
500
501 tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 24);
502 tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
503
504 tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, arg, 0xff00);
505 tcg_out_opc_sa(s, OPC_SLL, TCG_TMP0, TCG_TMP0, 8);
506 tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
507
508 tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8);
509 tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, TCG_TMP0, 0xff00);
510 tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
511 }
512 }
513
tcg_out_ext8s(TCGContext * s,TCGReg ret,TCGReg arg)514 static inline void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg)
515 {
516 if (use_mips32r2_instructions) {
517 tcg_out_opc_reg(s, OPC_SEB, ret, 0, arg);
518 } else {
519 tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
520 tcg_out_opc_sa(s, OPC_SRA, ret, ret, 24);
521 }
522 }
523
tcg_out_ext16s(TCGContext * s,TCGReg ret,TCGReg arg)524 static inline void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg)
525 {
526 if (use_mips32r2_instructions) {
527 tcg_out_opc_reg(s, OPC_SEH, ret, 0, arg);
528 } else {
529 tcg_out_opc_sa(s, OPC_SLL, ret, arg, 16);
530 tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
531 }
532 }
533
tcg_out_ldst(TCGContext * s,MIPSInsn opc,TCGReg data,TCGReg addr,intptr_t ofs)534 static void tcg_out_ldst(TCGContext *s, MIPSInsn opc, TCGReg data,
535 TCGReg addr, intptr_t ofs)
536 {
537 int16_t lo = ofs;
538 if (ofs != lo) {
539 tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, ofs - lo);
540 if (addr != TCG_REG_ZERO) {
541 tcg_out_opc_reg(s, OPC_ADDU, TCG_TMP0, TCG_TMP0, addr);
542 }
543 addr = TCG_TMP0;
544 }
545 tcg_out_opc_imm(s, opc, data, addr, lo);
546 }
547
tcg_out_ld(TCGContext * s,TCGType type,TCGReg arg,TCGReg arg1,intptr_t arg2)548 static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
549 TCGReg arg1, intptr_t arg2)
550 {
551 tcg_out_ldst(s, OPC_LW, arg, arg1, arg2);
552 }
553
tcg_out_st(TCGContext * s,TCGType type,TCGReg arg,TCGReg arg1,intptr_t arg2)554 static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
555 TCGReg arg1, intptr_t arg2)
556 {
557 tcg_out_ldst(s, OPC_SW, arg, arg1, arg2);
558 }
559
tcg_out_addi(TCGContext * s,TCGReg reg,TCGArg val)560 static inline void tcg_out_addi(TCGContext *s, TCGReg reg, TCGArg val)
561 {
562 if (val == (int16_t)val) {
563 tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val);
564 } else {
565 tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, val);
566 tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_TMP0);
567 }
568 }
569
570 /* Bit 0 set if inversion required; bit 1 set if swapping required. */
571 #define MIPS_CMP_INV 1
572 #define MIPS_CMP_SWAP 2
573
574 static const uint8_t mips_cmp_map[16] = {
575 [TCG_COND_LT] = 0,
576 [TCG_COND_LTU] = 0,
577 [TCG_COND_GE] = MIPS_CMP_INV,
578 [TCG_COND_GEU] = MIPS_CMP_INV,
579 [TCG_COND_LE] = MIPS_CMP_INV | MIPS_CMP_SWAP,
580 [TCG_COND_LEU] = MIPS_CMP_INV | MIPS_CMP_SWAP,
581 [TCG_COND_GT] = MIPS_CMP_SWAP,
582 [TCG_COND_GTU] = MIPS_CMP_SWAP,
583 };
584
tcg_out_setcond(TCGContext * s,TCGCond cond,TCGReg ret,TCGReg arg1,TCGReg arg2)585 static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret,
586 TCGReg arg1, TCGReg arg2)
587 {
588 MIPSInsn s_opc = OPC_SLTU;
589 int cmp_map;
590
591 switch (cond) {
592 case TCG_COND_EQ:
593 if (arg2 != 0) {
594 tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
595 arg1 = ret;
596 }
597 tcg_out_opc_imm(s, OPC_SLTIU, ret, arg1, 1);
598 break;
599
600 case TCG_COND_NE:
601 if (arg2 != 0) {
602 tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
603 arg1 = ret;
604 }
605 tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg1);
606 break;
607
608 case TCG_COND_LT:
609 case TCG_COND_GE:
610 case TCG_COND_LE:
611 case TCG_COND_GT:
612 s_opc = OPC_SLT;
613 /* FALLTHRU */
614
615 case TCG_COND_LTU:
616 case TCG_COND_GEU:
617 case TCG_COND_LEU:
618 case TCG_COND_GTU:
619 cmp_map = mips_cmp_map[cond];
620 if (cmp_map & MIPS_CMP_SWAP) {
621 TCGReg t = arg1;
622 arg1 = arg2;
623 arg2 = t;
624 }
625 tcg_out_opc_reg(s, s_opc, ret, arg1, arg2);
626 if (cmp_map & MIPS_CMP_INV) {
627 tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
628 }
629 break;
630
631 default:
632 tcg_abort();
633 break;
634 }
635 }
636
tcg_out_brcond(TCGContext * s,TCGCond cond,TCGReg arg1,TCGReg arg2,int label_index)637 static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
638 TCGReg arg2, int label_index)
639 {
640 static const MIPSInsn b_zero[16] = {
641 [TCG_COND_LT] = OPC_BLTZ,
642 [TCG_COND_GT] = OPC_BGTZ,
643 [TCG_COND_LE] = OPC_BLEZ,
644 [TCG_COND_GE] = OPC_BGEZ,
645 };
646
647 TCGLabel *l;
648 MIPSInsn s_opc = OPC_SLTU;
649 MIPSInsn b_opc;
650 int cmp_map;
651
652 switch (cond) {
653 case TCG_COND_EQ:
654 b_opc = OPC_BEQ;
655 break;
656 case TCG_COND_NE:
657 b_opc = OPC_BNE;
658 break;
659
660 case TCG_COND_LT:
661 case TCG_COND_GT:
662 case TCG_COND_LE:
663 case TCG_COND_GE:
664 if (arg2 == 0) {
665 b_opc = b_zero[cond];
666 arg2 = arg1;
667 arg1 = 0;
668 break;
669 }
670 s_opc = OPC_SLT;
671 /* FALLTHRU */
672
673 case TCG_COND_LTU:
674 case TCG_COND_GTU:
675 case TCG_COND_LEU:
676 case TCG_COND_GEU:
677 cmp_map = mips_cmp_map[cond];
678 if (cmp_map & MIPS_CMP_SWAP) {
679 TCGReg t = arg1;
680 arg1 = arg2;
681 arg2 = t;
682 }
683 tcg_out_opc_reg(s, s_opc, TCG_TMP0, arg1, arg2);
684 b_opc = (cmp_map & MIPS_CMP_INV ? OPC_BEQ : OPC_BNE);
685 arg1 = TCG_TMP0;
686 arg2 = TCG_REG_ZERO;
687 break;
688
689 default:
690 tcg_abort();
691 break;
692 }
693
694 tcg_out_opc_br(s, b_opc, arg1, arg2);
695 l = &s->labels[label_index];
696 if (l->has_value) {
697 reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
698 } else {
699 tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, label_index, 0);
700 }
701 tcg_out_nop(s);
702 }
703
tcg_out_reduce_eq2(TCGContext * s,TCGReg tmp0,TCGReg tmp1,TCGReg al,TCGReg ah,TCGReg bl,TCGReg bh)704 static TCGReg tcg_out_reduce_eq2(TCGContext *s, TCGReg tmp0, TCGReg tmp1,
705 TCGReg al, TCGReg ah,
706 TCGReg bl, TCGReg bh)
707 {
708 /* Merge highpart comparison into AH. */
709 if (bh != 0) {
710 if (ah != 0) {
711 tcg_out_opc_reg(s, OPC_XOR, tmp0, ah, bh);
712 ah = tmp0;
713 } else {
714 ah = bh;
715 }
716 }
717 /* Merge lowpart comparison into AL. */
718 if (bl != 0) {
719 if (al != 0) {
720 tcg_out_opc_reg(s, OPC_XOR, tmp1, al, bl);
721 al = tmp1;
722 } else {
723 al = bl;
724 }
725 }
726 /* Merge high and low part comparisons into AL. */
727 if (ah != 0) {
728 if (al != 0) {
729 tcg_out_opc_reg(s, OPC_OR, tmp0, ah, al);
730 al = tmp0;
731 } else {
732 al = ah;
733 }
734 }
735 return al;
736 }
737
tcg_out_setcond2(TCGContext * s,TCGCond cond,TCGReg ret,TCGReg al,TCGReg ah,TCGReg bl,TCGReg bh)738 static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
739 TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh)
740 {
741 TCGReg tmp0 = TCG_TMP0;
742 TCGReg tmp1 = ret;
743
744 assert(ret != TCG_TMP0);
745 if (ret == ah || ret == bh) {
746 assert(ret != TCG_TMP1);
747 tmp1 = TCG_TMP1;
748 }
749
750 switch (cond) {
751 case TCG_COND_EQ:
752 case TCG_COND_NE:
753 tmp1 = tcg_out_reduce_eq2(s, tmp0, tmp1, al, ah, bl, bh);
754 tcg_out_setcond(s, cond, ret, tmp1, TCG_REG_ZERO);
755 break;
756
757 default:
758 tcg_out_setcond(s, TCG_COND_EQ, tmp0, ah, bh);
759 tcg_out_setcond(s, tcg_unsigned_cond(cond), tmp1, al, bl);
760 tcg_out_opc_reg(s, OPC_AND, tmp1, tmp1, tmp0);
761 tcg_out_setcond(s, tcg_high_cond(cond), tmp0, ah, bh);
762 tcg_out_opc_reg(s, OPC_OR, ret, tmp1, tmp0);
763 break;
764 }
765 }
766
tcg_out_brcond2(TCGContext * s,TCGCond cond,TCGReg al,TCGReg ah,TCGReg bl,TCGReg bh,int label_index)767 static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
768 TCGReg bl, TCGReg bh, int label_index)
769 {
770 TCGCond b_cond = TCG_COND_NE;
771 TCGReg tmp = TCG_TMP1;
772
773 /* With branches, we emit between 4 and 9 insns with 2 or 3 branches.
774 With setcond, we emit between 3 and 10 insns and only 1 branch,
775 which ought to get better branch prediction. */
776 switch (cond) {
777 case TCG_COND_EQ:
778 case TCG_COND_NE:
779 b_cond = cond;
780 tmp = tcg_out_reduce_eq2(s, TCG_TMP0, TCG_TMP1, al, ah, bl, bh);
781 break;
782
783 default:
784 /* Minimize code size by preferring a compare not requiring INV. */
785 if (mips_cmp_map[cond] & MIPS_CMP_INV) {
786 cond = tcg_invert_cond(cond);
787 b_cond = TCG_COND_EQ;
788 }
789 tcg_out_setcond2(s, cond, tmp, al, ah, bl, bh);
790 break;
791 }
792
793 tcg_out_brcond(s, b_cond, tmp, TCG_REG_ZERO, label_index);
794 }
795
tcg_out_movcond(TCGContext * s,TCGCond cond,TCGReg ret,TCGReg c1,TCGReg c2,TCGReg v)796 static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
797 TCGReg c1, TCGReg c2, TCGReg v)
798 {
799 MIPSInsn m_opc = OPC_MOVN;
800
801 switch (cond) {
802 case TCG_COND_EQ:
803 m_opc = OPC_MOVZ;
804 /* FALLTHRU */
805 case TCG_COND_NE:
806 if (c2 != 0) {
807 tcg_out_opc_reg(s, OPC_XOR, TCG_TMP0, c1, c2);
808 c1 = TCG_TMP0;
809 }
810 break;
811
812 default:
813 /* Minimize code size by preferring a compare not requiring INV. */
814 if (mips_cmp_map[cond] & MIPS_CMP_INV) {
815 cond = tcg_invert_cond(cond);
816 m_opc = OPC_MOVZ;
817 }
818 tcg_out_setcond(s, cond, TCG_TMP0, c1, c2);
819 c1 = TCG_TMP0;
820 break;
821 }
822
823 tcg_out_opc_reg(s, m_opc, ret, v, c1);
824 }
825
tcg_out_call_int(TCGContext * s,tcg_insn_unit * arg,bool tail)826 static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
827 {
828 /* Note that the ABI requires the called function's address to be
829 loaded into T9, even if a direct branch is in range. */
830 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T9, (uintptr_t)arg);
831
832 /* But do try a direct branch, allowing the cpu better insn prefetch. */
833 if (tail) {
834 if (!tcg_out_opc_jmp(s, OPC_J, arg)) {
835 tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_T9, 0);
836 }
837 } else {
838 if (!tcg_out_opc_jmp(s, OPC_JAL, arg)) {
839 tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
840 }
841 }
842 }
843
tcg_out_call(TCGContext * s,tcg_insn_unit * arg)844 static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
845 {
846 tcg_out_call_int(s, arg, false);
847 tcg_out_nop(s);
848 }
849
850 #if defined(CONFIG_SOFTMMU)
851 static void * const qemu_ld_helpers[16] = {
852 [MO_UB] = helper_ret_ldub_mmu,
853 [MO_SB] = helper_ret_ldsb_mmu,
854 [MO_LEUW] = helper_le_lduw_mmu,
855 [MO_LESW] = helper_le_ldsw_mmu,
856 [MO_LEUL] = helper_le_ldul_mmu,
857 [MO_LEQ] = helper_le_ldq_mmu,
858 [MO_BEUW] = helper_be_lduw_mmu,
859 [MO_BESW] = helper_be_ldsw_mmu,
860 [MO_BEUL] = helper_be_ldul_mmu,
861 [MO_BEQ] = helper_be_ldq_mmu,
862 };
863
864 static void * const qemu_st_helpers[16] = {
865 [MO_UB] = helper_ret_stb_mmu,
866 [MO_LEUW] = helper_le_stw_mmu,
867 [MO_LEUL] = helper_le_stl_mmu,
868 [MO_LEQ] = helper_le_stq_mmu,
869 [MO_BEUW] = helper_be_stw_mmu,
870 [MO_BEUL] = helper_be_stl_mmu,
871 [MO_BEQ] = helper_be_stq_mmu,
872 };
873
874 /* Helper routines for marshalling helper function arguments into
875 * the correct registers and stack.
876 * I is where we want to put this argument, and is updated and returned
877 * for the next call. ARG is the argument itself.
878 *
879 * We provide routines for arguments which are: immediate, 32 bit
880 * value in register, 16 and 8 bit values in register (which must be zero
881 * extended before use) and 64 bit value in a lo:hi register pair.
882 */
883
tcg_out_call_iarg_reg(TCGContext * s,int i,TCGReg arg)884 static int tcg_out_call_iarg_reg(TCGContext *s, int i, TCGReg arg)
885 {
886 if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
887 tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[i], arg);
888 } else {
889 tcg_out_st(s, TCG_TYPE_REG, arg, TCG_REG_SP, 4 * i);
890 }
891 return i + 1;
892 }
893
tcg_out_call_iarg_reg8(TCGContext * s,int i,TCGReg arg)894 static int tcg_out_call_iarg_reg8(TCGContext *s, int i, TCGReg arg)
895 {
896 TCGReg tmp = TCG_TMP0;
897 if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
898 tmp = tcg_target_call_iarg_regs[i];
899 }
900 tcg_out_opc_imm(s, OPC_ANDI, tmp, arg, 0xff);
901 return tcg_out_call_iarg_reg(s, i, tmp);
902 }
903
tcg_out_call_iarg_reg16(TCGContext * s,int i,TCGReg arg)904 static int tcg_out_call_iarg_reg16(TCGContext *s, int i, TCGReg arg)
905 {
906 TCGReg tmp = TCG_TMP0;
907 if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
908 tmp = tcg_target_call_iarg_regs[i];
909 }
910 tcg_out_opc_imm(s, OPC_ANDI, tmp, arg, 0xffff);
911 return tcg_out_call_iarg_reg(s, i, tmp);
912 }
913
tcg_out_call_iarg_imm(TCGContext * s,int i,TCGArg arg)914 static int tcg_out_call_iarg_imm(TCGContext *s, int i, TCGArg arg)
915 {
916 TCGReg tmp = TCG_TMP0;
917 if (arg == 0) {
918 tmp = TCG_REG_ZERO;
919 } else {
920 if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
921 tmp = tcg_target_call_iarg_regs[i];
922 }
923 tcg_out_movi(s, TCG_TYPE_REG, tmp, arg);
924 }
925 return tcg_out_call_iarg_reg(s, i, tmp);
926 }
927
tcg_out_call_iarg_reg2(TCGContext * s,int i,TCGReg al,TCGReg ah)928 static int tcg_out_call_iarg_reg2(TCGContext *s, int i, TCGReg al, TCGReg ah)
929 {
930 i = (i + 1) & ~1;
931 i = tcg_out_call_iarg_reg(s, i, (MIPS_BE ? ah : al));
932 i = tcg_out_call_iarg_reg(s, i, (MIPS_BE ? al : ah));
933 return i;
934 }
935
936 /* Perform the tlb comparison operation. The complete host address is
937 placed in BASE. Clobbers AT, T0, A0. */
tcg_out_tlb_load(TCGContext * s,TCGReg base,TCGReg addrl,TCGReg addrh,int mem_index,TCGMemOp s_bits,tcg_insn_unit * label_ptr[2],bool is_load)938 static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
939 TCGReg addrh, int mem_index, TCGMemOp s_bits,
940 tcg_insn_unit *label_ptr[2], bool is_load)
941 {
942 int cmp_off
943 = (is_load
944 ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
945 : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write));
946 int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend);
947
948 tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addrl,
949 TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
950 tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0,
951 (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
952 tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
953
954 /* Compensate for very large offsets. */
955 if (add_off >= 0x8000) {
956 /* Most target env are smaller than 32k; none are larger than 64k.
957 Simplify the logic here merely to offset by 0x7ff0, giving us a
958 range just shy of 64k. Check this assumption. */
959 QEMU_BUILD_BUG_ON(offsetof(CPUArchState,
960 tlb_table[NB_MMU_MODES - 1][1])
961 > 0x7ff0 + 0x7fff);
962 tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_A0, TCG_REG_A0, 0x7ff0);
963 cmp_off -= 0x7ff0;
964 add_off -= 0x7ff0;
965 }
966
967 /* Load the tlb comparator. */
968 tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
969 if (TARGET_LONG_BITS == 64) {
970 tcg_out_opc_imm(s, OPC_LW, base, TCG_REG_A0, cmp_off + HI_OFF);
971 }
972
973 /* Mask the page bits, keeping the alignment bits to compare against.
974 In between, load the tlb addend for the fast path. */
975 tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1,
976 TARGET_PAGE_MASK | ((1 << s_bits) - 1));
977 tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
978 tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrl);
979
980 label_ptr[0] = s->code_ptr;
981 tcg_out_opc_br(s, OPC_BNE, TCG_TMP1, TCG_TMP0);
982
983 if (TARGET_LONG_BITS == 64) {
984 /* delay slot */
985 tcg_out_nop(s);
986
987 label_ptr[1] = s->code_ptr;
988 tcg_out_opc_br(s, OPC_BNE, addrh, base);
989 }
990
991 /* delay slot */
992 tcg_out_opc_reg(s, OPC_ADDU, base, TCG_REG_A0, addrl);
993 }
994
add_qemu_ldst_label(TCGContext * s,int is_ld,TCGMemOp opc,TCGReg datalo,TCGReg datahi,TCGReg addrlo,TCGReg addrhi,int mem_index,void * raddr,tcg_insn_unit * label_ptr[2])995 static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOp opc,
996 TCGReg datalo, TCGReg datahi,
997 TCGReg addrlo, TCGReg addrhi,
998 int mem_index, void *raddr,
999 tcg_insn_unit *label_ptr[2])
1000 {
1001 TCGLabelQemuLdst *label = new_ldst_label(s);
1002
1003 label->is_ld = is_ld;
1004 label->opc = opc;
1005 label->datalo_reg = datalo;
1006 label->datahi_reg = datahi;
1007 label->addrlo_reg = addrlo;
1008 label->addrhi_reg = addrhi;
1009 label->mem_index = mem_index;
1010 label->raddr = raddr;
1011 label->label_ptr[0] = label_ptr[0];
1012 if (TARGET_LONG_BITS == 64) {
1013 label->label_ptr[1] = label_ptr[1];
1014 }
1015 }
1016
tcg_out_qemu_ld_slow_path(TCGContext * s,TCGLabelQemuLdst * l)1017 static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
1018 {
1019 TCGMemOp opc = l->opc;
1020 TCGReg v0;
1021 int i;
1022
1023 /* resolve label address */
1024 reloc_pc16(l->label_ptr[0], s->code_ptr);
1025 if (TARGET_LONG_BITS == 64) {
1026 reloc_pc16(l->label_ptr[1], s->code_ptr);
1027 }
1028
1029 i = 1;
1030 if (TARGET_LONG_BITS == 64) {
1031 i = tcg_out_call_iarg_reg2(s, i, l->addrlo_reg, l->addrhi_reg);
1032 } else {
1033 i = tcg_out_call_iarg_reg(s, i, l->addrlo_reg);
1034 }
1035 i = tcg_out_call_iarg_imm(s, i, l->mem_index);
1036 i = tcg_out_call_iarg_imm(s, i, (intptr_t)l->raddr);
1037 tcg_out_call_int(s, qemu_ld_helpers[opc], false);
1038 /* delay slot */
1039 tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
1040
1041 v0 = l->datalo_reg;
1042 if ((opc & MO_SIZE) == MO_64) {
1043 /* We eliminated V0 from the possible output registers, so it
1044 cannot be clobbered here. So we must move V1 first. */
1045 if (MIPS_BE) {
1046 tcg_out_mov(s, TCG_TYPE_I32, v0, TCG_REG_V1);
1047 v0 = l->datahi_reg;
1048 } else {
1049 tcg_out_mov(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_V1);
1050 }
1051 }
1052
1053 reloc_pc16(s->code_ptr, l->raddr);
1054 tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
1055 /* delay slot */
1056 tcg_out_mov(s, TCG_TYPE_REG, v0, TCG_REG_V0);
1057 }
1058
tcg_out_qemu_st_slow_path(TCGContext * s,TCGLabelQemuLdst * l)1059 static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
1060 {
1061 TCGMemOp opc = l->opc;
1062 TCGMemOp s_bits = opc & MO_SIZE;
1063 int i;
1064
1065 /* resolve label address */
1066 reloc_pc16(l->label_ptr[0], s->code_ptr);
1067 if (TARGET_LONG_BITS == 64) {
1068 reloc_pc16(l->label_ptr[1], s->code_ptr);
1069 }
1070
1071 i = 1;
1072 if (TARGET_LONG_BITS == 64) {
1073 i = tcg_out_call_iarg_reg2(s, i, l->addrlo_reg, l->addrhi_reg);
1074 } else {
1075 i = tcg_out_call_iarg_reg(s, i, l->addrlo_reg);
1076 }
1077 switch (s_bits) {
1078 case MO_8:
1079 i = tcg_out_call_iarg_reg8(s, i, l->datalo_reg);
1080 break;
1081 case MO_16:
1082 i = tcg_out_call_iarg_reg16(s, i, l->datalo_reg);
1083 break;
1084 case MO_32:
1085 i = tcg_out_call_iarg_reg(s, i, l->datalo_reg);
1086 break;
1087 case MO_64:
1088 i = tcg_out_call_iarg_reg2(s, i, l->datalo_reg, l->datahi_reg);
1089 break;
1090 default:
1091 tcg_abort();
1092 }
1093 i = tcg_out_call_iarg_imm(s, i, l->mem_index);
1094
1095 /* Tail call to the store helper. Thus force the return address
1096 computation to take place in the return address register. */
1097 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (intptr_t)l->raddr);
1098 i = tcg_out_call_iarg_reg(s, i, TCG_REG_RA);
1099 tcg_out_call_int(s, qemu_st_helpers[opc], true);
1100 /* delay slot */
1101 tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
1102 }
1103 #endif
1104
tcg_out_qemu_ld_direct(TCGContext * s,TCGReg datalo,TCGReg datahi,TCGReg base,TCGMemOp opc)1105 static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
1106 TCGReg base, TCGMemOp opc)
1107 {
1108 switch (opc) {
1109 case MO_UB:
1110 tcg_out_opc_imm(s, OPC_LBU, datalo, base, 0);
1111 break;
1112 case MO_SB:
1113 tcg_out_opc_imm(s, OPC_LB, datalo, base, 0);
1114 break;
1115 case MO_UW | MO_BSWAP:
1116 tcg_out_opc_imm(s, OPC_LHU, TCG_TMP1, base, 0);
1117 tcg_out_bswap16(s, datalo, TCG_TMP1);
1118 break;
1119 case MO_UW:
1120 tcg_out_opc_imm(s, OPC_LHU, datalo, base, 0);
1121 break;
1122 case MO_SW | MO_BSWAP:
1123 tcg_out_opc_imm(s, OPC_LHU, TCG_TMP1, base, 0);
1124 tcg_out_bswap16s(s, datalo, TCG_TMP1);
1125 break;
1126 case MO_SW:
1127 tcg_out_opc_imm(s, OPC_LH, datalo, base, 0);
1128 break;
1129 case MO_UL | MO_BSWAP:
1130 tcg_out_opc_imm(s, OPC_LW, TCG_TMP1, base, 0);
1131 tcg_out_bswap32(s, datalo, TCG_TMP1);
1132 break;
1133 case MO_UL:
1134 tcg_out_opc_imm(s, OPC_LW, datalo, base, 0);
1135 break;
1136 case MO_Q | MO_BSWAP:
1137 tcg_out_opc_imm(s, OPC_LW, TCG_TMP1, base, HI_OFF);
1138 tcg_out_bswap32(s, datalo, TCG_TMP1);
1139 tcg_out_opc_imm(s, OPC_LW, TCG_TMP1, base, LO_OFF);
1140 tcg_out_bswap32(s, datahi, TCG_TMP1);
1141 break;
1142 case MO_Q:
1143 tcg_out_opc_imm(s, OPC_LW, datalo, base, LO_OFF);
1144 tcg_out_opc_imm(s, OPC_LW, datahi, base, HI_OFF);
1145 break;
1146 default:
1147 tcg_abort();
1148 }
1149 }
1150
tcg_out_qemu_ld(TCGContext * s,const TCGArg * args,bool is_64)1151 static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
1152 {
1153 TCGReg addr_regl, addr_regh QEMU_UNUSED_VAR;
1154 TCGReg data_regl, data_regh;
1155 TCGMemOp opc;
1156 #if defined(CONFIG_SOFTMMU)
1157 tcg_insn_unit *label_ptr[2];
1158 int mem_index;
1159 TCGMemOp s_bits;
1160 #endif
1161 /* Note that we've eliminated V0 from the output registers,
1162 so we won't overwrite the base register during loading. */
1163 TCGReg base = TCG_REG_V0;
1164
1165 data_regl = *args++;
1166 data_regh = (is_64 ? *args++ : 0);
1167 addr_regl = *args++;
1168 addr_regh = (TARGET_LONG_BITS == 64 ? *args++ : 0);
1169 opc = *args++;
1170
1171 #if defined(CONFIG_SOFTMMU)
1172 mem_index = *args;
1173 s_bits = opc & MO_SIZE;
1174
1175 tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
1176 s_bits, label_ptr, 1);
1177 tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc);
1178 add_qemu_ldst_label(s, 1, opc, data_regl, data_regh, addr_regl, addr_regh,
1179 mem_index, s->code_ptr, label_ptr);
1180 #else
1181 if (GUEST_BASE == 0 && data_regl != addr_regl) {
1182 base = addr_regl;
1183 } else if (GUEST_BASE == (int16_t)GUEST_BASE) {
1184 tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, GUEST_BASE);
1185 } else {
1186 tcg_out_movi(s, TCG_TYPE_PTR, base, GUEST_BASE);
1187 tcg_out_opc_reg(s, OPC_ADDU, base, base, addr_regl);
1188 }
1189 tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc);
1190 #endif
1191 }
1192
tcg_out_qemu_st_direct(TCGContext * s,TCGReg datalo,TCGReg datahi,TCGReg base,TCGMemOp opc)1193 static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
1194 TCGReg base, TCGMemOp opc)
1195 {
1196 switch (opc) {
1197 case MO_8:
1198 tcg_out_opc_imm(s, OPC_SB, datalo, base, 0);
1199 break;
1200
1201 case MO_16 | MO_BSWAP:
1202 tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP1, datalo, 0xffff);
1203 tcg_out_bswap16(s, TCG_TMP1, TCG_TMP1);
1204 datalo = TCG_TMP1;
1205 /* FALLTHRU */
1206 case MO_16:
1207 tcg_out_opc_imm(s, OPC_SH, datalo, base, 0);
1208 break;
1209
1210 case MO_32 | MO_BSWAP:
1211 tcg_out_bswap32(s, TCG_TMP1, datalo);
1212 datalo = TCG_TMP1;
1213 /* FALLTHRU */
1214 case MO_32:
1215 tcg_out_opc_imm(s, OPC_SW, datalo, base, 0);
1216 break;
1217
1218 case MO_64 | MO_BSWAP:
1219 tcg_out_bswap32(s, TCG_TMP1, datalo);
1220 tcg_out_opc_imm(s, OPC_SW, TCG_TMP1, base, HI_OFF);
1221 tcg_out_bswap32(s, TCG_TMP1, datahi);
1222 tcg_out_opc_imm(s, OPC_SW, TCG_TMP1, base, LO_OFF);
1223 break;
1224 case MO_64:
1225 tcg_out_opc_imm(s, OPC_SW, datalo, base, LO_OFF);
1226 tcg_out_opc_imm(s, OPC_SW, datahi, base, HI_OFF);
1227 break;
1228
1229 default:
1230 tcg_abort();
1231 }
1232 }
1233
tcg_out_addsub2(TCGContext * s,TCGReg rl,TCGReg rh,TCGReg al,TCGReg ah,TCGArg bl,TCGArg bh,bool cbl,bool cbh,bool is_sub)1234 static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
1235 TCGReg ah, TCGArg bl, TCGArg bh, bool cbl,
1236 bool cbh, bool is_sub)
1237 {
1238 TCGReg th = TCG_TMP1;
1239
1240 /* If we have a negative constant such that negating it would
1241 make the high part zero, we can (usually) eliminate one insn. */
1242 if (cbl && cbh && bh == -1 && bl != 0) {
1243 bl = -bl;
1244 bh = 0;
1245 is_sub = !is_sub;
1246 }
1247
1248 /* By operating on the high part first, we get to use the final
1249 carry operation to move back from the temporary. */
1250 if (!cbh) {
1251 tcg_out_opc_reg(s, (is_sub ? OPC_SUBU : OPC_ADDU), th, ah, bh);
1252 } else if (bh != 0 || ah == rl) {
1253 tcg_out_opc_imm(s, OPC_ADDIU, th, ah, (is_sub ? -bh : bh));
1254 } else {
1255 th = ah;
1256 }
1257
1258 /* Note that tcg optimization should eliminate the bl == 0 case. */
1259 if (is_sub) {
1260 if (cbl) {
1261 tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, al, bl);
1262 tcg_out_opc_imm(s, OPC_ADDIU, rl, al, -bl);
1263 } else {
1264 tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, al, bl);
1265 tcg_out_opc_reg(s, OPC_SUBU, rl, al, bl);
1266 }
1267 tcg_out_opc_reg(s, OPC_SUBU, rh, th, TCG_TMP0);
1268 } else {
1269 if (cbl) {
1270 tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
1271 tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
1272 } else {
1273 tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
1274 tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl));
1275 }
1276 tcg_out_opc_reg(s, OPC_ADDU, rh, th, TCG_TMP0);
1277 }
1278 }
1279
tcg_out_qemu_st(TCGContext * s,const TCGArg * args,bool is_64)1280 static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
1281 {
1282 TCGReg addr_regl, addr_regh QEMU_UNUSED_VAR;
1283 TCGReg data_regl, data_regh, base;
1284 TCGMemOp opc;
1285 #if defined(CONFIG_SOFTMMU)
1286 tcg_insn_unit *label_ptr[2];
1287 int mem_index;
1288 TCGMemOp s_bits;
1289 #endif
1290
1291 data_regl = *args++;
1292 data_regh = (is_64 ? *args++ : 0);
1293 addr_regl = *args++;
1294 addr_regh = (TARGET_LONG_BITS == 64 ? *args++ : 0);
1295 opc = *args++;
1296
1297 #if defined(CONFIG_SOFTMMU)
1298 mem_index = *args;
1299 s_bits = opc & 3;
1300
1301 /* Note that we eliminated the helper's address argument,
1302 so we can reuse that for the base. */
1303 base = (TARGET_LONG_BITS == 32 ? TCG_REG_A1 : TCG_REG_A2);
1304 tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
1305 s_bits, label_ptr, 0);
1306 tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
1307 add_qemu_ldst_label(s, 0, opc, data_regl, data_regh, addr_regl, addr_regh,
1308 mem_index, s->code_ptr, label_ptr);
1309 #else
1310 if (GUEST_BASE == 0) {
1311 base = addr_regl;
1312 } else {
1313 base = TCG_REG_A0;
1314 if (GUEST_BASE == (int16_t)GUEST_BASE) {
1315 tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, GUEST_BASE);
1316 } else {
1317 tcg_out_movi(s, TCG_TYPE_PTR, base, GUEST_BASE);
1318 tcg_out_opc_reg(s, OPC_ADDU, base, base, addr_regl);
1319 }
1320 }
1321 tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
1322 #endif
1323 }
1324
tcg_out_op(TCGContext * s,TCGOpcode opc,const TCGArg * args,const int * const_args)1325 static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
1326 const TCGArg *args, const int *const_args)
1327 {
1328 MIPSInsn i1, i2;
1329 TCGArg a0, a1, a2;
1330 int c2;
1331
1332 a0 = args[0];
1333 a1 = args[1];
1334 a2 = args[2];
1335 c2 = const_args[2];
1336
1337 switch (opc) {
1338 case INDEX_op_exit_tb:
1339 {
1340 TCGReg b0 = TCG_REG_ZERO;
1341
1342 if (a0 & ~0xffff) {
1343 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff);
1344 b0 = TCG_REG_V0;
1345 }
1346 if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) {
1347 tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0,
1348 (uintptr_t)tb_ret_addr);
1349 tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
1350 }
1351 tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff);
1352 }
1353 break;
1354 case INDEX_op_goto_tb:
1355 if (s->tb_jmp_offset) {
1356 /* direct jump method */
1357 s->tb_jmp_offset[a0] = tcg_current_code_size(s);
1358 /* Avoid clobbering the address during retranslation. */
1359 tcg_out32(s, OPC_J | (*(uint32_t *)s->code_ptr & 0x3ffffff));
1360 } else {
1361 /* indirect jump method */
1362 tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
1363 (uintptr_t)(s->tb_next + a0));
1364 tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
1365 }
1366 tcg_out_nop(s);
1367 s->tb_next_offset[a0] = tcg_current_code_size(s);
1368 break;
1369 case INDEX_op_br:
1370 tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, a0);
1371 break;
1372
1373 case INDEX_op_ld8u_i32:
1374 i1 = OPC_LBU;
1375 goto do_ldst;
1376 case INDEX_op_ld8s_i32:
1377 i1 = OPC_LB;
1378 goto do_ldst;
1379 case INDEX_op_ld16u_i32:
1380 i1 = OPC_LHU;
1381 goto do_ldst;
1382 case INDEX_op_ld16s_i32:
1383 i1 = OPC_LH;
1384 goto do_ldst;
1385 case INDEX_op_ld_i32:
1386 i1 = OPC_LW;
1387 goto do_ldst;
1388 case INDEX_op_st8_i32:
1389 i1 = OPC_SB;
1390 goto do_ldst;
1391 case INDEX_op_st16_i32:
1392 i1 = OPC_SH;
1393 goto do_ldst;
1394 case INDEX_op_st_i32:
1395 i1 = OPC_SW;
1396 do_ldst:
1397 tcg_out_ldst(s, i1, a0, a1, a2);
1398 break;
1399
1400 case INDEX_op_add_i32:
1401 i1 = OPC_ADDU, i2 = OPC_ADDIU;
1402 goto do_binary;
1403 case INDEX_op_or_i32:
1404 i1 = OPC_OR, i2 = OPC_ORI;
1405 goto do_binary;
1406 case INDEX_op_xor_i32:
1407 i1 = OPC_XOR, i2 = OPC_XORI;
1408 do_binary:
1409 if (c2) {
1410 tcg_out_opc_imm(s, i2, a0, a1, a2);
1411 break;
1412 }
1413 do_binaryv:
1414 tcg_out_opc_reg(s, i1, a0, a1, a2);
1415 break;
1416
1417 case INDEX_op_sub_i32:
1418 if (c2) {
1419 tcg_out_opc_imm(s, OPC_ADDIU, a0, a1, -a2);
1420 break;
1421 }
1422 i1 = OPC_SUBU;
1423 goto do_binary;
1424 case INDEX_op_and_i32:
1425 if (c2 && a2 != (uint16_t)a2) {
1426 int msb = ctz32(~a2) - 1;
1427 assert(use_mips32r2_instructions);
1428 assert(is_p2m1(a2));
1429 tcg_out_opc_bf(s, OPC_EXT, a0, a1, msb, 0);
1430 break;
1431 }
1432 i1 = OPC_AND, i2 = OPC_ANDI;
1433 goto do_binary;
1434 case INDEX_op_nor_i32:
1435 i1 = OPC_NOR;
1436 goto do_binaryv;
1437
1438 case INDEX_op_mul_i32:
1439 if (use_mips32_instructions) {
1440 tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2);
1441 break;
1442 }
1443 i1 = OPC_MULT, i2 = OPC_MFLO;
1444 goto do_hilo1;
1445 case INDEX_op_mulsh_i32:
1446 i1 = OPC_MULT, i2 = OPC_MFHI;
1447 goto do_hilo1;
1448 case INDEX_op_muluh_i32:
1449 i1 = OPC_MULTU, i2 = OPC_MFHI;
1450 goto do_hilo1;
1451 case INDEX_op_div_i32:
1452 i1 = OPC_DIV, i2 = OPC_MFLO;
1453 goto do_hilo1;
1454 case INDEX_op_divu_i32:
1455 i1 = OPC_DIVU, i2 = OPC_MFLO;
1456 goto do_hilo1;
1457 case INDEX_op_rem_i32:
1458 i1 = OPC_DIV, i2 = OPC_MFHI;
1459 goto do_hilo1;
1460 case INDEX_op_remu_i32:
1461 i1 = OPC_DIVU, i2 = OPC_MFHI;
1462 do_hilo1:
1463 tcg_out_opc_reg(s, i1, 0, a1, a2);
1464 tcg_out_opc_reg(s, i2, a0, 0, 0);
1465 break;
1466
1467 case INDEX_op_muls2_i32:
1468 i1 = OPC_MULT;
1469 goto do_hilo2;
1470 case INDEX_op_mulu2_i32:
1471 i1 = OPC_MULTU;
1472 do_hilo2:
1473 tcg_out_opc_reg(s, i1, 0, a2, args[3]);
1474 tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0);
1475 tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0);
1476 break;
1477
1478 case INDEX_op_not_i32:
1479 i1 = OPC_NOR;
1480 goto do_unary;
1481 case INDEX_op_bswap16_i32:
1482 i1 = OPC_WSBH;
1483 goto do_unary;
1484 case INDEX_op_ext8s_i32:
1485 i1 = OPC_SEB;
1486 goto do_unary;
1487 case INDEX_op_ext16s_i32:
1488 i1 = OPC_SEH;
1489 do_unary:
1490 tcg_out_opc_reg(s, i1, a0, TCG_REG_ZERO, a1);
1491 break;
1492
1493 case INDEX_op_sar_i32:
1494 i1 = OPC_SRAV, i2 = OPC_SRA;
1495 goto do_shift;
1496 case INDEX_op_shl_i32:
1497 i1 = OPC_SLLV, i2 = OPC_SLL;
1498 goto do_shift;
1499 case INDEX_op_shr_i32:
1500 i1 = OPC_SRLV, i2 = OPC_SRL;
1501 goto do_shift;
1502 case INDEX_op_rotr_i32:
1503 i1 = OPC_ROTRV, i2 = OPC_ROTR;
1504 do_shift:
1505 if (c2) {
1506 tcg_out_opc_sa(s, i2, a0, a1, a2);
1507 } else {
1508 tcg_out_opc_reg(s, i1, a0, a2, a1);
1509 }
1510 break;
1511 case INDEX_op_rotl_i32:
1512 if (c2) {
1513 tcg_out_opc_sa(s, OPC_ROTR, a0, a1, 32 - a2);
1514 } else {
1515 tcg_out_opc_reg(s, OPC_SUBU, TCG_TMP0, TCG_REG_ZERO, a2);
1516 tcg_out_opc_reg(s, OPC_ROTRV, a0, TCG_TMP0, a1);
1517 }
1518 break;
1519
1520 case INDEX_op_bswap32_i32:
1521 tcg_out_opc_reg(s, OPC_WSBH, a0, 0, a1);
1522 tcg_out_opc_sa(s, OPC_ROTR, a0, a0, 16);
1523 break;
1524
1525 case INDEX_op_deposit_i32:
1526 tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]);
1527 break;
1528
1529 case INDEX_op_brcond_i32:
1530 tcg_out_brcond(s, a2, a0, a1, args[3]);
1531 break;
1532 case INDEX_op_brcond2_i32:
1533 tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], args[5]);
1534 break;
1535
1536 case INDEX_op_movcond_i32:
1537 tcg_out_movcond(s, args[5], a0, a1, a2, args[3]);
1538 break;
1539
1540 case INDEX_op_setcond_i32:
1541 tcg_out_setcond(s, args[3], a0, a1, a2);
1542 break;
1543 case INDEX_op_setcond2_i32:
1544 tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]);
1545 break;
1546
1547 case INDEX_op_qemu_ld_i32:
1548 tcg_out_qemu_ld(s, args, false);
1549 break;
1550 case INDEX_op_qemu_ld_i64:
1551 tcg_out_qemu_ld(s, args, true);
1552 break;
1553 case INDEX_op_qemu_st_i32:
1554 tcg_out_qemu_st(s, args, false);
1555 break;
1556 case INDEX_op_qemu_st_i64:
1557 tcg_out_qemu_st(s, args, true);
1558 break;
1559
1560 case INDEX_op_add2_i32:
1561 tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
1562 const_args[4], const_args[5], false);
1563 break;
1564 case INDEX_op_sub2_i32:
1565 tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
1566 const_args[4], const_args[5], true);
1567 break;
1568
1569 case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
1570 case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */
1571 case INDEX_op_call: /* Always emitted via tcg_out_call. */
1572 default:
1573 tcg_abort();
1574 }
1575 }
1576
1577 static const TCGTargetOpDef mips_op_defs[] = {
1578 { INDEX_op_exit_tb, { } },
1579 { INDEX_op_goto_tb, { } },
1580 { INDEX_op_br, { } },
1581
1582 { INDEX_op_ld8u_i32, { "r", "r" } },
1583 { INDEX_op_ld8s_i32, { "r", "r" } },
1584 { INDEX_op_ld16u_i32, { "r", "r" } },
1585 { INDEX_op_ld16s_i32, { "r", "r" } },
1586 { INDEX_op_ld_i32, { "r", "r" } },
1587 { INDEX_op_st8_i32, { "rZ", "r" } },
1588 { INDEX_op_st16_i32, { "rZ", "r" } },
1589 { INDEX_op_st_i32, { "rZ", "r" } },
1590
1591 { INDEX_op_add_i32, { "r", "rZ", "rJ" } },
1592 { INDEX_op_mul_i32, { "r", "rZ", "rZ" } },
1593 { INDEX_op_muls2_i32, { "r", "r", "rZ", "rZ" } },
1594 { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } },
1595 { INDEX_op_mulsh_i32, { "r", "rZ", "rZ" } },
1596 { INDEX_op_muluh_i32, { "r", "rZ", "rZ" } },
1597 { INDEX_op_div_i32, { "r", "rZ", "rZ" } },
1598 { INDEX_op_divu_i32, { "r", "rZ", "rZ" } },
1599 { INDEX_op_rem_i32, { "r", "rZ", "rZ" } },
1600 { INDEX_op_remu_i32, { "r", "rZ", "rZ" } },
1601 { INDEX_op_sub_i32, { "r", "rZ", "rN" } },
1602
1603 { INDEX_op_and_i32, { "r", "rZ", "rIK" } },
1604 { INDEX_op_nor_i32, { "r", "rZ", "rZ" } },
1605 { INDEX_op_not_i32, { "r", "rZ" } },
1606 { INDEX_op_or_i32, { "r", "rZ", "rIZ" } },
1607 { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } },
1608
1609 { INDEX_op_shl_i32, { "r", "rZ", "ri" } },
1610 { INDEX_op_shr_i32, { "r", "rZ", "ri" } },
1611 { INDEX_op_sar_i32, { "r", "rZ", "ri" } },
1612 { INDEX_op_rotr_i32, { "r", "rZ", "ri" } },
1613 { INDEX_op_rotl_i32, { "r", "rZ", "ri" } },
1614
1615 { INDEX_op_bswap16_i32, { "r", "r" } },
1616 { INDEX_op_bswap32_i32, { "r", "r" } },
1617
1618 { INDEX_op_ext8s_i32, { "r", "rZ" } },
1619 { INDEX_op_ext16s_i32, { "r", "rZ" } },
1620
1621 { INDEX_op_deposit_i32, { "r", "0", "rZ" } },
1622
1623 { INDEX_op_brcond_i32, { "rZ", "rZ" } },
1624 { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rZ", "0" } },
1625 { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
1626 { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } },
1627
1628 { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rN", "rN" } },
1629 { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rN", "rN" } },
1630 { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } },
1631
1632 #if TARGET_LONG_BITS == 32
1633 { INDEX_op_qemu_ld_i32, { "L", "lZ" } },
1634 { INDEX_op_qemu_st_i32, { "SZ", "SZ" } },
1635 { INDEX_op_qemu_ld_i64, { "L", "L", "lZ" } },
1636 { INDEX_op_qemu_st_i64, { "SZ", "SZ", "SZ" } },
1637 #else
1638 { INDEX_op_qemu_ld_i32, { "L", "lZ", "lZ" } },
1639 { INDEX_op_qemu_st_i32, { "SZ", "SZ", "SZ" } },
1640 { INDEX_op_qemu_ld_i64, { "L", "L", "lZ", "lZ" } },
1641 { INDEX_op_qemu_st_i64, { "SZ", "SZ", "SZ", "SZ" } },
1642 #endif
1643 { -1 },
1644 };
1645
1646 static int tcg_target_callee_save_regs[] = {
1647 TCG_REG_S0, /* used for the global env (TCG_AREG0) */
1648 TCG_REG_S1,
1649 TCG_REG_S2,
1650 TCG_REG_S3,
1651 TCG_REG_S4,
1652 TCG_REG_S5,
1653 TCG_REG_S6,
1654 TCG_REG_S7,
1655 TCG_REG_S8,
1656 TCG_REG_RA, /* should be last for ABI compliance */
1657 };
1658
1659 /* The Linux kernel doesn't provide any information about the available
1660 instruction set. Probe it using a signal handler. */
1661
1662 #include <signal.h>
1663
1664 #ifndef use_movnz_instructions
1665 bool use_movnz_instructions = false;
1666 #endif
1667
1668 #ifndef use_mips32_instructions
1669 bool use_mips32_instructions = false;
1670 #endif
1671
1672 #ifndef use_mips32r2_instructions
1673 bool use_mips32r2_instructions = false;
1674 #endif
1675
1676 static volatile sig_atomic_t got_sigill;
1677
sigill_handler(int signo,siginfo_t * si,void * data)1678 static void sigill_handler(int signo, siginfo_t *si, void *data)
1679 {
1680 /* Skip the faulty instruction */
1681 ucontext_t *uc = (ucontext_t *)data;
1682 uc->uc_mcontext.pc += 4;
1683
1684 got_sigill = 1;
1685 }
1686
tcg_target_detect_isa(void)1687 static void tcg_target_detect_isa(void)
1688 {
1689 struct sigaction sa_old, sa_new;
1690
1691 memset(&sa_new, 0, sizeof(sa_new));
1692 sa_new.sa_flags = SA_SIGINFO;
1693 sa_new.sa_sigaction = sigill_handler;
1694 sigaction(SIGILL, &sa_new, &sa_old);
1695
1696 /* Probe for movn/movz, necessary to implement movcond. */
1697 #ifndef use_movnz_instructions
1698 got_sigill = 0;
1699 asm volatile(".set push\n"
1700 ".set mips32\n"
1701 "movn $zero, $zero, $zero\n"
1702 "movz $zero, $zero, $zero\n"
1703 ".set pop\n"
1704 : : : );
1705 use_movnz_instructions = !got_sigill;
1706 #endif
1707
1708 /* Probe for MIPS32 instructions. As no subsetting is allowed
1709 by the specification, it is only necessary to probe for one
1710 of the instructions. */
1711 #ifndef use_mips32_instructions
1712 got_sigill = 0;
1713 asm volatile(".set push\n"
1714 ".set mips32\n"
1715 "mul $zero, $zero\n"
1716 ".set pop\n"
1717 : : : );
1718 use_mips32_instructions = !got_sigill;
1719 #endif
1720
1721 /* Probe for MIPS32r2 instructions if MIPS32 instructions are
1722 available. As no subsetting is allowed by the specification,
1723 it is only necessary to probe for one of the instructions. */
1724 #ifndef use_mips32r2_instructions
1725 if (use_mips32_instructions) {
1726 got_sigill = 0;
1727 asm volatile(".set push\n"
1728 ".set mips32r2\n"
1729 "seb $zero, $zero\n"
1730 ".set pop\n"
1731 : : : );
1732 use_mips32r2_instructions = !got_sigill;
1733 }
1734 #endif
1735
1736 sigaction(SIGILL, &sa_old, NULL);
1737 }
1738
1739 /* Generate global QEMU prologue and epilogue code */
tcg_target_qemu_prologue(TCGContext * s)1740 static void tcg_target_qemu_prologue(TCGContext *s)
1741 {
1742 int i, frame_size;
1743
1744 /* reserve some stack space, also for TCG temps. */
1745 frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4
1746 + TCG_STATIC_CALL_ARGS_SIZE
1747 + CPU_TEMP_BUF_NLONGS * sizeof(long);
1748 frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
1749 ~(TCG_TARGET_STACK_ALIGN - 1);
1750 tcg_set_frame(s, TCG_REG_SP, ARRAY_SIZE(tcg_target_callee_save_regs) * 4
1751 + TCG_STATIC_CALL_ARGS_SIZE,
1752 CPU_TEMP_BUF_NLONGS * sizeof(long));
1753
1754 /* TB prologue */
1755 tcg_out_addi(s, TCG_REG_SP, -frame_size);
1756 for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
1757 tcg_out_st(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
1758 TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
1759 }
1760
1761 /* Call generated code */
1762 tcg_out_opc_reg(s, OPC_JR, 0, tcg_target_call_iarg_regs[1], 0);
1763 tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
1764 tb_ret_addr = s->code_ptr;
1765
1766 /* TB epilogue */
1767 for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
1768 tcg_out_ld(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
1769 TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
1770 }
1771
1772 tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_RA, 0);
1773 tcg_out_addi(s, TCG_REG_SP, frame_size);
1774 }
1775
tcg_target_init(TCGContext * s)1776 static void tcg_target_init(TCGContext *s)
1777 {
1778 tcg_target_detect_isa();
1779 tcg_regset_set(s->tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff);
1780 tcg_regset_set(s->tcg_target_call_clobber_regs,
1781 (1 << TCG_REG_V0) |
1782 (1 << TCG_REG_V1) |
1783 (1 << TCG_REG_A0) |
1784 (1 << TCG_REG_A1) |
1785 (1 << TCG_REG_A2) |
1786 (1 << TCG_REG_A3) |
1787 (1 << TCG_REG_T0) |
1788 (1 << TCG_REG_T1) |
1789 (1 << TCG_REG_T2) |
1790 (1 << TCG_REG_T3) |
1791 (1 << TCG_REG_T4) |
1792 (1 << TCG_REG_T5) |
1793 (1 << TCG_REG_T6) |
1794 (1 << TCG_REG_T7) |
1795 (1 << TCG_REG_T8) |
1796 (1 << TCG_REG_T9));
1797
1798 tcg_regset_clear(s->reserved_regs);
1799 tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */
1800 tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0); /* kernel use only */
1801 tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1); /* kernel use only */
1802 tcg_regset_set_reg(s->reserved_regs, TCG_TMP0); /* internal use */
1803 tcg_regset_set_reg(s->reserved_regs, TCG_TMP1); /* internal use */
1804 tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */
1805 tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */
1806 tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP); /* global pointer */
1807
1808 tcg_add_target_add_op_defs(s, mips_op_defs);
1809 }
1810
tb_set_jmp_target1(uintptr_t jmp_addr,uintptr_t addr)1811 void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
1812 {
1813 uint32_t *ptr = (uint32_t *)jmp_addr;
1814 *ptr = deposit32(*ptr, 0, 26, addr >> 2);
1815 flush_icache_range(jmp_addr, jmp_addr + 4);
1816 }
1817