===================================================================
@@ -1048,6 +1048,19 @@ can_combine_use_p (df_ref use)
return true;
}
+/* Used to build set of return value regs. Add X to the set. */
+
+static void
+set_return_regs (rtx x, void *arg)
+{
+ HARD_REG_SET *regs = (HARD_REG_SET *) arg;
+
+ add_to_hard_reg_set (regs, GET_MODE (x), REGNO (x));
+}
+
+#define DONT_COMBINE_PARAMS 1
+#define DONT_COMBINE_CALL_ARGS 1
+
/* Fill in log links field for all insns. */
static void
@@ -1057,9 +1070,13 @@ create_log_links (void)
rtx_insn **next_use;
rtx_insn *insn;
df_ref def, use;
+ HARD_REG_SET hard_regs;
next_use = XCNEWVEC (rtx_insn *, max_reg_num ());
+ CLEAR_HARD_REG_SET (hard_regs);
+ diddle_return_value (set_return_regs, &hard_regs);
+
/* Pass through each block from the end, recording the uses of each
register and establishing log links when def is encountered.
Note that we do not clear next_use array in order to save time,
@@ -1069,10 +1086,37 @@ create_log_links (void)
usage -- these are taken from original flow.c did. Don't ask me why it is
done this way; I don't know and if it works, I don't want to know. */
- FOR_EACH_BB_FN (bb, cfun)
+ bool in_parameters = false;
+ FOR_EACH_BB_REVERSE_FN (bb, cfun)
{
FOR_BB_INSNS_REVERSE (bb, insn)
{
+ if (DONT_COMBINE_PARAMS
+ && NOTE_P (insn)
+ && NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG)
+ {
+ in_parameters = true;
+ continue;
+ }
+
+ if (CALL_P (insn))
+ {
+ /* Add function args passed in hard regs to HARD_REGS. */
+ CLEAR_HARD_REG_SET (hard_regs);
+ if (DONT_COMBINE_CALL_ARGS)
+ for (rtx link = CALL_INSN_FUNCTION_USAGE (insn);
+ link;
+ link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE)
+ {
+ rtx reg = XEXP (XEXP (link, 0), 0);
+ if (REG_P (reg)
+ && HARD_REGISTER_P (reg))
+ add_to_hard_reg_set (&hard_regs,
+ GET_MODE (reg), REGNO (reg));
+ }
+ }
+
if (!NONDEBUG_INSN_P (insn))
continue;
@@ -1079,13 +1123,27 @@ create_log_links (void)
/* Log links are created only once. */
gcc_assert (!LOG_LINKS (insn));
+ /* Exclude certain reg,reg copies when one is a hard reg.
+ Leaving these insns alone provides the register allocator
+ useful information. */
+ rtx reg_reg = 0;
+ int hard = 0;
+ if (GET_CODE (PATTERN (insn)) == SET)
+ {
+ reg_reg = PATTERN (insn);
+ if (REG_P (SET_DEST (reg_reg))
+ && REG_P (SET_SRC (reg_reg)))
+ hard = (HARD_REGISTER_P (SET_DEST (reg_reg))
+ - HARD_REGISTER_P (SET_SRC (reg_reg)));
+ }
+
FOR_EACH_INSN_DEF (def, insn)
- {
- unsigned int regno = DF_REF_REGNO (def);
- rtx_insn *use_insn;
+ {
+ unsigned int regno = DF_REF_REGNO (def);
+ rtx_insn *use_insn;
- if (!next_use[regno])
- continue;
+ if (!next_use[regno])
+ continue;
if (!can_combine_def_p (def))
continue;
@@ -1096,6 +1154,14 @@ create_log_links (void)
if (BLOCK_FOR_INSN (use_insn) != bb)
continue;
+ if (in_parameters && hard < 0)
+ {
+ /* This is a reg,reg copy from a hard reg to a pseudo,
+ such as those copying parameter registers to
+ pseudos. Don't set up LOG_LINKS to this insn. */
+ continue;
+ }
+
/* flow.c claimed:
We don't build a LOG_LINK for hard registers contained
@@ -1110,18 +1176,36 @@ create_log_links (void)
/* Don't add duplicate links between instructions. */
struct insn_link *links;
FOR_EACH_LOG_LINK (links, use_insn)
- if (insn == links->insn && regno == links->regno)
+ if (insn == links->insn && regno == links->regno)
break;
if (!links)
LOG_LINKS (use_insn)
= alloc_insn_link (insn, regno, LOG_LINKS (use_insn));
- }
+ }
FOR_EACH_INSN_USE (use, insn)
- if (can_combine_use_p (use))
- next_use[DF_REF_REGNO (use)] = insn;
+ {
+ if (hard > 0
+ && overlaps_hard_reg_set_p (hard_regs,
+ GET_MODE (SET_DEST (reg_reg)),
+ REGNO (SET_DEST (reg_reg))))
+ {
+ /* This is a reg,reg copy to a hard register, such
+ as those setting the function return value, or
+ setting up arguments for a function call. Don't
+ provide LOG_LINKS from this insn. This prevents
+ the insn defining the pseudo from being combined
+ into the reg,reg copy insn. */
+ remove_from_hard_reg_set (&hard_regs,
+ GET_MODE (SET_DEST (reg_reg)),
+ REGNO (SET_DEST (reg_reg)));
+ }
+ else if (can_combine_use_p (use))
+ next_use[DF_REF_REGNO (use)] = insn;
+ }
}
+ CLEAR_HARD_REG_SET (hard_regs);
}
free (next_use);