create push ebp/pop ebp for frame pointer setups
[libfirm] / ir / be / ia32 / ia32_x87.c
index 2a032ea..b47b0e2 100644 (file)
 #include "gen_ia32_regalloc_if.h"
 #include "ia32_x87.h"
 
-#ifndef NDEBUG
-#define DEBUG_ONLY(x) x
-#else  /* NDEBUG */
-#define DEBUG_ONLY(x)
-#endif /* NDEBUG */
-
 #define N_x87_REGS 8
 
 /* first and second binop index */
@@ -54,7 +48,7 @@
 #define MASK_TOS(x)            ((x) & (N_x87_REGS - 1))
 
 /** the debug handle */
-static firm_dbg_module_t *dbg = NULL;
+DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
 /**
  * An exchange template.
@@ -207,7 +201,7 @@ static int x87_on_stack(const x87_state *state, int reg_idx) {
  * Push a virtual Register onto the stack.
  */
 static void x87_push(x87_state *state, int reg_idx, ir_node *node) {
-//     assert(x87_on_stack(state, reg_idx) == -1 && "double push");
+       assert(x87_on_stack(state, reg_idx) == -1 && "double push");
        assert(state->depth < N_x87_REGS && "stack overrun");
 
        ++state->depth;
@@ -823,7 +817,7 @@ static void sim_load(x87_state *state, ir_node *n, const arch_env_t *env, ir_op
 /**
  * Simulate a virtual Store
  */
-static void sim_fst(x87_state *state, ir_node *n, const arch_env_t *env) {
+static void sim_store(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op, ir_op *op_p) {
        int op2_idx;
        const arch_register_t *op2 = arch_get_irn_register(env, get_irn_n(n, STORE_VAL_IDX));
        ia32_attr_t *attr;
@@ -838,10 +832,10 @@ static void sim_fst(x87_state *state, ir_node *n, const arch_env_t *env) {
                x87_create_fxch(state, n, op2_idx, STORE_VAL_IDX);
 
        if (is_vfp_live(op2, live))
-               x87_patch_insn(n, op_ia32_fst);
+               x87_patch_insn(n, op);
        else {
                x87_pop(state);
-               x87_patch_insn(n, op_ia32_fstp);
+               x87_patch_insn(n, op_p);
        }
 
        attr = get_ia32_attr(n);
@@ -882,25 +876,35 @@ static void sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
        sim_unop(state, n, env, op_ia32_##op); \
 }
 
+#define GEN_STORE(op) \
+static void sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
+       sim_store(state, n, env, op_ia32_##op, op_ia32_##op##p); \
+}
+
 /* all stubs */
 GEN_BINOP(fadd)
 GEN_BINOPR(fsub)
 GEN_BINOP(fmul)
 GEN_BINOPR(fdiv)
 
-GEN_LOAD(fld)
-GEN_LOAD(fldz)
-GEN_LOAD(fld1)
-GEN_LOAD2(fConst, fldConst)
-
 GEN_UNOP(fabs)
 GEN_UNOP(fchs)
 GEN_UNOP(fsin)
 GEN_UNOP(fcos)
 GEN_UNOP(fsqrt)
 
+GEN_LOAD(fld)
+GEN_LOAD(fild)
+GEN_LOAD(fldz)
+GEN_LOAD(fld1)
+GEN_LOAD2(fConst, fldConst)
+
+GEN_STORE(fst)
+GEN_STORE(fist)
+
+
 /**
- * Simulate a virtual Copy
+ * Simulate a be_Copy.
  */
 static void sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
        ir_mode *mode = get_irn_mode(n);
@@ -946,6 +950,50 @@ static void sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
        }
 }
 
+/**
+ * Simulate a be_Call
+ */
+static void sim_Call(x87_state *state, ir_node *n, const arch_env_t *env) {
+       ir_type *call_tp = be_Call_get_type(n);
+
+       /* at the begin of a call the x87 state should be empty */
+       assert(state->depth == 0 && "stack not empty before call");
+
+       /*
+        * If the called function returns a float, it is returned in st(0).
+        * This even happens if the return value is NOT used.
+        * Moreover, only one return result is supported.
+        */
+       if (get_method_n_ress(call_tp) > 0) {
+               ir_type *res_type = get_method_res_type(call_tp, 0);
+               ir_mode *mode     = get_type_mode(res_type);
+
+               if (mode && mode_is_float(mode)) {
+                       /*
+                        * TODO: what to push here? The result might be unused and currently
+                        * we have no possibility to detect this :-(
+                        */
+                       x87_push(state, 0, n);
+               }
+       }
+}
+
+/**
+ * Simulate a be_Spill.
+ */
+static void sim_Spill(x87_state *state, ir_node *n, const arch_env_t *env) {
+       assert(0 && "Spill not lowered");
+       sim_fst(state, n, env);
+}
+
+/**
+ * Simulate a be_Reload
+ */
+static void sim_Reload(x87_state *state, ir_node *n, const arch_env_t *env) {
+       assert(0 && "Reload not lowered");
+       sim_fld(state, n, env);
+}
+
 /**
  * Run a simulation and fix all virtual instructions for a block.
  *
@@ -1026,7 +1074,7 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg, const arch_env
        sim->blk_states = pmap_create();
        sim->env        = env;
 
-  FIRM_DBG_REGISTER(dbg, "firm.be.ia32.x87");
+       FIRM_DBG_REGISTER(dbg, "firm.be.ia32.x87");
        firm_dbg_set_mask(dbg, SET_LEVEL_2);
 
        DB((dbg, LEVEL_1, "--------------------------------\n"
@@ -1040,6 +1088,7 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg, const arch_env
 #define ASSOC_BE(op)    (op_be_ ## op)->ops.generic = (op_func)(sim_##op)
        ASSOC_IA32(fConst);
        ASSOC_IA32(fld);
+       ASSOC_IA32(fild);
        ASSOC_IA32(fld1);
        ASSOC_IA32(fldz);
        ASSOC_IA32(fadd);
@@ -1052,8 +1101,12 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg, const arch_env
        ASSOC_IA32(fsin);
        ASSOC_IA32(fcos);
        ASSOC_IA32(fsqrt);
+       ASSOC_IA32(fist);
        ASSOC_IA32(fst);
        ASSOC_BE(Copy);
+       ASSOC_BE(Call);
+       ASSOC_BE(Spill);
+       ASSOC_BE(Reload);
        ASSOC(Phi);
 #undef ASSOC_BE
 #undef ASSOC_IA32
@@ -1081,10 +1134,10 @@ void x87_simulate_graph(const arch_env_t *env, ir_graph *irg, ir_node **blk_list
        x87_simulator sim;
        int i;
 
-  /* we need liveness info for the current graph */
+       /* we need liveness info for the current graph */
        be_liveness(irg);
 
-  /* create the simulator */
+       /* create the simulator */
        x87_init_simulator(&sim, irg, env);
 
        start_block = get_irg_start_block(irg);
@@ -1108,6 +1161,6 @@ void x87_simulate_graph(const arch_env_t *env, ir_graph *irg, ir_node **blk_list
                }
        } while (! pdeq_empty(worklist));
 
-  /* kill it */
+       /* kill it */
        x87_destroy_simulator(&sim);
 }