+ res = new_ir_node(NULL, irg, bl, op_be_Barrier, mode_T, -1, NULL);
+ init_node_attr(res, -1);
+ for(i = 0; i < n; ++i) {
+ add_irn_n(res, in[i]);
+ add_register_req(res);
+ }
+
+ return res;
+}
+
+ir_node *be_Barrier_append_node(ir_node *barrier, ir_node *node)
+{
+ ir_graph *irg = get_irn_irg(barrier);
+ ir_node *block = get_nodes_block(barrier);
+ ir_mode *mode = get_irn_mode(node);
+ int n = add_irn_n(barrier, node);
+
+ ir_node *proj = new_r_Proj(irg, block, barrier, mode, n);
+ add_register_req(barrier);
+
+ return proj;
+}
+
+/* Construct a new be_Unwind. */
+ir_node *be_new_Unwind(dbg_info *dbg, ir_graph *irg, ir_node *block,
+ ir_node *mem, ir_node *sp)
+{
+ ir_node *res;
+ ir_node *in[2];
+
+ in[be_pos_Unwind_mem] = mem;
+ in[be_pos_Unwind_sp] = sp;
+ res = new_ir_node(dbg, irg, block, op_be_Unwind, mode_X, 2, in);
+ init_node_attr(res, -1);
+
+ return res;
+}
+
+int be_has_frame_entity(const ir_node *irn)
+{
+ switch (get_irn_opcode(irn)) {
+ case beo_Spill:
+ case beo_Reload:
+ case beo_FrameAddr:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+ir_entity *be_get_frame_entity(const ir_node *irn)
+{
+ if (be_has_frame_entity(irn)) {
+ const be_frame_attr_t *a = get_irn_attr_const(irn);
+ return a->ent;
+ }
+ return NULL;
+}
+
+int be_get_frame_offset(const ir_node *irn)
+{
+ assert(is_be_node(irn));
+ if (be_has_frame_entity(irn)) {
+ const be_frame_attr_t *a = get_irn_attr_const(irn);
+ return a->offset;
+ }
+ return 0;
+}
+
+void be_set_MemPerm_in_entity(const ir_node *irn, int n, ir_entity *ent)
+{
+ const be_memperm_attr_t *attr = get_irn_attr_const(irn);
+
+ assert(be_is_MemPerm(irn));
+ assert(n < be_get_MemPerm_entity_arity(irn));
+
+ attr->in_entities[n] = ent;
+}
+
+ir_entity* be_get_MemPerm_in_entity(const ir_node* irn, int n)
+{
+ const be_memperm_attr_t *attr = get_irn_attr_const(irn);
+
+ assert(be_is_MemPerm(irn));
+ assert(n < be_get_MemPerm_entity_arity(irn));
+
+ return attr->in_entities[n];
+}
+
+void be_set_MemPerm_out_entity(const ir_node *irn, int n, ir_entity *ent)
+{
+ const be_memperm_attr_t *attr = get_irn_attr_const(irn);
+
+ assert(be_is_MemPerm(irn));
+ assert(n < be_get_MemPerm_entity_arity(irn));
+
+ attr->out_entities[n] = ent;
+}
+
+ir_entity* be_get_MemPerm_out_entity(const ir_node* irn, int n)
+{
+ const be_memperm_attr_t *attr = get_irn_attr_const(irn);
+
+ assert(be_is_MemPerm(irn));
+ assert(n < be_get_MemPerm_entity_arity(irn));
+
+ return attr->out_entities[n];
+}
+
+int be_get_MemPerm_entity_arity(const ir_node *irn)
+{
+ return get_irn_arity(irn) - 1;
+}
+
+void be_set_constr_single_reg(ir_node *node, int pos, const arch_register_t *reg)
+{
+ arch_register_req_t *req = get_req(node, pos);
+ const arch_register_class_t *cls = arch_register_get_class(reg);
+ ir_graph *irg = get_irn_irg(node);
+ struct obstack *obst = get_irg_obstack(irg);
+ unsigned *limited_bitset;
+
+ assert(req->cls == NULL || req->cls == cls);
+ assert(! (req->type & arch_register_req_type_limited));
+ assert(req->limited == NULL);
+
+ limited_bitset = rbitset_obstack_alloc(obst, arch_register_class_n_regs(cls));
+ rbitset_set(limited_bitset, arch_register_get_index(reg));
+
+ req->cls = cls;
+ req->type |= arch_register_req_type_limited;
+ req->limited = limited_bitset;
+}
+
+void be_set_constr_limited(ir_node *node, int pos, const arch_register_req_t *req)
+{
+ ir_graph *irg = get_irn_irg(node);
+ struct obstack *obst = get_irg_obstack(irg);
+ arch_register_req_t *r = get_req(node, pos);
+
+ assert(arch_register_req_is(req, limited));
+ assert(!(req->type & (arch_register_req_type_should_be_same | arch_register_req_type_must_be_different)));
+ memcpy(r, req, sizeof(r[0]));
+ r->limited = rbitset_duplicate_obstack_alloc(obst, req->limited, req->cls->n_regs);
+}
+
+void be_node_set_flags(ir_node *irn, int pos, arch_irn_flags_t flags)
+{
+ be_req_t *bereq = get_be_req(irn, pos);
+ bereq->flags = flags;
+}
+
+void be_node_add_flags(ir_node *irn, int pos, arch_irn_flags_t flags)
+{
+ be_req_t *bereq = get_be_req(irn, pos);
+ bereq->flags |= flags;
+}
+
+void be_node_set_reg_class(ir_node *irn, int pos, const arch_register_class_t *cls)
+{
+ arch_register_req_t *req = get_req(irn, pos);
+
+ req->cls = cls;
+
+ if (cls == NULL) {
+ req->type = arch_register_req_type_none;
+ } else if (req->type == arch_register_req_type_none) {
+ req->type = arch_register_req_type_normal;
+ }
+}
+
+void be_node_set_req_type(ir_node *irn, int pos, arch_register_req_type_t type)
+{
+ arch_register_req_t *req = get_req(irn, pos);
+ req->type = type;
+}
+
+ir_node *be_get_IncSP_pred(ir_node *irn) {
+ assert(be_is_IncSP(irn));
+ return get_irn_n(irn, 0);
+}
+
+void be_set_IncSP_pred(ir_node *incsp, ir_node *pred) {
+ assert(be_is_IncSP(incsp));
+ set_irn_n(incsp, 0, pred);
+}
+
+void be_set_IncSP_offset(ir_node *irn, int offset)
+{
+ be_incsp_attr_t *a = get_irn_attr(irn);
+ assert(be_is_IncSP(irn));
+ a->offset = offset;
+}
+
+int be_get_IncSP_offset(const ir_node *irn)
+{
+ const be_incsp_attr_t *a = get_irn_attr_const(irn);
+ assert(be_is_IncSP(irn));
+ return a->offset;
+}
+
+int be_get_IncSP_align(const ir_node *irn)
+{
+ const be_incsp_attr_t *a = get_irn_attr_const(irn);
+ assert(be_is_IncSP(irn));
+ return a->align;
+}
+
+ir_node *be_spill(const arch_env_t *arch_env, ir_node *block, ir_node *irn)
+{
+ ir_graph *irg = get_irn_irg(block);
+ ir_node *frame = get_irg_frame(irg);
+ const arch_register_class_t *cls = arch_get_irn_reg_class(arch_env, irn, -1);
+ const arch_register_class_t *cls_frame = arch_get_irn_reg_class(arch_env, frame, -1);
+ ir_node *spill;
+
+ spill = be_new_Spill(cls, cls_frame, irg, block, frame, irn);
+ return spill;
+}
+
+ir_node *be_reload(const arch_env_t *arch_env, const arch_register_class_t *cls, ir_node *insert, ir_mode *mode, ir_node *spill)
+{
+ ir_node *reload;
+ ir_node *bl = is_Block(insert) ? insert : get_nodes_block(insert);
+ ir_graph *irg = get_irn_irg(bl);
+ ir_node *frame = get_irg_frame(irg);
+ const arch_register_class_t *cls_frame = arch_get_irn_reg_class(arch_env, frame, -1);
+
+ assert(be_is_Spill(spill) || (is_Phi(spill) && get_irn_mode(spill) == mode_M));
+
+ reload = be_new_Reload(cls, cls_frame, irg, bl, frame, spill, mode);
+
+ if (is_Block(insert)) {
+ insert = sched_skip(insert, 0, sched_skip_cf_predicator, (void *) arch_env);
+ sched_add_after(insert, reload);
+ } else {
+ sched_add_before(insert, reload);
+ }
+
+ return reload;
+}
+
+/*
+ ____ ____
+ | _ \ ___ __ _ | _ \ ___ __ _ ___
+ | |_) / _ \/ _` | | |_) / _ \/ _` / __|
+ | _ < __/ (_| | | _ < __/ (_| \__ \
+ |_| \_\___|\__, | |_| \_\___|\__, |___/
+ |___/ |_|
+
+*/
+
+
+static const
+arch_register_req_t *get_out_reg_req(const ir_node *irn, int out_pos)
+{
+ const be_node_attr_t *a = get_irn_attr_const(irn);
+
+ if(out_pos >= ARR_LEN(a->reg_data)) {
+ return arch_no_register_req;
+ }
+
+ return &a->reg_data[out_pos].req.req;
+}
+
+static const
+arch_register_req_t *get_in_reg_req(const ir_node *irn, int pos)
+{
+ const be_node_attr_t *a = get_irn_attr_const(irn);
+
+ if(pos >= get_irn_arity(irn) || pos >= ARR_LEN(a->reg_data))
+ return arch_no_register_req;
+
+ return &a->reg_data[pos].in_req.req;
+}
+
+static const arch_register_req_t *
+be_node_get_irn_reg_req(const ir_node *irn, int pos)
+{
+ int out_pos = pos;
+
+ if (pos < 0) {
+ if (get_irn_mode(irn) == mode_T)
+ return arch_no_register_req;
+
+ out_pos = redir_proj((const ir_node **)&irn);
+ assert(is_be_node(irn));
+ return get_out_reg_req(irn, out_pos);
+ } else if (is_be_node(irn)) {
+ /*
+ * For spills and reloads, we return "none" as requirement for frame
+ * pointer, so every input is ok. Some backends need this (e.g. STA).
+ */
+ if ((be_is_Spill(irn) && pos == be_pos_Spill_frame) ||
+ (be_is_Reload(irn) && pos == be_pos_Reload_frame))
+ return arch_no_register_req;
+
+ return get_in_reg_req(irn, pos);
+ }
+
+ return arch_no_register_req;
+}
+
+const arch_register_t *
+be_node_get_irn_reg(const ir_node *irn)
+{
+ be_reg_data_t *r;
+
+ if (get_irn_mode(irn) == mode_T)
+ return NULL;
+ r = retrieve_reg_data(irn);
+ return r->reg;
+}
+
+static arch_irn_class_t be_node_classify(const ir_node *irn)
+{
+restart:
+ switch (get_irn_opcode(irn)) {
+#define XXX(a,b) case a: return b
+ XXX(beo_Spill, arch_irn_class_spill);
+ XXX(beo_Reload, arch_irn_class_reload);
+ XXX(beo_Perm, arch_irn_class_perm);
+ XXX(beo_Copy, arch_irn_class_copy);
+ XXX(beo_Return, arch_irn_class_branch);
+#undef XXX
+ case iro_Proj:
+ irn = get_Proj_pred(irn);
+ if (is_Proj(irn)) {
+ assert(get_irn_mode(irn) == mode_T);
+ irn = get_Proj_pred(irn);
+ }
+ goto restart;
+ break;
+ default:
+ return arch_irn_class_normal;
+ }
+
+ return 0;
+}
+
+static arch_irn_flags_t be_node_get_flags(const ir_node *node)
+{
+ be_req_t *bereq;
+ int pos = -1;
+
+ if(is_Proj(node)) {
+ pos = OUT_POS(get_Proj_proj(node));
+ node = skip_Proj_const(node);
+ }
+
+ bereq = get_be_req(node, pos);
+
+ return bereq->flags;
+}
+
+static ir_entity *be_node_get_frame_entity(const ir_node *irn)
+{
+ return be_get_frame_entity(irn);
+}
+
+static void be_node_set_frame_entity(ir_node *irn, ir_entity *ent)
+{
+ be_frame_attr_t *a;
+
+ assert(be_has_frame_entity(irn));
+
+ a = get_irn_attr(irn);
+ a->ent = ent;
+}
+
+static void be_node_set_frame_offset(ir_node *irn, int offset)
+{
+ if(be_has_frame_entity(irn)) {
+ be_frame_attr_t *a = get_irn_attr(irn);
+ a->offset = offset;
+ }
+}
+
+static int be_node_get_sp_bias(const ir_node *irn)
+{
+ if(be_is_IncSP(irn))
+ return be_get_IncSP_offset(irn);
+ if(be_is_Call(irn))
+ return -(int)be_Call_get_pop(irn);
+
+ return 0;
+}
+
+/*
+ ___ ____ _ _ _ _ _ _
+ |_ _| _ \| \ | | | | | | __ _ _ __ __| | | ___ _ __
+ | || |_) | \| | | |_| |/ _` | '_ \ / _` | |/ _ \ '__|
+ | || _ <| |\ | | _ | (_| | | | | (_| | | __/ |
+ |___|_| \_\_| \_| |_| |_|\__,_|_| |_|\__,_|_|\___|_|
+
+*/
+
+static const arch_irn_ops_t be_node_irn_ops = {
+ be_node_get_irn_reg_req,
+ be_node_set_irn_reg,
+ be_node_get_irn_reg,
+ be_node_classify,
+ be_node_get_flags,
+ be_node_get_frame_entity,
+ be_node_set_frame_entity,
+ be_node_set_frame_offset,
+ be_node_get_sp_bias,
+ NULL, /* get_inverse */
+ NULL, /* get_op_estimated_cost */
+ NULL, /* possible_memory_operand */
+ NULL, /* perform_memory_operand */
+};
+
+/*
+ ____ _ _ ___ ____ _ _ _ _ _ _
+ | _ \| |__ (_) |_ _| _ \| \ | | | | | | __ _ _ __ __| | | ___ _ __
+ | |_) | '_ \| | | || |_) | \| | | |_| |/ _` | '_ \ / _` | |/ _ \ '__|
+ | __/| | | | | | || _ <| |\ | | _ | (_| | | | | (_| | | __/ |
+ |_| |_| |_|_| |___|_| \_\_| \_| |_| |_|\__,_|_| |_|\__,_|_|\___|_|
+
+*/
+
+typedef struct {
+ const arch_register_t *reg;
+ arch_register_req_t req;
+ arch_irn_flags_t flags;
+} phi_attr_t;
+
+struct {
+ arch_env_t *arch_env;
+ pmap *phi_attrs;
+} phi_handler;
+
+#define get_phi_handler_from_ops(h) container_of(h, phi_handler_t, irn_ops)
+
+static INLINE
+phi_attr_t *get_Phi_attr(const ir_node *phi)
+{
+ phi_attr_t *attr = pmap_get(phi_handler.phi_attrs, (void*) phi);
+ if(attr == NULL) {
+ ir_graph *irg = get_irn_irg(phi);
+ struct obstack *obst = get_irg_obstack(irg);
+ attr = obstack_alloc(obst, sizeof(attr[0]));
+ memset(attr, 0, sizeof(attr[0]));
+ pmap_insert(phi_handler.phi_attrs, phi, attr);
+ }
+
+ return attr;
+}
+
+/**
+ * Get register class of a Phi.
+ */
+static
+const arch_register_req_t *get_Phi_reg_req_recursive(const ir_node *phi,
+ pset **visited)
+{
+ int n = get_irn_arity(phi);
+ ir_node *op;
+ int i;
+
+ if(*visited && pset_find_ptr(*visited, phi))
+ return NULL;
+
+ for(i = 0; i < n; ++i) {
+ op = get_irn_n(phi, i);
+ /* Matze: don't we unnecessary constraint our phis with this?
+ * we only need to take the regclass IMO*/
+ if(!is_Phi(op))
+ return arch_get_register_req(phi_handler.arch_env, op, BE_OUT_POS(0));
+ }
+
+ /*
+ * The operands of that Phi were all Phis themselves.
+ * We have to start a DFS for a non-Phi argument now.
+ */
+ if(!*visited)
+ *visited = pset_new_ptr(16);
+
+ pset_insert_ptr(*visited, phi);
+
+ for(i = 0; i < n; ++i) {
+ const arch_register_req_t *req;
+ op = get_irn_n(phi, i);
+ req = get_Phi_reg_req_recursive(op, visited);
+ if(req != NULL)
+ return req;
+ }
+
+ return NULL;
+}
+
+static
+const arch_register_req_t *phi_get_irn_reg_req(const ir_node *irn, int pos)
+{
+ phi_attr_t *attr;
+ (void) pos;
+
+ if(!mode_is_datab(get_irn_mode(irn)))
+ return arch_no_register_req;
+
+ attr = get_Phi_attr(irn);
+
+ if(attr->req.type == arch_register_req_type_none) {
+ pset *visited = NULL;
+ const arch_register_req_t *req;
+ req = get_Phi_reg_req_recursive(irn, &visited);
+
+ memcpy(&attr->req, req, sizeof(req[0]));
+ assert(attr->req.cls != NULL);
+ attr->req.type = arch_register_req_type_normal;
+
+ if(visited != NULL)
+ del_pset(visited);
+ }
+
+ return &attr->req;
+}
+
+void be_set_phi_reg_req(const arch_env_t *arch_env, ir_node *node,
+ const arch_register_req_t *req)
+{
+ phi_attr_t *attr;
+ (void) arch_env;
+
+ assert(mode_is_datab(get_irn_mode(node)));
+
+ attr = get_Phi_attr(node);
+ memcpy(&attr->req, req, sizeof(req[0]));
+}
+
+void be_set_phi_flags(const arch_env_t *arch_env, ir_node *node,
+ arch_irn_flags_t flags)
+{
+ phi_attr_t *attr;
+ (void) arch_env;
+
+ assert(mode_is_datab(get_irn_mode(node)));
+
+ attr = get_Phi_attr(node);
+ attr->flags = flags;
+}
+
+static void phi_set_irn_reg(ir_node *irn, const arch_register_t *reg)
+{
+ phi_attr_t *attr = get_Phi_attr(irn);
+ attr->reg = reg;
+}
+
+static const arch_register_t *phi_get_irn_reg(const ir_node *irn)
+{
+ phi_attr_t *attr = get_Phi_attr(irn);
+ return attr->reg;
+}
+
+static arch_irn_class_t phi_classify(const ir_node *irn)
+{
+ (void) irn;
+ return arch_irn_class_normal;
+}
+
+static arch_irn_flags_t phi_get_flags(const ir_node *irn)
+{
+ phi_attr_t *attr = get_Phi_attr(irn);
+ return attr->flags;
+}
+
+static ir_entity *phi_get_frame_entity(const ir_node *irn)
+{
+ (void) irn;
+ return NULL;
+}
+
+static void phi_set_frame_entity(ir_node *irn, ir_entity *ent)
+{
+ (void) irn;
+ (void) ent;
+ panic("phi_set_frame_entity() should not be called");
+}
+
+static void phi_set_frame_offset(ir_node *irn, int bias)
+{
+ (void) irn;
+ (void) bias;
+ panic("phi_set_frame_offset() should not be called");
+}
+
+static int phi_get_sp_bias(const ir_node *irn)
+{
+ (void) irn;
+ return 0;
+}
+
+static const arch_irn_ops_t phi_irn_ops = {
+ phi_get_irn_reg_req,
+ phi_set_irn_reg,
+ phi_get_irn_reg,
+ phi_classify,
+ phi_get_flags,
+ phi_get_frame_entity,
+ phi_set_frame_entity,
+ phi_set_frame_offset,
+ phi_get_sp_bias,
+ NULL, /* get_inverse */
+ NULL, /* get_op_estimated_cost */
+ NULL, /* possible_memory_operand */
+ NULL, /* perform_memory_operand */
+};
+
+void be_phi_handler_new(be_main_env_t *env)
+{
+ phi_handler.arch_env = env->arch_env;
+ phi_handler.phi_attrs = pmap_create();
+ op_Phi->ops.be_ops = &phi_irn_ops;
+}
+
+void be_phi_handler_free(void)
+{
+ pmap_destroy(phi_handler.phi_attrs);
+ phi_handler.phi_attrs = NULL;
+ op_Phi->ops.be_ops = NULL;
+}
+
+void be_phi_handler_reset(void)
+{
+ if(phi_handler.phi_attrs)
+ pmap_destroy(phi_handler.phi_attrs);
+ phi_handler.phi_attrs = pmap_create();
+}
+
+/*
+ _ _ _ ____ _
+ | \ | | ___ __| | ___ | _ \ _ _ _ __ ___ _ __ (_)_ __ __ _
+ | \| |/ _ \ / _` |/ _ \ | | | | | | | '_ ` _ \| '_ \| | '_ \ / _` |
+ | |\ | (_) | (_| | __/ | |_| | |_| | | | | | | |_) | | | | | (_| |
+ |_| \_|\___/ \__,_|\___| |____/ \__,_|_| |_| |_| .__/|_|_| |_|\__, |
+ |_| |___/
+*/
+
+/**
+ * Dumps a register requirement to a file.
+ */
+static void dump_node_req(FILE *f, int idx, const arch_register_req_t *req,
+ const ir_node *node)
+{
+ int did_something = 0;
+ char buf[16];
+ const char *prefix = buf;
+
+ snprintf(buf, sizeof(buf), "#%d ", idx);
+ buf[sizeof(buf) - 1] = '\0';
+
+ if(req->cls != 0) {
+ char tmp[256];
+ fprintf(f, prefix);
+ arch_register_req_format(tmp, sizeof(tmp), req, node);
+ fprintf(f, "%s", tmp);
+ did_something = 1;
+ }
+
+ if(did_something)
+ fprintf(f, "\n");
+}
+
+/**
+ * Dumps node register requirements to a file.
+ */
+static void dump_node_reqs(FILE *f, ir_node *node)
+{
+ int i;
+ be_node_attr_t *a = get_irn_attr(node);
+ int len = ARR_LEN(a->reg_data);
+
+ fprintf(f, "registers: \n");
+ for(i = 0; i < len; ++i) {
+ be_reg_data_t *rd = &a->reg_data[i];
+ if(rd->reg)
+ fprintf(f, "#%d: %s\n", i, rd->reg->name);
+ }
+
+ fprintf(f, "in requirements:\n");
+ for(i = 0; i < len; ++i) {
+ dump_node_req(f, i, &a->reg_data[i].in_req.req, node);
+ }
+
+ fprintf(f, "\nout requirements:\n");
+ for(i = 0; i < len; ++i) {
+ dump_node_req(f, i, &a->reg_data[i].req.req, node);
+ }
+}
+
+/**
+ * ir_op-Operation: dump a be node to file
+ */
+static int dump_node(ir_node *irn, FILE *f, dump_reason_t reason)
+{
+ be_node_attr_t *at = get_irn_attr(irn);
+