This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Bug fix for combinable_i3pat
- To: kenner at vlsi1 dot ultra dot nyu dot edu (Richard Kenner)
- Subject: Bug fix for combinable_i3pat
- From: Joern Rennecke <amylaar at cygnus dot co dot uk>
- Date: Wed, 22 Oct 1997 12:00:34 +0100 (BST)
- Cc: egcs at cygnus dot com
While testing the d10v port (that's one to be submitted) in egcs,
I found a problem with my combinable_i3pat patch from December.
When there is a function call that receives several arguments in
hard registers, and combine combines a somewhat complex insn with
any but the first argument register setting insns, reload might
allocate a spill register for the combined insn in one of the
argument registers that have been previously set.
This had been covered by the previous check, even though this
was not documented and presumably not even anticipated.
Note that when we allow the first arguemnt register setting insn for
a call to be combined, it might end up as a part of a PARALLEL with multiple
SETs, while following non-combined argument register setting insns should
have only a single SET.
Here is a patch:
Tue Oct 21 15:02:58 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
* combine.c (sets_function_arg_p): New function.
(combinable_i3pat): Check if combining with any but the first
argument register setting insn for a function call.
*** combine.c-971021 Wed Oct 22 11:21:11 1997
--- combine.c Wed Oct 22 11:37:33 1997
*************** can_combine_p (insn, i3, pred, succ, pde
*** 1048,1053 ****
--- 1048,1090 ----
return 1;
}
+ /* Check if PAT is an insn - or a part of it - used to set up an
+ argument for a function in a hard register. */
+
+ static int
+ sets_function_arg_p (pat)
+ rtx pat;
+ {
+ for (;;)
+ switch (GET_CODE (pat))
+ {
+ case INSN:
+ pat = PATTERN (pat);
+ continue;
+ case PARALLEL:
+ {
+ int i;
+ for (i = XVECLEN (pat, 0); --i >= 0;)
+ if (sets_function_arg_p (XVECEXP (pat, 0, i)))
+ return 1;
+ return 0;
+ }
+ case SET:
+ {
+ rtx inner_dest = SET_DEST (pat);
+ while (GET_CODE (inner_dest) == STRICT_LOW_PART
+ || GET_CODE (inner_dest) == SUBREG
+ || GET_CODE (inner_dest) == ZERO_EXTRACT)
+ inner_dest = XEXP (inner_dest, 0);
+ return (GET_CODE (inner_dest) == REG
+ && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
+ && FUNCTION_ARG_REGNO_P (REGNO (inner_dest)));
+ }
+ default:
+ return 0;
+ }
+ }
+
/* LOC is the location within I3 that contains its pattern or the component
of a PARALLEL of the pattern. We validate that it is valid for combining.
*************** combinable_i3pat (i3, loc, i2dest, i1des
*** 1149,1161 ****
Moreover, we can't test all_adjacent; we don't have to, since
this instruction will stay in place, thus we are not considering
to increase the lifetime of INNER_DEST. */
|| (GET_CODE (inner_dest) == REG
&& REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))
|| (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
&& ! REG_USERVAR_P (inner_dest)
! && FUNCTION_VALUE_REGNO_P (REGNO (inner_dest)))))
|| (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
return 0;
--- 1186,1208 ----
Moreover, we can't test all_adjacent; we don't have to, since
this instruction will stay in place, thus we are not considering
to increase the lifetime of INNER_DEST. */
+ /* However, there is another problem we have to look out for:
+ if this insn sets a function argument, combining it with
+ something that might need a spill could clobber a previous
+ function argument; the all_adjacent test in can_combine_p
+ also checks this; here, we do a more specific test for
+ this case. */
+
|| (GET_CODE (inner_dest) == REG
&& REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))
|| (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
&& ! REG_USERVAR_P (inner_dest)
! && (FUNCTION_VALUE_REGNO_P (REGNO (inner_dest))
! || (FUNCTION_ARG_REGNO_P (REGNO (inner_dest))
! && i3 && single_set (i3)
! && sets_function_arg_p (prev_nonnote_insn (i3)))))))
|| (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
return 0;