- implemented __builtin_return_address(0)
[libfirm] / ir / be / ia32 / bearch_ia32.c
index 4d08fcd..035d96f 100644 (file)
@@ -101,6 +101,14 @@ static set *cur_reg_set = NULL;
 ir_mode         *mode_fpcw       = NULL;
 ia32_code_gen_t *ia32_current_cg = NULL;
 
+/** The current omit-fp state */
+static unsigned ia32_curr_fp_ommitted  = 0;
+static ir_type *omit_fp_between_type   = NULL;
+static ir_type *between_type           = NULL;
+static ir_entity *old_bp_ent           = NULL;
+static ir_entity *ret_addr_ent         = NULL;
+static ir_entity *omit_fp_ret_addr_ent = NULL;
+
 /**
  * The environment for the intrinsic mapping.
  */
@@ -337,6 +345,7 @@ static const arch_register_t *ia32_abi_prologue(void *self, ir_node **mem, pmap
        ia32_code_gen_t  *cg       = ia32_current_cg;
        const arch_env_t *arch_env = env->aenv;
 
+       ia32_curr_fp_ommitted = env->flags.try_omit_fp;
        if (! env->flags.try_omit_fp) {
                ir_graph *irg     = env->irg;
                ir_node  *bl      = get_irg_start_block(irg);
@@ -464,23 +473,11 @@ static void ia32_abi_done(void *self) {
 }
 
 /**
- * Produces the type which sits between the stack args and the locals on the stack.
- * it will contain the return address and space to store the old base pointer.
- * @return The Firm type modeling the ABI between type.
+ * Build the between type and entities if not already build.
  */
-static ir_type *ia32_abi_get_between_type(void *self)
-{
+static void ia32_build_between_type(void) {
 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
-       static ir_type *omit_fp_between_type = NULL;
-       static ir_type *between_type         = NULL;
-
-       ia32_abi_env_t *env = self;
-
        if (! between_type) {
-               ir_entity *old_bp_ent;
-               ir_entity *ret_addr_ent;
-               ir_entity *omit_fp_ret_addr_ent;
-
                ir_type *old_bp_type   = new_type_primitive(IDENT("bp"), mode_Iu);
                ir_type *ret_addr_type = new_type_primitive(IDENT("return_addr"), mode_Iu);
 
@@ -500,9 +497,28 @@ static ir_type *ia32_abi_get_between_type(void *self)
                set_type_size_bytes(omit_fp_between_type, get_type_size_bytes(ret_addr_type));
                set_type_state(omit_fp_between_type, layout_fixed);
        }
+#undef IDENT
+}
 
+/**
+ * Produces the type which sits between the stack args and the locals on the stack.
+ * it will contain the return address and space to store the old base pointer.
+ * @return The Firm type modeling the ABI between type.
+ */
+static ir_type *ia32_abi_get_between_type(void *self)
+{
+       ia32_abi_env_t *env = self;
+
+       ia32_build_between_type();
        return env->flags.try_omit_fp ? omit_fp_between_type : between_type;
-#undef IDENT
+}
+
+/**
+ * Return the stack entity that contains the return address.
+ */
+ir_entity *ia32_get_return_address_entity(void) {
+       ia32_build_between_type();
+       return ia32_curr_fp_ommitted ? omit_fp_ret_addr_ent : ret_addr_ent;
 }
 
 /**
@@ -2119,7 +2135,7 @@ static int psi_is_Abs(ir_node *cmp, ir_node *sel, ir_node *t, ir_node *f) {
 
 
 /**
- * Allows or disallows the creation of Psi nodes for the given Phi nodes.
+ * Allows or disallows the creation of Mux nodes for the given Phi nodes.
  *
  * @param sel        A selector of a Cond.
  * @param phi_list   List of Phi nodes about to be converted (linked via get_Phi_next() field)
@@ -2128,14 +2144,14 @@ static int psi_is_Abs(ir_node *cmp, ir_node *sel, ir_node *t, ir_node *f) {
  *
  * @return 1 if allowed, 0 otherwise
  */
-static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
+static int ia32_is_mux_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
 {
        ir_node *phi;
        ir_node *cmp;
        pn_Cmp  pn;
        ir_node *cl, *cr;
 
-       /* we can't handle Psis with 64bit compares yet */
+       /* we can't handle Muxs with 64bit compares yet */
        if (is_Proj(sel)) {
                cmp = get_Proj_pred(sel);
                if (is_Cmp(cmp)) {
@@ -2156,6 +2172,9 @@ static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
                        /* we do not support nodes without Cmp yet */
                        return 0;
                }
+       } else {
+               /* we do not support nodes without Cmp yet */
+               return 0;
        }
 
        pn = get_Proj_proj(sel);
@@ -2176,10 +2195,10 @@ static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
                                        /* SSE2 supports Min & Max */
                                        if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
                                                if (cl == t && cr == f) {
-                                                       /* Psi(a <=/>= b, a, b) => MIN, MAX */
+                                                       /* Mux(a <=/>= b, a, b) => MIN, MAX */
                                                        continue;
                                                } else if (cl == f && cr == t) {
-                                                       /* Psi(a <=/>= b, b, a) => MAX, MIN */
+                                                       /* Mux(a <=/>= b, b, a) => MAX, MIN */
                                                        continue;
                                                }
                                        }
@@ -2198,7 +2217,7 @@ static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
                                        ir_node *t = get_Phi_pred(phi, i);
                                        ir_node *f = get_Phi_pred(phi, j);
 
-                                       /* always support Psi(!float, C1, C2) */
+                                       /* always support Mux(!float, C1, C2) */
                                        if (is_Const(t) && is_Const(f) && !mode_is_float(get_irn_mode(cl)))
                                                continue;
                                        /* only abs or nabs supported */
@@ -2221,7 +2240,7 @@ static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
                        f = get_Phi_pred(phi, j);
 
                        if (mode_is_float(mode)) {
-                               /* always support Psi(!float, C1, C2) */
+                               /* always support Mux(!float, C1, C2) */
                                if (is_Const(t) && is_Const(f) && !mode_is_float(get_irn_mode(cl)))
                                        continue;
                                /* only abs or nabs supported */
@@ -2234,38 +2253,38 @@ static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
 
                        if (is_Const(t) && is_Const(f)) {
                                if ((is_Const_null(t) && is_Const_one(f)) || (is_Const_one(t) && is_Const_null(f))) {
-                                       /* always support Psi(x, C1, C2) */
+                                       /* always support Mux(x, C1, C2) */
                                        continue;
                                }
                        } else if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
 #if 0
                                if (cl == t && cr == f) {
-                                       /* Psi(a <=/>= b, a, b) => Min, Max */
+                                       /* Mux(a <=/>= b, a, b) => Min, Max */
                                        continue;
                                }
                                if (cl == f && cr == t) {
-                                       /* Psi(a <=/>= b, b, a) => Max, Min */
+                                       /* Mux(a <=/>= b, b, a) => Max, Min */
                                        continue;
                                }
 #endif
                                if ((pn & pn_Cmp_Gt) && !mode_is_signed(mode) &&
                                    is_Const(f) && is_Const_null(f) && is_Sub(t) &&
                                    get_Sub_left(t) == cl && get_Sub_right(t) == cr) {
-                                       /* Psi(a >=u b, a - b, 0) unsigned Doz */
+                                       /* Mux(a >=u b, a - b, 0) unsigned Doz */
                                        continue;
                                }
                                if ((pn & pn_Cmp_Lt) && !mode_is_signed(mode) &&
                                    is_Const(t) && is_Const_null(t) && is_Sub(f) &&
                                    get_Sub_left(f) == cl && get_Sub_right(f) == cr) {
-                                       /* Psi(a <=u b, 0, a - b) unsigned Doz */
+                                       /* Mux(a <=u b, 0, a - b) unsigned Doz */
                                        continue;
                                }
                                if (is_Const(cr) && is_Const_null(cr)) {
                                        if (cl == t && is_Minus(f) && get_Minus_op(f) == cl) {
-                                               /* Psi(a <=/>= 0 ? a : -a) Nabs/Abs */
+                                               /* Mux(a <=/>= 0 ? a : -a) Nabs/Abs */
                                                continue;
                                        } else if (cl == f && is_Minus(t) && get_Minus_op(t) == cl) {
-                                               /* Psi(a <=/>= 0 ? -a : a) Abs/Nabs */
+                                               /* Mux(a <=/>= 0 ? -a : a) Abs/Nabs */
                                                continue;
                                        }
                                }
@@ -2295,13 +2314,40 @@ static int ia32_is_valid_clobber(const void *self, const char *clobber)
        return ia32_get_clobber_register(clobber) != NULL;
 }
 
+/**
+ * Create the trampoline code.
+ */
+static ir_node *ia32_create_trampoline_fkt(ir_node *block, ir_node *mem, ir_node *trampoline, ir_node *env, ir_node *callee)
+{
+       ir_graph *irg    = get_Block_irg(block);
+       ir_node  *st, *p = trampoline;
+       ir_mode *mode    = get_irn_mode(p);
+
+       /* mov  ecx,<env> */
+       st  = new_r_Store(irg, block, mem, p, new_Const_long(mode_Bu, 0xb9), 0);
+       mem = new_r_Proj(irg, block, st, mode_M, pn_Store_M);
+       p   = new_r_Add(irg, block, p, new_Const_long(mode_Iu, 1), mode);
+       st  = new_r_Store(irg, block, mem, p, env, 0);
+       mem = new_r_Proj(irg, block, st, mode_M, pn_Store_M);
+       p   = new_r_Add(irg, block, p, new_Const_long(mode_Iu, 4), mode);
+       /* jmp  <callee> */
+       st  = new_r_Store(irg, block, mem, p, new_Const_long(mode_Bu, 0xe9), 0);
+       mem = new_r_Proj(irg, block, st, mode_M, pn_Store_M);
+       p   = new_r_Add(irg, block, p, new_Const_long(mode_Iu, 1), mode);
+       st  = new_r_Store(irg, block, mem, p, callee, 0);
+       mem = new_r_Proj(irg, block, st, mode_M, pn_Store_M);
+       p   = new_r_Add(irg, block, p, new_Const_long(mode_Iu, 4), mode);
+
+       return mem;
+}
+
 /**
  * Returns the libFirm configuration parameter for this backend.
  */
 static const backend_params *ia32_get_libfirm_params(void) {
        static const ir_settings_if_conv_t ifconv = {
-               4,                    /* maxdepth, doesn't matter for Psi-conversion */
-               ia32_is_psi_allowed   /* allows or disallows Psi creation for given selector */
+               4,                    /* maxdepth, doesn't matter for Mux-conversion */
+               ia32_is_mux_allowed   /* allows or disallows Mux creation for given selector */
        };
        static const ir_settings_arch_dep_t ad = {
                1,                   /* also use subs */
@@ -2316,12 +2362,14 @@ static const backend_params *ia32_get_libfirm_params(void) {
        static backend_params p = {
                1,     /* need dword lowering */
                1,     /* support inline assembly */
-               0,     /* no immediate floating point mode. */
                NULL,  /* will be set later */
                ia32_create_intrinsic_fkt,
                &intrinsic_env,  /* context for ia32_create_intrinsic_fkt */
-               NULL,  /* will be set below */
-               NULL   /* will be set below */
+               NULL,  /* ifconv info will be set below */
+               NULL,  /* float arithmetic mode, will be set below */
+               12,    /* size of trampoline code */
+               4,     /* alignment of trampoline code */
+               ia32_create_trampoline_fkt,
        };
 
        ia32_setup_cg_config();
@@ -2330,8 +2378,9 @@ static const backend_params *ia32_get_libfirm_params(void) {
         * is called... */
        init_asm_constraints();
 
-       p.dep_param    = &ad;
-       p.if_conv_info = &ifconv;
+       p.dep_param             = &ad;
+       p.if_conv_info          = &ifconv;
+       p.mode_float_arithmetic = mode_E;
        return &p;
 }