+static entity *ia32_get_frame_entity(const void *self, const ir_node *irn) {
+ return is_ia32_irn(irn) ? get_ia32_frame_ent(irn) : NULL;
+}
+
+static void ia32_set_stack_bias(const void *self, ir_node *irn, int bias) {
+ char buf[64];
+ const ia32_irn_ops_t *ops = self;
+
+ if (get_ia32_frame_ent(irn)) {
+ ia32_am_flavour_t am_flav = get_ia32_am_flavour(irn);
+
+ DBG((ops->cg->mod, LEVEL_1, "stack biased %+F with %d\n", irn, bias));
+ snprintf(buf, sizeof(buf), "%d", bias);
+
+ if (get_ia32_op_type(irn) == ia32_Normal) {
+ set_ia32_cnst(irn, buf);
+ }
+ else {
+ add_ia32_am_offs(irn, buf);
+ am_flav |= ia32_O;
+ set_ia32_am_flavour(irn, am_flav);
+ }
+ }
+}
+
+typedef struct {
+ be_abi_call_flags_bits_t flags;
+ const arch_isa_t *isa;
+ ir_graph *irg;
+} ia32_abi_env_t;
+
+static void *ia32_abi_init(const be_abi_call_t *call, const arch_env_t *aenv, ir_graph *irg)
+{
+ ia32_abi_env_t *env = xmalloc(sizeof(env[0]));
+ be_abi_call_flags_t fl = be_abi_call_get_flags(call);
+ env->flags = fl.bits;
+ env->irg = irg;
+ env->isa = aenv->isa;
+ return env;
+}
+
+static void ia32_abi_dont_save_regs(void *self, pset *s)
+{
+ ia32_abi_env_t *env = self;
+ if(env->flags.try_omit_fp)
+ pset_insert_ptr(s, env->isa->bp);
+}
+
+static const arch_register_t *ia32_abi_prologue(void *self, ir_node **mem, pmap *reg_map)
+{
+ ia32_abi_env_t *env = self;
+ const arch_register_t *frame_reg = env->isa->sp;
+
+ if(!env->flags.try_omit_fp) {
+ int reg_size = get_mode_size_bytes(env->isa->bp->reg_class->mode);
+ ir_node *bl = get_irg_start_block(env->irg);
+ ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+ ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
+ ir_node *curr_no_reg = be_abi_reg_map_get(reg_map, &ia32_gp_regs[REG_GP_NOREG]);
+ ir_node *store_bp;
+
+ curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, *mem, reg_size, be_stack_dir_expand);
+ store_bp = new_rd_ia32_Store(NULL, env->irg, bl, curr_sp, curr_no_reg, curr_bp, *mem, mode_T);
+ set_ia32_am_support(store_bp, ia32_am_Dest);
+ set_ia32_am_flavour(store_bp, ia32_B);
+ set_ia32_op_type(store_bp, ia32_AddrModeD);
+ *mem = new_r_Proj(env->irg, bl, store_bp, mode_M, 0);
+ curr_bp = be_new_Copy(env->isa->bp->reg_class, env->irg, bl, curr_sp);
+ be_set_constr_single_reg(curr_bp, BE_OUT_POS(0), env->isa->bp);
+ be_node_set_flags(curr_bp, BE_OUT_POS(0), arch_irn_flags_ignore);
+
+ be_abi_reg_map_set(reg_map, env->isa->sp, curr_sp);
+ be_abi_reg_map_set(reg_map, env->isa->bp, curr_bp);
+ }
+
+ return frame_reg;
+}
+
+static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_map)
+{
+ ia32_abi_env_t *env = self;
+ ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+ ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
+ ir_node *curr_no_reg = be_abi_reg_map_get(reg_map, &ia32_gp_regs[REG_GP_NOREG]);
+
+ if(env->flags.try_omit_fp) {
+ curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, *mem, BE_STACK_FRAME_SIZE, be_stack_dir_shrink);
+ }
+
+ else {
+ ir_node *load_bp;
+ ir_mode *mode_bp = env->isa->bp->reg_class->mode;
+
+ curr_sp = be_new_SetSP(env->isa->sp, env->irg, bl, curr_sp, curr_bp, *mem);
+ load_bp = new_rd_ia32_Load(NULL, env->irg, bl, curr_sp, curr_no_reg, *mem, mode_T);
+ set_ia32_am_support(load_bp, ia32_am_Source);
+ set_ia32_am_flavour(load_bp, ia32_B);
+ set_ia32_op_type(load_bp, ia32_AddrModeS);
+ set_ia32_ls_mode(load_bp, mode_bp);
+ curr_bp = new_r_Proj(env->irg, bl, load_bp, mode_bp, 0);
+ *mem = new_r_Proj(env->irg, bl, load_bp, mode_M, 1);
+ }
+
+ be_abi_reg_map_set(reg_map, env->isa->sp, curr_sp);
+ be_abi_reg_map_set(reg_map, env->isa->bp, curr_bp);
+}
+
+/**
+ * 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)
+{
+ static ir_type *omit_fp_between_type = NULL;
+ static ir_type *between_type = NULL;
+
+ ia32_abi_env_t *env = self;
+
+ if(!between_type) {
+ entity *old_bp_ent;
+ entity *ret_addr_ent;
+ entity *omit_fp_ret_addr_ent;
+
+ ir_type *old_bp_type = new_type_primitive(new_id_from_str("bp"), mode_P);
+ ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P);
+
+ between_type = new_type_class(new_id_from_str("ia32_between_type"));
+ old_bp_ent = new_entity(between_type, new_id_from_str("old_bp"), old_bp_type);
+ ret_addr_ent = new_entity(between_type, new_id_from_str("ret_addr"), ret_addr_type);
+
+ set_entity_offset_bytes(old_bp_ent, 0);
+ set_entity_offset_bytes(ret_addr_ent, get_type_size_bytes(old_bp_type));
+ set_type_size_bytes(between_type, get_type_size_bytes(old_bp_type) + get_type_size_bytes(ret_addr_type));
+
+ omit_fp_between_type = new_type_class(new_id_from_str("ia32_between_type_omit_fp"));
+ omit_fp_ret_addr_ent = new_entity(omit_fp_between_type, new_id_from_str("ret_addr"), ret_addr_type);
+
+ set_entity_offset_bytes(omit_fp_ret_addr_ent, 0);
+ set_type_size_bytes(omit_fp_between_type, get_type_size_bytes(ret_addr_type));
+ }
+
+ return env->flags.try_omit_fp ? omit_fp_between_type : between_type;
+}
+
+static const be_abi_callbacks_t ia32_abi_callbacks = {
+ ia32_abi_init,
+ free,
+ ia32_abi_get_between_type,
+ ia32_abi_dont_save_regs,
+ ia32_abi_prologue,
+ ia32_abi_epilogue,
+};
+