+ else if (g_func_pp->is_userstack) {
+ fprintf(fout, " %s = *esp++;", buf1);
+ break;
+ }
+ else
+ ferr(po, "stray pop encountered\n");
+ break;
+
+ case OP_NOP:
+ no_output = 1;
+ break;
+
+ // x87
+ case OP_FLD:
+ if (need_float_stack) {
+ out_src_opr_float(buf1, sizeof(buf1),
+ po, &po->operand[0], 1);
+ if (po->regmask_src & mxSTa) {
+ fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
+ buf1);
+ }
+ else
+ fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
+ }
+ else {
+ if (po->flags & OPF_FSHIFT)
+ fprintf(fout, " f_st1 = f_st0;");
+ if (po->operand[0].type == OPT_REG
+ && po->operand[0].reg == xST0)
+ {
+ strcat(g_comment, " fld st");
+ break;
+ }
+ fprintf(fout, " f_st0 = %s;",
+ out_src_opr_float(buf1, sizeof(buf1),
+ po, &po->operand[0], 0));
+ }
+ strcat(g_comment, " fld");
+ break;
+
+ case OP_FILD:
+ out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
+ lmod_cast(po, po->operand[0].lmod, 1), 0);
+ snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
+ if (need_float_stack) {
+ fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
+ }
+ else {
+ if (po->flags & OPF_FSHIFT)
+ fprintf(fout, " f_st1 = f_st0;");
+ fprintf(fout, " f_st0 = %s;", buf2);
+ }
+ strcat(g_comment, " fild");
+ break;
+
+ case OP_FLDc:
+ if (need_float_stack)
+ fprintf(fout, " f_st[--f_stp & 7] = ");
+ else {
+ if (po->flags & OPF_FSHIFT)
+ fprintf(fout, " f_st1 = f_st0;");
+ fprintf(fout, " f_st0 = ");
+ }
+ switch (po->operand[0].val) {
+ case X87_CONST_1: fprintf(fout, "1.0;"); break;
+ case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
+ case X87_CONST_Z: fprintf(fout, "0.0;"); break;
+ default: ferr(po, "TODO\n"); break;
+ }
+ break;
+
+ case OP_FST:
+ out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
+ need_float_stack);
+ dead_dst = po->operand[0].type == OPT_REG
+ && po->operand[0].reg == xST0;
+ if (need_float_stack) {
+ if (!dead_dst)
+ fprintf(fout, " %s = f_st[f_stp & 7];", buf1);
+ if (po->flags & OPF_FSHIFT)
+ fprintf(fout, " f_stp++;");
+ }
+ else {
+ if (!dead_dst)
+ fprintf(fout, " %s = f_st0;", buf1);
+ if (po->flags & OPF_FSHIFT)
+ fprintf(fout, " f_st0 = f_st1;");
+ }
+ if (dead_dst && !(po->flags & OPF_FSHIFT))
+ no_output = 1;
+ else
+ strcat(g_comment, " fst");
+ break;
+
+ case OP_FADD:
+ case OP_FDIV:
+ case OP_FMUL:
+ case OP_FSUB:
+ out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
+ need_float_stack);
+ out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
+ need_float_stack);
+ dead_dst = (po->flags & OPF_FPOP)
+ && po->operand[0].type == OPT_REG
+ && po->operand[0].reg == xST0;
+ switch (po->op) {
+ case OP_FADD: j = '+'; break;
+ case OP_FDIV: j = '/'; break;
+ case OP_FMUL: j = '*'; break;
+ case OP_FSUB: j = '-'; break;
+ default: j = 'x'; break;
+ }
+ if (need_float_stack) {
+ if (!dead_dst)
+ fprintf(fout, " %s %c= %s;", buf1, j, buf2);
+ if (po->flags & OPF_FSHIFT)
+ fprintf(fout, " f_stp++;");
+ }
+ else {
+ if (po->flags & OPF_FSHIFT) {
+ // note: assumes only 2 regs handled
+ if (!dead_dst)
+ fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
+ else
+ fprintf(fout, " f_st0 = f_st1;");
+ }
+ else if (!dead_dst)
+ fprintf(fout, " %s %c= %s;", buf1, j, buf2);
+ }
+ no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
+ break;
+
+ case OP_FDIVR:
+ case OP_FSUBR:
+ out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
+ need_float_stack);
+ out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
+ need_float_stack);
+ out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
+ need_float_stack);
+ dead_dst = (po->flags & OPF_FPOP)
+ && po->operand[0].type == OPT_REG
+ && po->operand[0].reg == xST0;
+ j = po->op == OP_FDIVR ? '/' : '-';
+ if (need_float_stack) {
+ if (!dead_dst)
+ fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
+ if (po->flags & OPF_FSHIFT)
+ fprintf(fout, " f_stp++;");
+ }
+ else {
+ if (po->flags & OPF_FSHIFT) {
+ if (!dead_dst)
+ fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
+ else
+ fprintf(fout, " f_st0 = f_st1;");
+ }
+ else if (!dead_dst)
+ fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
+ }
+ no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
+ break;
+
+ case OP_FIADD:
+ case OP_FIDIV:
+ case OP_FIMUL:
+ case OP_FISUB:
+ switch (po->op) {
+ case OP_FIADD: j = '+'; break;
+ case OP_FIDIV: j = '/'; break;
+ case OP_FIMUL: j = '*'; break;
+ case OP_FISUB: j = '-'; break;
+ default: j = 'x'; break;
+ }
+ fprintf(fout, " %s %c= (%s)%s;", float_st0,
+ j, float_type,
+ out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
+ lmod_cast(po, po->operand[0].lmod, 1), 0));
+ break;
+
+ case OP_FIDIVR:
+ case OP_FISUBR:
+ fprintf(fout, " %s = %s %c %s;", float_st0,
+ out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
+ need_float_stack),
+ po->op == OP_FIDIVR ? '/' : '-', float_st0);
+ break;
+
+ case OP_FCHS:
+ fprintf(fout, " %s = -%s;", float_st0, float_st0);
+ break;
+
+ case OP_FCOS:
+ fprintf(fout, " %s = cos%s(%s);", float_st0,
+ need_double ? "" : "f", float_st0);
+ break;
+
+ case OP_FPATAN:
+ if (need_float_stack) {
+ fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
+ need_double ? "" : "f", float_st1, float_st0);
+ fprintf(fout, " f_stp++;");
+ }
+ else {
+ fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
+ need_double ? "" : "f");
+ }
+ break;
+
+ case OP_FYL2X:
+ if (need_float_stack) {
+ fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
+ float_st1, need_double ? "" : "f", float_st0);
+ fprintf(fout, " f_stp++;");
+ }
+ else {
+ fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
+ need_double ? "" : "f");
+ }
+ break;
+
+ case OP_FSIN:
+ fprintf(fout, " %s = sin%s(%s);", float_st0,
+ need_double ? "" : "f", float_st0);
+ break;
+
+ case OP_FSQRT:
+ fprintf(fout, " %s = sqrt%s(%s);", float_st0,
+ need_double ? "" : "f", float_st0);
+ break;
+
+ case OP_FXCH:
+ dead_dst = po->operand[0].type == OPT_REG
+ && po->operand[0].reg == xST0;
+ if (!dead_dst) {
+ out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
+ need_float_stack);
+ fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
+ float_st0, float_st0, buf1, buf1);
+ strcat(g_comment, " fxch");