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]

ADDRESSOF still broken


The latest changes to the ADDRESSOF optimisation are still not enough to
make it work again.  There can be other insns beside CALL that require
operands to be in memory.  For example, the extv/insv patterns normally
require that the first operand is either a memory operand in QImode or a
register operand in SImode (this is the case on m68k).  In the example
below, the following insn is triggering the abort:

(insn 22 21 24 (set (reg:SI 35)
        (zero_extract:SI (mem/s:QI (addressof:SI (reg/v:SI 33) 32) 0)
            (const_int 1)
            (const_int 0))) 342 {extzv+1} (nil)
    (nil))

The (mem:QI (addressof (reg:SI))) is tried be replaced by (reg:QI) which
is not a valid operand for zero_extract (but a (reg:SI) would be).

Another problem is that doing the purging inside the REG_NOTES of an insn
cannot generate any new insns, and the register that is replaced for the
(mem (addressof)) must be exactly the same as in the insn.  For example,
consider the following insn that is generated after cse for the example
below:

(insn 23 22 24 (set (strict_low_part (subreg:QI (reg:SI 33) 0))
        (mem/s:QI (addressof:SI (reg/v:SI 32) 31) 0)) 54 {movstrictqi+1} (nil)
    (expr_list:REG_EQUAL (zero_extend:SI (mem/s:QI (addressof:SI (reg/v:SI 32) 31) 0))
        (nil)))

In the first pass the (mem (addressof)) is replaced by some register after
emitting an appropriate insn to set it, and when processing the note list
exactly the same replacement must be made without emitting any insns this
time.

The compiler was configured for the target m68k-linux.

$ cat ecofflink.i
typedef struct {
	unsigned fBitfield : 1;  
	unsigned continued : 1;  
	unsigned bt  : 6;	 
	unsigned tq4 : 4;
	unsigned tq5 : 4;
	unsigned tq0 : 4;
	unsigned tq1 : 4;	 
	unsigned tq2 : 4;
	unsigned tq3 : 4;
	} TIR, *pTIR;
typedef struct {
	unsigned	rfd : 12;     
	unsigned	index : 20;  
	} RNDXR, *pRNDXR;
