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]

Re: [RS6000] Fix ICE storing long long to mem.


On Tue, Dec 07, 2004 at 12:23:18PM +1030, Alan Modra wrote:
> The following patch fixes this by preventing CSE from doing the LO_SUM
> address transformation for DImode and other 64-bit quantities when
> generating 32-bit code.  Prior to Geoff's first patch, this test looked
> like:
> 
>       if (GET_MODE_BITSIZE (mode) > 32
> 	  && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode))
> 
> but that is bogus since we can have DFmode values in gprs.
> Unfortunately, this does mean poorer code when accessing memory with
> fprs.  I'm not sure what to do about that, perhaps a peephole..

Another approach occurred to me.  rs6000_split_multireg_move can handle
non-offsettable addresses for stores by offsetting the high-part
register for LO_SUM, or an index reg.  However, testing showed that
this produced poor code for -fprofile-generate where we load a long long
from memory, increment it, then store it back.  The problem being that
both the load and the store then need an extra address manipulation
instruction, a penalty of two instructions.  Disallowing LO_SUM for
64-bit mem accesses causes the address to be put in a register which is
then used for both the load and store, a penalty of just one insn.

Patch follows for amusement value, or in case others think extending
rs6000_split_multireg_move like this is a good idea.  Only lightly
tested..

	* config/rs6000/rs6000.c (rs6000_split_multireg_move): Handle
	non-offsettable mem stores.
	(find_addr_reg): Look in LO_SUM addresses too.
	* config/rs6000/rs6000.md (movdi_internal32): Allow r->m stores.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

--- gcc-virgin/gcc/config/rs6000/rs6000.c	2004-12-04 09:27:27.000000000 +1030
+++ gcc-current/gcc/config/rs6000/rs6000.c	2004-12-07 22:16:03.482438322 +1030
@@ -12177,10 +12190,7 @@ rs6000_emit_minmax (rtx dest, enum rtx_c
 }
 
 /* Emit instructions to move SRC to DST.  Called by splitters for
-   multi-register moves.  It will emit at most one instruction for
-   each register that is accessed; that is, it won't emit li/lis pairs
-   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
-   register.  */
+   multi-register moves.  One of SRC or DST must be a hard register.  */
 
 void
 rs6000_split_multireg_move (rtx dst, rtx src)
@@ -12299,7 +12309,38 @@ rs6000_split_multireg_move (rtx dst, rtx
 	      dst = gen_rtx_MEM (mode, breg);
 	    }
 	  else if (! offsettable_memref_p (dst))
-	    abort ();
+	    {
+	      rtx addreg, delta_rtx, mem, reg;
+
+	      addreg = find_addr_reg (XEXP (dst, 0));
+	      if (REGNO (addreg) > REGNO (src)
+		  && REGNO (addreg) < REGNO (src) + nregs)
+		abort ();
+
+	      delta_rtx = GEN_INT (reg_mode_size);
+	      mem = adjust_address_nv (dst, reg_mode, 0);
+	      for (i = 0; i < nregs; i++)
+		{
+		  rtx memoff;
+		  reg = simplify_gen_subreg (reg_mode, src, mode,
+					     i * reg_mode_size);
+		  emit_insn (gen_rtx_SET (VOIDmode, mem, reg));
+		  emit_insn (TARGET_32BIT
+			     ? gen_addsi3 (addreg, addreg, delta_rtx)
+			     : gen_adddi3 (addreg, addreg, delta_rtx));
+		  memoff = MEM_OFFSET (mem);
+		  if (memoff)
+		    {
+		      memoff = GEN_INT (INTVAL (memoff) + reg_mode_size);
+		      set_mem_offset (mem, memoff);
+		    }
+		}
+	      delta_rtx = GEN_INT (-nregs * reg_mode_size);
+	      emit_insn (TARGET_32BIT
+			 ? gen_addsi3 (addreg, addreg, delta_rtx)
+			 : gen_adddi3 (addreg, addreg, delta_rtx));
+	      return;
+	    }
 	}
 
       for (i = 0; i < nregs; i++)
@@ -17316,7 +17357,7 @@ rs6000_elf_in_small_data_p (tree decl)
 struct rtx_def *
 find_addr_reg (rtx addr)
 {
-  while (GET_CODE (addr) == PLUS)
+  while (GET_CODE (addr) == PLUS || GET_CODE (addr) == LO_SUM)
     {
       if (GET_CODE (XEXP (addr, 0)) == REG
 	  && REGNO (XEXP (addr, 0)) != 0)

--- gcc-virgin/gcc/config/rs6000/rs6000.md	2004-12-02 11:29:13.000000000 +1030
+++ gcc-current/gcc/config/rs6000/rs6000.md	2004-12-07 21:34:06.577773693 +1030
@@ -8493,11 +8498,9 @@
   ""
   "{ rs6000_emit_move (operands[0], operands[1], DImode); DONE; }")
 
-; List r->r after r->"o<>", otherwise reload will try to reload a
-; non-offsettable address by using r->r which won't make progress.
 (define_insn "*movdi_internal32"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=o<>,r,r,f,f,m,r")
-	(match_operand:DI 1 "input_operand" "r,r,m,f,m,f,IJKnGHF"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m,r")
+	(match_operand:DI 1 "input_operand" "r,m,r,f,m,f,IJKnGHF"))]
   "! TARGET_POWERPC64
    && (gpc_reg_operand (operands[0], DImode)
        || gpc_reg_operand (operands[1], DImode))"
@@ -8509,7 +8512,7 @@
    lfd%U1%X1 %0,%1
    stfd%U0%X0 %1,%0
    #"
-  [(set_attr "type" "load,*,store,fp,fpload,fpstore,*")])
+  [(set_attr "type" "*,load,store,fp,fpload,fpstore,*")])
 
 (define_split
   [(set (match_operand:DI 0 "gpc_reg_operand" "")


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