|
|
1.1 ! root 1: /* ! 2: * Tiny Code Generator for QEMU ! 3: * ! 4: * Copyright (c) 2008-2009 Arnaud Patard <[email protected]> ! 5: * Copyright (c) 2009 Aurelien Jarno <[email protected]> ! 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: #if defined(TCG_TARGET_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) ! 28: # define TCG_NEED_BSWAP 0 ! 29: #else ! 30: # define TCG_NEED_BSWAP 1 ! 31: #endif ! 32: ! 33: #ifndef NDEBUG ! 34: static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { ! 35: "zero", ! 36: "at", ! 37: "v0", ! 38: "v1", ! 39: "a0", ! 40: "a1", ! 41: "a2", ! 42: "a3", ! 43: "t0", ! 44: "t1", ! 45: "t2", ! 46: "t3", ! 47: "t4", ! 48: "t5", ! 49: "t6", ! 50: "t7", ! 51: "s0", ! 52: "s1", ! 53: "s2", ! 54: "s3", ! 55: "s4", ! 56: "s5", ! 57: "s6", ! 58: "s7", ! 59: "t8", ! 60: "t9", ! 61: "k0", ! 62: "k1", ! 63: "gp", ! 64: "sp", ! 65: "fp", ! 66: "ra", ! 67: }; ! 68: #endif ! 69: ! 70: /* check if we really need so many registers :P */ ! 71: static const int tcg_target_reg_alloc_order[] = { ! 72: TCG_REG_S0, ! 73: TCG_REG_S1, ! 74: TCG_REG_S2, ! 75: TCG_REG_S3, ! 76: TCG_REG_S4, ! 77: TCG_REG_S5, ! 78: TCG_REG_S6, ! 79: TCG_REG_S7, ! 80: TCG_REG_T1, ! 81: TCG_REG_T2, ! 82: TCG_REG_T3, ! 83: TCG_REG_T4, ! 84: TCG_REG_T5, ! 85: TCG_REG_T6, ! 86: TCG_REG_T7, ! 87: TCG_REG_T8, ! 88: TCG_REG_T9, ! 89: TCG_REG_A0, ! 90: TCG_REG_A1, ! 91: TCG_REG_A2, ! 92: TCG_REG_A3, ! 93: TCG_REG_V0, ! 94: TCG_REG_V1 ! 95: }; ! 96: ! 97: static const int tcg_target_call_iarg_regs[4] = { ! 98: TCG_REG_A0, ! 99: TCG_REG_A1, ! 100: TCG_REG_A2, ! 101: TCG_REG_A3 ! 102: }; ! 103: ! 104: static const int tcg_target_call_oarg_regs[2] = { ! 105: TCG_REG_V0, ! 106: TCG_REG_V1 ! 107: }; ! 108: ! 109: static uint8_t *tb_ret_addr; ! 110: ! 111: static inline uint32_t reloc_lo16_val (void *pc, tcg_target_long target) ! 112: { ! 113: return target & 0xffff; ! 114: } ! 115: ! 116: static inline void reloc_lo16 (void *pc, tcg_target_long target) ! 117: { ! 118: *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) ! 119: | reloc_lo16_val(pc, target); ! 120: } ! 121: ! 122: static inline uint32_t reloc_hi16_val (void *pc, tcg_target_long target) ! 123: { ! 124: return (target >> 16) & 0xffff; ! 125: } ! 126: ! 127: static inline void reloc_hi16 (void *pc, tcg_target_long target) ! 128: { ! 129: *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) ! 130: | reloc_hi16_val(pc, target); ! 131: } ! 132: ! 133: static inline uint32_t reloc_pc16_val (void *pc, tcg_target_long target) ! 134: { ! 135: int32_t disp; ! 136: ! 137: disp = target - (tcg_target_long) pc - 4; ! 138: if (disp != (disp << 14) >> 14) { ! 139: tcg_abort (); ! 140: } ! 141: ! 142: return (disp >> 2) & 0xffff; ! 143: } ! 144: ! 145: static inline void reloc_pc16 (void *pc, tcg_target_long target) ! 146: { ! 147: *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) ! 148: | reloc_pc16_val(pc, target); ! 149: } ! 150: ! 151: static inline uint32_t reloc_26_val (void *pc, tcg_target_long target) ! 152: { ! 153: if ((((tcg_target_long)pc + 4) & 0xf0000000) != (target & 0xf0000000)) { ! 154: tcg_abort (); ! 155: } ! 156: ! 157: return (target >> 2) & 0x3ffffff; ! 158: } ! 159: ! 160: static inline void reloc_pc26 (void *pc, tcg_target_long target) ! 161: { ! 162: *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3ffffff) ! 163: | reloc_26_val(pc, target); ! 164: } ! 165: ! 166: static void patch_reloc(uint8_t *code_ptr, int type, ! 167: tcg_target_long value, tcg_target_long addend) ! 168: { ! 169: value += addend; ! 170: switch(type) { ! 171: case R_MIPS_LO16: ! 172: reloc_lo16(code_ptr, value); ! 173: break; ! 174: case R_MIPS_HI16: ! 175: reloc_hi16(code_ptr, value); ! 176: break; ! 177: case R_MIPS_PC16: ! 178: reloc_pc16(code_ptr, value); ! 179: break; ! 180: case R_MIPS_26: ! 181: reloc_pc26(code_ptr, value); ! 182: break; ! 183: default: ! 184: tcg_abort(); ! 185: } ! 186: } ! 187: ! 188: /* maximum number of register used for input function arguments */ ! 189: static inline int tcg_target_get_call_iarg_regs_count(int flags) ! 190: { ! 191: return 4; ! 192: } ! 193: ! 194: /* parse target specific constraints */ ! 195: static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) ! 196: { ! 197: const char *ct_str; ! 198: ! 199: ct_str = *pct_str; ! 200: switch(ct_str[0]) { ! 201: case 'r': ! 202: ct->ct |= TCG_CT_REG; ! 203: tcg_regset_set(ct->u.regs, 0xffffffff); ! 204: break; ! 205: case 'C': ! 206: ct->ct |= TCG_CT_REG; ! 207: tcg_regset_clear(ct->u.regs); ! 208: tcg_regset_set_reg(ct->u.regs, TCG_REG_T9); ! 209: break; ! 210: case 'L': /* qemu_ld output arg constraint */ ! 211: ct->ct |= TCG_CT_REG; ! 212: tcg_regset_set(ct->u.regs, 0xffffffff); ! 213: tcg_regset_reset_reg(ct->u.regs, TCG_REG_V0); ! 214: break; ! 215: case 'l': /* qemu_ld input arg constraint */ ! 216: ct->ct |= TCG_CT_REG; ! 217: tcg_regset_set(ct->u.regs, 0xffffffff); ! 218: #if defined(CONFIG_SOFTMMU) ! 219: tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); ! 220: #endif ! 221: break; ! 222: case 'S': /* qemu_st constraint */ ! 223: ct->ct |= TCG_CT_REG; ! 224: tcg_regset_set(ct->u.regs, 0xffffffff); ! 225: #if defined(CONFIG_SOFTMMU) ! 226: tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); ! 227: # if TARGET_LONG_BITS == 64 ! 228: tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1); ! 229: # endif ! 230: tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2); ! 231: #endif ! 232: break; ! 233: case 'I': ! 234: ct->ct |= TCG_CT_CONST_U16; ! 235: break; ! 236: case 'J': ! 237: ct->ct |= TCG_CT_CONST_S16; ! 238: break; ! 239: case 'Z': ! 240: /* We are cheating a bit here, using the fact that the register ! 241: ZERO is also the register number 0. Hence there is no need ! 242: to check for const_args in each instruction. */ ! 243: ct->ct |= TCG_CT_CONST_ZERO; ! 244: break; ! 245: default: ! 246: return -1; ! 247: } ! 248: ct_str++; ! 249: *pct_str = ct_str; ! 250: return 0; ! 251: } ! 252: ! 253: /* test if a constant matches the constraint */ ! 254: static inline int tcg_target_const_match(tcg_target_long val, ! 255: const TCGArgConstraint *arg_ct) ! 256: { ! 257: int ct; ! 258: ct = arg_ct->ct; ! 259: if (ct & TCG_CT_CONST) ! 260: return 1; ! 261: else if ((ct & TCG_CT_CONST_ZERO) && val == 0) ! 262: return 1; ! 263: else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) ! 264: return 1; ! 265: else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) ! 266: return 1; ! 267: else ! 268: return 0; ! 269: } ! 270: ! 271: /* instruction opcodes */ ! 272: enum { ! 273: OPC_SPECIAL = 0x00 << 26, ! 274: OPC_BEQ = 0x04 << 26, ! 275: OPC_BNE = 0x05 << 26, ! 276: OPC_ADDIU = 0x09 << 26, ! 277: OPC_ANDI = 0x0C << 26, ! 278: OPC_ORI = 0x0D << 26, ! 279: OPC_XORI = 0x0E << 26, ! 280: OPC_LUI = 0x0F << 26, ! 281: OPC_LB = 0x20 << 26, ! 282: OPC_LH = 0x21 << 26, ! 283: OPC_LW = 0x23 << 26, ! 284: OPC_LBU = 0x24 << 26, ! 285: OPC_LHU = 0x25 << 26, ! 286: OPC_LWU = 0x27 << 26, ! 287: OPC_SB = 0x28 << 26, ! 288: OPC_SH = 0x29 << 26, ! 289: OPC_SW = 0x2B << 26, ! 290: OPC_SLL = OPC_SPECIAL | 0x00, ! 291: OPC_SRL = OPC_SPECIAL | 0x02, ! 292: OPC_SRA = OPC_SPECIAL | 0x03, ! 293: OPC_SLLV = OPC_SPECIAL | 0x04, ! 294: OPC_SRLV = OPC_SPECIAL | 0x06, ! 295: OPC_SRAV = OPC_SPECIAL | 0x07, ! 296: OPC_JR = OPC_SPECIAL | 0x08, ! 297: OPC_JALR = OPC_SPECIAL | 0x09, ! 298: OPC_MFHI = OPC_SPECIAL | 0x10, ! 299: OPC_MFLO = OPC_SPECIAL | 0x12, ! 300: OPC_MULT = OPC_SPECIAL | 0x18, ! 301: OPC_MULTU = OPC_SPECIAL | 0x19, ! 302: OPC_DIV = OPC_SPECIAL | 0x1A, ! 303: OPC_DIVU = OPC_SPECIAL | 0x1B, ! 304: OPC_ADDU = OPC_SPECIAL | 0x21, ! 305: OPC_SUBU = OPC_SPECIAL | 0x23, ! 306: OPC_AND = OPC_SPECIAL | 0x24, ! 307: OPC_OR = OPC_SPECIAL | 0x25, ! 308: OPC_XOR = OPC_SPECIAL | 0x26, ! 309: OPC_NOR = OPC_SPECIAL | 0x27, ! 310: OPC_SLT = OPC_SPECIAL | 0x2A, ! 311: OPC_SLTU = OPC_SPECIAL | 0x2B, ! 312: }; ! 313: ! 314: /* ! 315: * Type reg ! 316: */ ! 317: static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int rt) ! 318: { ! 319: int32_t inst; ! 320: ! 321: inst = opc; ! 322: inst |= (rs & 0x1F) << 21; ! 323: inst |= (rt & 0x1F) << 16; ! 324: inst |= (rd & 0x1F) << 11; ! 325: tcg_out32(s, inst); ! 326: } ! 327: ! 328: /* ! 329: * Type immediate ! 330: */ ! 331: static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int imm) ! 332: { ! 333: int32_t inst; ! 334: ! 335: inst = opc; ! 336: inst |= (rs & 0x1F) << 21; ! 337: inst |= (rt & 0x1F) << 16; ! 338: inst |= (imm & 0xffff); ! 339: tcg_out32(s, inst); ! 340: } ! 341: ! 342: /* ! 343: * Type sa ! 344: */ ! 345: static inline void tcg_out_opc_sa(TCGContext *s, int opc, int rd, int rt, int sa) ! 346: { ! 347: int32_t inst; ! 348: ! 349: inst = opc; ! 350: inst |= (rt & 0x1F) << 16; ! 351: inst |= (rd & 0x1F) << 11; ! 352: inst |= (sa & 0x1F) << 6; ! 353: tcg_out32(s, inst); ! 354: ! 355: } ! 356: ! 357: static inline void tcg_out_nop(TCGContext *s) ! 358: { ! 359: tcg_out32(s, 0); ! 360: } ! 361: ! 362: static inline void tcg_out_mov(TCGContext *s, int ret, int arg) ! 363: { ! 364: tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO); ! 365: } ! 366: ! 367: static inline void tcg_out_movi(TCGContext *s, TCGType type, ! 368: int reg, int32_t arg) ! 369: { ! 370: if (arg == (int16_t)arg) { ! 371: tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg); ! 372: } else if (arg == (uint16_t)arg) { ! 373: tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg); ! 374: } else { ! 375: tcg_out_opc_imm(s, OPC_LUI, reg, 0, arg >> 16); ! 376: tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff); ! 377: } ! 378: } ! 379: ! 380: static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) ! 381: { ! 382: /* ret and arg can't be register at */ ! 383: if (ret == TCG_REG_AT || arg == TCG_REG_AT) { ! 384: tcg_abort(); ! 385: } ! 386: ! 387: tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); ! 388: tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0x00ff); ! 389: ! 390: tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8); ! 391: tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00); ! 392: tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ! 393: } ! 394: ! 395: static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg) ! 396: { ! 397: /* ret and arg can't be register at */ ! 398: if (ret == TCG_REG_AT || arg == TCG_REG_AT) { ! 399: tcg_abort(); ! 400: } ! 401: ! 402: tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); ! 403: tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff); ! 404: ! 405: tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); ! 406: tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16); ! 407: tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ! 408: } ! 409: ! 410: static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg) ! 411: { ! 412: /* ret and arg must be different and can't be register at */ ! 413: if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) { ! 414: tcg_abort(); ! 415: } ! 416: ! 417: tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); ! 418: ! 419: tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24); ! 420: tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ! 421: ! 422: tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00); ! 423: tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8); ! 424: tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ! 425: ! 426: tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); ! 427: tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00); ! 428: tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ! 429: } ! 430: ! 431: static inline void tcg_out_ldst(TCGContext *s, int opc, int arg, ! 432: int arg1, tcg_target_long arg2) ! 433: { ! 434: if (arg2 == (int16_t) arg2) { ! 435: tcg_out_opc_imm(s, opc, arg, arg1, arg2); ! 436: } else { ! 437: tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, arg2); ! 438: tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, TCG_REG_AT, arg1); ! 439: tcg_out_opc_imm(s, opc, arg, TCG_REG_AT, 0); ! 440: } ! 441: } ! 442: ! 443: static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, ! 444: int arg1, tcg_target_long arg2) ! 445: { ! 446: tcg_out_ldst(s, OPC_LW, arg, arg1, arg2); ! 447: } ! 448: ! 449: static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, ! 450: int arg1, tcg_target_long arg2) ! 451: { ! 452: tcg_out_ldst(s, OPC_SW, arg, arg1, arg2); ! 453: } ! 454: ! 455: static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) ! 456: { ! 457: if (val == (int16_t)val) { ! 458: tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val); ! 459: } else { ! 460: tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, val); ! 461: tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_REG_AT); ! 462: } ! 463: } ! 464: ! 465: static void tcg_out_brcond(TCGContext *s, int cond, int arg1, ! 466: int arg2, int label_index) ! 467: { ! 468: TCGLabel *l = &s->labels[label_index]; ! 469: ! 470: switch (cond) { ! 471: case TCG_COND_EQ: ! 472: tcg_out_opc_imm(s, OPC_BEQ, arg1, arg2, 0); ! 473: break; ! 474: case TCG_COND_NE: ! 475: tcg_out_opc_imm(s, OPC_BNE, arg1, arg2, 0); ! 476: break; ! 477: case TCG_COND_LT: ! 478: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); ! 479: tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); ! 480: break; ! 481: case TCG_COND_LTU: ! 482: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); ! 483: tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); ! 484: break; ! 485: case TCG_COND_GE: ! 486: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); ! 487: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); ! 488: break; ! 489: case TCG_COND_GEU: ! 490: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); ! 491: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); ! 492: break; ! 493: case TCG_COND_LE: ! 494: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); ! 495: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); ! 496: break; ! 497: case TCG_COND_LEU: ! 498: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); ! 499: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); ! 500: break; ! 501: case TCG_COND_GT: ! 502: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); ! 503: tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); ! 504: break; ! 505: case TCG_COND_GTU: ! 506: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); ! 507: tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); ! 508: break; ! 509: default: ! 510: tcg_abort(); ! 511: break; ! 512: } ! 513: if (l->has_value) { ! 514: reloc_pc16(s->code_ptr - 4, l->u.value); ! 515: } else { ! 516: tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0); ! 517: } ! 518: tcg_out_nop(s); ! 519: } ! 520: ! 521: /* XXX: we implement it at the target level to avoid having to ! 522: handle cross basic blocks temporaries */ ! 523: static void tcg_out_brcond2(TCGContext *s, int cond, int arg1, ! 524: int arg2, int arg3, int arg4, int label_index) ! 525: { ! 526: void *label_ptr; ! 527: ! 528: switch(cond) { ! 529: case TCG_COND_NE: ! 530: tcg_out_brcond(s, TCG_COND_NE, arg2, arg4, label_index); ! 531: tcg_out_brcond(s, TCG_COND_NE, arg1, arg3, label_index); ! 532: return; ! 533: case TCG_COND_EQ: ! 534: break; ! 535: case TCG_COND_LT: ! 536: case TCG_COND_LE: ! 537: tcg_out_brcond(s, TCG_COND_LT, arg2, arg4, label_index); ! 538: break; ! 539: case TCG_COND_GT: ! 540: case TCG_COND_GE: ! 541: tcg_out_brcond(s, TCG_COND_GT, arg2, arg4, label_index); ! 542: break; ! 543: case TCG_COND_LTU: ! 544: case TCG_COND_LEU: ! 545: tcg_out_brcond(s, TCG_COND_LTU, arg2, arg4, label_index); ! 546: break; ! 547: case TCG_COND_GTU: ! 548: case TCG_COND_GEU: ! 549: tcg_out_brcond(s, TCG_COND_GTU, arg2, arg4, label_index); ! 550: break; ! 551: default: ! 552: tcg_abort(); ! 553: } ! 554: ! 555: label_ptr = s->code_ptr; ! 556: tcg_out_opc_imm(s, OPC_BNE, arg2, arg4, 0); ! 557: tcg_out_nop(s); ! 558: ! 559: switch(cond) { ! 560: case TCG_COND_EQ: ! 561: tcg_out_brcond(s, TCG_COND_EQ, arg1, arg3, label_index); ! 562: break; ! 563: case TCG_COND_LT: ! 564: case TCG_COND_LTU: ! 565: tcg_out_brcond(s, TCG_COND_LTU, arg1, arg3, label_index); ! 566: break; ! 567: case TCG_COND_LE: ! 568: case TCG_COND_LEU: ! 569: tcg_out_brcond(s, TCG_COND_LEU, arg1, arg3, label_index); ! 570: break; ! 571: case TCG_COND_GT: ! 572: case TCG_COND_GTU: ! 573: tcg_out_brcond(s, TCG_COND_GTU, arg1, arg3, label_index); ! 574: break; ! 575: case TCG_COND_GE: ! 576: case TCG_COND_GEU: ! 577: tcg_out_brcond(s, TCG_COND_GEU, arg1, arg3, label_index); ! 578: break; ! 579: default: ! 580: tcg_abort(); ! 581: } ! 582: ! 583: reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr); ! 584: } ! 585: ! 586: #if defined(CONFIG_SOFTMMU) ! 587: ! 588: #include "../../softmmu_defs.h" ! 589: ! 590: static void *qemu_ld_helpers[4] = { ! 591: __ldb_mmu, ! 592: __ldw_mmu, ! 593: __ldl_mmu, ! 594: __ldq_mmu, ! 595: }; ! 596: ! 597: static void *qemu_st_helpers[4] = { ! 598: __stb_mmu, ! 599: __stw_mmu, ! 600: __stl_mmu, ! 601: __stq_mmu, ! 602: }; ! 603: #endif ! 604: ! 605: static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, ! 606: int opc) ! 607: { ! 608: int addr_regl, addr_reg1, addr_meml; ! 609: int data_regl, data_regh, data_reg1, data_reg2; ! 610: int mem_index, s_bits; ! 611: #if defined(CONFIG_SOFTMMU) ! 612: void *label1_ptr, *label2_ptr; ! 613: int sp_args; ! 614: #endif ! 615: #if TARGET_LONG_BITS == 64 ! 616: # if defined(CONFIG_SOFTMMU) ! 617: uint8_t *label3_ptr; ! 618: # endif ! 619: int addr_regh, addr_reg2, addr_memh; ! 620: #endif ! 621: data_regl = *args++; ! 622: if (opc == 3) ! 623: data_regh = *args++; ! 624: else ! 625: data_regh = 0; ! 626: addr_regl = *args++; ! 627: #if TARGET_LONG_BITS == 64 ! 628: addr_regh = *args++; ! 629: #endif ! 630: mem_index = *args; ! 631: s_bits = opc & 3; ! 632: ! 633: if (opc == 3) { ! 634: #if defined(TCG_TARGET_WORDS_BIGENDIAN) ! 635: data_reg1 = data_regh; ! 636: data_reg2 = data_regl; ! 637: #else ! 638: data_reg1 = data_regl; ! 639: data_reg2 = data_regh; ! 640: #endif ! 641: } else { ! 642: data_reg1 = data_regl; ! 643: data_reg2 = 0; ! 644: } ! 645: #if TARGET_LONG_BITS == 64 ! 646: # if defined(TCG_TARGET_WORDS_BIGENDIAN) ! 647: addr_reg1 = addr_regh; ! 648: addr_reg2 = addr_regl; ! 649: addr_memh = 0; ! 650: addr_meml = 4; ! 651: # else ! 652: addr_reg1 = addr_regl; ! 653: addr_reg2 = addr_regh; ! 654: addr_memh = 4; ! 655: addr_meml = 0; ! 656: # endif ! 657: #else ! 658: addr_reg1 = addr_regl; ! 659: addr_meml = 0; ! 660: #endif ! 661: ! 662: #if defined(CONFIG_SOFTMMU) ! 663: tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); ! 664: tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); ! 665: tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0); ! 666: tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, ! 667: offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_meml); ! 668: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); ! 669: tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl); ! 670: ! 671: # if TARGET_LONG_BITS == 64 ! 672: label3_ptr = s->code_ptr; ! 673: tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); ! 674: tcg_out_nop(s); ! 675: ! 676: tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, ! 677: offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh); ! 678: ! 679: label1_ptr = s->code_ptr; ! 680: tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); ! 681: tcg_out_nop(s); ! 682: ! 683: reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); ! 684: # else ! 685: label1_ptr = s->code_ptr; ! 686: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); ! 687: tcg_out_nop(s); ! 688: # endif ! 689: ! 690: /* slow path */ ! 691: sp_args = TCG_REG_A0; ! 692: tcg_out_mov(s, sp_args++, addr_reg1); ! 693: # if TARGET_LONG_BITS == 64 ! 694: tcg_out_mov(s, sp_args++, addr_reg2); ! 695: # endif ! 696: tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index); ! 697: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]); ! 698: tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); ! 699: tcg_out_nop(s); ! 700: ! 701: switch(opc) { ! 702: case 0: ! 703: tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xff); ! 704: break; ! 705: case 0 | 4: ! 706: tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 24); ! 707: tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 24); ! 708: break; ! 709: case 1: ! 710: tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xffff); ! 711: break; ! 712: case 1 | 4: ! 713: tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 16); ! 714: tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 16); ! 715: break; ! 716: case 2: ! 717: tcg_out_mov(s, data_reg1, TCG_REG_V0); ! 718: break; ! 719: case 3: ! 720: tcg_out_mov(s, data_reg2, TCG_REG_V1); ! 721: tcg_out_mov(s, data_reg1, TCG_REG_V0); ! 722: break; ! 723: default: ! 724: tcg_abort(); ! 725: } ! 726: ! 727: label2_ptr = s->code_ptr; ! 728: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); ! 729: tcg_out_nop(s); ! 730: ! 731: /* label1: fast path */ ! 732: reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); ! 733: ! 734: tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0, ! 735: offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); ! 736: tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl); ! 737: ! 738: addr_reg1 = TCG_REG_V0; ! 739: #endif ! 740: ! 741: switch(opc) { ! 742: case 0: ! 743: tcg_out_opc_imm(s, OPC_LBU, data_reg1, addr_reg1, 0); ! 744: break; ! 745: case 0 | 4: ! 746: tcg_out_opc_imm(s, OPC_LB, data_reg1, addr_reg1, 0); ! 747: break; ! 748: case 1: ! 749: if (TCG_NEED_BSWAP) { ! 750: tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0); ! 751: tcg_out_bswap16(s, data_reg1, TCG_REG_T0); ! 752: } else { ! 753: tcg_out_opc_imm(s, OPC_LHU, data_reg1, addr_reg1, 0); ! 754: } ! 755: break; ! 756: case 1 | 4: ! 757: if (TCG_NEED_BSWAP) { ! 758: tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0); ! 759: tcg_out_bswap16s(s, data_reg1, TCG_REG_T0); ! 760: } else { ! 761: tcg_out_opc_imm(s, OPC_LH, data_reg1, addr_reg1, 0); ! 762: } ! 763: break; ! 764: case 2: ! 765: if (TCG_NEED_BSWAP) { ! 766: tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0); ! 767: tcg_out_bswap32(s, data_reg1, TCG_REG_T0); ! 768: } else { ! 769: tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0); ! 770: } ! 771: break; ! 772: case 3: ! 773: #if !defined(CONFIG_SOFTMMU) ! 774: tcg_out_mov(s, TCG_REG_V0, addr_reg1); ! 775: addr_reg1 = TCG_REG_V0; ! 776: #endif ! 777: if (TCG_NEED_BSWAP) { ! 778: tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 4); ! 779: tcg_out_bswap32(s, data_reg1, TCG_REG_T0); ! 780: tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0); ! 781: tcg_out_bswap32(s, data_reg2, TCG_REG_T0); ! 782: } else { ! 783: tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0); ! 784: tcg_out_opc_imm(s, OPC_LW, data_reg2, addr_reg1, 4); ! 785: } ! 786: break; ! 787: default: ! 788: tcg_abort(); ! 789: } ! 790: ! 791: #if defined(CONFIG_SOFTMMU) ! 792: reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); ! 793: #endif ! 794: } ! 795: ! 796: static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, ! 797: int opc) ! 798: { ! 799: int addr_regl, addr_reg1, addr_meml; ! 800: int data_regl, data_regh, data_reg1, data_reg2; ! 801: int mem_index, s_bits; ! 802: #if defined(CONFIG_SOFTMMU) ! 803: uint8_t *label1_ptr, *label2_ptr; ! 804: int sp_args; ! 805: #endif ! 806: #if TARGET_LONG_BITS == 64 ! 807: # if defined(CONFIG_SOFTMMU) ! 808: uint8_t *label3_ptr; ! 809: # endif ! 810: int addr_regh, addr_reg2, addr_memh; ! 811: #endif ! 812: ! 813: data_regl = *args++; ! 814: if (opc == 3) { ! 815: data_regh = *args++; ! 816: #if defined(TCG_TARGET_WORDS_BIGENDIAN) ! 817: data_reg1 = data_regh; ! 818: data_reg2 = data_regl; ! 819: #else ! 820: data_reg1 = data_regl; ! 821: data_reg2 = data_regh; ! 822: #endif ! 823: } else { ! 824: data_reg1 = data_regl; ! 825: data_reg2 = 0; ! 826: data_regh = 0; ! 827: } ! 828: addr_regl = *args++; ! 829: #if TARGET_LONG_BITS == 64 ! 830: addr_regh = *args++; ! 831: # if defined(TCG_TARGET_WORDS_BIGENDIAN) ! 832: addr_reg1 = addr_regh; ! 833: addr_reg2 = addr_regl; ! 834: addr_memh = 0; ! 835: addr_meml = 4; ! 836: # else ! 837: addr_reg1 = addr_regl; ! 838: addr_reg2 = addr_regh; ! 839: addr_memh = 4; ! 840: addr_meml = 0; ! 841: # endif ! 842: #else ! 843: addr_reg1 = addr_regl; ! 844: addr_meml = 0; ! 845: #endif ! 846: mem_index = *args; ! 847: s_bits = opc; ! 848: ! 849: #if defined(CONFIG_SOFTMMU) ! 850: tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); ! 851: tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); ! 852: tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0); ! 853: tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, ! 854: offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_meml); ! 855: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); ! 856: tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl); ! 857: ! 858: # if TARGET_LONG_BITS == 64 ! 859: label3_ptr = s->code_ptr; ! 860: tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); ! 861: tcg_out_nop(s); ! 862: ! 863: tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, ! 864: offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh); ! 865: ! 866: label1_ptr = s->code_ptr; ! 867: tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); ! 868: tcg_out_nop(s); ! 869: ! 870: reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); ! 871: # else ! 872: label1_ptr = s->code_ptr; ! 873: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); ! 874: tcg_out_nop(s); ! 875: # endif ! 876: ! 877: /* slow path */ ! 878: sp_args = TCG_REG_A0; ! 879: tcg_out_mov(s, sp_args++, addr_reg1); ! 880: # if TARGET_LONG_BITS == 64 ! 881: tcg_out_mov(s, sp_args++, addr_reg2); ! 882: # endif ! 883: switch(opc) { ! 884: case 0: ! 885: tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff); ! 886: break; ! 887: case 1: ! 888: tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff); ! 889: break; ! 890: case 2: ! 891: tcg_out_mov(s, sp_args++, data_reg1); ! 892: break; ! 893: case 3: ! 894: sp_args = (sp_args + 1) & ~1; ! 895: tcg_out_mov(s, sp_args++, data_reg1); ! 896: tcg_out_mov(s, sp_args++, data_reg2); ! 897: break; ! 898: default: ! 899: tcg_abort(); ! 900: } ! 901: if (sp_args > TCG_REG_A3) { ! 902: /* Push mem_index on the stack */ ! 903: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index); ! 904: tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16); ! 905: } else { ! 906: tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index); ! 907: } ! 908: ! 909: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]); ! 910: tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); ! 911: tcg_out_nop(s); ! 912: ! 913: label2_ptr = s->code_ptr; ! 914: tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); ! 915: tcg_out_nop(s); ! 916: ! 917: /* label1: fast path */ ! 918: reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); ! 919: ! 920: tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, ! 921: offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); ! 922: tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl); ! 923: ! 924: addr_reg1 = TCG_REG_A0; ! 925: #endif ! 926: ! 927: switch(opc) { ! 928: case 0: ! 929: tcg_out_opc_imm(s, OPC_SB, data_reg1, addr_reg1, 0); ! 930: break; ! 931: case 1: ! 932: if (TCG_NEED_BSWAP) { ! 933: tcg_out_bswap16(s, TCG_REG_T0, data_reg1); ! 934: tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, addr_reg1, 0); ! 935: } else { ! 936: tcg_out_opc_imm(s, OPC_SH, data_reg1, addr_reg1, 0); ! 937: } ! 938: break; ! 939: case 2: ! 940: if (TCG_NEED_BSWAP) { ! 941: tcg_out_bswap32(s, TCG_REG_T0, data_reg1); ! 942: tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0); ! 943: } else { ! 944: tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0); ! 945: } ! 946: break; ! 947: case 3: ! 948: if (TCG_NEED_BSWAP) { ! 949: tcg_out_bswap32(s, TCG_REG_T0, data_reg2); ! 950: tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0); ! 951: tcg_out_bswap32(s, TCG_REG_T0, data_reg1); ! 952: tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 4); ! 953: } else { ! 954: tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0); ! 955: tcg_out_opc_imm(s, OPC_SW, data_reg2, addr_reg1, 4); ! 956: } ! 957: break; ! 958: default: ! 959: tcg_abort(); ! 960: } ! 961: ! 962: #if defined(CONFIG_SOFTMMU) ! 963: reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); ! 964: #endif ! 965: } ! 966: ! 967: static inline void tcg_out_op(TCGContext *s, int opc, ! 968: const TCGArg *args, const int *const_args) ! 969: { ! 970: switch(opc) { ! 971: case INDEX_op_exit_tb: ! 972: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]); ! 973: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, (tcg_target_long)tb_ret_addr); ! 974: tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); ! 975: tcg_out_nop(s); ! 976: break; ! 977: case INDEX_op_goto_tb: ! 978: if (s->tb_jmp_offset) { ! 979: /* direct jump method */ ! 980: tcg_abort(); ! 981: } else { ! 982: /* indirect jump method */ ! 983: tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0])); ! 984: tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0); ! 985: tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); ! 986: } ! 987: tcg_out_nop(s); ! 988: s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; ! 989: break; ! 990: case INDEX_op_call: ! 991: tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0); ! 992: tcg_out_nop(s); ! 993: break; ! 994: case INDEX_op_jmp: ! 995: tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0); ! 996: tcg_out_nop(s); ! 997: break; ! 998: case INDEX_op_br: ! 999: tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]); ! 1000: break; ! 1001: ! 1002: case INDEX_op_mov_i32: ! 1003: tcg_out_mov(s, args[0], args[1]); ! 1004: break; ! 1005: case INDEX_op_movi_i32: ! 1006: tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); ! 1007: break; ! 1008: ! 1009: case INDEX_op_ld8u_i32: ! 1010: tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]); ! 1011: break; ! 1012: case INDEX_op_ld8s_i32: ! 1013: tcg_out_ldst(s, OPC_LB, args[0], args[1], args[2]); ! 1014: break; ! 1015: case INDEX_op_ld16u_i32: ! 1016: tcg_out_ldst(s, OPC_LHU, args[0], args[1], args[2]); ! 1017: break; ! 1018: case INDEX_op_ld16s_i32: ! 1019: tcg_out_ldst(s, OPC_LH, args[0], args[1], args[2]); ! 1020: break; ! 1021: case INDEX_op_ld_i32: ! 1022: tcg_out_ldst(s, OPC_LW, args[0], args[1], args[2]); ! 1023: break; ! 1024: case INDEX_op_st8_i32: ! 1025: tcg_out_ldst(s, OPC_SB, args[0], args[1], args[2]); ! 1026: break; ! 1027: case INDEX_op_st16_i32: ! 1028: tcg_out_ldst(s, OPC_SH, args[0], args[1], args[2]); ! 1029: break; ! 1030: case INDEX_op_st_i32: ! 1031: tcg_out_ldst(s, OPC_SW, args[0], args[1], args[2]); ! 1032: break; ! 1033: ! 1034: case INDEX_op_add_i32: ! 1035: if (const_args[2]) { ! 1036: tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], args[2]); ! 1037: } else { ! 1038: tcg_out_opc_reg(s, OPC_ADDU, args[0], args[1], args[2]); ! 1039: } ! 1040: break; ! 1041: case INDEX_op_add2_i32: ! 1042: if (const_args[4]) { ! 1043: tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], args[4]); ! 1044: } else { ! 1045: tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, args[2], args[4]); ! 1046: } ! 1047: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, TCG_REG_AT, args[2]); ! 1048: if (const_args[5]) { ! 1049: tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], args[5]); ! 1050: } else { ! 1051: tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]); ! 1052: } ! 1053: tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0); ! 1054: tcg_out_mov(s, args[0], TCG_REG_AT); ! 1055: break; ! 1056: case INDEX_op_sub_i32: ! 1057: if (const_args[2]) { ! 1058: tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], -args[2]); ! 1059: } else { ! 1060: tcg_out_opc_reg(s, OPC_SUBU, args[0], args[1], args[2]); ! 1061: } ! 1062: break; ! 1063: case INDEX_op_sub2_i32: ! 1064: if (const_args[4]) { ! 1065: tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], -args[4]); ! 1066: } else { ! 1067: tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, args[2], args[4]); ! 1068: } ! 1069: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, args[2], TCG_REG_AT); ! 1070: if (const_args[5]) { ! 1071: tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], -args[5]); ! 1072: } else { ! 1073: tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]); ! 1074: } ! 1075: tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0); ! 1076: tcg_out_mov(s, args[0], TCG_REG_AT); ! 1077: break; ! 1078: case INDEX_op_mul_i32: ! 1079: tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]); ! 1080: tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); ! 1081: break; ! 1082: case INDEX_op_mulu2_i32: ! 1083: tcg_out_opc_reg(s, OPC_MULTU, 0, args[2], args[3]); ! 1084: tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); ! 1085: tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0); ! 1086: break; ! 1087: case INDEX_op_div_i32: ! 1088: tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]); ! 1089: tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); ! 1090: break; ! 1091: case INDEX_op_divu_i32: ! 1092: tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]); ! 1093: tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); ! 1094: break; ! 1095: case INDEX_op_rem_i32: ! 1096: tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]); ! 1097: tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0); ! 1098: break; ! 1099: case INDEX_op_remu_i32: ! 1100: tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]); ! 1101: tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0); ! 1102: break; ! 1103: ! 1104: case INDEX_op_and_i32: ! 1105: if (const_args[2]) { ! 1106: tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]); ! 1107: } else { ! 1108: tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]); ! 1109: } ! 1110: break; ! 1111: case INDEX_op_or_i32: ! 1112: if (const_args[2]) { ! 1113: tcg_out_opc_imm(s, OPC_ORI, args[0], args[1], args[2]); ! 1114: } else { ! 1115: tcg_out_opc_reg(s, OPC_OR, args[0], args[1], args[2]); ! 1116: } ! 1117: break; ! 1118: case INDEX_op_not_i32: ! 1119: tcg_out_opc_reg(s, OPC_NOR, args[0], args[1], args[1]); ! 1120: break; ! 1121: case INDEX_op_xor_i32: ! 1122: if (const_args[2]) { ! 1123: tcg_out_opc_imm(s, OPC_XORI, args[0], args[1], args[2]); ! 1124: } else { ! 1125: tcg_out_opc_reg(s, OPC_XOR, args[0], args[1], args[2]); ! 1126: } ! 1127: break; ! 1128: ! 1129: case INDEX_op_sar_i32: ! 1130: if (const_args[2]) { ! 1131: tcg_out_opc_sa(s, OPC_SRA, args[0], args[1], args[2]); ! 1132: } else { ! 1133: tcg_out_opc_reg(s, OPC_SRAV, args[0], args[2], args[1]); ! 1134: } ! 1135: break; ! 1136: case INDEX_op_shl_i32: ! 1137: if (const_args[2]) { ! 1138: tcg_out_opc_sa(s, OPC_SLL, args[0], args[1], args[2]); ! 1139: } else { ! 1140: tcg_out_opc_reg(s, OPC_SLLV, args[0], args[2], args[1]); ! 1141: } ! 1142: break; ! 1143: case INDEX_op_shr_i32: ! 1144: if (const_args[2]) { ! 1145: tcg_out_opc_sa(s, OPC_SRL, args[0], args[1], args[2]); ! 1146: } else { ! 1147: tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]); ! 1148: } ! 1149: break; ! 1150: ! 1151: case INDEX_op_brcond_i32: ! 1152: tcg_out_brcond(s, args[2], args[0], args[1], args[3]); ! 1153: break; ! 1154: case INDEX_op_brcond2_i32: ! 1155: tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]); ! 1156: break; ! 1157: ! 1158: case INDEX_op_qemu_ld8u: ! 1159: tcg_out_qemu_ld(s, args, 0); ! 1160: break; ! 1161: case INDEX_op_qemu_ld8s: ! 1162: tcg_out_qemu_ld(s, args, 0 | 4); ! 1163: break; ! 1164: case INDEX_op_qemu_ld16u: ! 1165: tcg_out_qemu_ld(s, args, 1); ! 1166: break; ! 1167: case INDEX_op_qemu_ld16s: ! 1168: tcg_out_qemu_ld(s, args, 1 | 4); ! 1169: break; ! 1170: case INDEX_op_qemu_ld32u: ! 1171: tcg_out_qemu_ld(s, args, 2); ! 1172: break; ! 1173: case INDEX_op_qemu_ld64: ! 1174: tcg_out_qemu_ld(s, args, 3); ! 1175: break; ! 1176: case INDEX_op_qemu_st8: ! 1177: tcg_out_qemu_st(s, args, 0); ! 1178: break; ! 1179: case INDEX_op_qemu_st16: ! 1180: tcg_out_qemu_st(s, args, 1); ! 1181: break; ! 1182: case INDEX_op_qemu_st32: ! 1183: tcg_out_qemu_st(s, args, 2); ! 1184: break; ! 1185: case INDEX_op_qemu_st64: ! 1186: tcg_out_qemu_st(s, args, 3); ! 1187: break; ! 1188: ! 1189: default: ! 1190: tcg_abort(); ! 1191: } ! 1192: } ! 1193: ! 1194: static const TCGTargetOpDef mips_op_defs[] = { ! 1195: { INDEX_op_exit_tb, { } }, ! 1196: { INDEX_op_goto_tb, { } }, ! 1197: { INDEX_op_call, { "C" } }, ! 1198: { INDEX_op_jmp, { "r" } }, ! 1199: { INDEX_op_br, { } }, ! 1200: ! 1201: { INDEX_op_mov_i32, { "r", "r" } }, ! 1202: { INDEX_op_movi_i32, { "r" } }, ! 1203: { INDEX_op_ld8u_i32, { "r", "r" } }, ! 1204: { INDEX_op_ld8s_i32, { "r", "r" } }, ! 1205: { INDEX_op_ld16u_i32, { "r", "r" } }, ! 1206: { INDEX_op_ld16s_i32, { "r", "r" } }, ! 1207: { INDEX_op_ld_i32, { "r", "r" } }, ! 1208: { INDEX_op_st8_i32, { "rZ", "r" } }, ! 1209: { INDEX_op_st16_i32, { "rZ", "r" } }, ! 1210: { INDEX_op_st_i32, { "rZ", "r" } }, ! 1211: ! 1212: { INDEX_op_add_i32, { "r", "rZ", "rJZ" } }, ! 1213: { INDEX_op_mul_i32, { "r", "rZ", "rZ" } }, ! 1214: { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } }, ! 1215: { INDEX_op_div_i32, { "r", "rZ", "rZ" } }, ! 1216: { INDEX_op_divu_i32, { "r", "rZ", "rZ" } }, ! 1217: { INDEX_op_rem_i32, { "r", "rZ", "rZ" } }, ! 1218: { INDEX_op_remu_i32, { "r", "rZ", "rZ" } }, ! 1219: { INDEX_op_sub_i32, { "r", "rZ", "rJZ" } }, ! 1220: ! 1221: { INDEX_op_and_i32, { "r", "rZ", "rIZ" } }, ! 1222: { INDEX_op_not_i32, { "r", "rZ" } }, ! 1223: { INDEX_op_or_i32, { "r", "rZ", "rIZ" } }, ! 1224: { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } }, ! 1225: ! 1226: { INDEX_op_shl_i32, { "r", "rZ", "riZ" } }, ! 1227: { INDEX_op_shr_i32, { "r", "rZ", "riZ" } }, ! 1228: { INDEX_op_sar_i32, { "r", "rZ", "riZ" } }, ! 1229: ! 1230: { INDEX_op_brcond_i32, { "rZ", "rZ" } }, ! 1231: ! 1232: { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, ! 1233: { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, ! 1234: { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } }, ! 1235: ! 1236: #if TARGET_LONG_BITS == 32 ! 1237: { INDEX_op_qemu_ld8u, { "L", "lZ" } }, ! 1238: { INDEX_op_qemu_ld8s, { "L", "lZ" } }, ! 1239: { INDEX_op_qemu_ld16u, { "L", "lZ" } }, ! 1240: { INDEX_op_qemu_ld16s, { "L", "lZ" } }, ! 1241: { INDEX_op_qemu_ld32u, { "L", "lZ" } }, ! 1242: { INDEX_op_qemu_ld64, { "L", "L", "lZ" } }, ! 1243: ! 1244: { INDEX_op_qemu_st8, { "SZ", "SZ" } }, ! 1245: { INDEX_op_qemu_st16, { "SZ", "SZ" } }, ! 1246: { INDEX_op_qemu_st32, { "SZ", "SZ" } }, ! 1247: { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ" } }, ! 1248: #else ! 1249: { INDEX_op_qemu_ld8u, { "L", "lZ", "lZ" } }, ! 1250: { INDEX_op_qemu_ld8s, { "L", "lZ", "lZ" } }, ! 1251: { INDEX_op_qemu_ld16u, { "L", "lZ", "lZ" } }, ! 1252: { INDEX_op_qemu_ld16s, { "L", "lZ", "lZ" } }, ! 1253: { INDEX_op_qemu_ld32u, { "L", "lZ", "lZ" } }, ! 1254: { INDEX_op_qemu_ld64, { "L", "L", "lZ", "lZ" } }, ! 1255: ! 1256: { INDEX_op_qemu_st8, { "SZ", "SZ", "SZ" } }, ! 1257: { INDEX_op_qemu_st16, { "SZ", "SZ", "SZ" } }, ! 1258: { INDEX_op_qemu_st32, { "SZ", "SZ", "SZ" } }, ! 1259: { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ", "SZ" } }, ! 1260: #endif ! 1261: { -1 }, ! 1262: }; ! 1263: ! 1264: static int tcg_target_callee_save_regs[] = { ! 1265: TCG_REG_S0, ! 1266: TCG_REG_S1, ! 1267: TCG_REG_S2, ! 1268: TCG_REG_S3, ! 1269: TCG_REG_S4, ! 1270: TCG_REG_S5, ! 1271: TCG_REG_S6, ! 1272: TCG_REG_S7, ! 1273: TCG_REG_GP, ! 1274: /* TCG_REG_FP, */ /* currently used for the global env, so np ! 1275: need to save */ ! 1276: TCG_REG_RA, /* should be last for ABI compliance */ ! 1277: }; ! 1278: ! 1279: /* Generate global QEMU prologue and epilogue code */ ! 1280: void tcg_target_qemu_prologue(TCGContext *s) ! 1281: { ! 1282: int i, frame_size; ! 1283: ! 1284: /* reserve some stack space */ ! 1285: frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4 ! 1286: + TCG_STATIC_CALL_ARGS_SIZE; ! 1287: frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & ! 1288: ~(TCG_TARGET_STACK_ALIGN - 1); ! 1289: ! 1290: /* TB prologue */ ! 1291: tcg_out_addi(s, TCG_REG_SP, -frame_size); ! 1292: for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) { ! 1293: tcg_out_st(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i], ! 1294: TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4); ! 1295: } ! 1296: ! 1297: /* Call generated code */ ! 1298: tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_A0, 0); ! 1299: tcg_out_nop(s); ! 1300: tb_ret_addr = s->code_ptr; ! 1301: ! 1302: /* TB epilogue */ ! 1303: for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) { ! 1304: tcg_out_ld(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i], ! 1305: TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4); ! 1306: } ! 1307: ! 1308: tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_RA, 0); ! 1309: tcg_out_addi(s, TCG_REG_SP, frame_size); ! 1310: } ! 1311: ! 1312: void tcg_target_init(TCGContext *s) ! 1313: { ! 1314: tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff); ! 1315: tcg_regset_set(tcg_target_call_clobber_regs, ! 1316: (1 << TCG_REG_V0) | ! 1317: (1 << TCG_REG_V1) | ! 1318: (1 << TCG_REG_A0) | ! 1319: (1 << TCG_REG_A1) | ! 1320: (1 << TCG_REG_A2) | ! 1321: (1 << TCG_REG_A3) | ! 1322: (1 << TCG_REG_T1) | ! 1323: (1 << TCG_REG_T2) | ! 1324: (1 << TCG_REG_T3) | ! 1325: (1 << TCG_REG_T4) | ! 1326: (1 << TCG_REG_T5) | ! 1327: (1 << TCG_REG_T6) | ! 1328: (1 << TCG_REG_T7) | ! 1329: (1 << TCG_REG_T8) | ! 1330: (1 << TCG_REG_T9)); ! 1331: ! 1332: tcg_regset_clear(s->reserved_regs); ! 1333: tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */ ! 1334: tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0); /* kernel use only */ ! 1335: tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1); /* kernel use only */ ! 1336: tcg_regset_set_reg(s->reserved_regs, TCG_REG_AT); /* internal use */ ! 1337: tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0); /* internal use */ ! 1338: tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */ ! 1339: tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ ! 1340: ! 1341: tcg_add_target_add_op_defs(mips_op_defs); ! 1342: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.