X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=tools%2Ftranslate.c;h=591090de62a057ce1265f566f67e80da2ba695e4;hb=93b5bd181600ddf5097d133c52cdc7b1d4a2c7c8;hp=dc0c74ced75b7eb5ac2c9a8e86893c0dbda08b3a;hpb=306201740a8996e02008918dc3e6a5a8e0d00223;p=ia32rtools.git diff --git a/tools/translate.c b/tools/translate.c index dc0c74c..591090d 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -1782,7 +1782,6 @@ static void parse_stack_access(struct parsed_op *po, } else { bp_arg = parse_stack_el(name, ofs_reg, NULL, 0); - snprintf(g_comment, sizeof(g_comment), "%s", bp_arg); eq = equ_find(po, bp_arg, &offset); if (eq == NULL) ferr(po, "detected but missing eq\n"); @@ -1862,6 +1861,8 @@ static int stack_frame_access(struct parsed_op *po, parse_stack_access(po, name, ofs_reg, &offset, &stack_ra, &bp_arg, is_lea); + snprintf(g_comment, sizeof(g_comment), "%s", bp_arg); + if (offset > stack_ra) { arg_i = (offset - stack_ra - 4) / 4; @@ -1960,7 +1961,7 @@ static int stack_frame_access(struct parsed_op *po, } if (unaligned) - snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg); + strcat(g_comment, " unaligned"); // common problem guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type); @@ -2538,7 +2539,7 @@ static const char *op_to_c(struct parsed_op *po) // note: this skips over calls and rm'd stuff assuming they're handled // so it's intended to use at one of final passes static int scan_for_pop(int i, int opcnt, int magic, int reg, - int depth, int flags_set) + int depth, int seen_noreturn, int flags_set) { struct parsed_op *po; int relevant; @@ -2554,10 +2555,12 @@ static int scan_for_pop(int i, int opcnt, int magic, int reg, if (po->flags & OPF_TAIL) { if (po->op == OP_CALL) { if (po->pp != NULL && po->pp->is_noreturn) - // assume no stack cleanup for noreturn - return 1; + seen_noreturn = 1; + else + return -1; } - return -1; // deadend + else + return -1; // deadend } if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG)) @@ -2569,7 +2572,7 @@ static int scan_for_pop(int i, int opcnt, int magic, int reg, for (j = 0; j < po->btj->count; j++) { check_i(po, po->btj->d[j].bt_i); ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg, - depth, flags_set); + depth, seen_noreturn, flags_set); if (ret < 0) return ret; // dead end } @@ -2579,7 +2582,7 @@ static int scan_for_pop(int i, int opcnt, int magic, int reg, check_i(po, po->bt_i); if (po->flags & OPF_CJMP) { ret |= scan_for_pop(po->bt_i, opcnt, magic, reg, - depth, flags_set); + depth, seen_noreturn, flags_set); if (ret < 0) return ret; // dead end } @@ -2608,7 +2611,8 @@ static int scan_for_pop(int i, int opcnt, int magic, int reg, } } - return -1; + // for noreturn, assume msvc skipped stack cleanup + return seen_noreturn ? 1 : -1; } // scan for 'reg' pop backwards starting from i @@ -3095,8 +3099,11 @@ static int scan_for_mod_opr0(struct parsed_op *po_test, return -1; } -static int scan_for_flag_set(int i, int magic, int *branched, - int *setters, int *setter_cnt) +static int try_resolve_const(int i, const struct parsed_opr *opr, + int magic, unsigned int *val); + +static int scan_for_flag_set(int i, int opcnt, int magic, + int *branched, int *setters, int *setter_cnt) { struct label_ref *lr; int ret; @@ -3115,7 +3122,7 @@ static int scan_for_flag_set(int i, int magic, int *branched, lr = &g_label_refs[i]; for (; lr->next; lr = lr->next) { check_i(&ops[i], lr->i); - ret = scan_for_flag_set(lr->i, magic, + ret = scan_for_flag_set(lr->i, opcnt, magic, branched, setters, setter_cnt); if (ret < 0) return ret; @@ -3126,7 +3133,7 @@ static int scan_for_flag_set(int i, int magic, int *branched, i = lr->i; continue; } - ret = scan_for_flag_set(lr->i, magic, + ret = scan_for_flag_set(lr->i, opcnt, magic, branched, setters, setter_cnt); if (ret < 0) return ret; @@ -3136,6 +3143,20 @@ static int scan_for_flag_set(int i, int magic, int *branched, if (ops[i].flags & OPF_FLAGS) { setters[*setter_cnt] = i; (*setter_cnt)++; + + if (ops[i].flags & OPF_REP) { + struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX); + unsigned int uval; + + ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval); + if (ret != 1 || uval == 0) { + // can't treat it as full setter because of ecx=0 case, + // also disallow delayed compare + *branched = 1; + continue; + } + } + return 0; } @@ -3335,7 +3356,8 @@ static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags) } static const struct parsed_proto *try_recover_pp( - struct parsed_op *po, const struct parsed_opr *opr, int *search_instead) + struct parsed_op *po, const struct parsed_opr *opr, + int is_call, int *search_instead) { const struct parsed_proto *pp = NULL; char buf[256]; @@ -3374,10 +3396,12 @@ static const struct parsed_proto *try_recover_pp( if (arg == g_func_pp->argc) ferr(po, "stack arg %d not in prototype?\n", arg_i); - pp = g_func_pp->arg[arg].fptr; - if (pp == NULL) - ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1); - check_func_pp(po, pp, "icall arg"); + pp = g_func_pp->arg[arg].pp; + if (is_call) { + if (pp == NULL) + ferr(po, "icall arg: arg%d has no pp\n", arg + 1); + check_func_pp(po, pp, "icall arg"); + } } else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) { // label[index] @@ -3458,14 +3482,14 @@ static void scan_for_call_type(int i, const struct parsed_opr *opr, } if (i == g_func_pp->argc) return; - pp = g_func_pp->arg[i].fptr; + pp = g_func_pp->arg[i].pp; if (pp == NULL) ferr(po, "icall: arg%d (%s) is not a fptr?\n", i + 1, g_func_pp->arg[i].reg); check_func_pp(po, pp, "icall reg-arg"); } else - pp = try_recover_pp(po, opr, NULL); + pp = try_recover_pp(po, opr, 1, NULL); if (*pp_found != NULL && pp != NULL && *pp_found != pp) { if (!IS((*pp_found)->ret_type.name, pp->ret_type.name) @@ -3602,6 +3626,13 @@ static int get_pp_arg_regmask_dst(const struct parsed_proto *pp) return regmask | mxAX; } +static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2) +{ + return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt + && memcmp(po1->operand, po2->operand, + sizeof(po1->operand[0]) * po1->operand_cnt) == 0; +} + static void resolve_branches_parse_calls(int opcnt) { static const struct { @@ -4009,10 +4040,6 @@ static int resolve_origin(int i, const struct parsed_opr *opr, struct label_ref *lr; int ret = 0; - if (ops[i].cc_scratch == magic) - return 0; - ops[i].cc_scratch = magic; - while (1) { if (g_labels[i] != NULL) { lr = &g_label_refs[i]; @@ -4041,10 +4068,9 @@ static int resolve_origin(int i, const struct parsed_opr *opr, continue; if (*op_i >= 0) { - if (*op_i == i) + if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i])) return ret | 1; - // XXX: could check if the other op does the same return -1; } @@ -4063,10 +4089,6 @@ static int resolve_last_ref(int i, const struct parsed_opr *opr, struct label_ref *lr; int ret = 0; - if (ops[i].cc_scratch == magic) - return 0; - ops[i].cc_scratch = magic; - while (1) { if (g_labels[i] != NULL) { lr = &g_label_refs[i]; @@ -4320,16 +4342,103 @@ static int resolve_used_bits(int i, int opcnt, int reg, return 0; } +static const struct parsed_proto *resolve_deref(int i, int magic, + struct parsed_opr *opr, int level) +{ + struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0); + const struct parsed_proto *pp = NULL; + int from_caller = 0; + char s_reg[4]; + int offset = 0; + int len = 0; + int j = -1; + int k = -1; + int reg; + int ret; + + ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len); + if (ret != 2 || len != strlen(opr->name)) { + ret = sscanf(opr->name, "%3s%n", s_reg, &len); + if (ret != 1 || len != strlen(opr->name)) + return NULL; + } + + reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg); + if (reg < 0) + return NULL; + + opr_s.reg = reg; + ret = resolve_origin(i, &opr_s, i + magic, &j, NULL); + if (ret != 1) + return NULL; + + if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM + && strlen(ops[j].operand[1].name) == 3 + && ops[j].operand[0].lmod == OPLM_DWORD + && ops[j].pp == NULL // no hint + && level == 0) + { + // allow one simple dereference (com/directx) + reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), + ops[j].operand[1].name); + if (reg < 0) + return NULL; + opr_s.reg = reg; + ret = resolve_origin(j, &opr_s, j + magic, &k, NULL); + if (ret != 1) + return NULL; + j = k; + } + if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD) + return NULL; + + if (ops[j].pp != NULL) { + // type hint in asm + pp = ops[j].pp; + } + else if (ops[j].operand[1].type == OPT_REGMEM) { + pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL); + if (pp == NULL) { + // maybe structure ptr in structure + pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1); + } + } + else if (ops[j].operand[1].type == OPT_LABEL) + pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp); + else if (ops[j].operand[1].type == OPT_REG) { + // maybe arg reg? + k = -1; + ret = resolve_origin(j, &ops[j].operand[1], i + magic, + &k, &from_caller); + if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) { + for (k = 0; k < g_func_pp->argc; k++) { + if (g_func_pp->arg[k].reg == NULL) + continue; + if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) { + pp = g_func_pp->arg[k].pp; + break; + } + } + } + } + + if (pp == NULL) + return NULL; + if (pp->is_func || pp->is_fptr || !pp->type.is_struct) { + if (offset != 0) + ferr(&ops[j], "expected struct, got '%s %s'\n", + pp->type.name, pp->name); + return NULL; + } + + return proto_lookup_struct(g_fhdr, pp->type.name, offset); +} + static const struct parsed_proto *resolve_icall(int i, int opcnt, int *pp_i, int *multi_src) { const struct parsed_proto *pp = NULL; int search_advice = 0; - int offset = -1; - char name[256]; - char s_reg[4]; - int reg, len; - int ret; *multi_src = 0; *pp_i = -1; @@ -4337,67 +4446,14 @@ static const struct parsed_proto *resolve_icall(int i, int opcnt, switch (ops[i].operand[0].type) { case OPT_REGMEM: // try to resolve struct member calls - ret = sscanf(ops[i].operand[0].name, "%3s+%x%n", - s_reg, &offset, &len); - if (ret == 2 && len == strlen(ops[i].operand[0].name)) - { - reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg); - if (reg >= 0) { - struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg); - int j = -1; - ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL); - if (ret != 1) - break; - if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM - && ops[j].operand[0].lmod == OPLM_DWORD - && ops[j].pp == NULL) // no hint - { - // allow one simple dereference (directx) - reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), - ops[j].operand[1].name); - if (reg < 0) - break; - struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg); - int k = -1; - ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL); - if (ret != 1) - break; - j = k; - } - if (ops[j].op != OP_MOV) - break; - if (ops[j].operand[0].lmod != OPLM_DWORD) - break; - if (ops[j].pp != NULL) { - // type hint in asm - pp = ops[j].pp; - } - else if (ops[j].operand[1].type == OPT_REGMEM) { - // allow 'hello[ecx]' - assume array of same type items - ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]", - name, s_reg); - if (ret != 2) - break; - pp = proto_parse(g_fhdr, name, g_quiet_pp); - } - else if (ops[j].operand[1].type == OPT_LABEL) - pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp); - else - break; - if (pp == NULL) - break; - if (pp->is_func || pp->is_fptr || !pp->type.is_struct) { - pp = NULL; - break; - } - pp = proto_lookup_struct(g_fhdr, pp->type.name, offset); - } + pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0); + if (pp != NULL) break; - } // fallthrough case OPT_LABEL: case OPT_OFFSET: - pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice); + pp = try_recover_pp(&ops[i], &ops[i].operand[0], + 1, &search_advice); if (!search_advice) break; // fallthrough @@ -5066,9 +5122,10 @@ static void reg_use_pass(int i, int opcnt, unsigned char *cbits, flags_set = OPF_RSAVE | OPF_DONE; } - ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0); + ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0); if (ret == 1) { - scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set); + scan_for_pop(i + 1, opcnt, i + opcnt * 4, + reg, 0, 0, flags_set); } else { ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0); @@ -5274,9 +5331,11 @@ static void output_pp(FILE *fout, const struct parsed_proto *pp, for (i = 0; i < pp->argc; i++) { if (i > 0) fprintf(fout, ", "); - if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) { + if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func + && !(flags & OPP_SIMPLE_ARGS)) + { // func pointer - output_pp(fout, pp->arg[i].fptr, 0); + output_pp(fout, pp->arg[i].pp, 0); } else if (pp->arg[i].type.is_retreg) { fprintf(fout, "u32 *r_%s", pp->arg[i].reg); @@ -5316,7 +5375,6 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) char buf1[256], buf2[256], buf3[256], cast[64]; struct parsed_proto *pp, *pp_tmp; struct parsed_data *pd; - unsigned int uval; int save_arg_vars[MAX_ARG_GRP] = { 0, }; unsigned char cbits[MAX_OPS / 8]; const char *float_type; @@ -5523,7 +5581,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) { int setters[16], cnt = 0, branched = 0; - ret = scan_for_flag_set(i, i + opcnt * 6, + ret = scan_for_flag_set(i, opcnt, i + opcnt * 6, &branched, setters, &cnt); if (ret < 0 || cnt <= 0) ferr(po, "unable to trace flag setter(s)\n"); @@ -6065,32 +6123,6 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) pfomask = po->pfomask; - if (po->flags & (OPF_REPZ|OPF_REPNZ)) { - struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX); - ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval); - - if (ret != 1 || uval == 0) { - // we need initial flags for ecx=0 case.. - if (i > 0 && ops[i - 1].op == OP_XOR - && IS(ops[i - 1].operand[0].name, - ops[i - 1].operand[1].name)) - { - fprintf(fout, " cond_z = "); - if (pfomask & (1 << PFO_C)) - fprintf(fout, "cond_c = "); - fprintf(fout, "0;\n"); - } - else if (last_arith_dst != NULL) { - out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst); - out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0, - last_arith_dst->lmod, buf3); - fprintf(fout, " cond_z = %s;\n", buf1); - } - else - ferr(po, "missing initial ZF\n"); - } - } - switch (po->op) { case OP_MOV: @@ -6246,7 +6278,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (po->flags & OPF_REP) { assert_operand_cnt(3); fprintf(fout, - " for (; ecx != 0; ecx--) {\n"); + " while (ecx != 0) {\n"); if (pfomask & (1 << PFO_C)) { // ugh.. fprintf(fout, @@ -6257,6 +6289,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n", buf1, buf1, l, j, l, j); fprintf(fout, + " ecx--;\n" " if (cond_z %s 0) break;\n", (po->flags & OPF_REPZ) ? "==" : "!="); fprintf(fout, @@ -6284,12 +6317,13 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (po->flags & OPF_REP) { assert_operand_cnt(3); fprintf(fout, - " for (; ecx != 0; ecx--) {\n"); + " while (ecx != 0) {\n"); fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;\n", lmod_cast_u(po, po->operand[1].lmod), lmod_cast_u_ptr(po, po->operand[1].lmod), l, j); fprintf(fout, + " ecx--;\n" " if (cond_z %s 0) break;\n", (po->flags & OPF_REPZ) ? "==" : "!="); fprintf(fout, @@ -6482,9 +6516,13 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) propagate_lmod(po, &po->operand[0], &po->operand[1]); if (IS(opr_name(po, 0), opr_name(po, 1))) { // special case for XOR - if (pfomask & (1 << PFO_BE)) { // weird, but it happens.. - fprintf(fout, " cond_be = 1;\n"); - pfomask &= ~(1 << PFO_BE); + int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L); + for (j = 0; j <= PFO_LE; j++) { + if (pfomask & (1 << j)) { + fprintf(fout, " cond_%s = %d;\n", + parsed_flag_op_names[j], (1 << j) & z ? 0 : 1); + pfomask &= ~(1 << j); + } } fprintf(fout, " %s = 0;", out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0])); @@ -7625,11 +7663,11 @@ static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits, if (po->flags & OPF_DONE) continue; - ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0); + ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0); if (ret == 1) { regmask_save |= 1 << reg; po->flags |= OPF_RMD; - scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD); + scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD); continue; } }