+static ir_node *setup_frame(be_abi_irg_t *env)
+{
+ 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;
+ be_abi_call_flags_bits_t flags = env->call->flags.bits;
+ ir_graph *irg = env->birg->irg;
+ ir_node *bl = get_irg_start_block(irg);
+ ir_node *no_mem = get_irg_no_mem(irg);
+ ir_node *old_frame = get_irg_frame(irg);
+ ir_node *stack = pmap_get(env->regs, (void *) sp);
+ ir_node *frame = pmap_get(env->regs, (void *) bp);
+
+ int stack_nr = get_Proj_proj(stack);
+
+ if(flags.try_omit_fp) {
+ stack = be_new_IncSP(sp, irg, bl, stack, no_mem, BE_STACK_FRAME_SIZE, be_stack_dir_expand);
+ frame = stack;
+ }
+
+ else {
+ frame = be_new_Copy(bp->reg_class, irg, bl, stack);
+
+ be_node_set_flags(frame, -1, arch_irn_flags_dont_spill);
+ if(!flags.fp_free) {
+ be_set_constr_single_reg(frame, -1, bp);
+ be_node_set_flags(frame, -1, arch_irn_flags_ignore);
+ arch_set_irn_register(env->birg->main_env->arch_env, frame, bp);
+ }
+
+ stack = be_new_IncSP(sp, irg, bl, stack, frame, BE_STACK_FRAME_SIZE, be_stack_dir_expand);
+ }
+
+ be_node_set_flags(env->reg_params, -(stack_nr + 1), arch_irn_flags_ignore);
+ env->init_sp = stack;
+ set_irg_frame(irg, frame);
+ edges_reroute(old_frame, frame, irg);
+
+ return frame;
+}
+
+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)
+{
+ pmap_entry *ent;
+ int n = pmap_count(reg_map);
+ int i = 0;
+ reg_node_map_t *res = obstack_alloc(obst, n * sizeof(res[0]));
+
+ pmap_foreach(reg_map, ent) {
+ res[i].reg = ent->key;
+ res[i].irn = ent->value;
+ i++;
+ }
+
+ qsort(res, n, sizeof(res[0]), cmp_regs);
+ return res;
+}
+
+static void create_barrier(be_abi_irg_t *env, ir_node *bl, ir_node **mem, pmap *regs, int in_req)
+{
+ ir_graph *irg = env->birg->irg;
+ int n;
+ int n_regs = pmap_count(regs);
+ ir_node *irn;
+ ir_node **in;
+ reg_node_map_t *rm;
+
+ rm = reg_map_to_arr(&env->obst, regs);
+
+ for(n = 0; n < n_regs; ++n)
+ obstack_ptr_grow(&env->obst, rm[n].irn);
+
+ if(mem) {
+ obstack_ptr_grow(&env->obst, *mem);
+ n++;
+ }
+
+ in = (ir_node **) obstack_finish(&env->obst);
+ irn = be_new_Barrier(env->birg->irg, bl, n, in);
+ obstack_free(&env->obst, in);
+
+ for(n = 0; n < n_regs; ++n) {
+ int pos = BE_OUT_POS(n);
+ ir_node *proj;
+ const arch_register_t *reg = rm[n].reg;
+
+ proj = new_r_Proj(env->birg->irg, bl, irn, get_irn_mode(rm[n].irn), n);
+ be_node_set_reg_class(irn, n, reg->reg_class);
+ if(in_req)
+ be_set_constr_single_reg(irn, n, reg);
+ be_set_constr_single_reg(irn, pos, reg);
+ be_node_set_reg_class(irn, pos, reg->reg_class);
+ arch_set_irn_register(env->birg->main_env->arch_env, proj, reg);
+ if(arch_register_type_is(reg, ignore))
+ be_node_set_flags(irn, pos, arch_irn_flags_ignore);
+
+ pmap_insert(regs, (void *) reg, proj);
+ }
+
+ if(mem) {
+ *mem = new_r_Proj(env->birg->irg, bl, irn, mode_M, n);
+ }
+
+ obstack_free(&env->obst, rm);
+}
+