+ {
+ regset r = BASIC_BLOCK (i)->global_live_at_start;
+ if (REGNO_REG_SET_P (r, from))
+ {
+ CLEAR_REGNO_REG_SET (r, from);
+ SET_REGNO_REG_SET (r, to);
+ }
+ }
+}
+\f
+/* Used for communication between the following functions. Holds the
+ current life information. */
+static regset live_relevant_regs;
+
+/* Record in live_relevant_regs and REGS_SET that register REG became live.
+ This is called via note_stores. */
+static void
+reg_becomes_live (reg, setter, regs_set)
+ rtx reg;
+ rtx setter ATTRIBUTE_UNUSED;
+ void *regs_set;
+{
+ int regno;
+
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+
+ if (GET_CODE (reg) != REG)
+ return;
+
+ regno = REGNO (reg);
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ while (nregs-- > 0)
+ {
+ SET_REGNO_REG_SET (live_relevant_regs, regno);
+ if (! fixed_regs[regno])
+ SET_REGNO_REG_SET ((regset) regs_set, regno);
+ regno++;
+ }
+ }
+ else if (reg_renumber[regno] >= 0)
+ {
+ SET_REGNO_REG_SET (live_relevant_regs, regno);
+ SET_REGNO_REG_SET ((regset) regs_set, regno);
+ }
+}
+
+/* Record in live_relevant_regs that register REGNO died. */
+static void
+reg_dies (regno, mode, chain)
+ int regno;
+ enum machine_mode mode;
+ struct insn_chain *chain;
+{
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int nregs = HARD_REGNO_NREGS (regno, mode);
+ while (nregs-- > 0)
+ {
+ CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
+ if (! fixed_regs[regno])
+ SET_REGNO_REG_SET (&chain->dead_or_set, regno);
+ regno++;
+ }
+ }
+ else
+ {
+ CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
+ if (reg_renumber[regno] >= 0)
+ SET_REGNO_REG_SET (&chain->dead_or_set, regno);
+ }
+}
+
+/* Walk the insns of the current function and build reload_insn_chain,
+ and record register life information. */
+void
+build_insn_chain (first)
+ rtx first;
+{
+ struct insn_chain **p = &reload_insn_chain;
+ struct insn_chain *prev = 0;
+ int b = 0;
+ regset_head live_relevant_regs_head;
+
+ live_relevant_regs = INITIALIZE_REG_SET (live_relevant_regs_head);
+
+ for (; first; first = NEXT_INSN (first))
+ {
+ struct insn_chain *c;
+
+ if (first == BLOCK_HEAD (b))
+ {
+ int i;
+
+ CLEAR_REG_SET (live_relevant_regs);
+
+ EXECUTE_IF_SET_IN_BITMAP
+ (BASIC_BLOCK (b)->global_live_at_start, 0, i,
+ {
+ if (i < FIRST_PSEUDO_REGISTER
+ ? ! TEST_HARD_REG_BIT (eliminable_regset, i)
+ : reg_renumber[i] >= 0)
+ SET_REGNO_REG_SET (live_relevant_regs, i);
+ });
+ }
+
+ if (GET_CODE (first) != NOTE && GET_CODE (first) != BARRIER)
+ {
+ c = new_insn_chain ();
+ c->prev = prev;
+ prev = c;
+ *p = c;
+ p = &c->next;
+ c->insn = first;
+ c->block = b;
+
+ if (INSN_P (first))
+ {
+ rtx link;
+
+ /* Mark the death of everything that dies in this instruction. */
+
+ for (link = REG_NOTES (first); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_DEAD
+ && GET_CODE (XEXP (link, 0)) == REG)
+ reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
+ c);
+
+ COPY_REG_SET (&c->live_throughout, live_relevant_regs);
+
+ /* Mark everything born in this instruction as live. */
+
+ note_stores (PATTERN (first), reg_becomes_live,
+ &c->dead_or_set);
+ }
+ else
+ COPY_REG_SET (&c->live_throughout, live_relevant_regs);
+
+ if (INSN_P (first))
+ {
+ rtx link;
+
+ /* Mark anything that is set in this insn and then unused as dying. */
+
+ for (link = REG_NOTES (first); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_UNUSED
+ && GET_CODE (XEXP (link, 0)) == REG)
+ reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
+ c);
+ }
+ }
+
+ if (first == BLOCK_END (b))
+ b++;
+
+ /* Stop after we pass the end of the last basic block. Verify that
+ no real insns are after the end of the last basic block.
+
+ We may want to reorganize the loop somewhat since this test should
+ always be the right exit test. Allow an ADDR_VEC or ADDR_DIF_VEC if
+ the previous real insn is a JUMP_INSN. */
+ if (b == n_basic_blocks)
+ {
+ for (first = NEXT_INSN (first) ; first; first = NEXT_INSN (first))
+ if (INSN_P (first)
+ && GET_CODE (PATTERN (first)) != USE
+ && ! ((GET_CODE (PATTERN (first)) == ADDR_VEC
+ || GET_CODE (PATTERN (first)) == ADDR_DIFF_VEC)
+ && prev_real_insn (first) != 0
+ && GET_CODE (prev_real_insn (first)) == JUMP_INSN))
+ abort ();
+ break;
+ }
+ }
+ FREE_REG_SET (live_relevant_regs);
+ *p = 0;