+ unsigned int regno = mws->start_regno;
+ df_set_note (REG_UNUSED, insn, mws->mw_reg);
+ dead_debug_reset (debug, regno);
+
+#ifdef REG_DEAD_DEBUGGING
+ df_print_note ("adding 1: ", insn, REG_NOTES (insn));
+#endif
+ bitmap_set_bit (do_not_gen, regno);
+ /* Only do this if the value is totally dead. */
+ }
+ else
+ for (r = mws->start_regno; r <= mws->end_regno; r++)
+ {
+ if (!bitmap_bit_p (live, r)
+ && !bitmap_bit_p (artificial_uses, r))
+ {
+ df_set_note (REG_UNUSED, insn, regno_reg_rtx[r]);
+ dead_debug_reset (debug, r);
+#ifdef REG_DEAD_DEBUGGING
+ df_print_note ("adding 2: ", insn, REG_NOTES (insn));
+#endif
+ }
+ bitmap_set_bit (do_not_gen, r);
+ }
+}
+
+
+/* A subroutine of df_set_dead_notes_for_mw, with a selection of its
+ arguments. Return true if the register value described by MWS's
+ mw_reg is known to be completely dead, and if mw_reg can therefore
+ be used in a REG_DEAD note. */
+
+static bool
+df_whole_mw_reg_dead_p (struct df_mw_hardreg *mws,
+ bitmap live, bitmap artificial_uses,
+ bitmap do_not_gen)
+{
+ unsigned int r;
+
+ /* If MWS describes a partial reference, create REG_DEAD notes for
+ individual hard registers. */
+ if (mws->flags & DF_REF_PARTIAL)
+ return false;
+
+ /* Likewise if some part of the register is not dead. */
+ for (r = mws->start_regno; r <= mws->end_regno; r++)
+ if (bitmap_bit_p (live, r)
+ || bitmap_bit_p (artificial_uses, r)
+ || bitmap_bit_p (do_not_gen, r))
+ return false;
+
+ gcc_assert (REG_P (mws->mw_reg));
+ return true;
+}
+
+/* Set the REG_DEAD notes for the multiword hardreg use in INSN based
+ on the bits in LIVE. DO_NOT_GEN is used to keep REG_DEAD notes
+ from being set if the instruction both reads and writes the
+ register. */
+
+static void
+df_set_dead_notes_for_mw (rtx insn, struct df_mw_hardreg *mws,
+ bitmap live, bitmap do_not_gen,
+ bitmap artificial_uses, bool *added_notes_p)
+{
+ unsigned int r;
+ bool is_debug = *added_notes_p;
+
+ *added_notes_p = false;
+
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file)
+ {
+ fprintf (dump_file, "mw_set_dead looking at mws[%d..%d]\n do_not_gen =",
+ mws->start_regno, mws->end_regno);
+ df_print_regset (dump_file, do_not_gen);
+ fprintf (dump_file, " live =");
+ df_print_regset (dump_file, live);
+ fprintf (dump_file, " artificial uses =");
+ df_print_regset (dump_file, artificial_uses);
+ }
+#endif
+
+ if (df_whole_mw_reg_dead_p (mws, live, artificial_uses, do_not_gen))
+ {
+ /* Add a dead note for the entire multi word register. */
+ if (is_debug)
+ {
+ *added_notes_p = true;
+ return;
+ }
+ df_set_note (REG_DEAD, insn, mws->mw_reg);
+#ifdef REG_DEAD_DEBUGGING
+ df_print_note ("adding 1: ", insn, REG_NOTES (insn));
+#endif
+ }
+ else
+ {
+ for (r = mws->start_regno; r <= mws->end_regno; r++)
+ if (!bitmap_bit_p (live, r)
+ && !bitmap_bit_p (artificial_uses, r)
+ && !bitmap_bit_p (do_not_gen, r))
+ {
+ if (is_debug)
+ {
+ *added_notes_p = true;
+ return;
+ }
+ df_set_note (REG_DEAD, insn, regno_reg_rtx[r]);
+#ifdef REG_DEAD_DEBUGGING
+ df_print_note ("adding 2: ", insn, REG_NOTES (insn));
+#endif
+ }
+ }
+ return;
+}
+
+
+/* Create a REG_UNUSED note if necessary for DEF in INSN updating
+ LIVE. Do not generate notes for registers in ARTIFICIAL_USES. */
+
+static void
+df_create_unused_note (rtx insn, df_ref def,
+ bitmap live, bitmap artificial_uses,
+ struct dead_debug *debug)
+{
+ unsigned int dregno = DF_REF_REGNO (def);
+
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file)
+ {
+ fprintf (dump_file, " regular looking at def ");
+ df_ref_debug (def, dump_file);
+ }
+#endif
+
+ if (!((DF_REF_FLAGS (def) & DF_REF_MW_HARDREG)
+ || bitmap_bit_p (live, dregno)
+ || bitmap_bit_p (artificial_uses, dregno)
+ || df_ignore_stack_reg (dregno)))
+ {
+ rtx reg = (DF_REF_LOC (def))
+ ? *DF_REF_REAL_LOC (def): DF_REF_REG (def);
+ df_set_note (REG_UNUSED, insn, reg);
+ dead_debug_reset (debug, dregno);
+#ifdef REG_DEAD_DEBUGGING
+ df_print_note ("adding 3: ", insn, REG_NOTES (insn));
+#endif
+ }
+
+ return;
+}
+
+
+/* Initialize DEBUG to an empty list, and clear USED, if given. */
+static inline void
+dead_debug_init (struct dead_debug *debug, bitmap used)
+{
+ debug->head = NULL;
+ debug->used = used;
+ debug->to_rescan = NULL;
+ if (used)
+ bitmap_clear (used);
+}
+
+/* Reset all debug insns with pending uses. Release the bitmap in it,
+ unless it is USED. USED must be the same bitmap passed to
+ dead_debug_init. */
+static inline void
+dead_debug_finish (struct dead_debug *debug, bitmap used)
+{
+ struct dead_debug_use *head;
+ rtx insn = NULL;
+
+ if (debug->used != used)
+ BITMAP_FREE (debug->used);
+
+ while ((head = debug->head))
+ {
+ insn = DF_REF_INSN (head->use);
+ if (!head->next || DF_REF_INSN (head->next->use) != insn)
+ {
+ INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+ df_insn_rescan_debug_internal (insn);
+ if (debug->to_rescan)
+ bitmap_clear_bit (debug->to_rescan, INSN_UID (insn));
+ }
+ debug->head = head->next;
+ XDELETE (head);
+ }
+
+ if (debug->to_rescan)
+ {
+ bitmap_iterator bi;
+ unsigned int uid;
+
+ EXECUTE_IF_SET_IN_BITMAP (debug->to_rescan, 0, uid, bi)
+ {
+ struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
+ if (insn_info)
+ df_insn_rescan (insn_info->insn);
+ }
+ BITMAP_FREE (debug->to_rescan);
+ }
+}
+
+/* Reset DEBUG_INSNs with pending uses of DREGNO. */
+static void
+dead_debug_reset (struct dead_debug *debug, unsigned int dregno)
+{
+ struct dead_debug_use **tailp = &debug->head;
+ struct dead_debug_use **insnp = &debug->head;
+ struct dead_debug_use *cur;
+ rtx insn;
+
+ if (!debug->used || !bitmap_clear_bit (debug->used, dregno))
+ return;
+
+ while ((cur = *tailp))
+ {
+ if (DF_REF_REGNO (cur->use) == dregno)
+ {
+ *tailp = cur->next;
+ insn = DF_REF_INSN (cur->use);
+ INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+ if (debug->to_rescan == NULL)
+ debug->to_rescan = BITMAP_ALLOC (NULL);
+ bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
+ XDELETE (cur);
+ /* If the current use isn't the first one attached to INSN, go back
+ to this first use. We assume that the uses attached to an insn
+ are adjacent. */
+ if (tailp != insnp && DF_REF_INSN ((*insnp)->use) == insn)
+ tailp = insnp;
+ /* Then remove all the other uses attached to INSN. */
+ while ((cur = *tailp) && DF_REF_INSN (cur->use) == insn)
+ {
+ *tailp = cur->next;
+ XDELETE (cur);
+ }
+ insnp = tailp;
+ }
+ else
+ {
+ if (DF_REF_INSN ((*insnp)->use) != DF_REF_INSN (cur->use))
+ insnp = tailp;
+ tailp = &(*tailp)->next;
+ }
+ }
+}
+
+/* Add USE to DEBUG. It must be a dead reference to UREGNO in a debug
+ insn. Create a bitmap for DEBUG as needed. */
+static inline void
+dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno)
+{
+ struct dead_debug_use *newddu = XNEW (struct dead_debug_use);
+
+ newddu->use = use;
+ newddu->next = debug->head;
+ debug->head = newddu;
+
+ if (!debug->used)
+ debug->used = BITMAP_ALLOC (NULL);
+
+ bitmap_set_bit (debug->used, uregno);
+}
+
+/* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
+ before INSN that binds the REG to a debug temp, and replace all
+ uses of UREGNO in DEBUG with uses of the debug temp. INSN must be
+ the insn where UREGNO dies. */
+static inline void
+dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno,
+ rtx insn)
+{
+ struct dead_debug_use **tailp = &debug->head;
+ struct dead_debug_use *cur;
+ struct dead_debug_use *uses = NULL;
+ struct dead_debug_use **usesp = &uses;
+ rtx reg = NULL;
+ rtx dval;
+ rtx bind;
+
+ if (!debug->used || !bitmap_clear_bit (debug->used, uregno))
+ return;
+
+ /* Move all uses of uregno from debug->head to uses, setting mode to
+ the widest referenced mode. */
+ while ((cur = *tailp))
+ {
+ if (DF_REF_REGNO (cur->use) == uregno)
+ {
+ *usesp = cur;
+ usesp = &cur->next;
+ *tailp = cur->next;
+ cur->next = NULL;
+ if (!reg
+ || (GET_MODE_BITSIZE (GET_MODE (reg))
+ < GET_MODE_BITSIZE (GET_MODE (*DF_REF_REAL_LOC (cur->use)))))
+ reg = *DF_REF_REAL_LOC (cur->use);
+ }
+ else
+ tailp = &(*tailp)->next;
+ }
+
+ /* We may have dangling bits in debug->used for registers that were part
+ of a multi-register use, one component of which has been reset. */
+ if (reg == NULL)
+ return;
+
+ /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */
+ dval = make_debug_expr_from_rtl (reg);
+
+ /* Emit a debug bind insn before the insn in which reg dies. */
+ bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
+ DEBUG_EXPR_TREE_DECL (dval), reg,
+ VAR_INIT_STATUS_INITIALIZED);
+
+ bind = emit_debug_insn_before (bind, insn);
+ df_insn_rescan (bind);
+
+ /* Adjust all uses. */
+ while ((cur = uses))
+ {
+ if (GET_MODE (*DF_REF_REAL_LOC (cur->use)) == GET_MODE (reg))
+ *DF_REF_REAL_LOC (cur->use) = dval;
+ else
+ *DF_REF_REAL_LOC (cur->use)
+ = gen_lowpart_SUBREG (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval);
+ /* ??? Should we simplify subreg of subreg? */
+ if (debug->to_rescan == NULL)
+ debug->to_rescan = BITMAP_ALLOC (NULL);
+ bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use)));
+ uses = cur->next;
+ XDELETE (cur);
+ }
+}
+
+/* Recompute the REG_DEAD and REG_UNUSED notes and compute register
+ info: lifetime, bb, and number of defs and uses for basic block
+ BB. The three bitvectors are scratch regs used here. */
+
+static void
+df_note_bb_compute (unsigned int bb_index,
+ bitmap live, bitmap do_not_gen, bitmap artificial_uses)
+{
+ basic_block bb = BASIC_BLOCK (bb_index);
+ rtx insn;
+ df_ref *def_rec;
+ df_ref *use_rec;
+ struct dead_debug debug;
+
+ dead_debug_init (&debug, NULL);
+
+ bitmap_copy (live, df_get_live_out (bb));
+ bitmap_clear (artificial_uses);
+
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file)
+ {
+ fprintf (dump_file, "live at bottom ");
+ df_print_regset (dump_file, live);
+ }
+#endif
+
+ /* Process the artificial defs and uses at the bottom of the block
+ to begin processing. */
+ for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file)
+ fprintf (dump_file, "artificial def %d\n", DF_REF_REGNO (def));
+#endif
+
+ if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
+ bitmap_clear_bit (live, DF_REF_REGNO (def));
+ }
+
+ for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
+ {
+ df_ref use = *use_rec;
+ if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
+ {
+ unsigned int regno = DF_REF_REGNO (use);
+ bitmap_set_bit (live, regno);
+
+ /* Notes are not generated for any of the artificial registers
+ at the bottom of the block. */
+ bitmap_set_bit (artificial_uses, regno);
+ }
+ }
+
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file)
+ {
+ fprintf (dump_file, "live before artificials out ");
+ df_print_regset (dump_file, live);
+ }
+#endif
+
+ FOR_BB_INSNS_REVERSE (bb, insn)
+ {
+ unsigned int uid = INSN_UID (insn);
+ struct df_mw_hardreg **mws_rec;
+ int debug_insn;
+
+ if (!INSN_P (insn))
+ continue;
+
+ debug_insn = DEBUG_INSN_P (insn);
+
+ bitmap_clear (do_not_gen);
+ df_kill_notes (insn, live);
+
+ /* Process the defs. */
+ if (CALL_P (insn))
+ {
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file)
+ {
+ fprintf (dump_file, "processing call %d\n live =", INSN_UID (insn));
+ df_print_regset (dump_file, live);
+ }
+#endif
+ /* We only care about real sets for calls. Clobbers cannot
+ be depended on to really die. */
+ mws_rec = DF_INSN_UID_MWS (uid);
+ while (*mws_rec)
+ {
+ struct df_mw_hardreg *mws = *mws_rec;
+ if ((DF_MWS_REG_DEF_P (mws))
+ && !df_ignore_stack_reg (mws->start_regno))
+ df_set_unused_notes_for_mw (insn,
+ mws, live, do_not_gen,
+ artificial_uses, &debug);
+ mws_rec++;
+ }
+
+ /* All of the defs except the return value are some sort of
+ clobber. This code is for the return. */
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ unsigned int dregno = DF_REF_REGNO (def);
+ if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))
+ {
+ df_create_unused_note (insn,
+ def, live, artificial_uses, &debug);
+ bitmap_set_bit (do_not_gen, dregno);
+ }
+
+ if (!DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL | DF_REF_CONDITIONAL))
+ bitmap_clear_bit (live, dregno);
+ }
+ }
+ else
+ {
+ /* Regular insn. */
+ mws_rec = DF_INSN_UID_MWS (uid);
+ while (*mws_rec)
+ {
+ struct df_mw_hardreg *mws = *mws_rec;
+ if (DF_MWS_REG_DEF_P (mws))
+ df_set_unused_notes_for_mw (insn,
+ mws, live, do_not_gen,
+ artificial_uses, &debug);
+ mws_rec++;
+ }
+
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ unsigned int dregno = DF_REF_REGNO (def);
+ df_create_unused_note (insn,
+ def, live, artificial_uses, &debug);
+
+ if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))
+ bitmap_set_bit (do_not_gen, dregno);
+
+ if (!DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL | DF_REF_CONDITIONAL))
+ bitmap_clear_bit (live, dregno);
+ }
+ }
+
+ /* Process the uses. */
+ mws_rec = DF_INSN_UID_MWS (uid);
+ while (*mws_rec)
+ {
+ struct df_mw_hardreg *mws = *mws_rec;
+ if (DF_MWS_REG_USE_P (mws)
+ && !df_ignore_stack_reg (mws->start_regno))
+ {
+ bool really_add_notes = debug_insn != 0;
+
+ df_set_dead_notes_for_mw (insn,
+ mws, live, do_not_gen,
+ artificial_uses,
+ &really_add_notes);
+
+ if (really_add_notes)
+ debug_insn = -1;
+ }
+ mws_rec++;
+ }
+
+ for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+ {
+ df_ref use = *use_rec;
+ unsigned int uregno = DF_REF_REGNO (use);
+
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file && !debug_insn)
+ {
+ fprintf (dump_file, " regular looking at use ");
+ df_ref_debug (use, dump_file);
+ }
+#endif
+ if (!bitmap_bit_p (live, uregno))
+ {
+ if (debug_insn)
+ {
+ if (debug_insn > 0)
+ {
+ dead_debug_add (&debug, use, uregno);
+ continue;
+ }
+ break;
+ }
+ else
+ dead_debug_insert_before (&debug, uregno, insn);
+
+ if ( (!(DF_REF_FLAGS (use)
+ & (DF_REF_MW_HARDREG | DF_REF_READ_WRITE)))
+ && (!bitmap_bit_p (do_not_gen, uregno))
+ && (!bitmap_bit_p (artificial_uses, uregno))
+ && (!df_ignore_stack_reg (uregno)))
+ {
+ rtx reg = (DF_REF_LOC (use))
+ ? *DF_REF_REAL_LOC (use) : DF_REF_REG (use);
+ df_set_note (REG_DEAD, insn, reg);
+
+#ifdef REG_DEAD_DEBUGGING
+ df_print_note ("adding 4: ", insn, REG_NOTES (insn));
+#endif
+ }
+ /* This register is now live. */
+ bitmap_set_bit (live, uregno);
+ }
+ }
+
+ if (debug_insn == -1)
+ {
+ /* ??? We could probably do better here, replacing dead
+ registers with their definitions. */
+ INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+ df_insn_rescan_debug_internal (insn);
+ }
+ }
+
+ dead_debug_finish (&debug, NULL);
+}
+
+
+/* Compute register info: lifetime, bb, and number of defs and uses. */
+static void
+df_note_compute (bitmap all_blocks)
+{
+ unsigned int bb_index;
+ bitmap_iterator bi;
+ bitmap_head live, do_not_gen, artificial_uses;
+
+ bitmap_initialize (&live, &df_bitmap_obstack);
+ bitmap_initialize (&do_not_gen, &df_bitmap_obstack);
+ bitmap_initialize (&artificial_uses, &df_bitmap_obstack);
+
+#ifdef REG_DEAD_DEBUGGING
+ if (dump_file)
+ print_rtl_with_bb (dump_file, get_insns());
+#endif
+
+ EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+ {
+ df_note_bb_compute (bb_index, &live, &do_not_gen, &artificial_uses);
+ }
+
+ bitmap_clear (&live);
+ bitmap_clear (&do_not_gen);
+ bitmap_clear (&artificial_uses);
+}
+
+
+/* Free all storage associated with the problem. */
+
+static void
+df_note_free (void)
+{
+ free (df_note);
+}
+
+
+/* All of the information associated every instance of the problem. */
+
+static struct df_problem problem_NOTE =
+{
+ DF_NOTE, /* Problem id. */
+ DF_NONE, /* Direction. */
+ df_note_alloc, /* Allocate the problem specific data. */
+ NULL, /* Reset global information. */
+ NULL, /* Free basic block info. */
+ df_note_compute, /* Local compute function. */
+ NULL, /* Init the solution specific data. */
+ NULL, /* Iterative solver. */
+ NULL, /* Confluence operator 0. */
+ NULL, /* Confluence operator n. */
+ NULL, /* Transfer function. */
+ NULL, /* Finalize function. */
+ df_note_free, /* Free all of the problem information. */
+ df_note_free, /* Remove this problem from the stack of dataflow problems. */
+ NULL, /* Debugging. */
+ NULL, /* Debugging start block. */
+ NULL, /* Debugging end block. */
+ NULL, /* Incremental solution verify start. */
+ NULL, /* Incremental solution verify end. */
+ &problem_LR, /* Dependent problem. */
+ sizeof (struct df_scan_bb_info),/* Size of entry of block_info array. */
+ TV_DF_NOTE, /* Timing variable. */
+ false /* Reset blocks on dropping out of blocks_to_analyze. */
+};
+
+
+/* Create a new DATAFLOW instance and add it to an existing instance
+ of DF. The returned structure is what is used to get at the
+ solution. */
+
+void
+df_note_add_problem (void)
+{
+ df_add_problem (&problem_NOTE);
+}
+
+
+
+\f
+/*----------------------------------------------------------------------------
+ Functions for simulating the effects of single insns.
+
+ You can either simulate in the forwards direction, starting from
+ the top of a block or the backwards direction from the end of the
+ block. If you go backwards, defs are examined first to clear bits,
+ then uses are examined to set bits. If you go forwards, defs are
+ examined first to set bits, then REG_DEAD and REG_UNUSED notes
+ are examined to clear bits. In either case, the result of examining
+ a def can be undone (respectively by a use or a REG_UNUSED note).
+
+ If you start at the top of the block, use one of DF_LIVE_IN or
+ DF_LR_IN. If you start at the bottom of the block use one of
+ DF_LIVE_OUT or DF_LR_OUT. BE SURE TO PASS A COPY OF THESE SETS,
+ THEY WILL BE DESTROYED.
+----------------------------------------------------------------------------*/
+
+
+/* Find the set of DEFs for INSN. */
+
+void
+df_simulate_find_defs (rtx insn, bitmap defs)
+{
+ df_ref *def_rec;
+ unsigned int uid = INSN_UID (insn);
+
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ bitmap_set_bit (defs, DF_REF_REGNO (def));
+ }
+}
+
+/* Find the set of uses for INSN. This includes partial defs. */
+
+static void
+df_simulate_find_uses (rtx insn, bitmap uses)
+{
+ df_ref *rec;
+ unsigned int uid = INSN_UID (insn);
+
+ for (rec = DF_INSN_UID_DEFS (uid); *rec; rec++)
+ {
+ df_ref def = *rec;
+ if (DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL))
+ bitmap_set_bit (uses, DF_REF_REGNO (def));
+ }
+ for (rec = DF_INSN_UID_USES (uid); *rec; rec++)
+ {
+ df_ref use = *rec;
+ bitmap_set_bit (uses, DF_REF_REGNO (use));
+ }
+}
+
+/* Find the set of real DEFs, which are not clobbers, for INSN. */
+
+void
+df_simulate_find_noclobber_defs (rtx insn, bitmap defs)
+{
+ df_ref *def_rec;
+ unsigned int uid = INSN_UID (insn);
+
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ if (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER)))
+ bitmap_set_bit (defs, DF_REF_REGNO (def));
+ }
+}
+
+
+/* Simulate the effects of the defs of INSN on LIVE. */
+
+void
+df_simulate_defs (rtx insn, bitmap live)
+{
+ df_ref *def_rec;
+ unsigned int uid = INSN_UID (insn);
+
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ unsigned int dregno = DF_REF_REGNO (def);
+
+ /* If the def is to only part of the reg, it does
+ not kill the other defs that reach here. */
+ if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+ bitmap_clear_bit (live, dregno);
+ }
+}
+
+
+/* Simulate the effects of the uses of INSN on LIVE. */
+
+void
+df_simulate_uses (rtx insn, bitmap live)
+{
+ df_ref *use_rec;
+ unsigned int uid = INSN_UID (insn);
+
+ if (DEBUG_INSN_P (insn))
+ return;
+
+ for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+ {
+ df_ref use = *use_rec;
+ /* Add use to set of uses in this BB. */
+ bitmap_set_bit (live, DF_REF_REGNO (use));
+ }
+}
+
+
+/* Add back the always live regs in BB to LIVE. */
+
+static inline void
+df_simulate_fixup_sets (basic_block bb, bitmap live)
+{
+ /* These regs are considered always live so if they end up dying
+ because of some def, we need to bring the back again. */
+ if (bb_has_eh_pred (bb))
+ bitmap_ior_into (live, &df->eh_block_artificial_uses);
+ else
+ bitmap_ior_into (live, &df->regular_block_artificial_uses);
+}
+
+
+/*----------------------------------------------------------------------------
+ The following three functions are used only for BACKWARDS scanning:
+ i.e. they process the defs before the uses.
+
+ df_simulate_initialize_backwards should be called first with a
+ bitvector copyied from the DF_LIVE_OUT or DF_LR_OUT. Then
+ df_simulate_one_insn_backwards should be called for each insn in
+ the block, starting with the last one. Finally,
+ df_simulate_finalize_backwards can be called to get a new value
+ of the sets at the top of the block (this is rarely used).
+ ----------------------------------------------------------------------------*/
+
+/* Apply the artificial uses and defs at the end of BB in a backwards
+ direction. */
+
+void
+df_simulate_initialize_backwards (basic_block bb, bitmap live)
+{
+ df_ref *def_rec;
+ df_ref *use_rec;
+ int bb_index = bb->index;
+
+ for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
+ bitmap_clear_bit (live, DF_REF_REGNO (def));
+ }
+
+ for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
+ {
+ df_ref use = *use_rec;
+ if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
+ bitmap_set_bit (live, DF_REF_REGNO (use));
+ }
+}
+
+
+/* Simulate the backwards effects of INSN on the bitmap LIVE. */
+
+void
+df_simulate_one_insn_backwards (basic_block bb, rtx insn, bitmap live)
+{
+ if (!NONDEBUG_INSN_P (insn))
+ return;
+
+ df_simulate_defs (insn, live);
+ df_simulate_uses (insn, live);
+ df_simulate_fixup_sets (bb, live);
+}
+
+
+/* Apply the artificial uses and defs at the top of BB in a backwards
+ direction. */
+
+void
+df_simulate_finalize_backwards (basic_block bb, bitmap live)
+{
+ df_ref *def_rec;
+#ifdef EH_USES
+ df_ref *use_rec;
+#endif
+ int bb_index = bb->index;
+
+ for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
+ bitmap_clear_bit (live, DF_REF_REGNO (def));
+ }
+
+#ifdef EH_USES
+ for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
+ {
+ df_ref use = *use_rec;
+ if (DF_REF_FLAGS (use) & DF_REF_AT_TOP)
+ bitmap_set_bit (live, DF_REF_REGNO (use));
+ }
+#endif
+}
+/*----------------------------------------------------------------------------
+ The following three functions are used only for FORWARDS scanning:
+ i.e. they process the defs and the REG_DEAD and REG_UNUSED notes.
+ Thus it is important to add the DF_NOTES problem to the stack of
+ problems computed before using these functions.
+
+ df_simulate_initialize_forwards should be called first with a
+ bitvector copyied from the DF_LIVE_IN or DF_LR_IN. Then
+ df_simulate_one_insn_forwards should be called for each insn in
+ the block, starting with the first one.
+ ----------------------------------------------------------------------------*/
+
+/* Initialize the LIVE bitmap, which should be copied from DF_LIVE_IN or
+ DF_LR_IN for basic block BB, for forward scanning by marking artificial
+ defs live. */
+
+void
+df_simulate_initialize_forwards (basic_block bb, bitmap live)
+{
+ df_ref *def_rec;
+ int bb_index = bb->index;
+
+ for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+ {
+ df_ref def = *def_rec;
+ if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
+ bitmap_set_bit (live, DF_REF_REGNO (def));
+ }
+}
+
+/* Simulate the forwards effects of INSN on the bitmap LIVE. */
+
+void
+df_simulate_one_insn_forwards (basic_block bb, rtx insn, bitmap live)
+{
+ rtx link;
+ if (! INSN_P (insn))
+ return;
+
+ /* Make sure that DF_NOTE really is an active df problem. */
+ gcc_assert (df_note);
+
+ /* Note that this is the opposite as how the problem is defined, because
+ in the LR problem defs _kill_ liveness. However, they do so backwards,
+ while here the scan is performed forwards! So, first assume that the
+ def is live, and if this is not true REG_UNUSED notes will rectify the
+ situation. */
+ df_simulate_find_noclobber_defs (insn, live);
+
+ /* Clear all of the registers that go dead. */
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ {
+ switch (REG_NOTE_KIND (link))
+ {
+ case REG_DEAD:
+ case REG_UNUSED:
+ {
+ rtx reg = XEXP (link, 0);
+ int regno = REGNO (reg);
+ if (HARD_REGISTER_NUM_P (regno))
+ bitmap_clear_range (live, regno,
+ hard_regno_nregs[regno][GET_MODE (reg)]);
+ else
+ bitmap_clear_bit (live, regno);
+ }
+ break;
+ default:
+ break;
+ }