This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR36194


I made the mistake of recording truncated values where promoted subregs were
recorded (http://gcc.gnu.org/ml/gcc-patches/2006-01/msg00553.html).  This is
done before we start combining other insns into the current insn so obviously
we can't use the information we derive from the LHS of a set of the current
insn.  Specifically while combining insn 6 into insn 7:

  (insn 6 3 7 2 /tmp/s.c:6 (set (reg:SI 194 [ a+4 ])
          (truncate:SI (reg:DI 4 $4 [ a ]))) 123 {truncdisi2} (expr_list:REG_DEAD (reg:DI 4 $4 [ a ])
          (nil)))
  
  (insn 7 6 8 2 /tmp/s.c:6 (set (reg:SI 4 $4 [ a+4 ])
          (reg:SI 194 [ a+4 ])) 219 {*movsi_internal} (expr_list:REG_DEAD (reg:SI 194 [ a+4 ])
          (nil)))

we can not use the fact that reg 4 is set in mode SI in insn 7 and remove the
truncation:

  (insn 7 6 8 2 /tmp/s.c:6 (set (reg:SI 4 $4 [ a+4 ])
        (reg:SI 4 $4 [ a+4 ])) 219 {*movsi_internal} (nil))

Initially I thought of recording the effect of the set in
record_dead_and_set_regs_1 but it does not seem improve the code so I removed
it and now I only keep track of used values.  This is not surprising
considering what prompted this optimization.

Bootstrapped and regression tested on x86_64-linux-gnu and on
mips64-linux-gnu.  Also regression tested on mipsisa64-elf.  Besides the new
testcase it also fixes gcc.dg/pr35616.c execution test on mips64-linux-gnu.
With the patch, there is no difference in the MIPS code generated for gcc .i
files.

OK for trunk and later for the active release branches?

Adam


	PR middle-end/36194
        * combine.c (check_conversion): Rename to check_promoted_subreg. 
        Don't call record_truncated_value from here. 
        (record_truncated_value): Turn it into a for_each_rtx callback. 
        (record_truncated_values): New function. 
        (combine_instructions): Call note_uses with 
        record_truncated_values.  Change name of check_conversion to 
        check_promoted_subreg. 

testsuite/

	* gcc.dg/pr36194.c: New test.

Index: combine.c
===================================================================
*** combine.c	(revision 134973)
--- combine.c	(working copy)
*************** static rtx gen_lowpart_for_combine (enum
*** 425,431 ****
  static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
  static void update_table_tick (rtx);
  static void record_value_for_reg (rtx, rtx, rtx);
! static void check_conversions (rtx, rtx);
  static void record_dead_and_set_regs_1 (rtx, const_rtx, void *);
  static void record_dead_and_set_regs (rtx);
  static int get_last_value_validate (rtx *, rtx, int, int);
--- 425,431 ----
  static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
  static void update_table_tick (rtx);
  static void record_value_for_reg (rtx, rtx, rtx);
! static void check_promoted_subreg (rtx, rtx);
  static void record_dead_and_set_regs_1 (rtx, const_rtx, void *);
  static void record_dead_and_set_regs (rtx);
  static int get_last_value_validate (rtx *, rtx, int, int);
*************** static void mark_used_regs_combine (rtx)
*** 441,447 ****
  static void record_promoted_value (rtx, rtx);
  static int unmentioned_reg_p_1 (rtx *, void *);
  static bool unmentioned_reg_p (rtx, rtx);
! static void record_truncated_value (rtx);
  static bool reg_truncated_to_mode (enum machine_mode, const_rtx);
  static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
  
--- 441,448 ----
  static void record_promoted_value (rtx, rtx);
  static int unmentioned_reg_p_1 (rtx *, void *);
  static bool unmentioned_reg_p (rtx, rtx);
! static int record_truncated_value (rtx *, void *);
! static void record_truncated_values (rtx *, void *);
  static bool reg_truncated_to_mode (enum machine_mode, const_rtx);
  static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
  
*************** combine_instructions (rtx f, unsigned in
*** 1137,1143 ****
  	    {
  	      /* See if we know about function return values before this
  		 insn based upon SUBREG flags.  */
! 	      check_conversions (insn, PATTERN (insn));
  
  	      /* Try this insn with each insn it links back to.  */
  
--- 1138,1149 ----
  	    {
  	      /* See if we know about function return values before this
  		 insn based upon SUBREG flags.  */
! 	      check_promoted_subreg (insn, PATTERN (insn));
! 
! 	      /* See if we can find hardregs and subreg of pseudos in
! 		 narrower modes.  This could help turning TRUNCATEs
! 		 into SUBREGs.  */
! 	      note_uses (&PATTERN (insn), record_truncated_values, NULL);
  
  	      /* Try this insn with each insn it links back to.  */
  
*************** reg_truncated_to_mode (enum machine_mode
*** 11614,11626 ****
    return false;
  }
  
! /* X is a REG or a SUBREG.  If X is some sort of a truncation record
!    it.  For non-TRULY_NOOP_TRUNCATION targets we might be able to turn
!    a truncate into a subreg using this information.  */
  
! static void
! record_truncated_value (rtx x)
  {
    enum machine_mode truncated_mode;
    reg_stat_type *rsp;
  
--- 11620,11634 ----
    return false;
  }
  
! /* Callback for for_each_rtx.  If *P is a hard reg or a subreg record the mode
!    that the register is accessed in.  For non-TRULY_NOOP_TRUNCATION targets we
!    might be able to turn a truncate into a subreg using this information.
!    Return -1 if traversing *P is complete or 0 otherwise.  */
  
! static int
! record_truncated_value (rtx *p, void *data ATTRIBUTE_UNUSED)
  {
+   rtx x = *p;
    enum machine_mode truncated_mode;
    reg_stat_type *rsp;
  
*************** record_truncated_value (rtx x)
*** 11630,11640 ****
        truncated_mode = GET_MODE (x);
  
        if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
! 	return;
  
        if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (truncated_mode),
  				 GET_MODE_BITSIZE (original_mode)))
! 	return;
  
        x = SUBREG_REG (x);
      }
--- 11638,11648 ----
        truncated_mode = GET_MODE (x);
  
        if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
! 	return -1;
  
        if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (truncated_mode),
  				 GET_MODE_BITSIZE (original_mode)))
! 	return -1;
  
        x = SUBREG_REG (x);
      }