struct tir_ext {
	unsigned char	t_bits1[1];
	unsigned char	t_tq45[1];
	unsigned char	t_tq01[1];
	unsigned char	t_tq23[1];
};
struct rndx_ext {
	unsigned char	r_bits[4];
};
void
_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
     int bigend;
     const struct tir_ext *ext_copy;
     TIR *intern;
{
  struct tir_ext ext[1];
  *ext = *ext_copy;		 
  if (bigend) {
    intern->fBitfield   = 0 != (ext->t_bits1[0] & ((unsigned int) 0x80) );
    intern->continued   = 0 != (ext->t_bits1[0] & ((unsigned int) 0x40) );
    intern->bt          = (ext->t_bits1[0] & ((unsigned int) 0x3F) )
			>>		    0 ;
    intern->tq4         = (ext->t_tq45[0] & ((unsigned int) 0xF0) )
			>>		    4 ;
    intern->tq5         = (ext->t_tq45[0] & ((unsigned int) 0x0F) )
			>>		    0 ;
    intern->tq0         = (ext->t_tq01[0] & ((unsigned int) 0xF0) )
			>>		    4 ;
    intern->tq1         = (ext->t_tq01[0] & ((unsigned int) 0x0F) )
			>>		    0 ;
    intern->tq2         = (ext->t_tq23[0] & ((unsigned int) 0xF0) )
			>>		    4 ;
    intern->tq3         = (ext->t_tq23[0] & ((unsigned int) 0x0F) )
			>>		    0 ;
  } else {
    intern->fBitfield   = 0 != (ext->t_bits1[0] & ((unsigned int) 0x01) );
    intern->continued   = 0 != (ext->t_bits1[0] & ((unsigned int) 0x02) );
    intern->bt          = (ext->t_bits1[0] & ((unsigned int) 0xFC) )
			>>		    2 ;
    intern->tq4         = (ext->t_tq45[0] & ((unsigned int) 0x0F) )
			>>		    0 ;
    intern->tq5         = (ext->t_tq45[0] & ((unsigned int) 0xF0) )
			>>		    4 ;
    intern->tq0         = (ext->t_tq01[0] & ((unsigned int) 0x0F) )
			>>		    0 ;
    intern->tq1         = (ext->t_tq01[0] & ((unsigned int) 0xF0) )
			>>		    4 ;
    intern->tq2         = (ext->t_tq23[0] & ((unsigned int) 0x0F) )
			>>		    0 ;
    intern->tq3         = (ext->t_tq23[0] & ((unsigned int) 0xF0) )
			>>		    4 ;
  }
}
void
_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
     int bigend;
     const TIR *intern_copy;
     struct tir_ext *ext;
{
  TIR intern[1];
  *intern = *intern_copy;	 
  if (bigend) {
    ext->t_bits1[0] = ((intern->fBitfield ? ((unsigned int) 0x80)  : 0)
		       | (intern->continued ? ((unsigned int) 0x40)  : 0)
		       | ((intern->bt << 0 )
			  & ((unsigned int) 0x3F) ));
    ext->t_tq45[0] = (((intern->tq4 << 4 )
		       & ((unsigned int) 0xF0) )
		      | ((intern->tq5 << 0 )
			 & ((unsigned int) 0x0F) ));
    ext->t_tq01[0] = (((intern->tq0 << 4 )
		       & ((unsigned int) 0xF0) )
		      | ((intern->tq1 << 0 )
			 & ((unsigned int) 0x0F) ));
    ext->t_tq23[0] = (((intern->tq2 << 4 )
		       & ((unsigned int) 0xF0) )
		      | ((intern->tq3 << 0 )
			 & ((unsigned int) 0x0F) ));
  } else {
    ext->t_bits1[0] = ((intern->fBitfield ? ((unsigned int) 0x01)  : 0)
		       | (intern->continued ? ((unsigned int) 0x02)  : 0)
		       | ((intern->bt << 2 )
			  & ((unsigned int) 0xFC) ));
    ext->t_tq45[0] = (((intern->tq4 << 0 )
		       & ((unsigned int) 0x0F) )
		      | ((intern->tq5 << 4 )
			 & ((unsigned int) 0xF0) ));
    ext->t_tq01[0] = (((intern->tq0 << 0 )
		       & ((unsigned int) 0x0F) )
		      | ((intern->tq1 << 4 )
			 & ((unsigned int) 0xF0) ));
    ext->t_tq23[0] = (((intern->tq2 << 0 )
		       & ((unsigned int) 0x0F) )
		      | ((intern->tq3 << 4 )
			 & ((unsigned int) 0xF0) ));
  }
}
void
_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
     int bigend;
     const struct rndx_ext *ext_copy;
     RNDXR *intern;
{
  struct rndx_ext ext[1];
  *ext = *ext_copy;		 
  if (bigend) {
    intern->rfd   = (ext->r_bits[0] << 4 )
		  | ((ext->r_bits[1] & ((unsigned int) 0xF0) )
		    		    >> 4 );
    intern->index = ((ext->r_bits[1] & ((unsigned int) 0x0F) )
		    		    << 16 )
		  | (ext->r_bits[2] << 8 )
		  | (ext->r_bits[3] << 0 );
  } else {
    intern->rfd   = (ext->r_bits[0] << 0 )
		  | ((ext->r_bits[1] & ((unsigned int) 0x0F) )
		    		    << 8 );
    intern->index = ((ext->r_bits[1] & ((unsigned int) 0xF0) )
		    		    >> 4 )
		  | (ext->r_bits[2] << 4 )
		  | ((unsigned int) ext->r_bits[3]
		     << 12 );
  }
}
void
_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
     int bigend;
     const RNDXR *intern_copy;
     struct rndx_ext *ext;
{
  RNDXR intern[1];
  *intern = *intern_copy;	 
  if (bigend) {
    ext->r_bits[0] = intern->rfd >> 4 ;
    ext->r_bits[1] = (((intern->rfd << 4 )
		       & ((unsigned int) 0xF0) )
		      | ((intern->index >> 16 )
			 & ((unsigned int) 0x0F) ));
    ext->r_bits[2] = intern->index >> 8 ;
    ext->r_bits[3] = intern->index >> 0 ;
  } else {
    ext->r_bits[0] = intern->rfd >> 0 ;
    ext->r_bits[1] = (((intern->rfd >> 8 )
		       & ((unsigned int) 0x0F) )
		      | ((intern->index << 4 )
			 & ((unsigned int) 0xF0) ));
    ext->r_bits[2] = intern->index >> 4 ;
    ext->r_bits[3] = intern->index >> 12 ;
  }
}
$ /usr/local/egcs/bin/gcc -O2 -S ecofflink.i
../../gcc/function.c:2921: Internal compiler error in function purge_addressof_1

This is the insn the compiler is choking on:


