+ return irn;
+}
+
+/**
+ * Creates a be_Return for a Return node.
+ *
+ * @param @env the abi environment
+ * @param irn the Return node or NULL if there was none
+ * @param bl the block where the be_Retun should be placed
+ * @param mem the current memory
+ * @param n_res number of return results
+ */
+static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, ir_node *mem, int n_res) {
+ be_abi_call_t *call = env->call;
+ const arch_isa_t *isa = env->birg->main_env->arch_env->isa;
+
+ pmap *reg_map = pmap_create();
+ ir_node *keep = pmap_get(env->keep_map, bl);
+ int in_max;
+ ir_node *ret;
+ int i, n;
+ ir_node **in;
+ ir_node *stack;
+ const arch_register_t **regs;
+ pmap_entry *ent ;
+
+ /*
+ get the valid stack node in this block.
+ If we had a call in that block there is a Keep constructed by process_calls()
+ which points to the last stack modification in that block. we'll use
+ it then. Else we use the stack from the start block and let
+ the ssa construction fix the usage.
+ */
+ stack = be_abi_reg_map_get(env->regs, isa->sp);
+ if (keep) {
+ ir_node *bad = new_r_Bad(env->birg->irg);
+ stack = get_irn_n(keep, 0);
+ set_nodes_block(keep, bad);
+ set_irn_n(keep, 0, bad);
+ // exchange(keep, new_r_Bad(env->birg->irg));
+ }
+
+ /* Insert results for Return into the register map. */
+ for(i = 0; i < n_res; ++i) {
+ ir_node *res = get_Return_res(irn, i);
+ be_abi_call_arg_t *arg = get_call_arg(call, 1, i);
+ assert(arg->in_reg && "return value must be passed in register");
+ pmap_insert(reg_map, (void *) arg->reg, res);
+ }
+
+ /* Add uses of the callee save registers. */
+ pmap_foreach(env->regs, ent) {
+ const arch_register_t *reg = ent->key;
+ if(arch_register_type_is(reg, callee_save) || arch_register_type_is(reg, ignore))
+ pmap_insert(reg_map, ent->key, ent->value);
+ }
+
+ be_abi_reg_map_set(reg_map, isa->sp, stack);
+
+ /* Make the Epilogue node and call the arch's epilogue maker. */
+ create_barrier(env, bl, &mem, reg_map, 1);
+ call->cb->epilogue(env->cb, bl, &mem, reg_map);
+
+ /*
+ Maximum size of the in array for Return nodes is
+ return args + callee save/ignore registers + memory + stack pointer
+ */
+ in_max = pmap_count(reg_map) + n_res + 2;
+
+ in = obstack_alloc(&env->obst, in_max * sizeof(in[0]));
+ regs = obstack_alloc(&env->obst, in_max * sizeof(regs[0]));
+
+ in[0] = mem;
+ in[1] = be_abi_reg_map_get(reg_map, isa->sp);
+ regs[0] = NULL;
+ regs[1] = isa->sp;
+ n = 2;
+
+ /* clear SP entry, since it has already been grown. */
+ pmap_insert(reg_map, (void *) isa->sp, NULL);
+ for(i = 0; i < n_res; ++i) {
+ be_abi_call_arg_t *arg = get_call_arg(call, 1, i);
+
+ in[n] = be_abi_reg_map_get(reg_map, arg->reg);
+ regs[n++] = arg->reg;
+
+ /* Clear the map entry to mark the register as processed. */
+ be_abi_reg_map_set(reg_map, arg->reg, NULL);
+ }
+
+ /* grow the rest of the stuff. */
+ pmap_foreach(reg_map, ent) {
+ if(ent->value) {
+ in[n] = ent->value;
+ regs[n++] = ent->key;
+ }
+ }
+
+ /* The in array for the new back end return is now ready. */
+ ret = be_new_Return(irn ? get_irn_dbg_info(irn) : NULL, env->birg->irg, bl, n_res, n, in);
+
+ /* Set the register classes of the return's parameter accordingly. */
+ for(i = 0; i < n; ++i)
+ if(regs[i])
+ be_node_set_reg_class(ret, i, regs[i]->reg_class);
+
+ /* Free the space of the Epilog's in array and the register <-> proj map. */
+ obstack_free(&env->obst, in);
+ pmap_destroy(reg_map);
+
+ return ret;
+}
+
+typedef struct lower_frame_sels_env_t {
+ be_abi_irg_t *env;
+ entity *value_param_list; /**< the list of all value param antities */
+} lower_frame_sels_env_t;
+
+/**
+ * Walker: Replaces Sels of frame type and
+ * value param type entities by FrameAddress.
+ */
+static void lower_frame_sels_walker(ir_node *irn, void *data)
+{
+ lower_frame_sels_env_t *ctx = data;
+
+ if (is_Sel(irn)) {
+ ir_graph *irg = current_ir_graph;
+ ir_node *frame = get_irg_frame(irg);
+ ir_node *param_base = get_irg_value_param_base(irg);
+ ir_node *ptr = get_Sel_ptr(irn);
+
+ if (ptr == frame || ptr == param_base) {
+ be_abi_irg_t *env = ctx->env;
+ entity *ent = get_Sel_entity(irn);
+ ir_node *bl = get_nodes_block(irn);
+ ir_node *nw;
+
+ nw = be_new_FrameAddr(env->isa->sp->reg_class, irg, bl, frame, ent);
+ exchange(irn, nw);
+
+ if (ptr == param_base) {
+ set_entity_link(ent, ctx->value_param_list);
+ ctx->value_param_list = ent;
+ }
+ }
+ }
+}
+
+/**
+ * Check if a value parameter is transmitted as a register.
+ * This might happen if the address of an parameter is taken which is
+ * transmitted in registers.
+ *
+ * Note that on some architectures this case must be handled specially
+ * because the place of the backing store is determined by their ABI.
+ *
+ * In the default case we move the entity to the frame type and create
+ * a backing store into the first block.
+ */
+static void fix_address_of_parameter_access(be_abi_irg_t *env, entity *value_param_list) {
+ be_abi_call_t *call = env->call;
+ ir_graph *irg = env->birg->irg;
+ entity *ent, *next_ent, *new_list;
+ ir_type *frame_tp;
+ DEBUG_ONLY(firm_dbg_module_t *dbg = env->dbg;)
+
+ new_list = NULL;
+ for (ent = value_param_list; ent; ent = next_ent) {
+ int i = get_struct_member_index(get_entity_owner(ent), ent);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, i);
+
+ next_ent = get_entity_link(ent);
+ if (arg->in_reg) {
+ DBG((dbg, LEVEL_2, "\targ #%d need backing store\n", i));
+ set_entity_link(ent, new_list);
+ new_list = ent;
+ }
+ }
+ if (new_list) {
+ /* ok, change the graph */
+ ir_node *start_bl = get_irg_start_block(irg);
+ ir_node *first_bl = NULL;
+ ir_node *frame, *imem, *nmem, *store, *mem, *args, *args_bl;
+ const ir_edge_t *edge;
+ optimization_state_t state;
+ int offset;
+
+ foreach_block_succ(start_bl, edge) {
+ ir_node *succ = get_edge_src_irn(edge);
+ if (start_bl != succ) {
+ first_bl = succ;
+ break;
+ }
+ }
+ assert(first_bl);
+ /* we had already removed critical edges, so the following
+ assertion should be always true. */
+ assert(get_Block_n_cfgpreds(first_bl) == 1);
+
+ /* now create backing stores */
+ frame = get_irg_frame(irg);
+ imem = get_irg_initial_mem(irg);
+
+ save_optimization_state(&state);
+ set_optimize(0);
+ nmem = new_r_Proj(irg, first_bl, get_irg_start(irg), mode_M, pn_Start_M);
+ restore_optimization_state(&state);
+
+ /* reroute all edges to the new memory source */
+ edges_reroute(imem, nmem, irg);
+
+ store = NULL;
+ mem = imem;
+ args = get_irg_args(irg);
+ args_bl = get_nodes_block(args);
+ for (ent = new_list; ent; ent = get_entity_link(ent)) {
+ int i = get_struct_member_index(get_entity_owner(ent), ent);
+ ir_type *tp = get_entity_type(ent);
+ ir_mode *mode = get_type_mode(tp);
+ ir_node *addr;
+
+ /* address for the backing store */
+ addr = be_new_FrameAddr(env->isa->sp->reg_class, irg, first_bl, frame, ent);
+
+ if (store)
+ mem = new_r_Proj(irg, first_bl, store, mode_M, pn_Store_M);
+
+ /* the backing store itself */
+ store = new_r_Store(irg, first_bl, mem, addr,
+ new_r_Proj(irg, args_bl, args, mode, i));
+ }
+ /* the new memory Proj gets the last Proj from store */
+ set_Proj_pred(nmem, store);
+ set_Proj_proj(nmem, pn_Store_M);
+
+ /* move all entities to the frame type */
+ frame_tp = get_irg_frame_type(irg);
+ offset = get_type_size_bytes(frame_tp);
+ for (ent = new_list; ent; ent = get_entity_link(ent)) {
+ ir_type *tp = get_entity_type(ent);
+ int align = get_type_alignment_bytes(tp);
+
+ offset += align - 1;
+ offset &= -align;
+ set_entity_owner(ent, frame_tp);
+ add_class_member(frame_tp, ent);
+ /* must be automatic to set a fixed layout */
+ set_entity_allocation(ent, allocation_automatic);
+ set_entity_offset_bytes(ent, offset);
+ offset += get_type_size_bytes(tp);
+ }
+ set_type_size_bytes(frame_tp, offset);
+ }