diff mbox

Fix PR58139 but correctly initializing reg_raw_mode[]

Message ID 1376682791.5807.22.camel@otta
State New
Headers show

Commit Message

Peter Bergner Aug. 16, 2013, 7:53 p.m. UTC
PR58139 shows a case where sched2 is scheduling the definition of a volatile
VSX register across a call.  The volatile VSX register (62) is actually made
up the non-volatile FPR30 and another volatile doubleword, so it is actually
partially volatile.  Since FPR30 is defined by the PPC{,64} ABIs as being
non-volatile, it is not marked in CALL_USED_REGISTERS[].  This means that
the DF infrastruture doesn't record the dependency between the call and
the VSX instruction, so sched2 freely schedules the VSX instruction past
the call.

There is code in sched-deps.c:deps_analyze_insn() that looks for partial
clobbers by testing HARD_REGNO_CALL_PART_CLOBBERED (when insn is a call insn).
HARD_REGNO_CALL_PART_CLOBBERED is correctly handled, meaning passing in 62
and a vector mode like V2DFmode returns true.  However, we don't see the
clobber because the mode it uses when testing HARD_REGNO_CALL_PART_CLOBBERED
is reg_raw_mode[62], which is set to DImode, and hardreg 62 is not partially
clobbered in DImode.

The definition of reg_raw_mode[] is defined as:

  /* For each hard register, the widest mode object that it can contain.
     This will be a MODE_INT mode if the register can hold integers.  Otherwise
     it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
     register.  */

Now DImode is not the widest mode that can fit into hardreg 62, rather
it is the vector modes like V2DFmode, etc.  The code that initializes
reg_raw_mode[] is in reginfo.c:init_reg_modes_target() which uses the
value returned by choose_hard_reg_mode(i, 1, false).

Looking at choose_hard_reg_mode(), it loops through several mode classes
looking for modes that are ok.  The bug seems to be that it returns too
quickly when it finds a valid mode.  To find the "widest" mode, it really
should scan through all mode classes, choosing the widest mode it encounters.
The patch below does that and I can confirm with this patch, the scheduler
sees the dependency between the call and the vsx instruction, correctly
blocking the move.

Pat Haugen SPEC tested this on powerpc64-linux and saw no degradations.

This also passed powerpc64-linux bootstrap and regtesting.
Is this Ok for mainline?

Since this is a wrong code bug, is this also ok on the 4.8 branch after
a couple of weeks, as long as no one finds any issues with it?

Peter


	PR58139
	* gcc/reginfo.c (choose_hard_reg_mode): San through all mode classes
	looking for widest mode.

Comments

Jakub Jelinek Sept. 3, 2013, 3:12 p.m. UTC | #1
On Fri, Aug 16, 2013 at 02:53:11PM -0500, Peter Bergner wrote:

> 	PR58139
> 	* gcc/reginfo.c (choose_hard_reg_mode): San through all mode classes
> 	looking for widest mode.

Just ChangeLog nits:
1) no gcc/
2) Scan instead of San
3) PR target/58139

	Jakub
diff mbox

Patch

Index: gcc/reginfo.c
===================================================================
--- gcc/reginfo.c	(revision 201779)
+++ gcc/reginfo.c	(working copy)
@@ -620,40 +620,35 @@  choose_hard_reg_mode (unsigned int regno
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
 	&& HARD_REGNO_MODE_OK (regno, mode)
-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
-  if (found_mode != VOIDmode)
-    return found_mode;
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
 	&& HARD_REGNO_MODE_OK (regno, mode)
-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
-  if (found_mode != VOIDmode)
-    return found_mode;
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
 	&& HARD_REGNO_MODE_OK (regno, mode)
-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
-  if (found_mode != VOIDmode)
-    return found_mode;
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
 	&& HARD_REGNO_MODE_OK (regno, mode)
-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
       found_mode = mode;
 
   if (found_mode != VOIDmode)