+ 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);
+
+ assert(is_be_node(irn));
+
+ switch(reason) {
+ case dump_node_opcode_txt:
+ fprintf(f, get_op_name(get_irn_op(irn)));
+ break;
+ case dump_node_mode_txt:
+ if(be_is_Perm(irn) || be_is_Copy(irn) || be_is_CopyKeep(irn)) {
+ fprintf(f, " %s", get_mode_name(get_irn_mode(irn)));
+ }
+ break;
+ case dump_node_nodeattr_txt:
+ if(be_is_Call(irn)) {
+ be_call_attr_t *a = (be_call_attr_t *) at;
+ if (a->ent)
+ fprintf(f, " [%s] ", get_entity_name(a->ent));
+ }
+ if(be_is_IncSP(irn)) {
+ const be_incsp_attr_t *attr = get_irn_generic_attr_const(irn);
+ if(attr->offset == BE_STACK_FRAME_SIZE_EXPAND) {
+ fprintf(f, " [Setup Stackframe] ");
+ } else if(attr->offset == BE_STACK_FRAME_SIZE_SHRINK) {
+ fprintf(f, " [Destroy Stackframe] ");
+ } else {
+ fprintf(f, " [%d] ", attr->offset);
+ }
+ }
+ break;
+ case dump_node_info_txt:
+ dump_node_reqs(f, irn);
+
+ if(be_has_frame_entity(irn)) {
+ be_frame_attr_t *a = (be_frame_attr_t *) at;
+ if (a->ent) {
+ unsigned size = get_type_size_bytes(get_entity_type(a->ent));
+ ir_fprintf(f, "frame entity: %+F, offset 0x%x (%d), size 0x%x (%d) bytes\n",
+ a->ent, a->offset, a->offset, size, size);
+ }
+
+ }
+
+ switch (get_irn_opcode(irn)) {
+ case beo_IncSP:
+ {
+ be_incsp_attr_t *a = (be_incsp_attr_t *) at;
+ if (a->offset == BE_STACK_FRAME_SIZE_EXPAND)
+ fprintf(f, "offset: FRAME_SIZE\n");
+ else if(a->offset == BE_STACK_FRAME_SIZE_SHRINK)
+ fprintf(f, "offset: -FRAME SIZE\n");
+ else
+ fprintf(f, "offset: %u\n", a->offset);
+ }
+ break;
+ case beo_Call:
+ {
+ be_call_attr_t *a = (be_call_attr_t *) at;
+
+ if (a->ent)
+ fprintf(f, "\ncalling: %s\n", get_entity_name(a->ent));
+ }
+ break;
+ case beo_MemPerm:
+ {
+ int i;
+ for(i = 0; i < be_get_MemPerm_entity_arity(irn); ++i) {
+ ir_entity *in, *out;
+ in = be_get_MemPerm_in_entity(irn, i);
+ out = be_get_MemPerm_out_entity(irn, i);
+ if(in) {
+ fprintf(f, "\nin[%d]: %s\n", i, get_entity_name(in));
+ }
+ if(out) {
+ fprintf(f, "\nout[%d]: %s\n", i, get_entity_name(out));
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ir_op-Operation:
+ * Copies the backend specific attributes from old node to new node.
+ */
+static void copy_attr(const ir_node *old_node, ir_node *new_node)
+{
+ const be_node_attr_t *old_attr = get_irn_attr_const(old_node);
+ be_node_attr_t *new_attr = get_irn_attr(new_node);
+ struct obstack *obst = get_irg_obstack(get_irn_irg(new_node));
+ unsigned i, len;
+
+ assert(is_be_node(old_node));
+ assert(is_be_node(new_node));
+
+ memcpy(new_attr, old_attr, get_op_attr_size(get_irn_op(old_node)));
+ new_attr->reg_data = NULL;
+
+ if(old_attr->reg_data != NULL)
+ len = ARR_LEN(old_attr->reg_data);
+ else
+ len = 0;
+
+ if(get_irn_op(old_node)->opar == oparity_dynamic
+ || be_is_RegParams(old_node)) {
+ new_attr->reg_data = NEW_ARR_F(be_reg_data_t, len);
+ } else {
+ new_attr->reg_data = NEW_ARR_D(be_reg_data_t, obst, len);
+ }
+
+ if(len > 0) {
+ memcpy(new_attr->reg_data, old_attr->reg_data, len * sizeof(be_reg_data_t));
+ for(i = 0; i < len; ++i) {
+ const be_reg_data_t *rd = &old_attr->reg_data[i];
+ be_reg_data_t *newrd = &new_attr->reg_data[i];
+ if(arch_register_req_is(&rd->req.req, limited)) {
+ const arch_register_req_t *req = &rd->req.req;
+ arch_register_req_t *new_req = &newrd->req.req;
+ new_req->limited
+ = rbitset_duplicate_obstack_alloc(obst, req->limited, req->cls->n_regs);
+ }
+ if(arch_register_req_is(&rd->in_req.req, limited)) {
+ const arch_register_req_t *req = &rd->in_req.req;
+ arch_register_req_t *new_req = &newrd->in_req.req;
+ new_req->limited
+ = rbitset_duplicate_obstack_alloc(obst, req->limited, req->cls->n_regs);
+ }
+ }
+ }
+}
+
+static const ir_op_ops be_node_op_ops = {
+ firm_default_hash,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ copy_attr,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ dump_node,
+ NULL,
+ &be_node_irn_ops
+};
+
+int is_be_node(const ir_node *irn)
+{
+ return get_op_ops(get_irn_op(irn))->be_ops == &be_node_irn_ops;
+}
+
+void be_node_init(void) {
+ static int inited = 0;
+
+ if(inited)
+ return;
+
+ inited = 1;
+
+ /* Acquire all needed opcodes. */
+ op_be_Spill = new_ir_op(beo_Spill, "be_Spill", op_pin_state_pinned, N, oparity_unary, 0, sizeof(be_frame_attr_t), &be_node_op_ops);
+ op_be_Reload = new_ir_op(beo_Reload, "be_Reload", op_pin_state_pinned, N, oparity_zero, 0, sizeof(be_frame_attr_t), &be_node_op_ops);
+ op_be_Perm = new_ir_op(beo_Perm, "be_Perm", op_pin_state_pinned, N, oparity_variable, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_MemPerm = new_ir_op(beo_MemPerm, "be_MemPerm", op_pin_state_pinned, N, oparity_variable, 0, sizeof(be_memperm_attr_t), &be_node_op_ops);
+ op_be_Copy = new_ir_op(beo_Copy, "be_Copy", op_pin_state_floats, N, oparity_unary, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_Keep = new_ir_op(beo_Keep, "be_Keep", op_pin_state_pinned, K, oparity_dynamic, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_CopyKeep = new_ir_op(beo_CopyKeep, "be_CopyKeep", op_pin_state_pinned, K, oparity_variable, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_Call = new_ir_op(beo_Call, "be_Call", op_pin_state_pinned, F|M, oparity_variable, 0, sizeof(be_call_attr_t), &be_node_op_ops);
+ op_be_Return = new_ir_op(beo_Return, "be_Return", op_pin_state_pinned, X, oparity_dynamic, 0, sizeof(be_return_attr_t), &be_node_op_ops);
+ op_be_AddSP = new_ir_op(beo_AddSP, "be_AddSP", op_pin_state_pinned, N, oparity_unary, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_SubSP = new_ir_op(beo_SubSP, "be_SubSP", op_pin_state_pinned, N, oparity_unary, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_IncSP = new_ir_op(beo_IncSP, "be_IncSP", op_pin_state_pinned, N, oparity_unary, 0, sizeof(be_incsp_attr_t), &be_node_op_ops);
+ op_be_RegParams = new_ir_op(beo_RegParams, "be_RegParams", op_pin_state_pinned, N, oparity_zero, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_FrameAddr = new_ir_op(beo_FrameAddr, "be_FrameAddr", op_pin_state_floats, N, oparity_unary, 0, sizeof(be_frame_attr_t), &be_node_op_ops);
+ op_be_Barrier = new_ir_op(beo_Barrier, "be_Barrier", op_pin_state_pinned, N, oparity_dynamic, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+ op_be_Unwind = new_ir_op(beo_Unwind, "be_Unwind", op_pin_state_pinned, X, oparity_zero, 0, sizeof(be_node_attr_t), &be_node_op_ops);
+
+ op_be_Spill->ops.node_cmp_attr = FrameAddr_cmp_attr;
+ op_be_Reload->ops.node_cmp_attr = FrameAddr_cmp_attr;
+ op_be_Perm->ops.node_cmp_attr = node_cmp_attr;
+ op_be_MemPerm->ops.node_cmp_attr = node_cmp_attr;
+ op_be_Copy->ops.node_cmp_attr = node_cmp_attr;
+ op_be_Keep->ops.node_cmp_attr = node_cmp_attr;
+ op_be_CopyKeep->ops.node_cmp_attr = node_cmp_attr;
+ op_be_Call->ops.node_cmp_attr = Call_cmp_attr;
+ op_be_Return->ops.node_cmp_attr = Return_cmp_attr;
+ op_be_AddSP->ops.node_cmp_attr = node_cmp_attr;
+ op_be_SubSP->ops.node_cmp_attr = node_cmp_attr;
+ op_be_IncSP->ops.node_cmp_attr = IncSP_cmp_attr;
+ op_be_RegParams->ops.node_cmp_attr = node_cmp_attr;
+ op_be_FrameAddr->ops.node_cmp_attr = FrameAddr_cmp_attr;
+ op_be_Barrier->ops.node_cmp_attr = node_cmp_attr;
+ op_be_Unwind->ops.node_cmp_attr = node_cmp_attr;