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]

fix alpha glibc miscompilation


We've got hacks in cse and combine that honor putting an explicit
hard register in an asm operand and have it stay there.  This is
somewhat fragile, and really calls out for a better representation
inside the compiler.  I don't know that this is something that we
can address for 3.1 though.

Anyway, here's some more hacks for regrename.c to continue the fiction.


r~


        * regrename.c (build_def_use): Don't rename asm operands that
        were originally hard registers.
        (copyprop_hardreg_forward_1): Likewise.
        (find_oldest_value_reg): Copy ORIGINAL_REGNO from source.
        * varasm.c (make_decl_rtl): Use gen_rtx_raw_REG.  Set ORIGINAL_REGNO.

        * gcc.dg/asm-5.c: New.

Index: regrename.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regrename.c,v
retrieving revision 1.32
diff -c -p -d -r1.32 regrename.c
*** regrename.c	2001/12/17 16:46:09	1.32
--- regrename.c	2001/12/31 23:10:40
*************** build_def_use (bb)
*** 838,843 ****
--- 838,858 ----
  	    scan_rtx (insn, &CALL_INSN_FUNCTION_USAGE (insn),
  		      NO_REGS, terminate_all_read, OP_IN, 0);
  
+ 	  /* Step 2C: Can't rename asm operands that were originally
+ 	     hard registers.  */
+ 	  if (asm_noperands (PATTERN (insn)) > 0)
+ 	    for (i = 0; i < n_ops; i++)
+ 	      {
+ 		rtx *loc = recog_data.operand_loc[i];
+ 		rtx op = *loc;
+ 
+ 		if (GET_CODE (op) == REG
+ 		    && REGNO (op) == ORIGINAL_REGNO (op)
+ 		    && (recog_data.operand_type[i] == OP_IN
+ 			|| recog_data.operand_type[i] == OP_INOUT))
+ 		  scan_rtx (insn, loc, NO_REGS, terminate_all_read, OP_IN, 0);
+ 	      }
+ 
  	  /* Step 3: Append to chains for reads inside operands.  */
  	  for (i = 0; i < n_ops + recog_data.n_dups; i++)
  	    {
*************** build_def_use (bb)
*** 909,916 ****
  	  /* Step 6: Begin new chains for writes inside operands.  */
  	  /* ??? Many targets have output constraints on the SET_DEST
  	     of a call insn, which is stupid, since these are certainly
! 	     ABI defined hard registers.  Don't change calls at all.  */
! 	  if (GET_CODE (insn) != CALL_INSN)
  	    for (i = 0; i < n_ops + recog_data.n_dups; i++)
  	      {
  		int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops];
--- 924,950 ----
  	  /* Step 6: Begin new chains for writes inside operands.  */
  	  /* ??? Many targets have output constraints on the SET_DEST
  	     of a call insn, which is stupid, since these are certainly
! 	     ABI defined hard registers.  Don't change calls at all.
! 	     Similarly take special care for asm statement that originally
! 	     referenced hard registers.  */
! 	  if (asm_noperands (PATTERN (insn)) > 0)
! 	    {
! 	      for (i = 0; i < n_ops; i++)
! 		if (recog_data.operand_type[i] == OP_OUT)
! 		  {
! 		    rtx *loc = recog_data.operand_loc[i];
! 		    rtx op = *loc;
! 		    enum reg_class class = recog_op_alt[i][alt].class;
! 
! 		    if (GET_CODE (op) == REG
! 		        && REGNO (op) == ORIGINAL_REGNO (op))
! 		      continue;
! 
! 		    scan_rtx (insn, loc, class, mark_write, OP_OUT,
! 			      recog_op_alt[i][alt].earlyclobber);
! 		  }
! 	    }
! 	  else if (GET_CODE (insn) != CALL_INSN)
  	    for (i = 0; i < n_ops + recog_data.n_dups; i++)
  	      {
  		int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops];
*************** static int kill_autoinc_value PARAMS ((r
*** 1000,1008 ****
  static void copy_value PARAMS ((rtx, rtx, struct value_data *));
  static bool mode_change_ok PARAMS ((enum machine_mode, enum machine_mode,
  				    unsigned int));
! static rtx find_oldest_value_reg PARAMS ((enum reg_class, unsigned int,
! 					    enum machine_mode,
! 					    struct value_data *));
  static bool replace_oldest_value_reg PARAMS ((rtx *, enum reg_class, rtx,
  					      struct value_data *));
  static bool replace_oldest_value_addr PARAMS ((rtx *, enum reg_class,
--- 1034,1041 ----
  static void copy_value PARAMS ((rtx, rtx, struct value_data *));
  static bool mode_change_ok PARAMS ((enum machine_mode, enum machine_mode,
  				    unsigned int));
! static rtx find_oldest_value_reg PARAMS ((enum reg_class, rtx,
! 					  struct value_data *));
  static bool replace_oldest_value_reg PARAMS ((rtx *, enum reg_class, rtx,
  					      struct value_data *));
  static bool replace_oldest_value_addr PARAMS ((rtx *, enum reg_class,
*************** mode_change_ok (orig_mode, new_mode, reg
*** 1240,1258 ****
     of that oldest register, otherwise return NULL.  */
  
  static rtx
! find_oldest_value_reg (class, regno, mode, vd)
       enum reg_class class;
!      unsigned int regno;
!      enum machine_mode mode;
       struct value_data *vd;
  {
    unsigned int i;
  
    for (i = vd->e[regno].oldest_regno; i != regno; i = vd->e[i].next_regno)
      if (TEST_HARD_REG_BIT (reg_class_contents[class], i)
  	&& (vd->e[i].mode == mode
  	    || mode_change_ok (vd->e[i].mode, mode, regno)))
!       return gen_rtx_REG (mode, i);
  
    return NULL_RTX;
  }
--- 1273,1296 ----
     of that oldest register, otherwise return NULL.  */
  
  static rtx
! find_oldest_value_reg (class, reg, vd)
       enum reg_class class;
!      rtx reg;
       struct value_data *vd;
  {
+   unsigned int regno = REGNO (reg);
+   enum machine_mode mode = GET_MODE (reg);
    unsigned int i;
  
    for (i = vd->e[regno].oldest_regno; i != regno; i = vd->e[i].next_regno)
      if (TEST_HARD_REG_BIT (reg_class_contents[class], i)
  	&& (vd->e[i].mode == mode
  	    || mode_change_ok (vd->e[i].mode, mode, regno)))
!       {
! 	rtx new = gen_rtx_REG (mode, i);
! 	ORIGINAL_REGNO (new) = ORIGINAL_REGNO (reg);
! 	return new;
!       }
  
    return NULL_RTX;
  }
*************** replace_oldest_value_reg (loc, class, in
*** 1267,1273 ****
       rtx insn;
       struct value_data *vd;
  {
!   rtx new = find_oldest_value_reg (class, REGNO (*loc), GET_MODE (*loc), vd);
    if (new)
      {
        if (rtl_dump_file)
--- 1305,1311 ----
       rtx insn;
       struct value_data *vd;
  {
!   rtx new = find_oldest_value_reg (class, *loc, vd);
    if (new)
      {
        if (rtl_dump_file)
*************** copyprop_hardreg_forward_1 (bb, vd)
*** 1443,1448 ****
--- 1481,1487 ----
    for (insn = bb->head; ; insn = NEXT_INSN (insn))
      {
        int n_ops, i, alt, predicated;
+       bool is_asm;
        rtx set;
  
        if (! INSN_P (insn))
*************** copyprop_hardreg_forward_1 (bb, vd)
*** 1459,1464 ****
--- 1498,1504 ----
        preprocess_constraints ();
        alt = which_alternative;
        n_ops = recog_data.n_operands;
+       is_asm = asm_noperands (PATTERN (insn)) >= 0;
  
        /* Simplify the code below by rewriting things to reflect
  	 matching constraints.  Also promote OP_OUT to OP_INOUT
*************** copyprop_hardreg_forward_1 (bb, vd)
*** 1498,1505 ****
  	 be able to do the move from a different register class.  */
        if (set && REG_P (SET_SRC (set)))
  	{
! 	  unsigned int regno = REGNO (SET_SRC (set));
! 	  enum machine_mode mode = GET_MODE (SET_SRC (set));
  	  unsigned int i;
  	  rtx new;
  
--- 1538,1546 ----
  	 be able to do the move from a different register class.  */
        if (set && REG_P (SET_SRC (set)))
  	{
! 	  rtx src = SET_SRC (set);
! 	  unsigned int regno = REGNO (src);
! 	  enum machine_mode mode = GET_MODE (src);
  	  unsigned int i;
  	  rtx new;
  
*************** copyprop_hardreg_forward_1 (bb, vd)
*** 1507,1514 ****
  	     register in the same class.  */
  	  if (REG_P (SET_DEST (set)))
  	    {
! 	      new = find_oldest_value_reg (REGNO_REG_CLASS (regno),
! 					   regno, mode, vd);
  	      if (new && validate_change (insn, &SET_SRC (set), new, 0))
  		{
  		  if (rtl_dump_file)
--- 1548,1554 ----
  	     register in the same class.  */
  	  if (REG_P (SET_DEST (set)))
  	    {
! 	      new = find_oldest_value_reg (REGNO_REG_CLASS (regno), src, vd);
  	      if (new && validate_change (insn, &SET_SRC (set), new, 0))
  		{
  		  if (rtl_dump_file)
*************** copyprop_hardreg_forward_1 (bb, vd)
*** 1528,1533 ****
--- 1568,1574 ----
  		new = gen_rtx_REG (mode, i);
  		if (validate_change (insn, &SET_SRC (set), new, 0))
  		  {
+ 		    ORIGINAL_REGNO (new) = ORIGINAL_REGNO (src);
  		    if (rtl_dump_file)
  		      fprintf (rtl_dump_file,
  			       "insn %u: replaced reg %u with %u\n",
*************** copyprop_hardreg_forward_1 (bb, vd)
*** 1548,1553 ****
--- 1589,1600 ----
  	     information to pass down.  Any operands that we could
  	     substitute in will be represented elsewhere.  */
  	  if (recog_data.constraints[i][0] == '\0')
+ 	    continue;
+ 
+ 	  /* Don't replace in asms intentionally referencing hard regs.  */
+ 	  if (is_asm && GET_CODE (recog_data.operand[i]) == REG
+ 	      && (REGNO (recog_data.operand[i])
+ 		  == ORIGINAL_REGNO (recog_data.operand[i])))
  	    continue;
  
  	  if (recog_data.operand_type[i] == OP_IN)
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.240
diff -c -p -d -r1.240 varasm.c
*** varasm.c	2001/12/29 21:35:02	1.240
--- varasm.c	2001/12/31 23:10:40
*************** make_decl_rtl (decl, asmspec)
*** 898,911 ****
  
  	  /* If the user specified one of the eliminables registers here,
  	     e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
! 	     confused with that register and be eliminated.  Although this
! 	     usage is somewhat suspect, we nevertheless use the following
! 	     kludge to avoid setting DECL_RTL to frame_pointer_rtx.  */
  
! 	  SET_DECL_RTL (decl,
! 			gen_rtx_REG (DECL_MODE (decl),
! 				     FIRST_PSEUDO_REGISTER));
! 	  REGNO (DECL_RTL (decl)) = reg_number;
  	  REG_USERVAR_P (DECL_RTL (decl)) = 1;
  
  	  if (TREE_STATIC (decl))
--- 898,908 ----
  
  	  /* If the user specified one of the eliminables registers here,
  	     e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
! 	     confused with that register and be eliminated.  This usage is
! 	     somewhat suspect...  */
  
! 	  SET_DECL_RTL (decl, gen_rtx_raw_REG (DECL_MODE (decl), reg_number));
! 	  ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number;
  	  REG_USERVAR_P (DECL_RTL (decl)) = 1;
  
  	  if (TREE_STATIC (decl))
Index: testsuite/gcc.dg/asm-5.c
===================================================================
RCS file: asm-5.c
diff -N asm-5.c
*** /dev/null	Tue May  5 13:32:27 1998
--- asm-5.c	Mon Dec 31 15:11:12 2001
***************
*** 0 ****
--- 1,82 ----
+ /* Asm operands that are given as hard registers must keep the same
+    hard register all the way through compilation.  Example derived
+    from glibc source.  */
+ /* { dg-do compile { target alpha*-*-* } } */
+ /* { dg-options "-O2 -frename-registers -fcprop-registers" } */
+ /* { dg-final { scan-assembler "callsys1 .0 .19 .0 .16 .17" } } */
+ /* { dg-final { scan-assembler "callsys2 .0 .19 .0 .16 .17" } } */
+ 
+ struct stat {
+   int dummy;
+ };
+ 
+ struct kernel_stat {
+   int dummy;
+ };
+ 
+ extern int xstat_conv (int vers, struct kernel_stat *kbuf, void *ubuf);
+ extern int *__errno_location (void) __attribute__ ((__const__));
+ 
+ int
+ __fxstat (int vers, int fd, struct stat *buf)
+ {
+   struct kernel_stat kbuf;
+   int result;
+ 
+   if (vers == 0)
+     return
+       ({
+ 	long _sc_ret, _sc_err;
+ 	{
+ 	  register long _sc_0 __asm__("$0");
+ 	  register long _sc_16 __asm__("$16");
+ 	  register long _sc_17 __asm__("$17");
+ 	  register long _sc_19 __asm__("$19");
+ 	  _sc_0 = 91;
+ 	  _sc_16 = (long) (fd);
+ 	  _sc_17 = (long) (((struct kernel_stat *) buf));
+ 	  __asm__("callsys1 %0 %1 %2 %3 %4"
+ 		  : "=r"(_sc_0), "=r"(_sc_19)
+ 		  : "0"(_sc_0), "r"(_sc_16), "r"(_sc_17)
+ 		  : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+ 		    "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+ 	  _sc_ret = _sc_0, _sc_err = _sc_19;
+ 	}
+ 	if (_sc_err)
+ 	  {
+ 	    (*__errno_location ()) = (_sc_ret);
+ 	    _sc_ret = -1L;
+ 	  }
+ 	_sc_ret;
+       });
+ 
+   result =
+       ({
+ 	long _sc_ret, _sc_err;
+ 	{
+ 	  register long _sc_0 __asm__("$0");
+ 	  register long _sc_16 __asm__("$16");
+ 	  register long _sc_17 __asm__("$17");
+ 	  register long _sc_19 __asm__("$19");
+ 	  _sc_0 = 91;
+ 	  _sc_16 = (long) (fd);
+ 	  _sc_17 = (long) ((&kbuf));
+ 	  __asm__("callsys2 %0 %1 %2 %3 %4"
+ 		  : "=r"(_sc_0), "=r"(_sc_19)
+ 		  : "0"(_sc_0), "r"(_sc_16), "r"(_sc_17)
+ 		  : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+ 		    "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+ 	  _sc_ret = _sc_0, _sc_err = _sc_19;
+ 	}
+ 	if (_sc_err)
+ 	  {
+ 	    (*__errno_location ()) = (_sc_ret);
+ 	    _sc_ret = -1L;
+ 	  }
+ 	_sc_ret;
+       });
+   if (result == 0)
+     result = xstat_conv (vers, &kbuf, buf);
+ 
+   return result;
+ }


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