*************** record_truncated_value (rtx x)
*** 11643,11649 ****
    else if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
      truncated_mode = GET_MODE (x);
    else
!     return;
  
    rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
    if (rsp->truncated_to_mode == 0
--- 11651,11657 ----
    else if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
      truncated_mode = GET_MODE (x);
    else
!     return 0;
  
    rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
    if (rsp->truncated_to_mode == 0
*************** record_truncated_value (rtx x)
*** 11654,11666 ****
        rsp->truncated_to_mode = truncated_mode;
        rsp->truncation_label = label_tick;
      }
  }
  
! /* Scan X for promoted SUBREGs and truncated REGs.  For each one
!    found, note what it implies to the registers used in it.  */
  
  static void
! check_conversions (rtx insn, rtx x)
  {
    if (GET_CODE (x) == SUBREG || REG_P (x))
      {
--- 11662,11687 ----
        rsp->truncated_to_mode = truncated_mode;
        rsp->truncation_label = label_tick;
      }
+ 
+   return -1;
+ }
+ 
+ /* Callback for note_uses.  Find hardregs and subregs of pseudos and
+    the modes they are used in.  This can help truning TRUNCATEs into
+    SUBREGs.  */
+ 
+ static void
+ record_truncated_values (rtx *x, void *data ATTRIBUTE_UNUSED)
+ {
+   for_each_rtx (x, record_truncated_value, NULL);
  }
  
! 
! /* Scan X for promoted SUBREGs.  For each one found,
!    note what it implies to the registers used in it.  */
  
  static void
! check_promoted_subreg (rtx insn, rtx x)
  {
    if (GET_CODE (x) == SUBREG || REG_P (x))
      {
*************** check_conversions (rtx insn, rtx x)
*** 11668,11675 ****
  	  && SUBREG_PROMOTED_VAR_P (x)
  	  && REG_P (SUBREG_REG (x)))
  	record_promoted_value (insn, x);
- 
-       record_truncated_value (x);
      }
    else
      {
--- 11689,11694 ----
*************** check_conversions (rtx insn, rtx x)
*** 11680,11692 ****
  	switch (format[i])
  	  {
  	  case 'e':
! 	    check_conversions (insn, XEXP (x, i));
  	    break;
  	  case 'V':
  	  case 'E':
  	    if (XVEC (x, i) != 0)
  	      for (j = 0; j < XVECLEN (x, i); j++)
! 		check_conversions (insn, XVECEXP (x, i, j));
  	    break;
  	  }
      }
--- 11699,11711 ----
  	switch (format[i])
  	  {
  	  case 'e':
! 	    check_promoted_subreg (insn, XEXP (x, i));
  	    break;
  	  case 'V':
  	  case 'E':
  	    if (XVEC (x, i) != 0)
  	      for (j = 0; j < XVECLEN (x, i); j++)
! 		check_promoted_subreg (insn, XVECEXP (x, i, j));
  	    break;
  	  }
      }
Index: testsuite/gcc.dg/pr36194.c
===================================================================
*** testsuite/gcc.dg/pr36194.c	(revision 0)
--- testsuite/gcc.dg/pr36194.c	(revision 0)
***************
*** 0 ****
--- 1,25 ----
+ /* { dg-do run } */
+ /* { dg-options "-O2" } */
+ 
+ void abort (void);
+ 
+ __attribute__ ((noinline)) void
+ f (int i)
+ {
+   if (i != 0x87654321)
+     abort ();
+   asm ("");
+ }
+ 
+ __attribute__ ((noinline)) void
+ g (long long a)
+ {
+   f (a);
+   asm ("");
+ }
+ 
+ main ()
+ {
+   g (0x1234567887654321ll);
+   return 0;
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]