This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [RS6000] Fix ICE storing long long to mem.
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: gcc-patches at gcc dot gnu dot org, Geoff Keating <geoffk at geoffk dot org>
- Date: Tue, 7 Dec 2004 23:21:02 +1030
- Subject: Re: [RS6000] Fix ICE storing long long to mem.
- References: <20041207015318.GC17237@bubble.modra.org>
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" "")