+static bool can_move_up_into_delayslot(const ir_node *node, const ir_node *to)
+{
+ if (!be_can_move_up(heights, node, to))
+ return false;
+
+ /* node must not use any results of 'to' */
+ int arity = get_irn_arity(node);
+ for (int i = 0; i < arity; ++i) {
+ ir_node *in = get_irn_n(node, i);
+ ir_node *skipped = skip_Proj(in);
+ if (skipped == to)
+ return false;
+ }
+
+ /* register window cycling effects at Restore aren't correctly represented
+ * in the graph yet so we need this exception here */
+ if (is_sparc_Restore(node) || is_sparc_RestoreZero(node)) {
+ return false;
+ } else if (is_sparc_Call(to)) {
+ /* node must not overwrite any of the inputs of the call,
+ * (except for the dest_addr) */
+ int dest_addr_pos = is_sparc_reg_call(to)
+ ? get_sparc_Call_dest_addr_pos(to) : -1;
+
+ int call_arity = get_irn_arity(to);
+ for (int i = 0; i < call_arity; ++i) {
+ if (i == dest_addr_pos)
+ continue;
+ const arch_register_t *reg = arch_get_irn_register_in(to, i);
+ if (reg == NULL)
+ continue;
+ const arch_register_req_t *req = arch_get_irn_register_req_in(to, i);
+ if (writes_reg(node, reg->global_index, req->width))
+ return false;
+ }
+
+ /* node must not write to one of the call outputs */
+ unsigned n_call_outs = arch_get_irn_n_outs(to);
+ for (unsigned o = 0; o < n_call_outs; ++o) {
+ const arch_register_t *reg = arch_get_irn_register_out(to, o);
+ if (reg == NULL)
+ continue;
+ const arch_register_req_t *req = arch_get_irn_register_req_out(to, o);
+ if (writes_reg(node, reg->global_index, req->width))
+ return false;
+ }
+ } else if (is_sparc_SDiv(to) || is_sparc_UDiv(to)) {
+ /* node will be inserted between wr and div so it must not overwrite
+ * anything except the wr input */
+ int arity = get_irn_arity(to);
+ for (int i = 0; i < arity; ++i) {
+ assert((long)n_sparc_SDiv_dividend_high == (long)n_sparc_UDiv_dividend_high);
+ if (i == n_sparc_SDiv_dividend_high)
+ continue;
+ const arch_register_t *reg = arch_get_irn_register_in(to, i);
+ if (reg == NULL)
+ continue;
+ const arch_register_req_t *req = arch_get_irn_register_req_in(to, i);
+ if (writes_reg(node, reg->global_index, req->width))
+ return false;
+ }
+}
+ return true;
+}
+
+static void optimize_fallthrough(ir_node *node)
+{
+ ir_node *proj_true = NULL;
+ ir_node *proj_false = NULL;
+
+ assert((long)pn_sparc_Bicc_false == (long)pn_sparc_fbfcc_false);
+ assert((long)pn_sparc_Bicc_true == (long)pn_sparc_fbfcc_true);
+ foreach_out_edge(node, edge) {
+ ir_node *proj = get_edge_src_irn(edge);
+ long nr = get_Proj_proj(proj);
+ if (nr == pn_sparc_Bicc_true) {
+ proj_true = proj;
+ } else {
+ assert(nr == pn_sparc_Bicc_false);
+ proj_false = proj;
+ }
+ }
+ assert(proj_true != NULL && proj_false != NULL);
+
+ /* for now, the code works for scheduled and non-schedules blocks */
+ const ir_node *block = get_nodes_block(node);
+
+ /* we have a block schedule */
+ const ir_node *next_block = (ir_node*)get_irn_link(block);
+
+ if (get_jump_target(proj_true) == next_block) {
+ /* exchange both proj destinations so the second one can be omitted */
+ set_Proj_proj(proj_true, pn_sparc_Bicc_false);
+ set_Proj_proj(proj_false, pn_sparc_Bicc_true);
+
+ sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr(node);
+ attr->relation = get_negated_relation(attr->relation);
+ }
+}
+