-/* Encapsulate the block starting at FIRST and ending with LAST, which is
- logically equivalent to EQUIV, so it gets manipulated as a unit if it
- is possible to do so. */
-
-void
-maybe_encapsulate_block (rtx first, rtx last, rtx equiv)
-{
- if (!flag_non_call_exceptions || !may_trap_p (equiv))
- {
- /* We can't attach the REG_LIBCALL and REG_RETVAL notes when the
- encapsulated region would not be in one basic block, i.e. when
- there is a control_flow_insn_p insn between FIRST and LAST. */
- bool attach_libcall_retval_notes = true;
- rtx insn, next = NEXT_INSN (last);
-
- for (insn = first; insn != next; insn = NEXT_INSN (insn))
- if (control_flow_insn_p (insn))
- {
- attach_libcall_retval_notes = false;
- break;
- }
-
- if (attach_libcall_retval_notes)
- {
- REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
- REG_NOTES (first));
- REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
- REG_NOTES (last));
- }
- }
-}
-
-/* Emit code to perform a series of operations on a multi-word quantity, one
- word at a time.
-
- Such a block is preceded by a CLOBBER of the output, consists of multiple
- insns, each setting one word of the output, and followed by a SET copying
- the output to itself.
-
- Each of the insns setting words of the output receives a REG_NO_CONFLICT
- note indicating that it doesn't conflict with the (also multi-word)
- inputs. The entire block is surrounded by REG_LIBCALL and REG_RETVAL
- notes.
-
- INSNS is a block of code generated to perform the operation, not including
- the CLOBBER and final copy. All insns that compute intermediate values
- are first emitted, followed by the block as described above.
-
- TARGET, OP0, and OP1 are the output and inputs of the operations,
- respectively. OP1 may be zero for a unary operation.
-
- EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note
- on the last insn.
-
- If TARGET is not a register, INSNS is simply emitted with no special
- processing. Likewise if anything in INSNS is not an INSN or if
- there is a libcall block inside INSNS.
-
- The final insn emitted is returned. */
-
-rtx
-emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
-{
- rtx prev, next, first, last, insn;
-
- if (!REG_P (target) || reload_in_progress)
- return emit_insn (insns);
- else
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (!NONJUMP_INSN_P (insn)
- || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- return emit_insn (insns);
-
- /* First emit all insns that do not store into words of the output and remove
- these from the list. */
- for (insn = insns; insn; insn = next)
- {
- rtx note;
- struct no_conflict_data data;
-
- next = NEXT_INSN (insn);
-
- /* Some ports (cris) create a libcall regions at their own. We must
- avoid any potential nesting of LIBCALLs. */
- if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
- remove_note (insn, note);
- if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
- remove_note (insn, note);
-
- data.target = target;
- data.first = insns;
- data.insn = insn;
- data.must_stay = 0;
- note_stores (PATTERN (insn), no_conflict_move_test, &data);
- if (! data.must_stay)
- {
- if (PREV_INSN (insn))
- NEXT_INSN (PREV_INSN (insn)) = next;
- else
- insns = next;
-
- if (next)
- PREV_INSN (next) = PREV_INSN (insn);
-
- add_insn (insn);
- }
- }
-
- prev = get_last_insn ();
-
- /* Now write the CLOBBER of the output, followed by the setting of each
- of the words, followed by the final copy. */
- if (target != op0 && target != op1)
- emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
-
- for (insn = insns; insn; insn = next)
- {
- next = NEXT_INSN (insn);
- add_insn (insn);
-
- if (op1 && REG_P (op1))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
- REG_NOTES (insn));
-
- if (op0 && REG_P (op0))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
- REG_NOTES (insn));
- }
-
- if (optab_handler (mov_optab, GET_MODE (target))->insn_code
- != CODE_FOR_nothing)
- {
- last = emit_move_insn (target, target);
- if (equiv)
- set_unique_reg_note (last, REG_EQUAL, equiv);
- }
- else
- {
- last = get_last_insn ();
-
- /* Remove any existing REG_EQUAL note from "last", or else it will
- be mistaken for a note referring to the full contents of the
- alleged libcall value when found together with the REG_RETVAL
- note added below. An existing note can come from an insn
- expansion at "last". */
- remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
- }
-
- if (prev == 0)
- first = get_insns ();
- else
- first = NEXT_INSN (prev);
-
- maybe_encapsulate_block (first, last, equiv);
-
- return last;
-}