Commit d266f572 authored by Michael Beck's avatar Michael Beck
Browse files

- implemented __builtin_return_address(0)

[r24793]
parent 1da43c38
......@@ -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;
}
/**
......
......@@ -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
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment