|
|
1.1 ! root 1: /* ! 2: * Tiny Code Generator for QEMU ! 3: * ! 4: * Copyright (c) 2008 Fabrice Bellard ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: ! 25: /* define it to suppress various consistency checks (faster) */ ! 26: #define NDEBUG ! 27: ! 28: /* define it to use liveness analysis (better code) */ ! 29: #define USE_LIVENESS_ANALYSIS ! 30: ! 31: #include <assert.h> ! 32: #include <stdarg.h> ! 33: #include <stdlib.h> ! 34: #include <stdio.h> ! 35: #include <string.h> ! 36: #include <inttypes.h> ! 37: #ifdef _WIN32 ! 38: #include <malloc.h> ! 39: #endif ! 40: #ifdef _AIX ! 41: #include <alloca.h> ! 42: #endif ! 43: ! 44: #include "config.h" ! 45: #include "qemu-common.h" ! 46: #include "cache-utils.h" ! 47: ! 48: /* Note: the long term plan is to reduce the dependancies on the QEMU ! 49: CPU definitions. Currently they are used for qemu_ld/st ! 50: instructions */ ! 51: #define NO_CPU_IO_DEFS ! 52: #include "cpu.h" ! 53: #include "exec-all.h" ! 54: ! 55: #include "tcg-op.h" ! 56: #include "elf.h" ! 57: ! 58: ! 59: static void patch_reloc(uint8_t *code_ptr, int type, ! 60: tcg_target_long value, tcg_target_long addend); ! 61: ! 62: static TCGOpDef tcg_op_defs[] = { ! 63: #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size }, ! 64: #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 }, ! 65: #include "tcg-opc.h" ! 66: #undef DEF ! 67: #undef DEF2 ! 68: }; ! 69: ! 70: static TCGRegSet tcg_target_available_regs[2]; ! 71: static TCGRegSet tcg_target_call_clobber_regs; ! 72: ! 73: /* XXX: move that inside the context */ ! 74: uint16_t *gen_opc_ptr; ! 75: TCGArg *gen_opparam_ptr; ! 76: ! 77: static inline void tcg_out8(TCGContext *s, uint8_t v) ! 78: { ! 79: *s->code_ptr++ = v; ! 80: } ! 81: ! 82: static inline void tcg_out16(TCGContext *s, uint16_t v) ! 83: { ! 84: *(uint16_t *)s->code_ptr = v; ! 85: s->code_ptr += 2; ! 86: } ! 87: ! 88: static inline void tcg_out32(TCGContext *s, uint32_t v) ! 89: { ! 90: *(uint32_t *)s->code_ptr = v; ! 91: s->code_ptr += 4; ! 92: } ! 93: ! 94: /* label relocation processing */ ! 95: ! 96: void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, ! 97: int label_index, long addend) ! 98: { ! 99: TCGLabel *l; ! 100: TCGRelocation *r; ! 101: ! 102: l = &s->labels[label_index]; ! 103: if (l->has_value) { ! 104: /* FIXME: This may break relocations on RISC targets that ! 105: modify instruction fields in place. The caller may not have ! 106: written the initial value. */ ! 107: patch_reloc(code_ptr, type, l->u.value, addend); ! 108: } else { ! 109: /* add a new relocation entry */ ! 110: r = tcg_malloc(sizeof(TCGRelocation)); ! 111: r->type = type; ! 112: r->ptr = code_ptr; ! 113: r->addend = addend; ! 114: r->next = l->u.first_reloc; ! 115: l->u.first_reloc = r; ! 116: } ! 117: } ! 118: ! 119: static void tcg_out_label(TCGContext *s, int label_index, ! 120: tcg_target_long value) ! 121: { ! 122: TCGLabel *l; ! 123: TCGRelocation *r; ! 124: ! 125: l = &s->labels[label_index]; ! 126: if (l->has_value) ! 127: tcg_abort(); ! 128: r = l->u.first_reloc; ! 129: while (r != NULL) { ! 130: patch_reloc(r->ptr, r->type, value, r->addend); ! 131: r = r->next; ! 132: } ! 133: l->has_value = 1; ! 134: l->u.value = value; ! 135: } ! 136: ! 137: int gen_new_label(void) ! 138: { ! 139: TCGContext *s = &tcg_ctx; ! 140: int idx; ! 141: TCGLabel *l; ! 142: ! 143: if (s->nb_labels >= TCG_MAX_LABELS) ! 144: tcg_abort(); ! 145: idx = s->nb_labels++; ! 146: l = &s->labels[idx]; ! 147: l->has_value = 0; ! 148: l->u.first_reloc = NULL; ! 149: return idx; ! 150: } ! 151: ! 152: #include "tcg-target.c" ! 153: ! 154: /* pool based memory allocation */ ! 155: void *tcg_malloc_internal(TCGContext *s, int size) ! 156: { ! 157: TCGPool *p; ! 158: int pool_size; ! 159: ! 160: if (size > TCG_POOL_CHUNK_SIZE) { ! 161: /* big malloc: insert a new pool (XXX: could optimize) */ ! 162: p = qemu_malloc(sizeof(TCGPool) + size); ! 163: p->size = size; ! 164: if (s->pool_current) ! 165: s->pool_current->next = p; ! 166: else ! 167: s->pool_first = p; ! 168: p->next = s->pool_current; ! 169: } else { ! 170: p = s->pool_current; ! 171: if (!p) { ! 172: p = s->pool_first; ! 173: if (!p) ! 174: goto new_pool; ! 175: } else { ! 176: if (!p->next) { ! 177: new_pool: ! 178: pool_size = TCG_POOL_CHUNK_SIZE; ! 179: p = qemu_malloc(sizeof(TCGPool) + pool_size); ! 180: p->size = pool_size; ! 181: p->next = NULL; ! 182: if (s->pool_current) ! 183: s->pool_current->next = p; ! 184: else ! 185: s->pool_first = p; ! 186: } else { ! 187: p = p->next; ! 188: } ! 189: } ! 190: } ! 191: s->pool_current = p; ! 192: s->pool_cur = p->data + size; ! 193: s->pool_end = p->data + p->size; ! 194: return p->data; ! 195: } ! 196: ! 197: void tcg_pool_reset(TCGContext *s) ! 198: { ! 199: s->pool_cur = s->pool_end = NULL; ! 200: s->pool_current = NULL; ! 201: } ! 202: ! 203: void tcg_context_init(TCGContext *s) ! 204: { ! 205: int op, total_args, n; ! 206: TCGOpDef *def; ! 207: TCGArgConstraint *args_ct; ! 208: int *sorted_args; ! 209: ! 210: memset(s, 0, sizeof(*s)); ! 211: s->temps = s->static_temps; ! 212: s->nb_globals = 0; ! 213: ! 214: /* Count total number of arguments and allocate the corresponding ! 215: space */ ! 216: total_args = 0; ! 217: for(op = 0; op < NB_OPS; op++) { ! 218: def = &tcg_op_defs[op]; ! 219: n = def->nb_iargs + def->nb_oargs; ! 220: total_args += n; ! 221: } ! 222: ! 223: args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args); ! 224: sorted_args = qemu_malloc(sizeof(int) * total_args); ! 225: ! 226: for(op = 0; op < NB_OPS; op++) { ! 227: def = &tcg_op_defs[op]; ! 228: def->args_ct = args_ct; ! 229: def->sorted_args = sorted_args; ! 230: n = def->nb_iargs + def->nb_oargs; ! 231: sorted_args += n; ! 232: args_ct += n; ! 233: } ! 234: ! 235: tcg_target_init(s); ! 236: ! 237: /* init global prologue and epilogue */ ! 238: s->code_buf = code_gen_prologue; ! 239: s->code_ptr = s->code_buf; ! 240: tcg_target_qemu_prologue(s); ! 241: flush_icache_range((unsigned long)s->code_buf, ! 242: (unsigned long)s->code_ptr); ! 243: } ! 244: ! 245: void tcg_set_frame(TCGContext *s, int reg, ! 246: tcg_target_long start, tcg_target_long size) ! 247: { ! 248: s->frame_start = start; ! 249: s->frame_end = start + size; ! 250: s->frame_reg = reg; ! 251: } ! 252: ! 253: void tcg_func_start(TCGContext *s) ! 254: { ! 255: int i; ! 256: tcg_pool_reset(s); ! 257: s->nb_temps = s->nb_globals; ! 258: for(i = 0; i < (TCG_TYPE_COUNT * 2); i++) ! 259: s->first_free_temp[i] = -1; ! 260: s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); ! 261: s->nb_labels = 0; ! 262: s->current_frame_offset = s->frame_start; ! 263: ! 264: gen_opc_ptr = gen_opc_buf; ! 265: gen_opparam_ptr = gen_opparam_buf; ! 266: } ! 267: ! 268: static inline void tcg_temp_alloc(TCGContext *s, int n) ! 269: { ! 270: if (n > TCG_MAX_TEMPS) ! 271: tcg_abort(); ! 272: } ! 273: ! 274: static inline int tcg_global_reg_new_internal(TCGType type, int reg, ! 275: const char *name) ! 276: { ! 277: TCGContext *s = &tcg_ctx; ! 278: TCGTemp *ts; ! 279: int idx; ! 280: ! 281: #if TCG_TARGET_REG_BITS == 32 ! 282: if (type != TCG_TYPE_I32) ! 283: tcg_abort(); ! 284: #endif ! 285: if (tcg_regset_test_reg(s->reserved_regs, reg)) ! 286: tcg_abort(); ! 287: idx = s->nb_globals; ! 288: tcg_temp_alloc(s, s->nb_globals + 1); ! 289: ts = &s->temps[s->nb_globals]; ! 290: ts->base_type = type; ! 291: ts->type = type; ! 292: ts->fixed_reg = 1; ! 293: ts->reg = reg; ! 294: ts->name = name; ! 295: s->nb_globals++; ! 296: tcg_regset_set_reg(s->reserved_regs, reg); ! 297: return idx; ! 298: } ! 299: ! 300: TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name) ! 301: { ! 302: int idx; ! 303: ! 304: idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name); ! 305: return MAKE_TCGV_I32(idx); ! 306: } ! 307: ! 308: TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name) ! 309: { ! 310: int idx; ! 311: ! 312: idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name); ! 313: return MAKE_TCGV_I64(idx); ! 314: } ! 315: ! 316: static inline int tcg_global_mem_new_internal(TCGType type, int reg, ! 317: tcg_target_long offset, ! 318: const char *name) ! 319: { ! 320: TCGContext *s = &tcg_ctx; ! 321: TCGTemp *ts; ! 322: int idx; ! 323: ! 324: idx = s->nb_globals; ! 325: #if TCG_TARGET_REG_BITS == 32 ! 326: if (type == TCG_TYPE_I64) { ! 327: char buf[64]; ! 328: tcg_temp_alloc(s, s->nb_globals + 2); ! 329: ts = &s->temps[s->nb_globals]; ! 330: ts->base_type = type; ! 331: ts->type = TCG_TYPE_I32; ! 332: ts->fixed_reg = 0; ! 333: ts->mem_allocated = 1; ! 334: ts->mem_reg = reg; ! 335: #ifdef TCG_TARGET_WORDS_BIGENDIAN ! 336: ts->mem_offset = offset + 4; ! 337: #else ! 338: ts->mem_offset = offset; ! 339: #endif ! 340: pstrcpy(buf, sizeof(buf), name); ! 341: pstrcat(buf, sizeof(buf), "_0"); ! 342: ts->name = strdup(buf); ! 343: ts++; ! 344: ! 345: ts->base_type = type; ! 346: ts->type = TCG_TYPE_I32; ! 347: ts->fixed_reg = 0; ! 348: ts->mem_allocated = 1; ! 349: ts->mem_reg = reg; ! 350: #ifdef TCG_TARGET_WORDS_BIGENDIAN ! 351: ts->mem_offset = offset; ! 352: #else ! 353: ts->mem_offset = offset + 4; ! 354: #endif ! 355: pstrcpy(buf, sizeof(buf), name); ! 356: pstrcat(buf, sizeof(buf), "_1"); ! 357: ts->name = strdup(buf); ! 358: ! 359: s->nb_globals += 2; ! 360: } else ! 361: #endif ! 362: { ! 363: tcg_temp_alloc(s, s->nb_globals + 1); ! 364: ts = &s->temps[s->nb_globals]; ! 365: ts->base_type = type; ! 366: ts->type = type; ! 367: ts->fixed_reg = 0; ! 368: ts->mem_allocated = 1; ! 369: ts->mem_reg = reg; ! 370: ts->mem_offset = offset; ! 371: ts->name = name; ! 372: s->nb_globals++; ! 373: } ! 374: return idx; ! 375: } ! 376: ! 377: TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset, ! 378: const char *name) ! 379: { ! 380: int idx; ! 381: ! 382: idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name); ! 383: return MAKE_TCGV_I32(idx); ! 384: } ! 385: ! 386: TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset, ! 387: const char *name) ! 388: { ! 389: int idx; ! 390: ! 391: idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name); ! 392: return MAKE_TCGV_I64(idx); ! 393: } ! 394: ! 395: static inline int tcg_temp_new_internal(TCGType type, int temp_local) ! 396: { ! 397: TCGContext *s = &tcg_ctx; ! 398: TCGTemp *ts; ! 399: int idx, k; ! 400: ! 401: k = type; ! 402: if (temp_local) ! 403: k += TCG_TYPE_COUNT; ! 404: idx = s->first_free_temp[k]; ! 405: if (idx != -1) { ! 406: /* There is already an available temp with the ! 407: right type */ ! 408: ts = &s->temps[idx]; ! 409: s->first_free_temp[k] = ts->next_free_temp; ! 410: ts->temp_allocated = 1; ! 411: assert(ts->temp_local == temp_local); ! 412: } else { ! 413: idx = s->nb_temps; ! 414: #if TCG_TARGET_REG_BITS == 32 ! 415: if (type == TCG_TYPE_I64) { ! 416: tcg_temp_alloc(s, s->nb_temps + 2); ! 417: ts = &s->temps[s->nb_temps]; ! 418: ts->base_type = type; ! 419: ts->type = TCG_TYPE_I32; ! 420: ts->temp_allocated = 1; ! 421: ts->temp_local = temp_local; ! 422: ts->name = NULL; ! 423: ts++; ! 424: ts->base_type = TCG_TYPE_I32; ! 425: ts->type = TCG_TYPE_I32; ! 426: ts->temp_allocated = 1; ! 427: ts->temp_local = temp_local; ! 428: ts->name = NULL; ! 429: s->nb_temps += 2; ! 430: } else ! 431: #endif ! 432: { ! 433: tcg_temp_alloc(s, s->nb_temps + 1); ! 434: ts = &s->temps[s->nb_temps]; ! 435: ts->base_type = type; ! 436: ts->type = type; ! 437: ts->temp_allocated = 1; ! 438: ts->temp_local = temp_local; ! 439: ts->name = NULL; ! 440: s->nb_temps++; ! 441: } ! 442: } ! 443: return idx; ! 444: } ! 445: ! 446: TCGv_i32 tcg_temp_new_internal_i32(int temp_local) ! 447: { ! 448: int idx; ! 449: ! 450: idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); ! 451: return MAKE_TCGV_I32(idx); ! 452: } ! 453: ! 454: TCGv_i64 tcg_temp_new_internal_i64(int temp_local) ! 455: { ! 456: int idx; ! 457: ! 458: idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); ! 459: return MAKE_TCGV_I64(idx); ! 460: } ! 461: ! 462: static inline void tcg_temp_free_internal(int idx) ! 463: { ! 464: TCGContext *s = &tcg_ctx; ! 465: TCGTemp *ts; ! 466: int k; ! 467: ! 468: assert(idx >= s->nb_globals && idx < s->nb_temps); ! 469: ts = &s->temps[idx]; ! 470: assert(ts->temp_allocated != 0); ! 471: ts->temp_allocated = 0; ! 472: k = ts->base_type; ! 473: if (ts->temp_local) ! 474: k += TCG_TYPE_COUNT; ! 475: ts->next_free_temp = s->first_free_temp[k]; ! 476: s->first_free_temp[k] = idx; ! 477: } ! 478: ! 479: void tcg_temp_free_i32(TCGv_i32 arg) ! 480: { ! 481: tcg_temp_free_internal(GET_TCGV_I32(arg)); ! 482: } ! 483: ! 484: void tcg_temp_free_i64(TCGv_i64 arg) ! 485: { ! 486: tcg_temp_free_internal(GET_TCGV_I64(arg)); ! 487: } ! 488: ! 489: TCGv_i32 tcg_const_i32(int32_t val) ! 490: { ! 491: TCGv_i32 t0; ! 492: t0 = tcg_temp_new_i32(); ! 493: tcg_gen_movi_i32(t0, val); ! 494: return t0; ! 495: } ! 496: ! 497: TCGv_i64 tcg_const_i64(int64_t val) ! 498: { ! 499: TCGv_i64 t0; ! 500: t0 = tcg_temp_new_i64(); ! 501: tcg_gen_movi_i64(t0, val); ! 502: return t0; ! 503: } ! 504: ! 505: TCGv_i32 tcg_const_local_i32(int32_t val) ! 506: { ! 507: TCGv_i32 t0; ! 508: t0 = tcg_temp_local_new_i32(); ! 509: tcg_gen_movi_i32(t0, val); ! 510: return t0; ! 511: } ! 512: ! 513: TCGv_i64 tcg_const_local_i64(int64_t val) ! 514: { ! 515: TCGv_i64 t0; ! 516: t0 = tcg_temp_local_new_i64(); ! 517: tcg_gen_movi_i64(t0, val); ! 518: return t0; ! 519: } ! 520: ! 521: void tcg_register_helper(void *func, const char *name) ! 522: { ! 523: TCGContext *s = &tcg_ctx; ! 524: int n; ! 525: if ((s->nb_helpers + 1) > s->allocated_helpers) { ! 526: n = s->allocated_helpers; ! 527: if (n == 0) { ! 528: n = 4; ! 529: } else { ! 530: n *= 2; ! 531: } ! 532: s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo)); ! 533: s->allocated_helpers = n; ! 534: } ! 535: s->helpers[s->nb_helpers].func = (tcg_target_ulong)func; ! 536: s->helpers[s->nb_helpers].name = name; ! 537: s->nb_helpers++; ! 538: } ! 539: ! 540: /* Note: we convert the 64 bit args to 32 bit and do some alignment ! 541: and endian swap. Maybe it would be better to do the alignment ! 542: and endian swap in tcg_reg_alloc_call(). */ ! 543: void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, ! 544: int sizemask, TCGArg ret, int nargs, TCGArg *args) ! 545: { ! 546: int call_type; ! 547: int i; ! 548: int real_args; ! 549: int nb_rets; ! 550: TCGArg *nparam; ! 551: *gen_opc_ptr++ = INDEX_op_call; ! 552: nparam = gen_opparam_ptr++; ! 553: call_type = (flags & TCG_CALL_TYPE_MASK); ! 554: if (ret != TCG_CALL_DUMMY_ARG) { ! 555: #if TCG_TARGET_REG_BITS < 64 ! 556: if (sizemask & 1) { ! 557: #ifdef TCG_TARGET_WORDS_BIGENDIAN ! 558: *gen_opparam_ptr++ = ret + 1; ! 559: *gen_opparam_ptr++ = ret; ! 560: #else ! 561: *gen_opparam_ptr++ = ret; ! 562: *gen_opparam_ptr++ = ret + 1; ! 563: #endif ! 564: nb_rets = 2; ! 565: } else ! 566: #endif ! 567: { ! 568: *gen_opparam_ptr++ = ret; ! 569: nb_rets = 1; ! 570: } ! 571: } else { ! 572: nb_rets = 0; ! 573: } ! 574: real_args = 0; ! 575: for (i = 0; i < nargs; i++) { ! 576: #if TCG_TARGET_REG_BITS < 64 ! 577: if (sizemask & (2 << i)) { ! 578: #ifdef TCG_TARGET_I386 ! 579: /* REGPARM case: if the third parameter is 64 bit, it is ! 580: allocated on the stack */ ! 581: if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) { ! 582: call_type = TCG_CALL_TYPE_REGPARM_2; ! 583: flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; ! 584: } ! 585: #endif ! 586: #ifdef TCG_TARGET_CALL_ALIGN_ARGS ! 587: /* some targets want aligned 64 bit args */ ! 588: if (real_args & 1) { ! 589: *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; ! 590: real_args++; ! 591: } ! 592: #endif ! 593: #ifdef TCG_TARGET_WORDS_BIGENDIAN ! 594: *gen_opparam_ptr++ = args[i] + 1; ! 595: *gen_opparam_ptr++ = args[i]; ! 596: #else ! 597: *gen_opparam_ptr++ = args[i]; ! 598: *gen_opparam_ptr++ = args[i] + 1; ! 599: #endif ! 600: real_args += 2; ! 601: } else ! 602: #endif ! 603: { ! 604: *gen_opparam_ptr++ = args[i]; ! 605: real_args++; ! 606: } ! 607: } ! 608: *gen_opparam_ptr++ = GET_TCGV_PTR(func); ! 609: ! 610: *gen_opparam_ptr++ = flags; ! 611: ! 612: *nparam = (nb_rets << 16) | (real_args + 1); ! 613: ! 614: /* total parameters, needed to go backward in the instruction stream */ ! 615: *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; ! 616: } ! 617: ! 618: #if TCG_TARGET_REG_BITS == 32 ! 619: void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, ! 620: int c, int right, int arith) ! 621: { ! 622: if (c == 0) { ! 623: tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); ! 624: tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); ! 625: } else if (c >= 32) { ! 626: c -= 32; ! 627: if (right) { ! 628: if (arith) { ! 629: tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); ! 630: tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); ! 631: } else { ! 632: tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); ! 633: tcg_gen_movi_i32(TCGV_HIGH(ret), 0); ! 634: } ! 635: } else { ! 636: tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); ! 637: tcg_gen_movi_i32(TCGV_LOW(ret), 0); ! 638: } ! 639: } else { ! 640: TCGv_i32 t0, t1; ! 641: ! 642: t0 = tcg_temp_new_i32(); ! 643: t1 = tcg_temp_new_i32(); ! 644: if (right) { ! 645: tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); ! 646: if (arith) ! 647: tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); ! 648: else ! 649: tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); ! 650: tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); ! 651: tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0); ! 652: tcg_gen_mov_i32(TCGV_HIGH(ret), t1); ! 653: } else { ! 654: tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); ! 655: /* Note: ret can be the same as arg1, so we use t1 */ ! 656: tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c); ! 657: tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); ! 658: tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); ! 659: tcg_gen_mov_i32(TCGV_LOW(ret), t1); ! 660: } ! 661: tcg_temp_free_i32(t0); ! 662: tcg_temp_free_i32(t1); ! 663: } ! 664: } ! 665: #endif ! 666: ! 667: static void tcg_reg_alloc_start(TCGContext *s) ! 668: { ! 669: int i; ! 670: TCGTemp *ts; ! 671: for(i = 0; i < s->nb_globals; i++) { ! 672: ts = &s->temps[i]; ! 673: if (ts->fixed_reg) { ! 674: ts->val_type = TEMP_VAL_REG; ! 675: } else { ! 676: ts->val_type = TEMP_VAL_MEM; ! 677: } ! 678: } ! 679: for(i = s->nb_globals; i < s->nb_temps; i++) { ! 680: ts = &s->temps[i]; ! 681: ts->val_type = TEMP_VAL_DEAD; ! 682: ts->mem_allocated = 0; ! 683: ts->fixed_reg = 0; ! 684: } ! 685: for(i = 0; i < TCG_TARGET_NB_REGS; i++) { ! 686: s->reg_to_temp[i] = -1; ! 687: } ! 688: } ! 689: ! 690: static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, ! 691: int idx) ! 692: { ! 693: TCGTemp *ts; ! 694: ! 695: ts = &s->temps[idx]; ! 696: if (idx < s->nb_globals) { ! 697: pstrcpy(buf, buf_size, ts->name); ! 698: } else { ! 699: if (ts->temp_local) ! 700: snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); ! 701: else ! 702: snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); ! 703: } ! 704: return buf; ! 705: } ! 706: ! 707: char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg) ! 708: { ! 709: return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg)); ! 710: } ! 711: ! 712: char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg) ! 713: { ! 714: return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg)); ! 715: } ! 716: ! 717: static int helper_cmp(const void *p1, const void *p2) ! 718: { ! 719: const TCGHelperInfo *th1 = p1; ! 720: const TCGHelperInfo *th2 = p2; ! 721: if (th1->func < th2->func) ! 722: return -1; ! 723: else if (th1->func == th2->func) ! 724: return 0; ! 725: else ! 726: return 1; ! 727: } ! 728: ! 729: /* find helper definition (Note: A hash table would be better) */ ! 730: static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) ! 731: { ! 732: int m, m_min, m_max; ! 733: TCGHelperInfo *th; ! 734: tcg_target_ulong v; ! 735: ! 736: if (unlikely(!s->helpers_sorted)) { ! 737: qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), ! 738: helper_cmp); ! 739: s->helpers_sorted = 1; ! 740: } ! 741: ! 742: /* binary search */ ! 743: m_min = 0; ! 744: m_max = s->nb_helpers - 1; ! 745: while (m_min <= m_max) { ! 746: m = (m_min + m_max) >> 1; ! 747: th = &s->helpers[m]; ! 748: v = th->func; ! 749: if (v == val) ! 750: return th; ! 751: else if (val < v) { ! 752: m_max = m - 1; ! 753: } else { ! 754: m_min = m + 1; ! 755: } ! 756: } ! 757: return NULL; ! 758: } ! 759: ! 760: static const char * const cond_name[] = ! 761: { ! 762: [TCG_COND_EQ] = "eq", ! 763: [TCG_COND_NE] = "ne", ! 764: [TCG_COND_LT] = "lt", ! 765: [TCG_COND_GE] = "ge", ! 766: [TCG_COND_LE] = "le", ! 767: [TCG_COND_GT] = "gt", ! 768: [TCG_COND_LTU] = "ltu", ! 769: [TCG_COND_GEU] = "geu", ! 770: [TCG_COND_LEU] = "leu", ! 771: [TCG_COND_GTU] = "gtu" ! 772: }; ! 773: ! 774: void tcg_dump_ops(TCGContext *s, FILE *outfile) ! 775: { ! 776: const uint16_t *opc_ptr; ! 777: const TCGArg *args; ! 778: TCGArg arg; ! 779: int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; ! 780: const TCGOpDef *def; ! 781: char buf[128]; ! 782: ! 783: first_insn = 1; ! 784: opc_ptr = gen_opc_buf; ! 785: args = gen_opparam_buf; ! 786: while (opc_ptr < gen_opc_ptr) { ! 787: c = *opc_ptr++; ! 788: def = &tcg_op_defs[c]; ! 789: if (c == INDEX_op_debug_insn_start) { ! 790: uint64_t pc; ! 791: #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS ! 792: pc = ((uint64_t)args[1] << 32) | args[0]; ! 793: #else ! 794: pc = args[0]; ! 795: #endif ! 796: if (!first_insn) ! 797: fprintf(outfile, "\n"); ! 798: fprintf(outfile, " ---- 0x%" PRIx64, pc); ! 799: first_insn = 0; ! 800: nb_oargs = def->nb_oargs; ! 801: nb_iargs = def->nb_iargs; ! 802: nb_cargs = def->nb_cargs; ! 803: } else if (c == INDEX_op_call) { ! 804: TCGArg arg; ! 805: ! 806: /* variable number of arguments */ ! 807: arg = *args++; ! 808: nb_oargs = arg >> 16; ! 809: nb_iargs = arg & 0xffff; ! 810: nb_cargs = def->nb_cargs; ! 811: ! 812: fprintf(outfile, " %s ", def->name); ! 813: ! 814: /* function name */ ! 815: fprintf(outfile, "%s", ! 816: tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); ! 817: /* flags */ ! 818: fprintf(outfile, ",$0x%" TCG_PRIlx, ! 819: args[nb_oargs + nb_iargs]); ! 820: /* nb out args */ ! 821: fprintf(outfile, ",$%d", nb_oargs); ! 822: for(i = 0; i < nb_oargs; i++) { ! 823: fprintf(outfile, ","); ! 824: fprintf(outfile, "%s", ! 825: tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); ! 826: } ! 827: for(i = 0; i < (nb_iargs - 1); i++) { ! 828: fprintf(outfile, ","); ! 829: if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { ! 830: fprintf(outfile, "<dummy>"); ! 831: } else { ! 832: fprintf(outfile, "%s", ! 833: tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); ! 834: } ! 835: } ! 836: } else if (c == INDEX_op_movi_i32 ! 837: #if TCG_TARGET_REG_BITS == 64 ! 838: || c == INDEX_op_movi_i64 ! 839: #endif ! 840: ) { ! 841: tcg_target_ulong val; ! 842: TCGHelperInfo *th; ! 843: ! 844: nb_oargs = def->nb_oargs; ! 845: nb_iargs = def->nb_iargs; ! 846: nb_cargs = def->nb_cargs; ! 847: fprintf(outfile, " %s %s,$", def->name, ! 848: tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); ! 849: val = args[1]; ! 850: th = tcg_find_helper(s, val); ! 851: if (th) { ! 852: fprintf(outfile, "%s", th->name); ! 853: } else { ! 854: if (c == INDEX_op_movi_i32) ! 855: fprintf(outfile, "0x%x", (uint32_t)val); ! 856: else ! 857: fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); ! 858: } ! 859: } else { ! 860: fprintf(outfile, " %s ", def->name); ! 861: if (c == INDEX_op_nopn) { ! 862: /* variable number of arguments */ ! 863: nb_cargs = *args; ! 864: nb_oargs = 0; ! 865: nb_iargs = 0; ! 866: } else { ! 867: nb_oargs = def->nb_oargs; ! 868: nb_iargs = def->nb_iargs; ! 869: nb_cargs = def->nb_cargs; ! 870: } ! 871: ! 872: k = 0; ! 873: for(i = 0; i < nb_oargs; i++) { ! 874: if (k != 0) ! 875: fprintf(outfile, ","); ! 876: fprintf(outfile, "%s", ! 877: tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); ! 878: } ! 879: for(i = 0; i < nb_iargs; i++) { ! 880: if (k != 0) ! 881: fprintf(outfile, ","); ! 882: fprintf(outfile, "%s", ! 883: tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); ! 884: } ! 885: if (c == INDEX_op_brcond_i32 ! 886: #if TCG_TARGET_REG_BITS == 32 ! 887: || c == INDEX_op_brcond2_i32 ! 888: #elif TCG_TARGET_REG_BITS == 64 ! 889: || c == INDEX_op_brcond_i64 ! 890: #endif ! 891: ) { ! 892: if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) ! 893: fprintf(outfile, ",%s", cond_name[args[k++]]); ! 894: else ! 895: fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]); ! 896: i = 1; ! 897: } ! 898: else ! 899: i = 0; ! 900: for(; i < nb_cargs; i++) { ! 901: if (k != 0) ! 902: fprintf(outfile, ","); ! 903: arg = args[k++]; ! 904: fprintf(outfile, "$0x%" TCG_PRIlx, arg); ! 905: } ! 906: } ! 907: fprintf(outfile, "\n"); ! 908: args += nb_iargs + nb_oargs + nb_cargs; ! 909: } ! 910: } ! 911: ! 912: /* we give more priority to constraints with less registers */ ! 913: static int get_constraint_priority(const TCGOpDef *def, int k) ! 914: { ! 915: const TCGArgConstraint *arg_ct; ! 916: ! 917: int i, n; ! 918: arg_ct = &def->args_ct[k]; ! 919: if (arg_ct->ct & TCG_CT_ALIAS) { ! 920: /* an alias is equivalent to a single register */ ! 921: n = 1; ! 922: } else { ! 923: if (!(arg_ct->ct & TCG_CT_REG)) ! 924: return 0; ! 925: n = 0; ! 926: for(i = 0; i < TCG_TARGET_NB_REGS; i++) { ! 927: if (tcg_regset_test_reg(arg_ct->u.regs, i)) ! 928: n++; ! 929: } ! 930: } ! 931: return TCG_TARGET_NB_REGS - n + 1; ! 932: } ! 933: ! 934: /* sort from highest priority to lowest */ ! 935: static void sort_constraints(TCGOpDef *def, int start, int n) ! 936: { ! 937: int i, j, p1, p2, tmp; ! 938: ! 939: for(i = 0; i < n; i++) ! 940: def->sorted_args[start + i] = start + i; ! 941: if (n <= 1) ! 942: return; ! 943: for(i = 0; i < n - 1; i++) { ! 944: for(j = i + 1; j < n; j++) { ! 945: p1 = get_constraint_priority(def, def->sorted_args[start + i]); ! 946: p2 = get_constraint_priority(def, def->sorted_args[start + j]); ! 947: if (p1 < p2) { ! 948: tmp = def->sorted_args[start + i]; ! 949: def->sorted_args[start + i] = def->sorted_args[start + j]; ! 950: def->sorted_args[start + j] = tmp; ! 951: } ! 952: } ! 953: } ! 954: } ! 955: ! 956: void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) ! 957: { ! 958: int op; ! 959: TCGOpDef *def; ! 960: const char *ct_str; ! 961: int i, nb_args; ! 962: ! 963: for(;;) { ! 964: if (tdefs->op < 0) ! 965: break; ! 966: op = tdefs->op; ! 967: assert(op >= 0 && op < NB_OPS); ! 968: def = &tcg_op_defs[op]; ! 969: nb_args = def->nb_iargs + def->nb_oargs; ! 970: for(i = 0; i < nb_args; i++) { ! 971: ct_str = tdefs->args_ct_str[i]; ! 972: tcg_regset_clear(def->args_ct[i].u.regs); ! 973: def->args_ct[i].ct = 0; ! 974: if (ct_str[0] >= '0' && ct_str[0] <= '9') { ! 975: int oarg; ! 976: oarg = ct_str[0] - '0'; ! 977: assert(oarg < def->nb_oargs); ! 978: assert(def->args_ct[oarg].ct & TCG_CT_REG); ! 979: /* TCG_CT_ALIAS is for the output arguments. The input ! 980: argument is tagged with TCG_CT_IALIAS. */ ! 981: def->args_ct[i] = def->args_ct[oarg]; ! 982: def->args_ct[oarg].ct = TCG_CT_ALIAS; ! 983: def->args_ct[oarg].alias_index = i; ! 984: def->args_ct[i].ct |= TCG_CT_IALIAS; ! 985: def->args_ct[i].alias_index = oarg; ! 986: } else { ! 987: for(;;) { ! 988: if (*ct_str == '\0') ! 989: break; ! 990: switch(*ct_str) { ! 991: case 'i': ! 992: def->args_ct[i].ct |= TCG_CT_CONST; ! 993: ct_str++; ! 994: break; ! 995: default: ! 996: if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { ! 997: fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", ! 998: ct_str, i, def->name); ! 999: exit(1); ! 1000: } ! 1001: } ! 1002: } ! 1003: } ! 1004: } ! 1005: ! 1006: /* sort the constraints (XXX: this is just an heuristic) */ ! 1007: sort_constraints(def, 0, def->nb_oargs); ! 1008: sort_constraints(def, def->nb_oargs, def->nb_iargs); ! 1009: ! 1010: #if 0 ! 1011: { ! 1012: int i; ! 1013: ! 1014: printf("%s: sorted=", def->name); ! 1015: for(i = 0; i < def->nb_oargs + def->nb_iargs; i++) ! 1016: printf(" %d", def->sorted_args[i]); ! 1017: printf("\n"); ! 1018: } ! 1019: #endif ! 1020: tdefs++; ! 1021: } ! 1022: ! 1023: } ! 1024: ! 1025: #ifdef USE_LIVENESS_ANALYSIS ! 1026: ! 1027: /* set a nop for an operation using 'nb_args' */ ! 1028: static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, ! 1029: TCGArg *args, int nb_args) ! 1030: { ! 1031: if (nb_args == 0) { ! 1032: *opc_ptr = INDEX_op_nop; ! 1033: } else { ! 1034: *opc_ptr = INDEX_op_nopn; ! 1035: args[0] = nb_args; ! 1036: args[nb_args - 1] = nb_args; ! 1037: } ! 1038: } ! 1039: ! 1040: /* liveness analysis: end of function: globals are live, temps are ! 1041: dead. */ ! 1042: /* XXX: at this stage, not used as there would be little gains because ! 1043: most TBs end with a conditional jump. */ ! 1044: static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) ! 1045: { ! 1046: memset(dead_temps, 0, s->nb_globals); ! 1047: memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); ! 1048: } ! 1049: ! 1050: /* liveness analysis: end of basic block: globals are live, temps are ! 1051: dead, local temps are live. */ ! 1052: static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) ! 1053: { ! 1054: int i; ! 1055: TCGTemp *ts; ! 1056: ! 1057: memset(dead_temps, 0, s->nb_globals); ! 1058: ts = &s->temps[s->nb_globals]; ! 1059: for(i = s->nb_globals; i < s->nb_temps; i++) { ! 1060: if (ts->temp_local) ! 1061: dead_temps[i] = 0; ! 1062: else ! 1063: dead_temps[i] = 1; ! 1064: ts++; ! 1065: } ! 1066: } ! 1067: ! 1068: /* Liveness analysis : update the opc_dead_iargs array to tell if a ! 1069: given input arguments is dead. Instructions updating dead ! 1070: temporaries are removed. */ ! 1071: static void tcg_liveness_analysis(TCGContext *s) ! 1072: { ! 1073: int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops; ! 1074: TCGArg *args; ! 1075: const TCGOpDef *def; ! 1076: uint8_t *dead_temps; ! 1077: unsigned int dead_iargs; ! 1078: ! 1079: gen_opc_ptr++; /* skip end */ ! 1080: ! 1081: nb_ops = gen_opc_ptr - gen_opc_buf; ! 1082: ! 1083: /* XXX: make it really dynamic */ ! 1084: s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t)); ! 1085: ! 1086: dead_temps = tcg_malloc(s->nb_temps); ! 1087: memset(dead_temps, 1, s->nb_temps); ! 1088: ! 1089: args = gen_opparam_ptr; ! 1090: op_index = nb_ops - 1; ! 1091: while (op_index >= 0) { ! 1092: op = gen_opc_buf[op_index]; ! 1093: def = &tcg_op_defs[op]; ! 1094: switch(op) { ! 1095: case INDEX_op_call: ! 1096: { ! 1097: int call_flags; ! 1098: ! 1099: nb_args = args[-1]; ! 1100: args -= nb_args; ! 1101: nb_iargs = args[0] & 0xffff; ! 1102: nb_oargs = args[0] >> 16; ! 1103: args++; ! 1104: call_flags = args[nb_oargs + nb_iargs]; ! 1105: ! 1106: /* pure functions can be removed if their result is not ! 1107: used */ ! 1108: if (call_flags & TCG_CALL_PURE) { ! 1109: for(i = 0; i < nb_oargs; i++) { ! 1110: arg = args[i]; ! 1111: if (!dead_temps[arg]) ! 1112: goto do_not_remove_call; ! 1113: } ! 1114: tcg_set_nop(s, gen_opc_buf + op_index, ! 1115: args - 1, nb_args); ! 1116: } else { ! 1117: do_not_remove_call: ! 1118: ! 1119: /* output args are dead */ ! 1120: for(i = 0; i < nb_oargs; i++) { ! 1121: arg = args[i]; ! 1122: dead_temps[arg] = 1; ! 1123: } ! 1124: ! 1125: /* globals are live (they may be used by the call) */ ! 1126: memset(dead_temps, 0, s->nb_globals); ! 1127: ! 1128: /* input args are live */ ! 1129: dead_iargs = 0; ! 1130: for(i = 0; i < nb_iargs; i++) { ! 1131: arg = args[i + nb_oargs]; ! 1132: if (arg != TCG_CALL_DUMMY_ARG) { ! 1133: if (dead_temps[arg]) { ! 1134: dead_iargs |= (1 << i); ! 1135: } ! 1136: dead_temps[arg] = 0; ! 1137: } ! 1138: } ! 1139: s->op_dead_iargs[op_index] = dead_iargs; ! 1140: } ! 1141: args--; ! 1142: } ! 1143: break; ! 1144: case INDEX_op_set_label: ! 1145: args--; ! 1146: /* mark end of basic block */ ! 1147: tcg_la_bb_end(s, dead_temps); ! 1148: break; ! 1149: case INDEX_op_debug_insn_start: ! 1150: args -= def->nb_args; ! 1151: break; ! 1152: case INDEX_op_nopn: ! 1153: nb_args = args[-1]; ! 1154: args -= nb_args; ! 1155: break; ! 1156: case INDEX_op_discard: ! 1157: args--; ! 1158: /* mark the temporary as dead */ ! 1159: dead_temps[args[0]] = 1; ! 1160: break; ! 1161: case INDEX_op_end: ! 1162: break; ! 1163: /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ ! 1164: default: ! 1165: args -= def->nb_args; ! 1166: nb_iargs = def->nb_iargs; ! 1167: nb_oargs = def->nb_oargs; ! 1168: ! 1169: /* Test if the operation can be removed because all ! 1170: its outputs are dead. We assume that nb_oargs == 0 ! 1171: implies side effects */ ! 1172: if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { ! 1173: for(i = 0; i < nb_oargs; i++) { ! 1174: arg = args[i]; ! 1175: if (!dead_temps[arg]) ! 1176: goto do_not_remove; ! 1177: } ! 1178: tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); ! 1179: #ifdef CONFIG_PROFILER ! 1180: s->del_op_count++; ! 1181: #endif ! 1182: } else { ! 1183: do_not_remove: ! 1184: ! 1185: /* output args are dead */ ! 1186: for(i = 0; i < nb_oargs; i++) { ! 1187: arg = args[i]; ! 1188: dead_temps[arg] = 1; ! 1189: } ! 1190: ! 1191: /* if end of basic block, update */ ! 1192: if (def->flags & TCG_OPF_BB_END) { ! 1193: tcg_la_bb_end(s, dead_temps); ! 1194: } else if (def->flags & TCG_OPF_CALL_CLOBBER) { ! 1195: /* globals are live */ ! 1196: memset(dead_temps, 0, s->nb_globals); ! 1197: } ! 1198: ! 1199: /* input args are live */ ! 1200: dead_iargs = 0; ! 1201: for(i = 0; i < nb_iargs; i++) { ! 1202: arg = args[i + nb_oargs]; ! 1203: if (dead_temps[arg]) { ! 1204: dead_iargs |= (1 << i); ! 1205: } ! 1206: dead_temps[arg] = 0; ! 1207: } ! 1208: s->op_dead_iargs[op_index] = dead_iargs; ! 1209: } ! 1210: break; ! 1211: } ! 1212: op_index--; ! 1213: } ! 1214: ! 1215: if (args != gen_opparam_buf) ! 1216: tcg_abort(); ! 1217: } ! 1218: #else ! 1219: /* dummy liveness analysis */ ! 1220: void tcg_liveness_analysis(TCGContext *s) ! 1221: { ! 1222: int nb_ops; ! 1223: nb_ops = gen_opc_ptr - gen_opc_buf; ! 1224: ! 1225: s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); ! 1226: memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t)); ! 1227: } ! 1228: #endif ! 1229: ! 1230: #ifndef NDEBUG ! 1231: static void dump_regs(TCGContext *s) ! 1232: { ! 1233: TCGTemp *ts; ! 1234: int i; ! 1235: char buf[64]; ! 1236: ! 1237: for(i = 0; i < s->nb_temps; i++) { ! 1238: ts = &s->temps[i]; ! 1239: printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); ! 1240: switch(ts->val_type) { ! 1241: case TEMP_VAL_REG: ! 1242: printf("%s", tcg_target_reg_names[ts->reg]); ! 1243: break; ! 1244: case TEMP_VAL_MEM: ! 1245: printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]); ! 1246: break; ! 1247: case TEMP_VAL_CONST: ! 1248: printf("$0x%" TCG_PRIlx, ts->val); ! 1249: break; ! 1250: case TEMP_VAL_DEAD: ! 1251: printf("D"); ! 1252: break; ! 1253: default: ! 1254: printf("???"); ! 1255: break; ! 1256: } ! 1257: printf("\n"); ! 1258: } ! 1259: ! 1260: for(i = 0; i < TCG_TARGET_NB_REGS; i++) { ! 1261: if (s->reg_to_temp[i] >= 0) { ! 1262: printf("%s: %s\n", ! 1263: tcg_target_reg_names[i], ! 1264: tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i])); ! 1265: } ! 1266: } ! 1267: } ! 1268: ! 1269: static void check_regs(TCGContext *s) ! 1270: { ! 1271: int reg, k; ! 1272: TCGTemp *ts; ! 1273: char buf[64]; ! 1274: ! 1275: for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { ! 1276: k = s->reg_to_temp[reg]; ! 1277: if (k >= 0) { ! 1278: ts = &s->temps[k]; ! 1279: if (ts->val_type != TEMP_VAL_REG || ! 1280: ts->reg != reg) { ! 1281: printf("Inconsistency for register %s:\n", ! 1282: tcg_target_reg_names[reg]); ! 1283: goto fail; ! 1284: } ! 1285: } ! 1286: } ! 1287: for(k = 0; k < s->nb_temps; k++) { ! 1288: ts = &s->temps[k]; ! 1289: if (ts->val_type == TEMP_VAL_REG && ! 1290: !ts->fixed_reg && ! 1291: s->reg_to_temp[ts->reg] != k) { ! 1292: printf("Inconsistency for temp %s:\n", ! 1293: tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); ! 1294: fail: ! 1295: printf("reg state:\n"); ! 1296: dump_regs(s); ! 1297: tcg_abort(); ! 1298: } ! 1299: } ! 1300: } ! 1301: #endif ! 1302: ! 1303: static void temp_allocate_frame(TCGContext *s, int temp) ! 1304: { ! 1305: TCGTemp *ts; ! 1306: ts = &s->temps[temp]; ! 1307: s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1); ! 1308: if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) ! 1309: tcg_abort(); ! 1310: ts->mem_offset = s->current_frame_offset; ! 1311: ts->mem_reg = s->frame_reg; ! 1312: ts->mem_allocated = 1; ! 1313: s->current_frame_offset += sizeof(tcg_target_long); ! 1314: } ! 1315: ! 1316: /* free register 'reg' by spilling the corresponding temporary if necessary */ ! 1317: static void tcg_reg_free(TCGContext *s, int reg) ! 1318: { ! 1319: TCGTemp *ts; ! 1320: int temp; ! 1321: ! 1322: temp = s->reg_to_temp[reg]; ! 1323: if (temp != -1) { ! 1324: ts = &s->temps[temp]; ! 1325: assert(ts->val_type == TEMP_VAL_REG); ! 1326: if (!ts->mem_coherent) { ! 1327: if (!ts->mem_allocated) ! 1328: temp_allocate_frame(s, temp); ! 1329: tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); ! 1330: } ! 1331: ts->val_type = TEMP_VAL_MEM; ! 1332: s->reg_to_temp[reg] = -1; ! 1333: } ! 1334: } ! 1335: ! 1336: /* Allocate a register belonging to reg1 & ~reg2 */ ! 1337: static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) ! 1338: { ! 1339: int i, reg; ! 1340: TCGRegSet reg_ct; ! 1341: ! 1342: tcg_regset_andnot(reg_ct, reg1, reg2); ! 1343: ! 1344: /* first try free registers */ ! 1345: for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { ! 1346: reg = tcg_target_reg_alloc_order[i]; ! 1347: if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1) ! 1348: return reg; ! 1349: } ! 1350: ! 1351: /* XXX: do better spill choice */ ! 1352: for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { ! 1353: reg = tcg_target_reg_alloc_order[i]; ! 1354: if (tcg_regset_test_reg(reg_ct, reg)) { ! 1355: tcg_reg_free(s, reg); ! 1356: return reg; ! 1357: } ! 1358: } ! 1359: ! 1360: tcg_abort(); ! 1361: } ! 1362: ! 1363: /* save a temporary to memory. 'allocated_regs' is used in case a ! 1364: temporary registers needs to be allocated to store a constant. */ ! 1365: static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) ! 1366: { ! 1367: TCGTemp *ts; ! 1368: int reg; ! 1369: ! 1370: ts = &s->temps[temp]; ! 1371: if (!ts->fixed_reg) { ! 1372: switch(ts->val_type) { ! 1373: case TEMP_VAL_REG: ! 1374: tcg_reg_free(s, ts->reg); ! 1375: break; ! 1376: case TEMP_VAL_DEAD: ! 1377: ts->val_type = TEMP_VAL_MEM; ! 1378: break; ! 1379: case TEMP_VAL_CONST: ! 1380: reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], ! 1381: allocated_regs); ! 1382: if (!ts->mem_allocated) ! 1383: temp_allocate_frame(s, temp); ! 1384: tcg_out_movi(s, ts->type, reg, ts->val); ! 1385: tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); ! 1386: ts->val_type = TEMP_VAL_MEM; ! 1387: break; ! 1388: case TEMP_VAL_MEM: ! 1389: break; ! 1390: default: ! 1391: tcg_abort(); ! 1392: } ! 1393: } ! 1394: } ! 1395: ! 1396: /* save globals to their cannonical location and assume they can be ! 1397: modified be the following code. 'allocated_regs' is used in case a ! 1398: temporary registers needs to be allocated to store a constant. */ ! 1399: static void save_globals(TCGContext *s, TCGRegSet allocated_regs) ! 1400: { ! 1401: int i; ! 1402: ! 1403: for(i = 0; i < s->nb_globals; i++) { ! 1404: temp_save(s, i, allocated_regs); ! 1405: } ! 1406: } ! 1407: ! 1408: /* at the end of a basic block, we assume all temporaries are dead and ! 1409: all globals are stored at their canonical location. */ ! 1410: static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) ! 1411: { ! 1412: TCGTemp *ts; ! 1413: int i; ! 1414: ! 1415: for(i = s->nb_globals; i < s->nb_temps; i++) { ! 1416: ts = &s->temps[i]; ! 1417: if (ts->temp_local) { ! 1418: temp_save(s, i, allocated_regs); ! 1419: } else { ! 1420: if (ts->val_type == TEMP_VAL_REG) { ! 1421: s->reg_to_temp[ts->reg] = -1; ! 1422: } ! 1423: ts->val_type = TEMP_VAL_DEAD; ! 1424: } ! 1425: } ! 1426: ! 1427: save_globals(s, allocated_regs); ! 1428: } ! 1429: ! 1430: #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1) ! 1431: ! 1432: static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) ! 1433: { ! 1434: TCGTemp *ots; ! 1435: tcg_target_ulong val; ! 1436: ! 1437: ots = &s->temps[args[0]]; ! 1438: val = args[1]; ! 1439: ! 1440: if (ots->fixed_reg) { ! 1441: /* for fixed registers, we do not do any constant ! 1442: propagation */ ! 1443: tcg_out_movi(s, ots->type, ots->reg, val); ! 1444: } else { ! 1445: /* The movi is not explicitly generated here */ ! 1446: if (ots->val_type == TEMP_VAL_REG) ! 1447: s->reg_to_temp[ots->reg] = -1; ! 1448: ots->val_type = TEMP_VAL_CONST; ! 1449: ots->val = val; ! 1450: } ! 1451: } ! 1452: ! 1453: static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, ! 1454: const TCGArg *args, ! 1455: unsigned int dead_iargs) ! 1456: { ! 1457: TCGTemp *ts, *ots; ! 1458: int reg; ! 1459: const TCGArgConstraint *arg_ct; ! 1460: ! 1461: ots = &s->temps[args[0]]; ! 1462: ts = &s->temps[args[1]]; ! 1463: arg_ct = &def->args_ct[0]; ! 1464: ! 1465: /* XXX: always mark arg dead if IS_DEAD_IARG(0) */ ! 1466: if (ts->val_type == TEMP_VAL_REG) { ! 1467: if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) { ! 1468: /* the mov can be suppressed */ ! 1469: if (ots->val_type == TEMP_VAL_REG) ! 1470: s->reg_to_temp[ots->reg] = -1; ! 1471: reg = ts->reg; ! 1472: s->reg_to_temp[reg] = -1; ! 1473: ts->val_type = TEMP_VAL_DEAD; ! 1474: } else { ! 1475: if (ots->val_type == TEMP_VAL_REG) { ! 1476: reg = ots->reg; ! 1477: } else { ! 1478: reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); ! 1479: } ! 1480: if (ts->reg != reg) { ! 1481: tcg_out_mov(s, reg, ts->reg); ! 1482: } ! 1483: } ! 1484: } else if (ts->val_type == TEMP_VAL_MEM) { ! 1485: if (ots->val_type == TEMP_VAL_REG) { ! 1486: reg = ots->reg; ! 1487: } else { ! 1488: reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); ! 1489: } ! 1490: tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); ! 1491: } else if (ts->val_type == TEMP_VAL_CONST) { ! 1492: if (ots->fixed_reg) { ! 1493: reg = ots->reg; ! 1494: tcg_out_movi(s, ots->type, reg, ts->val); ! 1495: } else { ! 1496: /* propagate constant */ ! 1497: if (ots->val_type == TEMP_VAL_REG) ! 1498: s->reg_to_temp[ots->reg] = -1; ! 1499: ots->val_type = TEMP_VAL_CONST; ! 1500: ots->val = ts->val; ! 1501: return; ! 1502: } ! 1503: } else { ! 1504: tcg_abort(); ! 1505: } ! 1506: s->reg_to_temp[reg] = args[0]; ! 1507: ots->reg = reg; ! 1508: ots->val_type = TEMP_VAL_REG; ! 1509: ots->mem_coherent = 0; ! 1510: } ! 1511: ! 1512: static void tcg_reg_alloc_op(TCGContext *s, ! 1513: const TCGOpDef *def, int opc, ! 1514: const TCGArg *args, ! 1515: unsigned int dead_iargs) ! 1516: { ! 1517: TCGRegSet allocated_regs; ! 1518: int i, k, nb_iargs, nb_oargs, reg; ! 1519: TCGArg arg; ! 1520: const TCGArgConstraint *arg_ct; ! 1521: TCGTemp *ts; ! 1522: TCGArg new_args[TCG_MAX_OP_ARGS]; ! 1523: int const_args[TCG_MAX_OP_ARGS]; ! 1524: ! 1525: nb_oargs = def->nb_oargs; ! 1526: nb_iargs = def->nb_iargs; ! 1527: ! 1528: /* copy constants */ ! 1529: memcpy(new_args + nb_oargs + nb_iargs, ! 1530: args + nb_oargs + nb_iargs, ! 1531: sizeof(TCGArg) * def->nb_cargs); ! 1532: ! 1533: /* satisfy input constraints */ ! 1534: tcg_regset_set(allocated_regs, s->reserved_regs); ! 1535: for(k = 0; k < nb_iargs; k++) { ! 1536: i = def->sorted_args[nb_oargs + k]; ! 1537: arg = args[i]; ! 1538: arg_ct = &def->args_ct[i]; ! 1539: ts = &s->temps[arg]; ! 1540: if (ts->val_type == TEMP_VAL_MEM) { ! 1541: reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); ! 1542: tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); ! 1543: ts->val_type = TEMP_VAL_REG; ! 1544: ts->reg = reg; ! 1545: ts->mem_coherent = 1; ! 1546: s->reg_to_temp[reg] = arg; ! 1547: } else if (ts->val_type == TEMP_VAL_CONST) { ! 1548: if (tcg_target_const_match(ts->val, arg_ct)) { ! 1549: /* constant is OK for instruction */ ! 1550: const_args[i] = 1; ! 1551: new_args[i] = ts->val; ! 1552: goto iarg_end; ! 1553: } else { ! 1554: /* need to move to a register */ ! 1555: reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); ! 1556: tcg_out_movi(s, ts->type, reg, ts->val); ! 1557: ts->val_type = TEMP_VAL_REG; ! 1558: ts->reg = reg; ! 1559: ts->mem_coherent = 0; ! 1560: s->reg_to_temp[reg] = arg; ! 1561: } ! 1562: } ! 1563: assert(ts->val_type == TEMP_VAL_REG); ! 1564: if (arg_ct->ct & TCG_CT_IALIAS) { ! 1565: if (ts->fixed_reg) { ! 1566: /* if fixed register, we must allocate a new register ! 1567: if the alias is not the same register */ ! 1568: if (arg != args[arg_ct->alias_index]) ! 1569: goto allocate_in_reg; ! 1570: } else { ! 1571: /* if the input is aliased to an output and if it is ! 1572: not dead after the instruction, we must allocate ! 1573: a new register and move it */ ! 1574: if (!IS_DEAD_IARG(i - nb_oargs)) ! 1575: goto allocate_in_reg; ! 1576: } ! 1577: } ! 1578: reg = ts->reg; ! 1579: if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { ! 1580: /* nothing to do : the constraint is satisfied */ ! 1581: } else { ! 1582: allocate_in_reg: ! 1583: /* allocate a new register matching the constraint ! 1584: and move the temporary register into it */ ! 1585: reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); ! 1586: tcg_out_mov(s, reg, ts->reg); ! 1587: } ! 1588: new_args[i] = reg; ! 1589: const_args[i] = 0; ! 1590: tcg_regset_set_reg(allocated_regs, reg); ! 1591: iarg_end: ; ! 1592: } ! 1593: ! 1594: if (def->flags & TCG_OPF_BB_END) { ! 1595: tcg_reg_alloc_bb_end(s, allocated_regs); ! 1596: } else { ! 1597: /* mark dead temporaries and free the associated registers */ ! 1598: for(i = 0; i < nb_iargs; i++) { ! 1599: arg = args[nb_oargs + i]; ! 1600: if (IS_DEAD_IARG(i)) { ! 1601: ts = &s->temps[arg]; ! 1602: if (!ts->fixed_reg) { ! 1603: if (ts->val_type == TEMP_VAL_REG) ! 1604: s->reg_to_temp[ts->reg] = -1; ! 1605: ts->val_type = TEMP_VAL_DEAD; ! 1606: } ! 1607: } ! 1608: } ! 1609: ! 1610: if (def->flags & TCG_OPF_CALL_CLOBBER) { ! 1611: /* XXX: permit generic clobber register list ? */ ! 1612: for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { ! 1613: if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { ! 1614: tcg_reg_free(s, reg); ! 1615: } ! 1616: } ! 1617: /* XXX: for load/store we could do that only for the slow path ! 1618: (i.e. when a memory callback is called) */ ! 1619: ! 1620: /* store globals and free associated registers (we assume the insn ! 1621: can modify any global. */ ! 1622: save_globals(s, allocated_regs); ! 1623: } ! 1624: ! 1625: /* satisfy the output constraints */ ! 1626: tcg_regset_set(allocated_regs, s->reserved_regs); ! 1627: for(k = 0; k < nb_oargs; k++) { ! 1628: i = def->sorted_args[k]; ! 1629: arg = args[i]; ! 1630: arg_ct = &def->args_ct[i]; ! 1631: ts = &s->temps[arg]; ! 1632: if (arg_ct->ct & TCG_CT_ALIAS) { ! 1633: reg = new_args[arg_ct->alias_index]; ! 1634: } else { ! 1635: /* if fixed register, we try to use it */ ! 1636: reg = ts->reg; ! 1637: if (ts->fixed_reg && ! 1638: tcg_regset_test_reg(arg_ct->u.regs, reg)) { ! 1639: goto oarg_end; ! 1640: } ! 1641: reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); ! 1642: } ! 1643: tcg_regset_set_reg(allocated_regs, reg); ! 1644: /* if a fixed register is used, then a move will be done afterwards */ ! 1645: if (!ts->fixed_reg) { ! 1646: if (ts->val_type == TEMP_VAL_REG) ! 1647: s->reg_to_temp[ts->reg] = -1; ! 1648: ts->val_type = TEMP_VAL_REG; ! 1649: ts->reg = reg; ! 1650: /* temp value is modified, so the value kept in memory is ! 1651: potentially not the same */ ! 1652: ts->mem_coherent = 0; ! 1653: s->reg_to_temp[reg] = arg; ! 1654: } ! 1655: oarg_end: ! 1656: new_args[i] = reg; ! 1657: } ! 1658: } ! 1659: ! 1660: /* emit instruction */ ! 1661: tcg_out_op(s, opc, new_args, const_args); ! 1662: ! 1663: /* move the outputs in the correct register if needed */ ! 1664: for(i = 0; i < nb_oargs; i++) { ! 1665: ts = &s->temps[args[i]]; ! 1666: reg = new_args[i]; ! 1667: if (ts->fixed_reg && ts->reg != reg) { ! 1668: tcg_out_mov(s, ts->reg, reg); ! 1669: } ! 1670: } ! 1671: } ! 1672: ! 1673: #ifdef TCG_TARGET_STACK_GROWSUP ! 1674: #define STACK_DIR(x) (-(x)) ! 1675: #else ! 1676: #define STACK_DIR(x) (x) ! 1677: #endif ! 1678: ! 1679: static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, ! 1680: int opc, const TCGArg *args, ! 1681: unsigned int dead_iargs) ! 1682: { ! 1683: int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; ! 1684: TCGArg arg, func_arg; ! 1685: TCGTemp *ts; ! 1686: tcg_target_long stack_offset, call_stack_size, func_addr; ! 1687: int const_func_arg, allocate_args; ! 1688: TCGRegSet allocated_regs; ! 1689: const TCGArgConstraint *arg_ct; ! 1690: ! 1691: arg = *args++; ! 1692: ! 1693: nb_oargs = arg >> 16; ! 1694: nb_iargs = arg & 0xffff; ! 1695: nb_params = nb_iargs - 1; ! 1696: ! 1697: flags = args[nb_oargs + nb_iargs]; ! 1698: ! 1699: nb_regs = tcg_target_get_call_iarg_regs_count(flags); ! 1700: if (nb_regs > nb_params) ! 1701: nb_regs = nb_params; ! 1702: ! 1703: /* assign stack slots first */ ! 1704: /* XXX: preallocate call stack */ ! 1705: call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); ! 1706: call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & ! 1707: ~(TCG_TARGET_STACK_ALIGN - 1); ! 1708: allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); ! 1709: if (allocate_args) { ! 1710: tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); ! 1711: } ! 1712: ! 1713: stack_offset = TCG_TARGET_CALL_STACK_OFFSET; ! 1714: for(i = nb_regs; i < nb_params; i++) { ! 1715: arg = args[nb_oargs + i]; ! 1716: #ifdef TCG_TARGET_STACK_GROWSUP ! 1717: stack_offset -= sizeof(tcg_target_long); ! 1718: #endif ! 1719: if (arg != TCG_CALL_DUMMY_ARG) { ! 1720: ts = &s->temps[arg]; ! 1721: if (ts->val_type == TEMP_VAL_REG) { ! 1722: tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); ! 1723: } else if (ts->val_type == TEMP_VAL_MEM) { ! 1724: reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], ! 1725: s->reserved_regs); ! 1726: /* XXX: not correct if reading values from the stack */ ! 1727: tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); ! 1728: tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); ! 1729: } else if (ts->val_type == TEMP_VAL_CONST) { ! 1730: reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], ! 1731: s->reserved_regs); ! 1732: /* XXX: sign extend may be needed on some targets */ ! 1733: tcg_out_movi(s, ts->type, reg, ts->val); ! 1734: tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); ! 1735: } else { ! 1736: tcg_abort(); ! 1737: } ! 1738: } ! 1739: #ifndef TCG_TARGET_STACK_GROWSUP ! 1740: stack_offset += sizeof(tcg_target_long); ! 1741: #endif ! 1742: } ! 1743: ! 1744: /* assign input registers */ ! 1745: tcg_regset_set(allocated_regs, s->reserved_regs); ! 1746: for(i = 0; i < nb_regs; i++) { ! 1747: arg = args[nb_oargs + i]; ! 1748: if (arg != TCG_CALL_DUMMY_ARG) { ! 1749: ts = &s->temps[arg]; ! 1750: reg = tcg_target_call_iarg_regs[i]; ! 1751: tcg_reg_free(s, reg); ! 1752: if (ts->val_type == TEMP_VAL_REG) { ! 1753: if (ts->reg != reg) { ! 1754: tcg_out_mov(s, reg, ts->reg); ! 1755: } ! 1756: } else if (ts->val_type == TEMP_VAL_MEM) { ! 1757: tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); ! 1758: } else if (ts->val_type == TEMP_VAL_CONST) { ! 1759: /* XXX: sign extend ? */ ! 1760: tcg_out_movi(s, ts->type, reg, ts->val); ! 1761: } else { ! 1762: tcg_abort(); ! 1763: } ! 1764: tcg_regset_set_reg(allocated_regs, reg); ! 1765: } ! 1766: } ! 1767: ! 1768: /* assign function address */ ! 1769: func_arg = args[nb_oargs + nb_iargs - 1]; ! 1770: arg_ct = &def->args_ct[0]; ! 1771: ts = &s->temps[func_arg]; ! 1772: func_addr = ts->val; ! 1773: const_func_arg = 0; ! 1774: if (ts->val_type == TEMP_VAL_MEM) { ! 1775: reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); ! 1776: tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); ! 1777: func_arg = reg; ! 1778: tcg_regset_set_reg(allocated_regs, reg); ! 1779: } else if (ts->val_type == TEMP_VAL_REG) { ! 1780: reg = ts->reg; ! 1781: if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { ! 1782: reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); ! 1783: tcg_out_mov(s, reg, ts->reg); ! 1784: } ! 1785: func_arg = reg; ! 1786: tcg_regset_set_reg(allocated_regs, reg); ! 1787: } else if (ts->val_type == TEMP_VAL_CONST) { ! 1788: if (tcg_target_const_match(func_addr, arg_ct)) { ! 1789: const_func_arg = 1; ! 1790: func_arg = func_addr; ! 1791: } else { ! 1792: reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); ! 1793: tcg_out_movi(s, ts->type, reg, func_addr); ! 1794: func_arg = reg; ! 1795: tcg_regset_set_reg(allocated_regs, reg); ! 1796: } ! 1797: } else { ! 1798: tcg_abort(); ! 1799: } ! 1800: ! 1801: ! 1802: /* mark dead temporaries and free the associated registers */ ! 1803: for(i = 0; i < nb_iargs; i++) { ! 1804: arg = args[nb_oargs + i]; ! 1805: if (IS_DEAD_IARG(i)) { ! 1806: ts = &s->temps[arg]; ! 1807: if (!ts->fixed_reg) { ! 1808: if (ts->val_type == TEMP_VAL_REG) ! 1809: s->reg_to_temp[ts->reg] = -1; ! 1810: ts->val_type = TEMP_VAL_DEAD; ! 1811: } ! 1812: } ! 1813: } ! 1814: ! 1815: /* clobber call registers */ ! 1816: for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { ! 1817: if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { ! 1818: tcg_reg_free(s, reg); ! 1819: } ! 1820: } ! 1821: ! 1822: /* store globals and free associated registers (we assume the call ! 1823: can modify any global. */ ! 1824: save_globals(s, allocated_regs); ! 1825: ! 1826: tcg_out_op(s, opc, &func_arg, &const_func_arg); ! 1827: ! 1828: if (allocate_args) { ! 1829: tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); ! 1830: } ! 1831: ! 1832: /* assign output registers and emit moves if needed */ ! 1833: for(i = 0; i < nb_oargs; i++) { ! 1834: arg = args[i]; ! 1835: ts = &s->temps[arg]; ! 1836: reg = tcg_target_call_oarg_regs[i]; ! 1837: assert(s->reg_to_temp[reg] == -1); ! 1838: if (ts->fixed_reg) { ! 1839: if (ts->reg != reg) { ! 1840: tcg_out_mov(s, ts->reg, reg); ! 1841: } ! 1842: } else { ! 1843: if (ts->val_type == TEMP_VAL_REG) ! 1844: s->reg_to_temp[ts->reg] = -1; ! 1845: ts->val_type = TEMP_VAL_REG; ! 1846: ts->reg = reg; ! 1847: ts->mem_coherent = 0; ! 1848: s->reg_to_temp[reg] = arg; ! 1849: } ! 1850: } ! 1851: ! 1852: return nb_iargs + nb_oargs + def->nb_cargs + 1; ! 1853: } ! 1854: ! 1855: #ifdef CONFIG_PROFILER ! 1856: ! 1857: static int64_t tcg_table_op_count[NB_OPS]; ! 1858: ! 1859: void dump_op_count(void) ! 1860: { ! 1861: int i; ! 1862: FILE *f; ! 1863: f = fopen("/tmp/op.log", "w"); ! 1864: for(i = INDEX_op_end; i < NB_OPS; i++) { ! 1865: fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]); ! 1866: } ! 1867: fclose(f); ! 1868: } ! 1869: #endif ! 1870: ! 1871: ! 1872: static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, ! 1873: long search_pc) ! 1874: { ! 1875: int opc, op_index; ! 1876: const TCGOpDef *def; ! 1877: unsigned int dead_iargs; ! 1878: const TCGArg *args; ! 1879: ! 1880: #ifdef DEBUG_DISAS ! 1881: if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { ! 1882: qemu_log("OP:\n"); ! 1883: tcg_dump_ops(s, logfile); ! 1884: qemu_log("\n"); ! 1885: } ! 1886: #endif ! 1887: ! 1888: #ifdef CONFIG_PROFILER ! 1889: s->la_time -= profile_getclock(); ! 1890: #endif ! 1891: tcg_liveness_analysis(s); ! 1892: #ifdef CONFIG_PROFILER ! 1893: s->la_time += profile_getclock(); ! 1894: #endif ! 1895: ! 1896: #ifdef DEBUG_DISAS ! 1897: if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) { ! 1898: qemu_log("OP after la:\n"); ! 1899: tcg_dump_ops(s, logfile); ! 1900: qemu_log("\n"); ! 1901: } ! 1902: #endif ! 1903: ! 1904: tcg_reg_alloc_start(s); ! 1905: ! 1906: s->code_buf = gen_code_buf; ! 1907: s->code_ptr = gen_code_buf; ! 1908: ! 1909: args = gen_opparam_buf; ! 1910: op_index = 0; ! 1911: ! 1912: for(;;) { ! 1913: opc = gen_opc_buf[op_index]; ! 1914: #ifdef CONFIG_PROFILER ! 1915: tcg_table_op_count[opc]++; ! 1916: #endif ! 1917: def = &tcg_op_defs[opc]; ! 1918: #if 0 ! 1919: printf("%s: %d %d %d\n", def->name, ! 1920: def->nb_oargs, def->nb_iargs, def->nb_cargs); ! 1921: // dump_regs(s); ! 1922: #endif ! 1923: switch(opc) { ! 1924: case INDEX_op_mov_i32: ! 1925: #if TCG_TARGET_REG_BITS == 64 ! 1926: case INDEX_op_mov_i64: ! 1927: #endif ! 1928: dead_iargs = s->op_dead_iargs[op_index]; ! 1929: tcg_reg_alloc_mov(s, def, args, dead_iargs); ! 1930: break; ! 1931: case INDEX_op_movi_i32: ! 1932: #if TCG_TARGET_REG_BITS == 64 ! 1933: case INDEX_op_movi_i64: ! 1934: #endif ! 1935: tcg_reg_alloc_movi(s, args); ! 1936: break; ! 1937: case INDEX_op_debug_insn_start: ! 1938: /* debug instruction */ ! 1939: break; ! 1940: case INDEX_op_nop: ! 1941: case INDEX_op_nop1: ! 1942: case INDEX_op_nop2: ! 1943: case INDEX_op_nop3: ! 1944: break; ! 1945: case INDEX_op_nopn: ! 1946: args += args[0]; ! 1947: goto next; ! 1948: case INDEX_op_discard: ! 1949: { ! 1950: TCGTemp *ts; ! 1951: ts = &s->temps[args[0]]; ! 1952: /* mark the temporary as dead */ ! 1953: if (!ts->fixed_reg) { ! 1954: if (ts->val_type == TEMP_VAL_REG) ! 1955: s->reg_to_temp[ts->reg] = -1; ! 1956: ts->val_type = TEMP_VAL_DEAD; ! 1957: } ! 1958: } ! 1959: break; ! 1960: case INDEX_op_set_label: ! 1961: tcg_reg_alloc_bb_end(s, s->reserved_regs); ! 1962: tcg_out_label(s, args[0], (long)s->code_ptr); ! 1963: break; ! 1964: case INDEX_op_call: ! 1965: dead_iargs = s->op_dead_iargs[op_index]; ! 1966: args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs); ! 1967: goto next; ! 1968: case INDEX_op_end: ! 1969: goto the_end; ! 1970: default: ! 1971: /* Note: in order to speed up the code, it would be much ! 1972: faster to have specialized register allocator functions for ! 1973: some common argument patterns */ ! 1974: dead_iargs = s->op_dead_iargs[op_index]; ! 1975: tcg_reg_alloc_op(s, def, opc, args, dead_iargs); ! 1976: break; ! 1977: } ! 1978: args += def->nb_args; ! 1979: next: ! 1980: if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { ! 1981: return op_index; ! 1982: } ! 1983: op_index++; ! 1984: #ifndef NDEBUG ! 1985: check_regs(s); ! 1986: #endif ! 1987: } ! 1988: the_end: ! 1989: return -1; ! 1990: } ! 1991: ! 1992: int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) ! 1993: { ! 1994: #ifdef CONFIG_PROFILER ! 1995: { ! 1996: int n; ! 1997: n = (gen_opc_ptr - gen_opc_buf); ! 1998: s->op_count += n; ! 1999: if (n > s->op_count_max) ! 2000: s->op_count_max = n; ! 2001: ! 2002: s->temp_count += s->nb_temps; ! 2003: if (s->nb_temps > s->temp_count_max) ! 2004: s->temp_count_max = s->nb_temps; ! 2005: } ! 2006: #endif ! 2007: ! 2008: tcg_gen_code_common(s, gen_code_buf, -1); ! 2009: ! 2010: /* flush instruction cache */ ! 2011: flush_icache_range((unsigned long)gen_code_buf, ! 2012: (unsigned long)s->code_ptr); ! 2013: return s->code_ptr - gen_code_buf; ! 2014: } ! 2015: ! 2016: /* Return the index of the micro operation such as the pc after is < ! 2017: offset bytes from the start of the TB. The contents of gen_code_buf must ! 2018: not be changed, though writing the same values is ok. ! 2019: Return -1 if not found. */ ! 2020: int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) ! 2021: { ! 2022: return tcg_gen_code_common(s, gen_code_buf, offset); ! 2023: } ! 2024: ! 2025: #ifdef CONFIG_PROFILER ! 2026: void tcg_dump_info(FILE *f, ! 2027: int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) ! 2028: { ! 2029: TCGContext *s = &tcg_ctx; ! 2030: int64_t tot; ! 2031: ! 2032: tot = s->interm_time + s->code_time; ! 2033: cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", ! 2034: tot, tot / 2.4e9); ! 2035: cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", ! 2036: s->tb_count, ! 2037: s->tb_count1 - s->tb_count, ! 2038: s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); ! 2039: cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", ! 2040: s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); ! 2041: cpu_fprintf(f, "deleted ops/TB %0.2f\n", ! 2042: s->tb_count ? ! 2043: (double)s->del_op_count / s->tb_count : 0); ! 2044: cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", ! 2045: s->tb_count ? ! 2046: (double)s->temp_count / s->tb_count : 0, ! 2047: s->temp_count_max); ! 2048: ! 2049: cpu_fprintf(f, "cycles/op %0.1f\n", ! 2050: s->op_count ? (double)tot / s->op_count : 0); ! 2051: cpu_fprintf(f, "cycles/in byte %0.1f\n", ! 2052: s->code_in_len ? (double)tot / s->code_in_len : 0); ! 2053: cpu_fprintf(f, "cycles/out byte %0.1f\n", ! 2054: s->code_out_len ? (double)tot / s->code_out_len : 0); ! 2055: if (tot == 0) ! 2056: tot = 1; ! 2057: cpu_fprintf(f, " gen_interm time %0.1f%%\n", ! 2058: (double)s->interm_time / tot * 100.0); ! 2059: cpu_fprintf(f, " gen_code time %0.1f%%\n", ! 2060: (double)s->code_time / tot * 100.0); ! 2061: cpu_fprintf(f, "liveness/code time %0.1f%%\n", ! 2062: (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); ! 2063: cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", ! 2064: s->restore_count); ! 2065: cpu_fprintf(f, " avg cycles %0.1f\n", ! 2066: s->restore_count ? (double)s->restore_time / s->restore_count : 0); ! 2067: { ! 2068: extern void dump_op_count(void); ! 2069: dump_op_count(); ! 2070: } ! 2071: } ! 2072: #else ! 2073: void tcg_dump_info(FILE *f, ! 2074: int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) ! 2075: { ! 2076: cpu_fprintf(f, "[TCG profiler not compiled]\n"); ! 2077: } ! 2078: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.