+static void clearup_frame(be_abi_irg_t *env, ir_node *ret, pmap *reg_map, struct obstack *obst)
+{
+ const arch_isa_t *isa = env->birg->main_env->arch_env->isa;
+ const arch_register_t *sp = isa->sp;
+ const arch_register_t *bp = isa->bp;
+ ir_graph *irg = env->birg->irg;
+ ir_node *ret_mem = get_Return_mem(ret);
+ ir_node *frame = get_irg_frame(irg);
+ ir_node *bl = get_nodes_block(ret);
+ ir_node *stack = get_irn_link(bl);
+
+ pmap_entry *ent;
+
+ if(env->call->flags.bits.try_omit_fp) {
+ stack = be_new_IncSP(sp, irg, bl, stack, ret_mem, BE_STACK_FRAME_SIZE, be_stack_dir_shrink);
+ }
+
+ else {
+ stack = be_new_SetSP(sp, irg, bl, stack, frame, ret_mem);
+ be_set_constr_single_reg(stack, -1, sp);
+ be_node_set_flags(stack, -1, arch_irn_flags_ignore);
+ }
+
+ pmap_foreach(env->regs, ent) {
+ const arch_register_t *reg = ent->key;
+ ir_node *irn = ent->value;
+
+ if(reg == sp)
+ obstack_ptr_grow(&env->obst, stack);
+ else if(reg == bp)
+ obstack_ptr_grow(&env->obst, frame);
+ else if(arch_register_type_is(reg, callee_save) || arch_register_type_is(reg, ignore))
+ obstack_ptr_grow(obst, irn);
+ }
+}
+
+static ir_type *compute_arg_type(be_abi_irg_t *env, be_abi_call_t *call, ir_type *method_type)
+{
+ int dir = env->call->flags.bits.left_to_right ? 1 : -1;
+ int inc = env->birg->main_env->arch_env->isa->stack_dir * dir;
+ int n = get_method_n_params(method_type);
+ int curr = inc > 0 ? 0 : n - 1;
+ int ofs = 0;
+
+ char buf[128];
+ ir_type *res;
+ int i;
+
+ snprintf(buf, sizeof(buf), "%s_arg_type", get_entity_name(get_irg_entity(env->birg->irg)));
+ res = new_type_class(new_id_from_str(buf));
+
+ for(i = 0; i < n; ++i, curr += inc) {
+ type *param_type = get_method_param_type(method_type, curr);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, curr);
+
+ if(arg->on_stack) {
+ snprintf(buf, sizeof(buf), "param_%d", i);
+ arg->stack_ent = new_entity(res, new_id_from_str(buf), param_type);
+ ofs += arg->space_before;
+ ofs = round_up2(ofs, arg->alignment);
+ set_entity_offset_bytes(arg->stack_ent, ofs);
+ ofs += arg->space_after;
+ ofs += get_type_size_bytes(param_type);
+ }
+ }
+
+ set_type_size_bytes(res, ofs);
+ return res;
+}
+
+static void create_register_perms(const arch_isa_t *isa, ir_graph *irg, ir_node *bl, pmap *regs)
+{
+ int i, j, n;
+ struct obstack obst;
+
+ obstack_init(&obst);
+
+ /* Create a Perm after the RegParams node to delimit it. */
+ for(i = 0, n = arch_isa_get_n_reg_class(isa); i < n; ++i) {
+ const arch_register_class_t *cls = arch_isa_get_reg_class(isa, i);
+ ir_node *perm;
+ ir_node **in;
+ int n_regs;
+
+ for(n_regs = 0, j = 0; j < cls->n_regs; ++j) {
+ const arch_register_t *reg = &cls->regs[j];
+ ir_node *irn = pmap_get(regs, (void *) reg);
+
+ if(irn && !arch_register_type_is(reg, ignore)) {
+ n_regs++;
+ obstack_ptr_grow(&obst, irn);
+ set_irn_link(irn, (void *) reg);
+ }
+ }
+
+ obstack_ptr_grow(&obst, NULL);
+ in = obstack_finish(&obst);
+ if(n_regs > 0) {
+ perm = be_new_Perm(cls, irg, bl, n_regs, in);
+ for(j = 0; j < n_regs; ++j) {
+ ir_node *arg = in[j];
+ arch_register_t *reg = get_irn_link(arg);
+ pmap_insert(regs, reg, arg);
+ be_set_constr_single_reg(perm, BE_OUT_POS(j), reg);
+ }
+ }
+ obstack_free(&obst, in);
+ }
+
+ obstack_free(&obst, NULL);
+}
+
+typedef struct {
+ const arch_register_t *reg;
+ ir_node *irn;
+} reg_node_map_t;
+
+static int cmp_regs(const void *a, const void *b)
+{
+ const reg_node_map_t *p = a;
+ const reg_node_map_t *q = b;
+
+ if(p->reg->reg_class == q->reg->reg_class)
+ return p->reg->index - q->reg->index;
+ else
+ return p->reg->reg_class - q->reg->reg_class;
+}
+
+static reg_node_map_t *reg_map_to_arr(struct obstack *obst, pmap *reg_map)