+static bool is_legal_delay_slot_filler(const ir_node *node)
+{
+ if (is_no_instruction(node))
+ return false;
+ if (emits_multiple_instructions(node))
+ return false;
+ if (rbitset_is_set(delay_slot_fillers, get_irn_idx(node)))
+ return false;
+ return true;
+}
+
+static bool can_move_down_into_delayslot(const ir_node *node, const ir_node *to)
+{
+ if (!is_legal_delay_slot_filler(node))
+ return false;
+
+ if (!be_can_move_down(heights, node, to))
+ return false;
+
+ if (is_sparc_Call(to)) {
+ ir_node *check;
+ /** all inputs are used after the delay slot so, we're fine */
+ if (!is_sparc_reg_call(to))
+ return true;
+
+ check = get_irn_n(to, get_sparc_Call_dest_addr_pos(to));
+ if (skip_Proj(check) == node)
+ return false;
+
+ /* the Call also destroys the value of %o7, but since this is
+ * currently marked as ignore register in the backend, it
+ * should never be used by the instruction in the delay slot. */
+ if (uses_reg(node, REG_O7, 1))
+ return false;
+ return true;
+ } else if (is_sparc_Return(to)) {
+ /* return uses the value of %o7, all other values are not
+ * immediately used */
+ if (writes_reg(node, REG_O7, 1))
+ return false;
+ return true;
+ } else {
+ /* the node must not use our computed values */
+ int arity = get_irn_arity(to);
+ for (int i = 0; i < arity; ++i) {
+ ir_node *in = get_irn_n(to, i);
+ if (skip_Proj(in) == node)
+ return false;
+ }
+ return true;
+ }
+}
+
+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;
+}