- implemented __builtin_return_address(0)
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Thu, 18 Dec 2008 18:19:51 +0000 (18:19 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Thu, 18 Dec 2008 18:19:51 +0000 (18:19 +0000)
[r24793]

ir/be/ia32/bearch_ia32.c
ir/be/ia32/bearch_ia32_t.h
ir/be/ia32/ia32_transform.c

index 44f08c6..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;
 }
 
 /**
index 110f239..a85ca4b 100644 (file)
@@ -176,4 +176,9 @@ ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                      const ir_mode *imode, const ir_mode *omode,
                                      void *context);
 
+/**
+ * Return the stack entity that contains the return address.
+ */
+ir_entity *ia32_get_return_address_entity(void);
+
 #endif
index 8f2615e..0248137 100644 (file)
@@ -90,8 +90,6 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
 static ir_node         *initial_fpcw = NULL;
 
-extern ir_op *get_op_Mulh(void);
-
 typedef ir_node *construct_binop_func(dbg_info *db, ir_node *block,
         ir_node *base, ir_node *index, ir_node *mem, ir_node *op1,
         ir_node *op2);
@@ -4520,6 +4518,82 @@ static ir_node *gen_be_Call(ir_node *node)
        return call;
 }
 
+/**
+ * Transform Builtin return_address
+ */
+static ir_node *gen_return_address(ir_node *node) {
+       ir_node *param = get_Builtin_param(node, 0);
+       ir_node *frame = get_Builtin_param(node, 1);
+       dbg_info *dbgi = get_irn_dbg_info(node);
+       tarval  *tv    = get_Const_tarval(param);
+       long    value  = get_tarval_long(tv);
+
+       ir_node *block = be_transform_node(get_nodes_block(node));
+
+       if (value == 0) {
+               /* the return address of the current function */
+               ir_node   *new_op = be_transform_node(frame);
+               ir_node   *noreg  = ia32_new_NoReg_gp(env_cg);
+               ir_node   *new_node;
+
+               new_node = new_bd_ia32_Load(dbgi, block, new_op, noreg, get_irg_no_mem(current_ir_graph));
+
+               set_irn_pinned(new_node, get_irn_pinned(node));
+               set_ia32_op_type(new_node, ia32_AddrModeS);
+               set_ia32_ls_mode(new_node, mode_Iu);
+
+               set_ia32_am_offs_int(new_node, 0);
+               set_ia32_use_frame(new_node);
+               set_ia32_frame_ent(new_node, ia32_get_return_address_entity());
+
+               if (get_irn_pinned(node) == op_pin_state_floats) {
+                       assert(pn_ia32_xLoad_res == pn_ia32_vfld_res
+                                       && pn_ia32_vfld_res == pn_ia32_Load_res
+                                       && pn_ia32_Load_res == pn_ia32_res);
+                       arch_irn_add_flags(new_node, arch_irn_flags_rematerializable);
+               }
+
+               SET_IA32_ORIG_NODE(new_node, node);
+               return new_rd_Proj(dbgi, current_ir_graph, block, new_node, mode_Iu, pn_ia32_Load_res);
+       }
+       panic("builtin_return_address(%ld) not supported in IA32", value);
+}
+
+/**
+ * Transform Builtin node.
+ */
+static ir_node *gen_Builtin(ir_node *node) {
+       ir_builtin_kind kind = get_Builtin_kind(node);
+
+       switch (kind) {
+       case ir_bk_return_address:
+               return gen_return_address(node);
+       case ir_bk_frame_addess:
+       case ir_bk_prefetch:
+               break;
+       }
+       panic("Builtin %s not implemented in IA32", get_builtin_kind_name(kind));
+}
+
+/**
+ * Transform Proj(Builtin) node.
+ */
+static ir_node *gen_Proj_Builtin(ir_node *proj) {
+       ir_node         *node = get_Proj_pred(proj);
+       ir_node         *new_node = be_transform_node(node);
+       ir_builtin_kind kind      = get_Builtin_kind(node);
+
+       switch (kind) {
+       case ir_bk_return_address:
+       case ir_bk_frame_addess:
+               assert(get_Proj_proj(proj) == pn_Builtin_1_result);
+               return new_node;
+       case ir_bk_prefetch:
+               break;
+       }
+       panic("Builtin %s not implemented in IA32", get_builtin_kind_name(kind));
+}
+
 static ir_node *gen_be_IncSP(ir_node *node)
 {
        ir_node *res = be_duplicate_node(node);
@@ -4725,6 +4799,8 @@ static ir_node *gen_Proj(ir_node *node)
                return gen_Proj_Load(node);
        case iro_ASM:
                return gen_Proj_ASM(node);
+       case iro_Builtin:
+               return gen_Proj_Builtin(node);
        case iro_Div:
        case iro_Mod:
        case iro_DivMod:
@@ -4868,7 +4944,7 @@ static void register_transformers(void)
        BAD(EndExcept);
 
        /* handle builtins */
-       BAD(Builtin);
+       GEN(Builtin);
 
        /* handle generic backend nodes */
        GEN(be_FrameAddr);