This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix PR target/17245
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 8 Oct 2004 15:43:38 +0200
- Subject: Fix PR target/17245
This is an ICE at -O -mcpu=v9 on SPARC 32-bit, a regression present on the
3.4 branch. The reload pass generates an invalid insn:
ultrasp11.c: In function `f':
ultrasp11.c:25: error: insn does not satisfy its constraints:
(insn 169 9 11 0 (set (reg:TF 10 %o2)
(mem/u/f:TF (lo_sum:SI (reg/f:SI 1 %g1 [111])
(symbol_ref/u:SI ("*.LLC0") [flags 0x2])) [0 S16 A64])) 98
{*movtf_insn_sp32} (nil)
(nil))
ultrasp11.c:25: internal compiler error: in reload_cse_simplify_operands, at
postreload.c:391
It is invalid because the address is not offsettable (with the Sun assembler)
and the pattern wants it to be offsettable for subsequent splitting.
This insn is emitted as part of reload #1 for:
(insn 11 9 13 0 (set (reg/v:TF 109 [ W ])
(mem/u/f:TF (lo_sum:SI (reg/f:SI 111)
(symbol_ref/u:SI ("*.LLC0") [flags 0x2])) [0 S16 A64])) 98
{*movtf_insn_sp32} (insn_list 9 (nil))
(expr_list:REG_DEAD (reg/f:SI 111)
(nil)))
(reg/v:TF 109 [ W ]) doesn't get a hard-reg so reload needs to fix up a move
between two MEMs with TFmode. %o2 is selected as the reload register and
the insn loading the register is emitted without further ado since the
address is generically valid.
This appears to be a limitation of the reload pass, as the SPARC back-end
already has provisions to dealt with it in a very similar case, the REG+REG
address form which is not offsettable either:
/* We prohibit REG + REG for TFmode when there are no instructions
which accept REG+REG instructions. We do this because REG+REG
is not an offsetable address. If we get the situation in reload
where source and destination of a movtf pattern are both MEMs with
REG+REG address, then only one of them gets converted to an
offsetable address. */
So I think it is reasonable to prohibit LO_SUM for TFmode too, when LO_SUM is
not offsettable. Note that the testcase doesn't ICE with -mcpu=v8 because
LO_SUM is already rejected in this case, and actually doubly rejected since
input_operand and legitimate_address_p contain redundant code.
Bootstrapped/regtested on sparc64-sun-solaris2.9 and sparc-sun-solaris2.8,
applied to mainline and 3.4 branch.
2004-10-08 Eric Botcazou <ebotcazou@libertysurf.fr>
PR target/17245
* config/sparc/sparc.c (input_operand): Remove redundant code
for handling LO_SUM.
(legitimate_address_p) <REG+REG>: Do not recheck TARGET_V9.
<LO_SUM>: If LO_SUM is offsettable, accept it for TFmode on V9.
Otherwise only accept it for TFmode if quad move insns are available.
2004-10-08 Christian Ehrhardt <ehrhardt@mathematik.uni-ulm.de>
* gcc.dg/ultrasp11.c: New test.
--
Eric Botcazou
Index: config/sparc/sparc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v
retrieving revision 1.271.4.20
diff -u -p -r1.271.4.20 sparc.c
--- config/sparc/sparc.c 17 Jul 2004 21:18:57 -0000 1.271.4.20
+++ config/sparc/sparc.c 8 Oct 2004 13:16:02 -0000
@@ -1315,23 +1315,7 @@ input_operand (rtx op, enum machine_mode
/* Check for valid MEM forms. */
if (GET_CODE (op) == MEM)
- {
- rtx inside = XEXP (op, 0);
-
- if (GET_CODE (inside) == LO_SUM)
- {
- /* We can't allow these because all of the splits
- (eventually as they trickle down into DFmode
- splits) require offsettable memory references. */
- if (! TARGET_V9
- && GET_MODE (op) == TFmode)
- return 0;
-
- return (register_operand (XEXP (inside, 0), Pmode)
- && CONSTANT_P (XEXP (inside, 1)));
- }
- return memory_address_p (mode, inside);
- }
+ return memory_address_p (mode, XEXP (op, 0));
return 0;
}
@@ -3374,15 +3358,14 @@ legitimate_address_p (enum machine_mode
else if ((REG_P (rs1) || GET_CODE (rs1) == SUBREG)
&& (REG_P (rs2) || GET_CODE (rs2) == SUBREG))
{
- /* We prohibit REG + REG for TFmode when there are no instructions
- which accept REG+REG instructions. We do this because REG+REG
- is not an offsetable address. If we get the situation in reload
+ /* We prohibit REG + REG for TFmode when there are no quad move insns
+ and we consequently need to split. We do this because REG+REG
+ is not an offsettable address. If we get the situation in reload
where source and destination of a movtf pattern are both MEMs with
REG+REG address, then only one of them gets converted to an
- offsetable address. */
+ offsettable address. */
if (mode == TFmode
- && !(TARGET_FPU && TARGET_ARCH64 && TARGET_V9
- && TARGET_HARD_QUAD))
+ && ! (TARGET_FPU && TARGET_ARCH64 && TARGET_HARD_QUAD))
return 0;
/* We prohibit REG + REG on ARCH32 if not optimizing for
@@ -3415,10 +3398,25 @@ legitimate_address_p (enum machine_mode
if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
return 0;
- /* We can't allow TFmode, because an offset greater than or equal to the
- alignment (8) may cause the LO_SUM to overflow if !v9. */
- if (mode == TFmode && !TARGET_V9)
- return 0;
+ if (USE_AS_OFFSETABLE_LO10)
+ {
+ /* We can't allow TFmode, because an offset greater than or equal to
+ the alignment (8) may cause the LO_SUM to overflow if !v9. */
+ if (mode == TFmode && ! TARGET_V9)
+ return 0;
+ }
+ else
+ {
+ /* We prohibit LO_SUM for TFmode when there are no quad move insns
+ and we consequently need to split. We do this because LO_SUM
+ is not an offsettable address. If we get the situation in reload
+ where source and destination of a movtf pattern are both MEMs with
+ LO_SUM address, then only one of them gets converted to an
+ offsettable address. */
+ if (mode == TFmode
+ && ! (TARGET_FPU && TARGET_ARCH64 && TARGET_HARD_QUAD))
+ return 0;
+ }
}
else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr))
return 1;
/* PR target/17245 */
/* Origin: <aaronw@net.com> */
/* Testcase by Christian Ehrhardt <ehrhardt@mathematik.uni-ulm.de> */
/* { dg-do compile { target sparc*-*-* } } */
/* { dg-options "-O -mcpu=v9" } */
/* This used to fail on 32-bit Ultrasparc because reload was emitting
a move insn that doesn't satisfy its constraints. */
int n;
double range ;
double bin ;
double wmean;
double f ()
{
int i ;
long double W = 0 ;
for ( i = 0 ; i < n ; i ++) {
double xi = range;
double wi = bin;
W += wi ;
wmean += ( xi - wmean) * ( wi / W);
}
}