From 2c31fb4cf1427f5a24c4eed0a08dbd3f3a2dacce Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 4 Oct 2015 22:50:38 +0300 Subject: [PATCH] translate: more float stuff --- c_auto.h | 10 ++++++ tests/x87.expect.c | 10 +++--- tools/protoparse.h | 7 ++-- tools/translate.c | 87 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 88 insertions(+), 26 deletions(-) diff --git a/c_auto.h b/c_auto.h index 31e89e1..9b34f88 100644 --- a/c_auto.h +++ b/c_auto.h @@ -45,6 +45,16 @@ static inline BOOL PtInRect_sa(LPCRECT r, int x, int y) return PtInRect(r, p); } +static inline int do_parity(unsigned int v) +{ + v ^= v >> 4; + v ^= v >> 2; + v ^= v >> 1; + return (v ^ 1) & 1; +} + #define do_skip_code_abort() \ printf("%s:%d: skip_code_abort\n", __FILE__, __LINE__); \ *(volatile int *)0 = 1 + +// vim:ts=2:sw=2:expandtab diff --git a/tests/x87.expect.c b/tests/x87.expect.c index ae64239..50ad1cc 100644 --- a/tests/x87.expect.c +++ b/tests/x87.expect.c @@ -12,22 +12,22 @@ int sub_test(int a1, int a2) f_st0 = (double)(s32)sf.d[0]; // var_20 fild f_st0 /= (double)(s32)a1; // arg_0 - f_st0 *= *(double *)((u32)&sf.q[1]); // var_18 + f_st0 *= sf.q[1]; // var_18 f_st1 = f_st0; f_st0 = (double)(s32)sf.d[0]; // var_20 fild f_st1 /= f_st0; f_st0 = f_st1 + f_st0; - f_st1 = f_st0; f_st0 = *(double *)((u32)&sf.q[1]); // var_18 fld + f_st1 = f_st0; f_st0 = sf.q[1]; // var_18 fld fs_3 = f_st0; f_st0 = f_st1; // fst fs_1 = f_st0; // fst f_st0 = pow(fs_1, fs_3); - f_sw = f_st0 <= *(double *)((u32)&sf.q[1]) ? 0x4100 : 0; // var_18 z_chk_det + f_sw = f_st0 <= sf.q[1] ? 0x4100 : 0; // var_18 z_chk_det eax = 0; LOWORD(eax) = f_sw; cond_z = ((u8)((u8)(eax >> 8) & 0x41) == 0); eax = 0; LOBYTE(eax) = (cond_z); f_st1 = f_st0; f_st0 = 1.0; - f_st0 = *(double *)((u32)&sf.q[1]) / f_st0; // var_18 + f_st0 = sf.q[1] / f_st0; // var_18 { double t = f_st0; f_st0 = f_st1; f_st1 = t; } // fxch f_st0 = -f_st0; f_st0 = f_st1; @@ -35,7 +35,7 @@ int sub_test(int a1, int a2) f_st0 = f_st1 * log2(f_st0); // fyl2x f_st1 = f_st0; // fld st sf.d[0] = (s32)f_st0; f_st0 = f_st1; // var_20 fist - *(double *)((u32)&sf.q[1]) = f_st0; // var_18 fst + sf.q[1] = f_st0; // var_18 fst eax = (s32)f_st0; // ftol return eax; } diff --git a/tools/protoparse.h b/tools/protoparse.h index 93129a1..897171e 100644 --- a/tools/protoparse.h +++ b/tools/protoparse.h @@ -15,6 +15,7 @@ struct parsed_type { unsigned int is_struct:1; // split for args unsigned int is_retreg:1; // register to return to caller unsigned int is_va_list:1; + unsigned int is_64bit:1; }; struct parsed_proto_arg { @@ -670,11 +671,13 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) if (!arg->type.is_ptr && (strstr(arg->type.name, "int64") || IS(arg->type.name, "double"))) { + arg->type.is_64bit = 1; // hack.. - free(arg->type.name); - arg->type.name = strdup("int"); pp_copy_arg(&pp->arg[xarg], arg); + arg = &pp->arg[xarg]; xarg++; + free(arg->type.name); + arg->type.name = strdup("dummy"); } ret = check_struct_arg(arg); diff --git a/tools/translate.c b/tools/translate.c index d51d64c..07f290a 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -69,6 +69,7 @@ enum op_flags { OPF_FPUSH = (1 << 22), /* pushes x87 stack */ OPF_FPOP = (1 << 23), /* pops x87 stack */ OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */ + OPF_FINT = (1 << 25), /* integer float op arg */ }; enum op_op { @@ -1071,14 +1072,14 @@ static const struct { { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 }, // x87 { "fld", OP_FLD, 1, 1, OPF_FPUSH }, - { "fild", OP_FILD, 1, 1, OPF_FPUSH }, + { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT }, { "fld1", OP_FLDc, 0, 0, OPF_FPUSH }, { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH }, { "fldz", OP_FLDc, 0, 0, OPF_FPUSH }, { "fst", OP_FST, 1, 1, 0 }, { "fstp", OP_FST, 1, 1, OPF_FPOP }, - { "fist", OP_FIST, 1, 1, 0 }, - { "fistp", OP_FIST, 1, 1, OPF_FPOP }, + { "fist", OP_FIST, 1, 1, OPF_FINT }, + { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT }, { "fadd", OP_FADD, 0, 2, 0 }, { "faddp", OP_FADD, 0, 2, OPF_FPOP }, { "fdiv", OP_FDIV, 0, 2, 0 }, @@ -1091,12 +1092,12 @@ static const struct { { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP }, { "fsubr", OP_FSUBR, 0, 2, 0 }, { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP }, - { "fiadd", OP_FIADD, 1, 1, 0 }, - { "fidiv", OP_FIDIV, 1, 1, 0 }, - { "fimul", OP_FIMUL, 1, 1, 0 }, - { "fisub", OP_FISUB, 1, 1, 0 }, - { "fidivr", OP_FIDIVR, 1, 1, 0 }, - { "fisubr", OP_FISUBR, 1, 1, 0 }, + { "fiadd", OP_FIADD, 1, 1, OPF_FINT }, + { "fidiv", OP_FIDIV, 1, 1, OPF_FINT }, + { "fimul", OP_FIMUL, 1, 1, OPF_FINT }, + { "fisub", OP_FISUB, 1, 1, OPF_FINT }, + { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT }, + { "fisubr", OP_FISUBR, 1, 1, OPF_FINT }, { "fcom", OP_FCOM, 0, 1, 0 }, { "fcomp", OP_FCOM, 0, 1, OPF_FPOP }, { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA }, @@ -1116,6 +1117,7 @@ static const struct { { "_allshr",OPP_ALLSHR }, { "_ftol", OPP_FTOL }, { "_CIpow", OPP_CIPOW }, + { "abort", OPP_ABORT }, // must be last { "ud2", OP_UD2 }, }; @@ -1981,6 +1983,14 @@ static int stack_frame_access(struct parsed_op *po, } break; + case OPLM_QWORD: + ferr_assert(po, !(offset & 7)); + if (cast[0]) + prefix = cast; + snprintf(buf, buf_size, "%s%sa%d", + prefix, is_lea ? "&" : "", i + 1); + break; + default: ferr(po, "bp_arg bad lmod: %d\n", popr->lmod); } @@ -2054,10 +2064,9 @@ static int stack_frame_access(struct parsed_op *po, ferr_assert(po, !(sf_ofs & 7)); ferr_assert(po, ofs_reg[0] == 0); // only used for x87 int64/float, float sets is_lea - if (is_lea) - snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8); - else - snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8); + if (!is_lea && (po->flags & OPF_FINT)) + prefix = "*(s64 *)&"; + snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8); break; default: @@ -2294,8 +2303,9 @@ static char *out_src_opr_u32(char *buf, size_t buf_size, return out_src_opr(buf, buf_size, po, popr, NULL, 0); } -static char *out_src_opr_float(char *buf, size_t buf_size, - struct parsed_op *po, struct parsed_opr *popr, int need_float_stack) +static char *out_opr_float(char *buf, size_t buf_size, + struct parsed_op *po, struct parsed_opr *popr, int is_src, + int need_float_stack) { const char *cast = NULL; char tmp[256]; @@ -2317,6 +2327,12 @@ static char *out_src_opr_float(char *buf, size_t buf_size, break; case OPT_REGMEM: + if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) { + stack_frame_access(po, popr, buf, buf_size, + popr->name, "", is_src, 0); + break; + } + // fallthrough case OPT_LABEL: case OPT_OFFSET: switch (popr->lmod) { @@ -2341,11 +2357,16 @@ static char *out_src_opr_float(char *buf, size_t buf_size, return buf; } +static char *out_src_opr_float(char *buf, size_t buf_size, + struct parsed_op *po, struct parsed_opr *popr, int need_float_stack) +{ + return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack); +} + static char *out_dst_opr_float(char *buf, size_t buf_size, struct parsed_op *po, struct parsed_opr *popr, int need_float_stack) { - // same? - return out_src_opr_float(buf, buf_size, po, popr, need_float_stack); + return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack); } static void out_test_for_cc(char *buf, size_t buf_size, @@ -2380,6 +2401,11 @@ static void out_test_for_cc(char *buf, size_t buf_size, snprintf(buf, buf_size, "(%d)", !!is_inv); break; + case PFO_P: // PF==1 + snprintf(buf, buf_size, "(%sdo_parity(%s))", + is_inv ? "!" : "", expr); + break; + default: ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo); } @@ -5455,6 +5481,9 @@ static void output_pp(FILE *fout, const struct parsed_proto *pp, if (!pp->is_fptr) fprintf(fout, " a%d", i + 1); } + + if (pp->arg[i].type.is_64bit) + i++; } if (pp->is_vararg) { if (i > 0) @@ -5499,6 +5528,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) int label_pending = 0; int need_double = 0; int stack_align = 0; + int stack_fsz_adj = 0; int regmask_save = 0; // used regs saved/restored in this func int regmask_arg; // regs from this function args (fastcall, etc) int regmask_ret; // regs needed on ret @@ -5537,6 +5567,20 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) // - handle ebp/esp frame, remove ops related to it scan_prologue_epilogue(opcnt, &stack_align); + // handle a case where sf size is unalignment, but is + // placed in a way that elements are still aligned + if (g_stack_fsz & 4) { + for (i = 0; i < g_eqcnt; i++) { + if (g_eqs[i].lmod != OPLM_QWORD) + continue; + if (!(g_eqs[i].offset & 4)) { + g_stack_fsz += 4; + stack_fsz_adj = 4; + } + break; + } + } + // pass3: // - remove dead labels // - set regs needed at ret @@ -5978,6 +6022,9 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) // declare stack frame, va_arg if (g_stack_fsz) { + if (stack_fsz_adj) + fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj); + fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4); if (g_func_lmods & (1 << OPLM_WORD)) fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2); @@ -5985,6 +6032,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, " u8 b[%d];", g_stack_fsz); if (g_func_lmods & (1 << OPLM_QWORD)) fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8); + if (stack_align > 8) ferr(ops, "unhandled stack align of %d\n", stack_align); else if (stack_align == 8) @@ -7435,7 +7483,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) z_check = ((long)po->datap >> 16) & 1; out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0], need_float_stack); - if (mask == 0x0100) { // C0 -> < + if (mask == 0x0100 || mask == 0x0500) { // C0 -> < fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;", float_st0, buf1); } @@ -7608,7 +7656,8 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) last_arith_dst = NULL; } - label_pending = 0; + if (!no_output) + label_pending = 0; } if (g_stack_fsz && !g_stack_frame_used) -- 2.39.2