+ DEBUG (mono_print_ins_index (i, ins));
+ }
+
+ // FIXME: Set MAX_FREGS to 8
+ // FIXME: Optimize generated code
+#if MONO_ARCH_USE_FPSTACK
+ /*
+ * Make a forward pass over the code, simulating the fp stack, making sure the
+ * arguments required by the fp opcodes are at the top of the stack.
+ */
+ if (has_fp) {
+ MonoInst *prev = NULL;
+ MonoInst *fxch;
+ int tmp;
+
+ for (ins = bb->code; ins; ins = ins->next) {
+ spec = ins_get_spec (ins->opcode);
+
+ DEBUG (printf ("processing:"));
+ DEBUG (mono_print_ins_index (0, ins));
+
+ if (ins->opcode == OP_FMOVE) {
+ /* Do it by renaming the source to the destination on the stack */
+ // FIXME: Is this correct ?
+ for (i = 0; i < sp; ++i)
+ if (fpstack [i] == ins->sreg1)
+ fpstack [i] = ins->dreg;
+ prev = ins;
+ continue;
+ }
+
+ if (sreg1_is_fp (spec) && sreg2_is_fp (spec) && (fpstack [sp - 2] != ins->sreg1)) {
+ /* Arg1 must be in %st(1) */
+ g_assert (prev);
+
+ i = 0;
+ while ((i < sp) && (fpstack [i] != ins->sreg1))
+ i ++;
+ g_assert (i < sp);
+
+ if (sp - 1 - i > 0) {
+ /* First move it to %st(0) */
+ DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp - 1 - i));
+
+ MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
+ fxch->inst_imm = sp - 1 - i;
+
+ prev->next = fxch;
+ fxch->next = ins;
+ prev = fxch;
+
+ tmp = fpstack [sp - 1];
+ fpstack [sp - 1] = fpstack [i];
+ fpstack [i] = tmp;
+ }
+
+ /* Then move it to %st(1) */
+ DEBUG (printf ("\tswap %%st(0) and %%st(1)\n"));
+
+ MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
+ fxch->inst_imm = 1;
+
+ prev->next = fxch;
+ fxch->next = ins;
+ prev = fxch;
+
+ tmp = fpstack [sp - 1];
+ fpstack [sp - 1] = fpstack [sp - 2];
+ fpstack [sp - 2] = tmp;
+ }
+
+ if (sreg2_is_fp (spec)) {
+ g_assert (sp > 0);
+
+ if (fpstack [sp - 1] != ins->sreg2) {
+ g_assert (prev);
+
+ i = 0;
+ while ((i < sp) && (fpstack [i] != ins->sreg2))
+ i ++;
+ g_assert (i < sp);
+
+ DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp - 1 - i));
+
+ MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
+ fxch->inst_imm = sp - 1 - i;
+
+ prev->next = fxch;
+ fxch->next = ins;
+ prev = fxch;
+
+ tmp = fpstack [sp - 1];
+ fpstack [sp - 1] = fpstack [i];
+ fpstack [i] = tmp;
+ }
+
+ sp --;
+ }
+
+ if (sreg1_is_fp (spec)) {
+ g_assert (sp > 0);
+
+ if (fpstack [sp - 1] != ins->sreg1) {
+ g_assert (prev);
+
+ i = 0;
+ while ((i < sp) && (fpstack [i] != ins->sreg1))
+ i ++;
+ g_assert (i < sp);
+
+ DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp - 1 - i));
+
+ MONO_INST_NEW (cfg, fxch, OP_X86_FXCH);
+ fxch->inst_imm = sp - 1 - i;
+
+ prev->next = fxch;
+ fxch->next = ins;
+ prev = fxch;
+
+ tmp = fpstack [sp - 1];
+ fpstack [sp - 1] = fpstack [i];
+ fpstack [i] = tmp;
+ }
+
+ sp --;
+ }
+
+ if (dreg_is_fp (spec)) {
+ g_assert (sp < 8);
+ fpstack [sp ++] = ins->dreg;
+ }
+
+ if (G_UNLIKELY (cfg->verbose_level >= 2)) {
+ printf ("\t[");
+ for (i = 0; i < sp; ++i)
+ printf ("%s%%fr%d", (i > 0) ? ", " : "", fpstack [i]);
+ printf ("]\n");
+ }
+
+ prev = ins;
+ }
+
+ if (sp && bb != cfg->bb_exit && !(bb->out_count == 1 && bb->out_bb [0] == cfg->bb_exit)) {
+ /* Remove remaining items from the fp stack */
+ /*
+ * These can remain for example as a result of a dead fmove like in
+ * System.Collections.Generic.EqualityComparer<double>.Equals ().
+ */
+ while (sp) {
+ MONO_INST_NEW (cfg, ins, OP_X86_FPOP);
+ mono_add_ins_to_end (bb, ins);
+ sp --;
+ }
+ }
+ }
+#endif
+}
+
+CompRelation
+mono_opcode_to_cond (int opcode)
+{
+ switch (opcode) {
+ case CEE_BEQ:
+ case OP_CEQ:
+ case OP_IBEQ:
+ case OP_ICEQ:
+ case OP_LBEQ:
+ case OP_LCEQ:
+ case OP_FBEQ:
+ case OP_FCEQ:
+ case OP_COND_EXC_EQ:
+ case OP_COND_EXC_IEQ:
+ case OP_CMOV_IEQ:
+ case OP_CMOV_LEQ:
+ return CMP_EQ;
+ case CEE_BNE_UN:
+ case OP_IBNE_UN:
+ case OP_LBNE_UN:
+ case OP_FBNE_UN:
+ case OP_COND_EXC_NE_UN:
+ case OP_COND_EXC_INE_UN:
+ case OP_CMOV_INE_UN:
+ case OP_CMOV_LNE_UN:
+ return CMP_NE;
+ case CEE_BLE:
+ case OP_IBLE:
+ case OP_LBLE:
+ case OP_FBLE:
+ case OP_CMOV_ILE:
+ case OP_CMOV_LLE:
+ return CMP_LE;
+ case CEE_BGE:
+ case OP_IBGE:
+ case OP_LBGE:
+ case OP_FBGE:
+ case OP_CMOV_IGE:
+ case OP_CMOV_LGE:
+ return CMP_GE;
+ case CEE_BLT:
+ case OP_CLT:
+ case OP_IBLT:
+ case OP_ICLT:
+ case OP_LBLT:
+ case OP_LCLT:
+ case OP_FBLT:
+ case OP_FCLT:
+ case OP_COND_EXC_LT:
+ case OP_COND_EXC_ILT:
+ case OP_CMOV_ILT:
+ case OP_CMOV_LLT:
+ return CMP_LT;
+ case CEE_BGT:
+ case OP_CGT:
+ case OP_IBGT:
+ case OP_ICGT:
+ case OP_LBGT:
+ case OP_LCGT:
+ case OP_FBGT:
+ case OP_FCGT:
+ case OP_COND_EXC_GT:
+ case OP_COND_EXC_IGT:
+ case OP_CMOV_IGT:
+ case OP_CMOV_LGT:
+ return CMP_GT;
+
+ case CEE_BLE_UN:
+ case OP_IBLE_UN:
+ case OP_LBLE_UN:
+ case OP_FBLE_UN:
+ case OP_COND_EXC_LE_UN:
+ case OP_COND_EXC_ILE_UN:
+ case OP_CMOV_ILE_UN:
+ case OP_CMOV_LLE_UN:
+ return CMP_LE_UN;
+ case CEE_BGE_UN:
+ case OP_IBGE_UN:
+ case OP_LBGE_UN:
+ case OP_FBGE_UN:
+ case OP_CMOV_IGE_UN:
+ case OP_CMOV_LGE_UN:
+ return CMP_GE_UN;
+ case CEE_BLT_UN:
+ case OP_CLT_UN:
+ case OP_IBLT_UN:
+ case OP_ICLT_UN:
+ case OP_LBLT_UN:
+ case OP_LCLT_UN:
+ case OP_FBLT_UN:
+ case OP_FCLT_UN:
+ case OP_COND_EXC_LT_UN:
+ case OP_COND_EXC_ILT_UN:
+ case OP_CMOV_ILT_UN:
+ case OP_CMOV_LLT_UN:
+ return CMP_LT_UN;
+ case CEE_BGT_UN:
+ case OP_CGT_UN:
+ case OP_IBGT_UN:
+ case OP_ICGT_UN:
+ case OP_LBGT_UN:
+ case OP_LCGT_UN:
+ case OP_FCGT_UN:
+ case OP_FBGT_UN:
+ case OP_COND_EXC_GT_UN:
+ case OP_COND_EXC_IGT_UN:
+ case OP_CMOV_IGT_UN:
+ case OP_CMOV_LGT_UN:
+ return CMP_GT_UN;
+ default:
+ printf ("%s\n", mono_inst_name (opcode));
+ g_assert_not_reached ();
+ return 0;
+ }
+}
+
+CompRelation
+mono_negate_cond (CompRelation cond)
+{
+ switch (cond) {
+ case CMP_EQ:
+ return CMP_NE;
+ case CMP_NE:
+ return CMP_EQ;
+ case CMP_LE:
+ return CMP_GT;
+ case CMP_GE:
+ return CMP_LT;
+ case CMP_LT:
+ return CMP_GE;
+ case CMP_GT:
+ return CMP_LE;
+ case CMP_LE_UN:
+ return CMP_GT_UN;
+ case CMP_GE_UN:
+ return CMP_LT_UN;
+ case CMP_LT_UN:
+ return CMP_GE_UN;
+ case CMP_GT_UN:
+ return CMP_LE_UN;
+ default:
+ g_assert_not_reached ();