1998-10-18  Andreas Schwab  <schwab@issan.cs.uni-dortmund.de>

	* function.c (purge_addressof_1): Instead of aborting when a
	bitfield insertion as a replacement for (MEM (ADDRESSOF)) does not
	work just put the ADDRESSOF on stack.  Otherwise remember all such
	successfull replacements, so that exactly the same replacements
	can be made on the REG_NOTEs.  Remove the special case for CALL
	insns again.
	(purge_addressof_replacements): New variable.
	(purge_addressof): Clear it at end.

--- egcs-2.92/gcc/function.c.~2~	Thu Oct 15 00:31:50 1998
+++ egcs-2.92/gcc/function.c	Sun Oct 18 20:21:55 1998
@@ -2812,6 +2812,10 @@
 		      TREE_USED (decl) || DECL_INITIAL (decl) != 0);
 }
 
+/* List of replacements made below in purge_addressof_1 when creating
+   bitfield insertions.  */
+static rtx purge_addressof_replacements;
+
 /* Helper function for purge_addressof.  See if the rtx expression at *LOC
    in INSN needs to be changed.  If FORCE, always put any ADDRESSOFs into
    the stack.  */
@@ -2874,6 +2878,25 @@
 	{
 	  int size_x, size_sub;
 
+	  if (!insn)
+	    {
+	      /* When processing REG_NOTES look at the list of
+		 replacements done on the insn to find the register that X
+		 was replaced by.  */
+	      rtx tem;
+
+	      for (tem = purge_addressof_replacements; tem != NULL_RTX;
+		   tem = XEXP (XEXP (tem, 1), 1))
+		if (rtx_equal_p (x, XEXP (tem, 0)))
+		  {
+		    *loc = XEXP (XEXP (tem, 1), 0);
+		    return;
+		  }
+
+	      /* There should always be such a replacement.  */
+	      abort ();
+	    }
+
 	  size_x = GET_MODE_BITSIZE (GET_MODE (x));
 	  size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
 
@@ -2889,12 +2912,15 @@
 
 	      if (store)
 		{
-		  /* If we can't replace with a register, be afraid.  */
-
 		  start_sequence ();
 		  val = gen_reg_rtx (GET_MODE (x));
 		  if (! validate_change (insn, loc, val, 0))
-		    abort ();
+		    {
+		      /* Discard the current sequence and put the
+			 ADDRESSOF on stack.  */
+		      end_sequence ();
+		      goto give_up;
+		    }
 		  seq = gen_sequence ();
 		  end_sequence ();
 		  emit_insn_before (seq, insn);
@@ -2916,21 +2942,33 @@
 					   GET_MODE_SIZE (GET_MODE (sub)),
 					   GET_MODE_SIZE (GET_MODE (sub)));
 
-		  /* If we can't replace with a register, be afraid.  */
 		  if (! validate_change (insn, loc, val, 0))
-		    abort ();
+		    {
+		      /* Discard the current sequence and put the
+			 ADDRESSOF on stack.  */
+		      end_sequence ();
+		      goto give_up;
+		    }
 
 		  seq = gen_sequence ();
 		  end_sequence ();
 		  emit_insn_before (seq, insn);
 		}
 
+	      /* Remember the replacement so that the same one can be done
+		 on the REG_NOTES.  */
+	      purge_addressof_replacements
+		= gen_rtx_EXPR_LIST (VOIDmode, x,
+				     gen_rtx_EXPR_LIST (VOIDmode, val,
+							purge_addressof_replacements));
+
 	      /* We replaced with a reg -- all done.  */
 	      return;
 	    }
 	}
       else if (validate_change (insn, loc, sub, 0))
 	goto restart;
+    give_up:;
       /* else give up and put it into the stack */
     }
   else if (code == ADDRESSOF)
@@ -2944,12 +2982,6 @@
       purge_addressof_1 (&SET_SRC (x), insn, force, 0);
       return;
     }
-  else if (code == CALL)
-    {
-      purge_addressof_1 (&XEXP (x, 0), insn, 1, 0);
-      purge_addressof_1 (&XEXP (x, 1), insn, force, 0);
-      return;
-    }
 
   /* Scan all subexpressions. */
   fmt = GET_RTX_FORMAT (code);
@@ -2980,6 +3012,7 @@
 			   asm_noperands (PATTERN (insn)) > 0, 0);
 	purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0);
       }
+  purge_addressof_replacements = 0;
 }
 
 /* Pass through the INSNS of function FNDECL and convert virtual register

-- 
Andreas Schwab                                      "And now for something
schwab@issan.cs.uni-dortmund.de                      completely different"
schwab@gnu.org


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