+static be_reg_data_t *retrieve_reg_data(const ir_node *node)
+{
+ const be_node_attr_t *attr;
+ int pos = 0;
+
+ if(is_Proj(node)) {
+ pos = get_Proj_proj(node);
+ node = get_Proj_pred(node);
+ }
+
+ assert(is_be_node(node));
+ attr = get_irn_attr_const(node);
+ assert(pos >= 0 && pos < ARR_LEN(attr->reg_data) && "illegal proj number");
+
+ return &attr->reg_data[pos];
+}
+
+static void
+be_node_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg)
+{
+ be_reg_data_t *r = retrieve_reg_data(irn);
+ (void) self;
+ r->reg = reg;
+}
+
+ir_node *be_new_Spill(const arch_register_class_t *cls, const arch_register_class_t *cls_frame,
+ ir_graph *irg, ir_node *bl, ir_node *frame, ir_node *to_spill)
+{
+ be_frame_attr_t *a;
+ ir_node *in[2];
+ ir_node *res;
+
+ in[0] = frame;
+ in[1] = to_spill;
+ res = new_ir_node(NULL, irg, bl, op_be_Spill, mode_M, 2, in);
+ a = init_node_attr(res, 2);
+ a->ent = NULL;
+ a->offset = 0;
+
+ be_node_set_reg_class(res, be_pos_Spill_frame, cls_frame);
+ be_node_set_reg_class(res, be_pos_Spill_val, cls);
+ return res;
+}
+
+ir_node *be_new_Reload(const arch_register_class_t *cls, const arch_register_class_t *cls_frame,
+ ir_graph *irg, ir_node *bl, ir_node *frame, ir_node *mem, ir_mode *mode)
+{
+ ir_node *in[2];
+ ir_node *res;
+
+ in[0] = frame;
+ in[1] = mem;
+ res = new_ir_node(NULL, irg, bl, op_be_Reload, mode, 2, in);
+
+ init_node_attr(res, 2);
+ be_node_set_reg_class(res, -1, cls);
+ be_node_set_reg_class(res, be_pos_Reload_frame, cls_frame);
+ be_node_set_flags(res, -1, arch_irn_flags_rematerializable);
+ return res;
+}
+
+ir_node *be_get_Reload_mem(const ir_node *irn)
+{
+ assert(be_is_Reload(irn));
+ return get_irn_n(irn, be_pos_Reload_mem);
+}
+
+ir_node *be_get_Reload_frame(const ir_node *irn)
+{
+ assert(be_is_Reload(irn));
+ return get_irn_n(irn, be_pos_Reload_frame);
+}
+
+ir_node *be_get_Spill_val(const ir_node *irn)
+{
+ assert(be_is_Spill(irn));
+ return get_irn_n(irn, be_pos_Spill_val);
+}
+
+ir_node *be_get_Spill_frame(const ir_node *irn)
+{
+ assert(be_is_Spill(irn));
+ return get_irn_n(irn, be_pos_Spill_frame);
+}
+
+ir_node *be_new_Perm(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, int n, ir_node *in[])
+{
+ int i;
+ ir_node *irn = new_ir_node(NULL, irg, bl, op_be_Perm, mode_T, n, in);
+ init_node_attr(irn, n);
+ for(i = 0; i < n; ++i) {
+ be_node_set_reg_class(irn, i, cls);
+ be_node_set_reg_class(irn, OUT_POS(i), cls);
+ }
+
+ return irn;
+}
+
+void be_Perm_reduce(ir_node *perm, int new_size, int *map)
+{
+ ir_graph *irg = get_irn_irg(perm);
+ int arity = get_irn_arity(perm);
+ be_reg_data_t *old_data = alloca(arity * sizeof(old_data[0]));
+ be_node_attr_t *attr = get_irn_attr(perm);
+ ir_node **new_in = NEW_ARR_D(ir_node *, irg->obst, new_size);
+
+ int i;
+
+ assert(be_is_Perm(perm));
+ assert(new_size <= arity);
+
+ /* save the old register data */
+ memcpy(old_data, attr->reg_data, arity * sizeof(old_data[0]));
+
+ /* compose the new in array and set the new register data directly in place */
+ for (i = 0; i < new_size; ++i) {
+ int idx = map[i];
+ new_in[i] = get_irn_n(perm, idx);
+ attr->reg_data[i] = old_data[idx];
+ }
+
+ set_irn_in(perm, new_size, new_in);
+}
+
+ir_node *be_new_MemPerm(const arch_env_t *arch_env, ir_graph *irg, ir_node *bl, int n, ir_node *in[])
+{
+ int i;
+ ir_node *frame = get_irg_frame(irg);
+ const arch_register_class_t *cls_frame = arch_get_irn_reg_class(arch_env, frame, -1);
+ ir_node *irn;
+ const arch_register_t *sp = arch_env->isa->sp;
+ be_memperm_attr_t *attr;
+ ir_node **real_in;
+
+ real_in = alloca((n+1) * sizeof(real_in[0]));
+ real_in[0] = frame;
+ memcpy(&real_in[1], in, n * sizeof(real_in[0]));
+
+ irn = new_ir_node(NULL, irg, bl, op_be_MemPerm, mode_T, n+1, real_in);
+
+ init_node_attr(irn, n + 1);
+ be_node_set_reg_class(irn, 0, sp->reg_class);
+ for (i = 0; i < n; ++i) {
+ be_node_set_reg_class(irn, i + 1, cls_frame);
+ be_node_set_reg_class(irn, OUT_POS(i), cls_frame);
+ }
+
+ attr = get_irn_attr(irn);
+
+ attr->in_entities = obstack_alloc(irg->obst, n * sizeof(attr->in_entities[0]));
+ memset(attr->in_entities, 0, n * sizeof(attr->in_entities[0]));
+ attr->out_entities = obstack_alloc(irg->obst, n*sizeof(attr->out_entities[0]));
+ memset(attr->out_entities, 0, n*sizeof(attr->out_entities[0]));
+
+ return irn;
+}
+
+
+ir_node *be_new_Copy(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, ir_node *op)
+{
+ ir_node *in[1];
+ ir_node *res;
+ arch_register_req_t *req;
+
+ in[0] = op;
+ res = new_ir_node(NULL, irg, bl, op_be_Copy, get_irn_mode(op), 1, in);
+ init_node_attr(res, 1);
+ be_node_set_reg_class(res, 0, cls);
+ be_node_set_reg_class(res, OUT_POS(0), cls);
+
+ req = get_req(res, OUT_POS(0));
+ req->cls = cls;
+ req->type = arch_register_req_type_should_be_same;
+ req->other_same = 1U << 0;
+
+ return res;
+}
+
+ir_node *be_get_Copy_op(const ir_node *cpy) {
+ return get_irn_n(cpy, be_pos_Copy_op);
+}
+
+void be_set_Copy_op(ir_node *cpy, ir_node *op) {
+ set_irn_n(cpy, be_pos_Copy_op, op);
+}
+
+ir_node *be_new_Keep(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, int n, ir_node *in[])
+{
+ int i;
+ ir_node *res;
+
+ res = new_ir_node(NULL, irg, bl, op_be_Keep, mode_ANY, -1, NULL);
+ init_node_attr(res, -1);
+
+ for(i = 0; i < n; ++i) {
+ add_irn_n(res, in[i]);
+ add_register_req(res);
+ be_node_set_reg_class(res, i, cls);
+ }
+ keep_alive(res);
+
+ return res;
+}
+
+void be_Keep_add_node(ir_node *keep, const arch_register_class_t *cls, ir_node *node)
+{
+ int n;
+
+ assert(be_is_Keep(keep));
+ n = add_irn_n(keep, node);
+ add_register_req(keep);
+ be_node_set_reg_class(keep, n, cls);
+}
+
+/* creates a be_Call */
+ir_node *be_new_Call(dbg_info *dbg, ir_graph *irg, ir_node *bl, ir_node *mem, ir_node *sp, ir_node *ptr,
+ int n_outs, int n, ir_node *in[], ir_type *call_tp)
+{
+ be_call_attr_t *a;
+ int real_n = be_pos_Call_first_arg + n;
+ ir_node *irn;
+ ir_node **real_in;
+
+ NEW_ARR_A(ir_node *, real_in, real_n);
+ real_in[be_pos_Call_mem] = mem;
+ real_in[be_pos_Call_sp] = sp;
+ real_in[be_pos_Call_ptr] = ptr;
+ memcpy(&real_in[be_pos_Call_first_arg], in, n * sizeof(in[0]));
+
+ irn = new_ir_node(dbg, irg, bl, op_be_Call, mode_T, real_n, real_in);
+ a = init_node_attr(irn, (n_outs > real_n ? n_outs : real_n));
+ a->ent = NULL;
+ a->call_tp = call_tp;
+ a->pop = 0;
+ return irn;
+}
+
+/* Gets the call entity or NULL if this is no static call. */
+ir_entity *be_Call_get_entity(const ir_node *call) {
+ const be_call_attr_t *a = get_irn_attr_const(call);
+ assert(be_is_Call(call));
+ return a->ent;
+}
+
+/* Sets the call entity. */
+void be_Call_set_entity(ir_node *call, ir_entity *ent) {
+ be_call_attr_t *a = get_irn_attr(call);
+ assert(be_is_Call(call));
+ a->ent = ent;
+}
+
+/* Gets the call type. */
+ir_type *be_Call_get_type(ir_node *call) {
+ const be_call_attr_t *a = get_irn_attr_const(call);
+ assert(be_is_Call(call));
+ return a->call_tp;
+}
+
+/* Sets the call type. */
+void be_Call_set_type(ir_node *call, ir_type *call_tp) {
+ be_call_attr_t *a = get_irn_attr(call);
+ assert(be_is_Call(call));
+ a->call_tp = call_tp;
+}
+
+void be_Call_set_pop(ir_node *call, unsigned pop) {
+ be_call_attr_t *a = get_irn_attr(call);
+ a->pop = pop;
+}
+
+unsigned be_Call_get_pop(const ir_node *call) {
+ const be_call_attr_t *a = get_irn_attr_const(call);
+ return a->pop;
+}
+
+/* Construct a new be_Return. */
+ir_node *be_new_Return(dbg_info *dbg, ir_graph *irg, ir_node *block, int n_res,
+ unsigned pop, int n, ir_node *in[])
+{
+ be_return_attr_t *a;
+ ir_node *res;
+ int i;
+
+ res = new_ir_node(dbg, irg, block, op_be_Return, mode_X, -1, NULL);
+ init_node_attr(res, -1);
+ for(i = 0; i < n; ++i) {
+ add_irn_n(res, in[i]);
+ add_register_req(res);
+ }
+
+ a = get_irn_attr(res);
+ a->num_ret_vals = n_res;
+ a->pop = pop;
+ a->emit_pop = 0;
+
+ return res;
+}
+
+/* Returns the number of real returns values */
+int be_Return_get_n_rets(const ir_node *ret) {
+ const be_return_attr_t *a = get_irn_generic_attr_const(ret);
+ return a->num_ret_vals;
+}
+
+/* return the number of bytes that should be popped from stack when executing the Return. */
+unsigned be_Return_get_pop(const ir_node *ret) {
+ const be_return_attr_t *a = get_irn_generic_attr_const(ret);
+ return a->pop;
+}
+
+/* return non-zero, if number of popped bytes must be always emitted */
+int be_Return_get_emit_pop(const ir_node *ret) {
+ const be_return_attr_t *a = get_irn_generic_attr_const(ret);
+ return a->emit_pop;
+}
+
+/* return non-zero, if number of popped bytes must be always emitted */
+void be_Return_set_emit_pop(ir_node *ret, int emit_pop) {
+ be_return_attr_t *a = get_irn_generic_attr(ret);
+ a->emit_pop = emit_pop;
+}
+
+int be_Return_append_node(ir_node *ret, ir_node *node) {
+ int pos;
+
+ pos = add_irn_n(ret, node);
+ add_register_req(ret);
+
+ return pos;
+}
+
+ir_node *be_new_IncSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl,
+ ir_node *old_sp, int offset, int align)
+{
+ be_incsp_attr_t *a;
+ ir_node *irn;
+ ir_node *in[1];
+
+ in[0] = old_sp;
+ irn = new_ir_node(NULL, irg, bl, op_be_IncSP, sp->reg_class->mode,
+ sizeof(in) / sizeof(in[0]), in);
+ a = init_node_attr(irn, 1);
+ a->offset = offset;
+ a->align = align;
+
+ be_node_set_flags(irn, -1, arch_irn_flags_ignore | arch_irn_flags_modify_sp);
+
+ /* Set output constraint to stack register. */
+ be_node_set_reg_class(irn, 0, sp->reg_class);
+ be_set_constr_single_reg(irn, BE_OUT_POS(0), sp);
+ be_node_set_irn_reg(NULL, irn, sp);
+
+ return irn;
+}
+
+ir_node *be_new_AddSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_node *old_sp, ir_node *sz)
+{
+ be_node_attr_t *a;
+ ir_node *irn;
+ ir_node *in[be_pos_AddSP_last];
+ const arch_register_class_t *class;
+
+ in[be_pos_AddSP_old_sp] = old_sp;
+ in[be_pos_AddSP_size] = sz;
+
+ irn = new_ir_node(NULL, irg, bl, op_be_AddSP, mode_T, be_pos_AddSP_last, in);
+ a = init_node_attr(irn, be_pos_AddSP_last);
+
+ be_node_set_flags(irn, OUT_POS(pn_be_AddSP_sp),
+ arch_irn_flags_ignore | arch_irn_flags_modify_sp);
+
+ /* Set output constraint to stack register. */
+ be_set_constr_single_reg(irn, be_pos_AddSP_old_sp, sp);
+ be_node_set_reg_class(irn, be_pos_AddSP_size, arch_register_get_class(sp));
+ be_set_constr_single_reg(irn, OUT_POS(pn_be_AddSP_sp), sp);
+ a->reg_data[pn_be_AddSP_sp].reg = sp;
+
+ class = arch_register_get_class(sp);
+ be_node_set_reg_class(irn, OUT_POS(pn_be_AddSP_res), class);
+
+ return irn;
+}
+
+ir_node *be_new_SubSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_node *old_sp, ir_node *sz)
+{
+ be_node_attr_t *a;
+ ir_node *irn;
+ ir_node *in[be_pos_SubSP_last];
+
+ in[be_pos_SubSP_old_sp] = old_sp;
+ in[be_pos_SubSP_size] = sz;
+
+ irn = new_ir_node(NULL, irg, bl, op_be_SubSP, mode_T, be_pos_SubSP_last, in);
+ a = init_node_attr(irn, be_pos_SubSP_last);
+
+ be_node_set_flags(irn, OUT_POS(pn_be_SubSP_sp),
+ arch_irn_flags_ignore | arch_irn_flags_modify_sp);
+
+ /* Set output constraint to stack register. */
+ be_set_constr_single_reg(irn, be_pos_SubSP_old_sp, sp);
+ be_node_set_reg_class(irn, be_pos_SubSP_size, arch_register_get_class(sp));
+ be_set_constr_single_reg(irn, OUT_POS(pn_be_SubSP_sp), sp);
+ a->reg_data[pn_be_SubSP_sp].reg = sp;
+
+ return irn;
+}
+
+ir_node *be_new_RegParams(ir_graph *irg, ir_node *bl, int n_outs)
+{
+ ir_node *res;
+ int i;
+
+ res = new_ir_node(NULL, irg, bl, op_be_RegParams, mode_T, 0, NULL);
+ init_node_attr(res, -1);
+ for(i = 0; i < n_outs; ++i)
+ add_register_req(res);
+
+ return res;
+}
+
+ir_node *be_RegParams_append_out_reg(ir_node *regparams,
+ const arch_env_t *arch_env,
+ const arch_register_t *reg)
+{
+ ir_graph *irg = get_irn_irg(regparams);
+ ir_node *block = get_nodes_block(regparams);
+ be_node_attr_t *attr = get_irn_attr(regparams);
+ const arch_register_class_t *cls = arch_register_get_class(reg);
+ ir_mode *mode = arch_register_class_mode(cls);
+ int n = ARR_LEN(attr->reg_data);
+ ir_node *proj;
+
+ assert(be_is_RegParams(regparams));
+ proj = new_r_Proj(irg, block, regparams, mode, n);
+ add_register_req(regparams);
+ be_set_constr_single_reg(regparams, BE_OUT_POS(n), reg);
+ arch_set_irn_register(arch_env, proj, reg);
+
+ /* TODO decide, whether we need to set ignore/modify sp flags here? */
+
+ return proj;
+}
+
+ir_node *be_new_FrameAddr(const arch_register_class_t *cls_frame, ir_graph *irg, ir_node *bl, ir_node *frame, ir_entity *ent)
+{
+ be_frame_attr_t *a;
+ ir_node *irn;
+ ir_node *in[1];
+
+ in[0] = frame;
+ irn = new_ir_node(NULL, irg, bl, op_be_FrameAddr, get_irn_mode(frame), 1, in);
+ a = init_node_attr(irn, 1);
+ a->ent = ent;
+ a->offset = 0;
+ be_node_set_reg_class(irn, 0, cls_frame);
+ be_node_set_reg_class(irn, OUT_POS(0), cls_frame);
+
+ return optimize_node(irn);
+}
+
+ir_node *be_get_FrameAddr_frame(const ir_node *node) {
+ assert(be_is_FrameAddr(node));
+ return get_irn_n(node, be_pos_FrameAddr_ptr);
+}
+
+ir_entity *be_get_FrameAddr_entity(const ir_node *node)
+{
+ const be_frame_attr_t *attr = get_irn_generic_attr_const(node);
+ return attr->ent;
+}
+
+ir_node *be_new_CopyKeep(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, ir_node *src, int n, ir_node *in_keep[], ir_mode *mode)
+{
+ ir_node *irn;
+ ir_node **in = (ir_node **) alloca((n + 1) * sizeof(in[0]));
+
+ in[0] = src;
+ memcpy(&in[1], in_keep, n * sizeof(in[0]));
+ irn = new_ir_node(NULL, irg, bl, op_be_CopyKeep, mode, n + 1, in);
+ init_node_attr(irn, n + 1);
+ be_node_set_reg_class(irn, OUT_POS(0), cls);
+ be_node_set_reg_class(irn, 0, cls);
+
+ return irn;
+}
+
+ir_node *be_new_CopyKeep_single(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, ir_node *src, ir_node *keep, ir_mode *mode)
+{
+ return be_new_CopyKeep(cls, irg, bl, src, 1, &keep, mode);
+}
+
+ir_node *be_get_CopyKeep_op(const ir_node *cpy) {
+ return get_irn_n(cpy, be_pos_CopyKeep_op);
+}
+
+void be_set_CopyKeep_op(ir_node *cpy, ir_node *op) {
+ set_irn_n(cpy, be_pos_CopyKeep_op, op);
+}
+
+ir_node *be_new_Barrier(ir_graph *irg, ir_node *bl, int n, ir_node *in[])
+{
+ ir_node *res;
+ int i;
+
+ 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_is_Spill (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Spill ; }
+int be_is_Reload (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Reload ; }
+int be_is_Copy (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Copy ; }
+int be_is_CopyKeep (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_CopyKeep ; }
+int be_is_Perm (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Perm ; }
+int be_is_MemPerm (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_MemPerm ; }
+int be_is_Keep (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Keep ; }
+int be_is_Call (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Call ; }
+int be_is_Return (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Return ; }
+int be_is_IncSP (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_IncSP ; }
+int be_is_AddSP (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_AddSP ; }
+int be_is_SubSP (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_SubSP ; }
+int be_is_RegParams (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_RegParams ; }
+int be_is_FrameAddr (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_FrameAddr ; }
+int be_is_Barrier (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Barrier ; }
+int be_is_Unwind (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Unwind ; }
+
+int be_has_frame_entity(const ir_node *irn)
+{
+ switch (be_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)