Commit b03cce8e08237bb84735aa86aea5d7d7c4633e2d
1 parent
4d7a0880
fixed global variable handling with qemu load/stores - initial global prologue/e…
…pilogue implementation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4406 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
219 additions
and
62 deletions
tcg/i386/tcg-target.c
| @@ -46,6 +46,8 @@ int tcg_target_reg_alloc_order[] = { | @@ -46,6 +46,8 @@ int tcg_target_reg_alloc_order[] = { | ||
| 46 | const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX }; | 46 | const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX }; |
| 47 | const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX }; | 47 | const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX }; |
| 48 | 48 | ||
| 49 | +static uint8_t *tb_ret_addr; | ||
| 50 | + | ||
| 49 | static void patch_reloc(uint8_t *code_ptr, int type, | 51 | static void patch_reloc(uint8_t *code_ptr, int type, |
| 50 | tcg_target_long value, tcg_target_long addend) | 52 | tcg_target_long value, tcg_target_long addend) |
| 51 | { | 53 | { |
| @@ -879,7 +881,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, | @@ -879,7 +881,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, | ||
| 879 | switch(opc) { | 881 | switch(opc) { |
| 880 | case INDEX_op_exit_tb: | 882 | case INDEX_op_exit_tb: |
| 881 | tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]); | 883 | tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]); |
| 882 | - tcg_out8(s, 0xc3); /* ret */ | 884 | + tcg_out8(s, 0xe9); /* jmp tb_ret_addr */ |
| 885 | + tcg_out32(s, tb_ret_addr - s->code_ptr - 4); | ||
| 883 | break; | 886 | break; |
| 884 | case INDEX_op_goto_tb: | 887 | case INDEX_op_goto_tb: |
| 885 | if (s->tb_jmp_offset) { | 888 | if (s->tb_jmp_offset) { |
| @@ -1145,6 +1148,53 @@ static const TCGTargetOpDef x86_op_defs[] = { | @@ -1145,6 +1148,53 @@ static const TCGTargetOpDef x86_op_defs[] = { | ||
| 1145 | { -1 }, | 1148 | { -1 }, |
| 1146 | }; | 1149 | }; |
| 1147 | 1150 | ||
| 1151 | +static int tcg_target_callee_save_regs[] = { | ||
| 1152 | + /* TCG_REG_EBP, */ /* currently used for the global env, so no | ||
| 1153 | + need to save */ | ||
| 1154 | + TCG_REG_EBX, | ||
| 1155 | + TCG_REG_ESI, | ||
| 1156 | + TCG_REG_EDI, | ||
| 1157 | +}; | ||
| 1158 | + | ||
| 1159 | +static inline void tcg_out_push(TCGContext *s, int reg) | ||
| 1160 | +{ | ||
| 1161 | + tcg_out_opc(s, 0x50 + reg); | ||
| 1162 | +} | ||
| 1163 | + | ||
| 1164 | +static inline void tcg_out_pop(TCGContext *s, int reg) | ||
| 1165 | +{ | ||
| 1166 | + tcg_out_opc(s, 0x58 + reg); | ||
| 1167 | +} | ||
| 1168 | + | ||
| 1169 | +/* Generate global QEMU prologue and epilogue code */ | ||
| 1170 | +void tcg_target_qemu_prologue(TCGContext *s) | ||
| 1171 | +{ | ||
| 1172 | + int i, frame_size, push_size, stack_addend; | ||
| 1173 | + | ||
| 1174 | + /* TB prologue */ | ||
| 1175 | + /* save all callee saved registers */ | ||
| 1176 | + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { | ||
| 1177 | + tcg_out_push(s, tcg_target_callee_save_regs[i]); | ||
| 1178 | + } | ||
| 1179 | + /* reserve some stack space */ | ||
| 1180 | + push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4; | ||
| 1181 | + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; | ||
| 1182 | + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & | ||
| 1183 | + ~(TCG_TARGET_STACK_ALIGN - 1); | ||
| 1184 | + stack_addend = frame_size - push_size; | ||
| 1185 | + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); | ||
| 1186 | + | ||
| 1187 | + tcg_out_modrm(s, 0xff, 4, TCG_REG_EAX); /* jmp *%eax */ | ||
| 1188 | + | ||
| 1189 | + /* TB epilogue */ | ||
| 1190 | + tb_ret_addr = s->code_ptr; | ||
| 1191 | + tcg_out_addi(s, TCG_REG_ESP, stack_addend); | ||
| 1192 | + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { | ||
| 1193 | + tcg_out_pop(s, tcg_target_callee_save_regs[i]); | ||
| 1194 | + } | ||
| 1195 | + tcg_out8(s, 0xc3); /* ret */ | ||
| 1196 | +} | ||
| 1197 | + | ||
| 1148 | void tcg_target_init(TCGContext *s) | 1198 | void tcg_target_init(TCGContext *s) |
| 1149 | { | 1199 | { |
| 1150 | /* fail safe */ | 1200 | /* fail safe */ |
tcg/tcg.c
| @@ -242,6 +242,13 @@ void tcg_context_init(TCGContext *s) | @@ -242,6 +242,13 @@ void tcg_context_init(TCGContext *s) | ||
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | tcg_target_init(s); | 244 | tcg_target_init(s); |
| 245 | + | ||
| 246 | + /* init global prologue and epilogue */ | ||
| 247 | + s->code_buf = code_gen_prologue; | ||
| 248 | + s->code_ptr = s->code_buf; | ||
| 249 | + tcg_target_qemu_prologue(s); | ||
| 250 | + flush_icache_range((unsigned long)s->code_buf, | ||
| 251 | + (unsigned long)s->code_ptr); | ||
| 245 | } | 252 | } |
| 246 | 253 | ||
| 247 | void tcg_set_frame(TCGContext *s, int reg, | 254 | void tcg_set_frame(TCGContext *s, int reg, |
| @@ -680,36 +687,57 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) | @@ -680,36 +687,57 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) | ||
| 680 | nb_oargs = arg >> 16; | 687 | nb_oargs = arg >> 16; |
| 681 | nb_iargs = arg & 0xffff; | 688 | nb_iargs = arg & 0xffff; |
| 682 | nb_cargs = def->nb_cargs; | 689 | nb_cargs = def->nb_cargs; |
| 683 | - } else if (c == INDEX_op_nopn) { | ||
| 684 | - /* variable number of arguments */ | ||
| 685 | - nb_cargs = *args; | ||
| 686 | - nb_oargs = 0; | ||
| 687 | - nb_iargs = 0; | ||
| 688 | - } else { | ||
| 689 | - nb_oargs = def->nb_oargs; | ||
| 690 | - nb_iargs = def->nb_iargs; | ||
| 691 | - nb_cargs = def->nb_cargs; | ||
| 692 | - } | ||
| 693 | 690 | ||
| 694 | - k = 0; | ||
| 695 | - for(i = 0; i < nb_oargs; i++) { | ||
| 696 | - if (k != 0) | ||
| 697 | - fprintf(outfile, ","); | ||
| 698 | - fprintf(outfile, "%s", | ||
| 699 | - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); | ||
| 700 | - } | ||
| 701 | - for(i = 0; i < nb_iargs; i++) { | ||
| 702 | - if (k != 0) | ||
| 703 | - fprintf(outfile, ","); | 691 | + /* function name */ |
| 704 | /* XXX: dump helper name for call */ | 692 | /* XXX: dump helper name for call */ |
| 705 | fprintf(outfile, "%s", | 693 | fprintf(outfile, "%s", |
| 706 | - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); | ||
| 707 | - } | ||
| 708 | - for(i = 0; i < nb_cargs; i++) { | ||
| 709 | - if (k != 0) | 694 | + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); |
| 695 | + /* flags */ | ||
| 696 | + fprintf(outfile, ",$0x%" TCG_PRIlx, | ||
| 697 | + args[nb_oargs + nb_iargs]); | ||
| 698 | + /* nb out args */ | ||
| 699 | + fprintf(outfile, ",$%d", nb_oargs); | ||
| 700 | + for(i = 0; i < nb_oargs; i++) { | ||
| 701 | + fprintf(outfile, ","); | ||
| 702 | + fprintf(outfile, "%s", | ||
| 703 | + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); | ||
| 704 | + } | ||
| 705 | + for(i = 0; i < (nb_iargs - 1); i++) { | ||
| 710 | fprintf(outfile, ","); | 706 | fprintf(outfile, ","); |
| 711 | - arg = args[k++]; | ||
| 712 | - fprintf(outfile, "$0x%" TCG_PRIlx, arg); | 707 | + fprintf(outfile, "%s", |
| 708 | + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); | ||
| 709 | + } | ||
| 710 | + } else { | ||
| 711 | + if (c == INDEX_op_nopn) { | ||
| 712 | + /* variable number of arguments */ | ||
| 713 | + nb_cargs = *args; | ||
| 714 | + nb_oargs = 0; | ||
| 715 | + nb_iargs = 0; | ||
| 716 | + } else { | ||
| 717 | + nb_oargs = def->nb_oargs; | ||
| 718 | + nb_iargs = def->nb_iargs; | ||
| 719 | + nb_cargs = def->nb_cargs; | ||
| 720 | + } | ||
| 721 | + | ||
| 722 | + k = 0; | ||
| 723 | + for(i = 0; i < nb_oargs; i++) { | ||
| 724 | + if (k != 0) | ||
| 725 | + fprintf(outfile, ","); | ||
| 726 | + fprintf(outfile, "%s", | ||
| 727 | + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); | ||
| 728 | + } | ||
| 729 | + for(i = 0; i < nb_iargs; i++) { | ||
| 730 | + if (k != 0) | ||
| 731 | + fprintf(outfile, ","); | ||
| 732 | + fprintf(outfile, "%s", | ||
| 733 | + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); | ||
| 734 | + } | ||
| 735 | + for(i = 0; i < nb_cargs; i++) { | ||
| 736 | + if (k != 0) | ||
| 737 | + fprintf(outfile, ","); | ||
| 738 | + arg = args[k++]; | ||
| 739 | + fprintf(outfile, "$0x%" TCG_PRIlx, arg); | ||
| 740 | + } | ||
| 713 | } | 741 | } |
| 714 | fprintf(outfile, "\n"); | 742 | fprintf(outfile, "\n"); |
| 715 | args += nb_iargs + nb_oargs + nb_cargs; | 743 | args += nb_iargs + nb_oargs + nb_cargs; |
| @@ -1027,6 +1055,9 @@ void tcg_liveness_analysis(TCGContext *s) | @@ -1027,6 +1055,9 @@ void tcg_liveness_analysis(TCGContext *s) | ||
| 1027 | /* if end of basic block, update */ | 1055 | /* if end of basic block, update */ |
| 1028 | if (def->flags & TCG_OPF_BB_END) { | 1056 | if (def->flags & TCG_OPF_BB_END) { |
| 1029 | tcg_la_bb_end(s, dead_temps); | 1057 | tcg_la_bb_end(s, dead_temps); |
| 1058 | + } else if (def->flags & TCG_OPF_CALL_CLOBBER) { | ||
| 1059 | + /* globals are live */ | ||
| 1060 | + memset(dead_temps, 0, s->nb_globals); | ||
| 1030 | } | 1061 | } |
| 1031 | 1062 | ||
| 1032 | /* input args are live */ | 1063 | /* input args are live */ |
| @@ -1119,9 +1150,7 @@ static void check_regs(TCGContext *s) | @@ -1119,9 +1150,7 @@ static void check_regs(TCGContext *s) | ||
| 1119 | ts->reg != reg) { | 1150 | ts->reg != reg) { |
| 1120 | printf("Inconsistency for register %s:\n", | 1151 | printf("Inconsistency for register %s:\n", |
| 1121 | tcg_target_reg_names[reg]); | 1152 | tcg_target_reg_names[reg]); |
| 1122 | - printf("reg state:\n"); | ||
| 1123 | - dump_regs(s); | ||
| 1124 | - tcg_abort(); | 1153 | + goto fail; |
| 1125 | } | 1154 | } |
| 1126 | } | 1155 | } |
| 1127 | } | 1156 | } |
| @@ -1132,10 +1161,16 @@ static void check_regs(TCGContext *s) | @@ -1132,10 +1161,16 @@ static void check_regs(TCGContext *s) | ||
| 1132 | s->reg_to_temp[ts->reg] != k) { | 1161 | s->reg_to_temp[ts->reg] != k) { |
| 1133 | printf("Inconsistency for temp %s:\n", | 1162 | printf("Inconsistency for temp %s:\n", |
| 1134 | tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); | 1163 | tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); |
| 1164 | + fail: | ||
| 1135 | printf("reg state:\n"); | 1165 | printf("reg state:\n"); |
| 1136 | dump_regs(s); | 1166 | dump_regs(s); |
| 1137 | tcg_abort(); | 1167 | tcg_abort(); |
| 1138 | } | 1168 | } |
| 1169 | + if (ts->val_type == TEMP_VAL_CONST && k < s->nb_globals) { | ||
| 1170 | + printf("constant forbidden in global %s\n", | ||
| 1171 | + tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); | ||
| 1172 | + goto fail; | ||
| 1173 | + } | ||
| 1139 | } | 1174 | } |
| 1140 | } | 1175 | } |
| 1141 | #endif | 1176 | #endif |
| @@ -1376,13 +1411,26 @@ static void tcg_reg_alloc_op(TCGContext *s, | @@ -1376,13 +1411,26 @@ static void tcg_reg_alloc_op(TCGContext *s, | ||
| 1376 | } | 1411 | } |
| 1377 | } | 1412 | } |
| 1378 | 1413 | ||
| 1379 | - /* XXX: permit generic clobber register list ? */ | ||
| 1380 | if (def->flags & TCG_OPF_CALL_CLOBBER) { | 1414 | if (def->flags & TCG_OPF_CALL_CLOBBER) { |
| 1415 | + /* XXX: permit generic clobber register list ? */ | ||
| 1381 | for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { | 1416 | for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { |
| 1382 | if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { | 1417 | if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { |
| 1383 | tcg_reg_free(s, reg); | 1418 | tcg_reg_free(s, reg); |
| 1384 | } | 1419 | } |
| 1385 | } | 1420 | } |
| 1421 | + /* XXX: for load/store we could do that only for the slow path | ||
| 1422 | + (i.e. when a memory callback is called) */ | ||
| 1423 | + | ||
| 1424 | + /* store globals and free associated registers (we assume the insn | ||
| 1425 | + can modify any global. */ | ||
| 1426 | + for(i = 0; i < s->nb_globals; i++) { | ||
| 1427 | + ts = &s->temps[i]; | ||
| 1428 | + if (!ts->fixed_reg) { | ||
| 1429 | + if (ts->val_type == TEMP_VAL_REG) { | ||
| 1430 | + tcg_reg_free(s, ts->reg); | ||
| 1431 | + } | ||
| 1432 | + } | ||
| 1433 | + } | ||
| 1386 | } | 1434 | } |
| 1387 | 1435 | ||
| 1388 | /* satisfy the output constraints */ | 1436 | /* satisfy the output constraints */ |
| @@ -1435,6 +1483,12 @@ static void tcg_reg_alloc_op(TCGContext *s, | @@ -1435,6 +1483,12 @@ static void tcg_reg_alloc_op(TCGContext *s, | ||
| 1435 | } | 1483 | } |
| 1436 | } | 1484 | } |
| 1437 | 1485 | ||
| 1486 | +#ifdef TCG_TARGET_STACK_GROWSUP | ||
| 1487 | +#define STACK_DIR(x) (-(x)) | ||
| 1488 | +#else | ||
| 1489 | +#define STACK_DIR(x) (x) | ||
| 1490 | +#endif | ||
| 1491 | + | ||
| 1438 | static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | 1492 | static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, |
| 1439 | int opc, const TCGArg *args, | 1493 | int opc, const TCGArg *args, |
| 1440 | unsigned int dead_iargs) | 1494 | unsigned int dead_iargs) |
| @@ -1443,7 +1497,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | @@ -1443,7 +1497,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | ||
| 1443 | TCGArg arg, func_arg; | 1497 | TCGArg arg, func_arg; |
| 1444 | TCGTemp *ts; | 1498 | TCGTemp *ts; |
| 1445 | tcg_target_long stack_offset, call_stack_size, func_addr; | 1499 | tcg_target_long stack_offset, call_stack_size, func_addr; |
| 1446 | - int const_func_arg; | 1500 | + int const_func_arg, allocate_args; |
| 1447 | TCGRegSet allocated_regs; | 1501 | TCGRegSet allocated_regs; |
| 1448 | const TCGArgConstraint *arg_ct; | 1502 | const TCGArgConstraint *arg_ct; |
| 1449 | 1503 | ||
| @@ -1464,12 +1518,11 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | @@ -1464,12 +1518,11 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | ||
| 1464 | call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); | 1518 | call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); |
| 1465 | call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & | 1519 | call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & |
| 1466 | ~(TCG_TARGET_STACK_ALIGN - 1); | 1520 | ~(TCG_TARGET_STACK_ALIGN - 1); |
| 1467 | -#ifdef TCG_TARGET_STACK_GROWSUP | ||
| 1468 | - tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size); | ||
| 1469 | -#else | ||
| 1470 | - tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size); | ||
| 1471 | -#endif | ||
| 1472 | - | 1521 | + allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); |
| 1522 | + if (allocate_args) { | ||
| 1523 | + tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); | ||
| 1524 | + } | ||
| 1525 | + /* XXX: on some architectures it does not start at zero */ | ||
| 1473 | stack_offset = 0; | 1526 | stack_offset = 0; |
| 1474 | for(i = nb_regs; i < nb_params; i++) { | 1527 | for(i = nb_regs; i < nb_params; i++) { |
| 1475 | arg = args[nb_oargs + i]; | 1528 | arg = args[nb_oargs + i]; |
| @@ -1491,11 +1544,8 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | @@ -1491,11 +1544,8 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | ||
| 1491 | } else { | 1544 | } else { |
| 1492 | tcg_abort(); | 1545 | tcg_abort(); |
| 1493 | } | 1546 | } |
| 1494 | -#ifdef TCG_TARGET_STACK_GROWSUP | ||
| 1495 | - stack_offset -= sizeof(tcg_target_long); | ||
| 1496 | -#else | ||
| 1497 | - stack_offset += sizeof(tcg_target_long); | ||
| 1498 | -#endif | 1547 | + /* XXX: not necessarily in the same order */ |
| 1548 | + stack_offset += STACK_DIR(sizeof(tcg_target_long)); | ||
| 1499 | } | 1549 | } |
| 1500 | 1550 | ||
| 1501 | /* assign input registers */ | 1551 | /* assign input registers */ |
| @@ -1525,9 +1575,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | @@ -1525,9 +1575,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | ||
| 1525 | arg_ct = &def->args_ct[0]; | 1575 | arg_ct = &def->args_ct[0]; |
| 1526 | ts = &s->temps[func_arg]; | 1576 | ts = &s->temps[func_arg]; |
| 1527 | func_addr = ts->val; | 1577 | func_addr = ts->val; |
| 1528 | -#ifdef HOST_HPPA | ||
| 1529 | - func_addr = (tcg_target_long)__canonicalize_funcptr_for_compare((void *)func_addr); | ||
| 1530 | -#endif | ||
| 1531 | const_func_arg = 0; | 1578 | const_func_arg = 0; |
| 1532 | if (ts->val_type == TEMP_VAL_MEM) { | 1579 | if (ts->val_type == TEMP_VAL_MEM) { |
| 1533 | reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); | 1580 | reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); |
| @@ -1586,11 +1633,9 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | @@ -1586,11 +1633,9 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, | ||
| 1586 | 1633 | ||
| 1587 | tcg_out_op(s, opc, &func_arg, &const_func_arg); | 1634 | tcg_out_op(s, opc, &func_arg, &const_func_arg); |
| 1588 | 1635 | ||
| 1589 | -#ifdef TCG_TARGET_STACK_GROWSUP | ||
| 1590 | - tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size); | ||
| 1591 | -#else | ||
| 1592 | - tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size); | ||
| 1593 | -#endif | 1636 | + if (allocate_args) { |
| 1637 | + tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); | ||
| 1638 | + } | ||
| 1594 | 1639 | ||
| 1595 | /* assign output registers and emit moves if needed */ | 1640 | /* assign output registers and emit moves if needed */ |
| 1596 | for(i = 0; i < nb_oargs; i++) { | 1641 | for(i = 0; i < nb_oargs; i++) { |
| @@ -1672,10 +1717,6 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, | @@ -1672,10 +1717,6 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, | ||
| 1672 | args = gen_opparam_buf; | 1717 | args = gen_opparam_buf; |
| 1673 | op_index = 0; | 1718 | op_index = 0; |
| 1674 | 1719 | ||
| 1675 | -#ifdef TCG_TARGET_NEEDS_PROLOGUE | ||
| 1676 | - tcg_target_prologue(s); | ||
| 1677 | -#endif | ||
| 1678 | - | ||
| 1679 | for(;;) { | 1720 | for(;;) { |
| 1680 | opc = gen_opc_buf[op_index]; | 1721 | opc = gen_opc_buf[op_index]; |
| 1681 | #ifdef CONFIG_PROFILER | 1722 | #ifdef CONFIG_PROFILER |
tcg/tcg.h
| @@ -90,6 +90,10 @@ typedef struct TCGPool { | @@ -90,6 +90,10 @@ typedef struct TCGPool { | ||
| 90 | 90 | ||
| 91 | #define TCG_MAX_TEMPS 512 | 91 | #define TCG_MAX_TEMPS 512 |
| 92 | 92 | ||
| 93 | +/* when the size of the arguments of a called function is smaller than | ||
| 94 | + this value, they are statically allocated in the TB stack frame */ | ||
| 95 | +#define TCG_STATIC_CALL_ARGS_SIZE 128 | ||
| 96 | + | ||
| 93 | typedef int TCGType; | 97 | typedef int TCGType; |
| 94 | 98 | ||
| 95 | #define TCG_TYPE_I32 0 | 99 | #define TCG_TYPE_I32 0 |
| @@ -285,8 +289,11 @@ typedef struct TCGArgConstraint { | @@ -285,8 +289,11 @@ typedef struct TCGArgConstraint { | ||
| 285 | 289 | ||
| 286 | #define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic | 290 | #define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic |
| 287 | block */ | 291 | block */ |
| 288 | -#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers */ | ||
| 289 | -#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects */ | 292 | +#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers |
| 293 | + and potentially update globals. */ | ||
| 294 | +#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it | ||
| 295 | + cannot be removed if its output | ||
| 296 | + are not used */ | ||
| 290 | 297 | ||
| 291 | typedef struct TCGOpDef { | 298 | typedef struct TCGOpDef { |
| 292 | const char *name; | 299 | const char *name; |
| @@ -305,6 +312,7 @@ typedef struct TCGTargetOpDef { | @@ -305,6 +312,7 @@ typedef struct TCGTargetOpDef { | ||
| 305 | extern TCGOpDef tcg_op_defs[]; | 312 | extern TCGOpDef tcg_op_defs[]; |
| 306 | 313 | ||
| 307 | void tcg_target_init(TCGContext *s); | 314 | void tcg_target_init(TCGContext *s); |
| 315 | +void tcg_target_qemu_prologue(TCGContext *s); | ||
| 308 | 316 | ||
| 309 | #define tcg_abort() \ | 317 | #define tcg_abort() \ |
| 310 | do {\ | 318 | do {\ |
| @@ -358,3 +366,6 @@ int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2); | @@ -358,3 +366,6 @@ int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2); | ||
| 358 | int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2); | 366 | int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2); |
| 359 | uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2); | 367 | uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2); |
| 360 | uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2); | 368 | uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2); |
| 369 | + | ||
| 370 | +extern uint8_t code_gen_prologue[]; | ||
| 371 | +#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr) |
tcg/x86_64/tcg-target.c
| @@ -73,6 +73,8 @@ const int tcg_target_call_oarg_regs[2] = { | @@ -73,6 +73,8 @@ const int tcg_target_call_oarg_regs[2] = { | ||
| 73 | TCG_REG_RDX | 73 | TCG_REG_RDX |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | +static uint8_t *tb_ret_addr; | ||
| 77 | + | ||
| 76 | static void patch_reloc(uint8_t *code_ptr, int type, | 78 | static void patch_reloc(uint8_t *code_ptr, int type, |
| 77 | tcg_target_long value, tcg_target_long addend) | 79 | tcg_target_long value, tcg_target_long addend) |
| 78 | { | 80 | { |
| @@ -841,7 +843,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, | @@ -841,7 +843,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, | ||
| 841 | switch(opc) { | 843 | switch(opc) { |
| 842 | case INDEX_op_exit_tb: | 844 | case INDEX_op_exit_tb: |
| 843 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]); | 845 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]); |
| 844 | - tcg_out8(s, 0xc3); /* ret */ | 846 | + tcg_out8(s, 0xe9); /* jmp tb_ret_addr */ |
| 847 | + tcg_out32(s, tb_ret_addr - s->code_ptr - 4); | ||
| 845 | break; | 848 | break; |
| 846 | case INDEX_op_goto_tb: | 849 | case INDEX_op_goto_tb: |
| 847 | if (s->tb_jmp_offset) { | 850 | if (s->tb_jmp_offset) { |
| @@ -1129,6 +1132,58 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, | @@ -1129,6 +1132,58 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, | ||
| 1129 | } | 1132 | } |
| 1130 | } | 1133 | } |
| 1131 | 1134 | ||
| 1135 | +static int tcg_target_callee_save_regs[] = { | ||
| 1136 | + TCG_REG_R10, | ||
| 1137 | + TCG_REG_R11, | ||
| 1138 | + TCG_REG_RBP, | ||
| 1139 | + TCG_REG_RBX, | ||
| 1140 | + TCG_REG_R12, | ||
| 1141 | + TCG_REG_R13, | ||
| 1142 | + /* TCG_REG_R14, */ /* currently used for the global env, so no | ||
| 1143 | + need to save */ | ||
| 1144 | + TCG_REG_R15, | ||
| 1145 | +}; | ||
| 1146 | + | ||
| 1147 | +static inline void tcg_out_push(TCGContext *s, int reg) | ||
| 1148 | +{ | ||
| 1149 | + tcg_out_opc(s, (0x50 + (reg & 7)), 0, reg, 0); | ||
| 1150 | +} | ||
| 1151 | + | ||
| 1152 | +static inline void tcg_out_pop(TCGContext *s, int reg) | ||
| 1153 | +{ | ||
| 1154 | + tcg_out_opc(s, (0x58 + (reg & 7)), 0, reg, 0); | ||
| 1155 | +} | ||
| 1156 | + | ||
| 1157 | +/* Generate global QEMU prologue and epilogue code */ | ||
| 1158 | +void tcg_target_qemu_prologue(TCGContext *s) | ||
| 1159 | +{ | ||
| 1160 | + int i, frame_size, push_size, stack_addend; | ||
| 1161 | + | ||
| 1162 | + /* TB prologue */ | ||
| 1163 | + /* save all callee saved registers */ | ||
| 1164 | + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { | ||
| 1165 | + tcg_out_push(s, tcg_target_callee_save_regs[i]); | ||
| 1166 | + | ||
| 1167 | + } | ||
| 1168 | + /* reserve some stack space */ | ||
| 1169 | + push_size = 8 + ARRAY_SIZE(tcg_target_callee_save_regs) * 8; | ||
| 1170 | + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; | ||
| 1171 | + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & | ||
| 1172 | + ~(TCG_TARGET_STACK_ALIGN - 1); | ||
| 1173 | + stack_addend = frame_size - push_size; | ||
| 1174 | + tcg_out_addi(s, TCG_REG_RSP, -stack_addend); | ||
| 1175 | + | ||
| 1176 | + tcg_out_modrm(s, 0xff, 4, TCG_REG_RDI); /* jmp *%rdi */ | ||
| 1177 | + | ||
| 1178 | + /* TB epilogue */ | ||
| 1179 | + tb_ret_addr = s->code_ptr; | ||
| 1180 | + tcg_out_addi(s, TCG_REG_RSP, stack_addend); | ||
| 1181 | + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { | ||
| 1182 | + tcg_out_pop(s, tcg_target_callee_save_regs[i]); | ||
| 1183 | + } | ||
| 1184 | + tcg_out8(s, 0xc3); /* ret */ | ||
| 1185 | +} | ||
| 1186 | + | ||
| 1132 | static const TCGTargetOpDef x86_64_op_defs[] = { | 1187 | static const TCGTargetOpDef x86_64_op_defs[] = { |
| 1133 | { INDEX_op_exit_tb, { } }, | 1188 | { INDEX_op_exit_tb, { } }, |
| 1134 | { INDEX_op_goto_tb, { } }, | 1189 | { INDEX_op_goto_tb, { } }, |
| @@ -1212,6 +1267,10 @@ static const TCGTargetOpDef x86_64_op_defs[] = { | @@ -1212,6 +1267,10 @@ static const TCGTargetOpDef x86_64_op_defs[] = { | ||
| 1212 | 1267 | ||
| 1213 | void tcg_target_init(TCGContext *s) | 1268 | void tcg_target_init(TCGContext *s) |
| 1214 | { | 1269 | { |
| 1270 | + /* fail safe */ | ||
| 1271 | + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) | ||
| 1272 | + tcg_abort(); | ||
| 1273 | + | ||
| 1215 | tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); | 1274 | tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); |
| 1216 | tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); | 1275 | tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); |
| 1217 | tcg_regset_set32(tcg_target_call_clobber_regs, 0, | 1276 | tcg_regset_set32(tcg_target_call_clobber_regs, 0, |
| @@ -1227,10 +1286,6 @@ void tcg_target_init(TCGContext *s) | @@ -1227,10 +1286,6 @@ void tcg_target_init(TCGContext *s) | ||
| 1227 | 1286 | ||
| 1228 | tcg_regset_clear(s->reserved_regs); | 1287 | tcg_regset_clear(s->reserved_regs); |
| 1229 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP); | 1288 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP); |
| 1230 | - /* XXX: will be suppresed when proper global TB entry code will be | ||
| 1231 | - generated */ | ||
| 1232 | - tcg_regset_set_reg(s->reserved_regs, TCG_REG_RBX); | ||
| 1233 | - tcg_regset_set_reg(s->reserved_regs, TCG_REG_RBP); | ||
| 1234 | 1289 | ||
| 1235 | tcg_add_target_add_op_defs(x86_64_op_defs); | 1290 | tcg_add_target_add_op_defs(x86_64_op_defs); |
| 1236 | } | 1291 | } |