This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix optimization/10904
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 7 Jun 2003 22:56:17 +0200
- Subject: [PATCH] Fix optimization/10904
Hi,
GCC emits illegal assembly on mainline and 3.3 branch
fdtox %f10, %f7 (illegal, odd-numbered FP reg)
at -O2 for
int a = (long)(b * ((double) 0.1));
under certain circumstances on SPARC64. Note that this is a progression from
GCC 3.2.x which silently generates wrong code in the same situation.
Here's the chain of events: the combiner turns
(insn 30 29 31 0 0x40182fc0 (set (reg:DI 118)
(fix:DI (fix:DF (reg:DF 117)))) 167 {fix_truncdfdi2} (insn_list 29
(nil))
(expr_list:REG_DEAD (reg:DF 117)
(nil)))
(insn 31 30 33 0 0x40182fc0 (set (reg/v:SI 112)
(subreg:SI (reg:DI 118) 4)) 51 {*movsi_insn} (insn_list 30 (nil))
(expr_list:REG_DEAD (reg:DI 118)
(nil)))
into
(insn 31 30 33 0 0x40182fc0 (set (subreg:DI (reg/v:SI 112) 0)
(fix:DI (fix:DF (reg:DF 117)))) 167 {fix_truncdfdi2} (insn_list 29
(nil))
(expr_list:REG_DEAD (reg:DF 117)
(nil)))
which I think is correct on big-endian targets.
Then the (global) register allocator allocates %f8 to (reg/v:SI 112) because
it doesn't know that the pseudo has been paradoxically subreged. So
(subreg:DI (reg/v:SI 112) 0) ends up being assigned %f7-%f8.
I'm not sure how this is supposed to be fixed but, since the SPARC port
doesn't have constraints to enforce register alignments, I think the register
allocator must align the registers at the first go. There is already a
machinery to take into account constraints derived from subregization, based
on CANNOT_CHANGE_MODE_CLASS and regclass.c:cannot_change_mode_set_regs().
However it doesn't have the right granularity for the SPARC port, so I
overrided REG_CANNOT_CHANGE_MODE_P which gave me control on the REGNO.
Is this the right approach? I'm a bit worried because I'm afraid that reload
might screw up everything afterwards.
Bootstrapped/regtested (c,c++,objc,f77 mainline) on sparc64-sun-solaris2.9,
boostrapped on sparc-sun-solaris2.8 and i586-redhat-linux-gnu.
--
Eric Botcazou
2003-06-07 Eric Botcazou <ebotcazou@libertysurf.fr>
PR optimization/10904
* combine.c (subst): Conditionalize on REG_CANNOT_CHANGE_MODE_P
instead of CANNOT_CHANGE_MODE_CLASS.
(simplify_set): Likewise.
(gen_lowpart_for_combine): Likewise.
* flow.c (life_analysis): Likewise.
(mark_used_regs): Likewise.
* global.c (find_reg): Likewise.
* local-alloc.c (find_free_reg): Likewise.
* ra-build.c (init_one_web_common): Likewise.
(remember_web_was_spilled): Likewise.
* ra-colorize.c (colorize_one_web): Likewise.
* ra.c (init_ra): Likewise.
* recog.c (register_operand): Likewise.
* regclass.c (subregs_of_mode): Likewise.
(cannot_change_mode_set_regs): Likewise.
* regrename.c (mode_change_ok): Likewise.
* reload.c (push_reload): Likewise.
* reload1.c (choose_reload_reg): Likewise.
* simplify-rtx.c (simplify_subreg): Likewise.
* hard-reg-set.h (REG_CANNOT_CHANGE_MODE_P): Define if not defined
and CANNOT_CHANGE_MODE_CLASS is defined.
* config/sparc/sparc.h (REG_CANNOT_CHANGE_MODE_P): Define. Return
true on v9 for unaligned paradoxical subregs of floating-point registers.
* doc/tm.texi (REG_CANNOT_CHANGE_MODE_P): Document.
2003-06-07 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.c-torture/execute/20030607-1.c: New test.
Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.359
diff -u -p -r1.359 combine.c
--- combine.c 3 Jun 2003 17:10:48 -0000 1.359
+++ combine.c 5 Jun 2003 12:13:06 -0000
@@ -3469,7 +3469,7 @@ subst (x, from, to, in_dest, unique_copy
)
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (code == SUBREG
&& GET_CODE (to) == REG
&& REGNO (to) < FIRST_PSEUDO_REGISTER
@@ -5257,7 +5257,7 @@ simplify_set (x)
/ UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
&& ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
GET_MODE (SUBREG_REG (src)),
@@ -10174,7 +10174,7 @@ gen_lowpart_for_combine (mode, x)
}
result = gen_lowpart_common (mode, x);
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (result != 0
&& GET_CODE (result) == SUBREG
&& GET_CODE (SUBREG_REG (result)) == REG
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.551
diff -u -p -r1.551 flow.c
--- flow.c 3 Jun 2003 23:17:27 -0000 1.551
+++ flow.c 5 Jun 2003 12:13:29 -0000
@@ -433,8 +433,7 @@ life_analysis (f, file, flags)
SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
#endif
-
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (flags & PROP_REG_INFO)
bitmap_initialize (&subregs_of_mode, 1);
#endif
@@ -3842,7 +3841,7 @@ mark_used_regs (pbi, x, cond, insn)
break;
case SUBREG:
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (x))
@@ -3891,7 +3890,7 @@ mark_used_regs (pbi, x, cond, insn)
|| GET_CODE (testreg) == SIGN_EXTRACT
|| GET_CODE (testreg) == SUBREG)
{
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (GET_CODE (testreg) == SUBREG
&& GET_CODE (SUBREG_REG (testreg)) == REG
&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER)
Index: global.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/global.c,v
retrieving revision 1.91
diff -u -p -r1.91 global.c
--- global.c 14 Apr 2003 21:51:07 -0000 1.91
+++ global.c 5 Jun 2003 12:13:41 -0000
@@ -1023,7 +1023,7 @@ find_reg (num, losers, alt_regs_p, accep
IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
cannot_change_mode_set_regs (&used1, mode, allocno[num].reg);
#endif
Index: hard-reg-set.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/hard-reg-set.h,v
retrieving revision 1.19
diff -u -p -r1.19 hard-reg-set.h
--- hard-reg-set.h 31 Jan 2003 23:34:13 -0000 1.19
+++ hard-reg-set.h 5 Jun 2003 12:13:41 -0000
@@ -488,9 +488,11 @@ extern int n_non_fixed_regs;
extern const char * reg_names[FIRST_PSEUDO_REGISTER];
-/* Given a hard REGN a FROM mode and a TO mode, return nonzero if
- REGN cannot change modes between the specified modes. */
-#define REG_CANNOT_CHANGE_MODE_P(REGN, FROM, TO) \
- CANNOT_CHANGE_MODE_CLASS (FROM, TO, REGNO_REG_CLASS (REGN))
+/* Given a hard REGNO, a FROM mode and a TO mode, return nonzero if
+ REGNO cannot change modes between the specified modes. */
+#if (!defined REG_CANNOT_CHANGE_MODE_P) && (defined CANNOT_CHANGE_MODE_CLASS)
+#define REG_CANNOT_CHANGE_MODE_P(REGNO, FROM, TO) \
+ CANNOT_CHANGE_MODE_CLASS (FROM, TO, REGNO_REG_CLASS (REGNO))
+#endif
#endif /* ! GCC_HARD_REG_SET_H */
Index: local-alloc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/local-alloc.c,v
retrieving revision 1.117
diff -u -p -r1.117 local-alloc.c
--- local-alloc.c 17 Jan 2003 03:28:08 -0000 1.117
+++ local-alloc.c 5 Jun 2003 12:13:53 -0000
@@ -2223,7 +2223,7 @@ find_free_reg (class, mode, qtyno, accep
SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM);
#endif
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
cannot_change_mode_set_regs (&used, mode, qty[qtyno].first_reg);
#endif
Index: ra-build.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ra-build.c,v
retrieving revision 1.18
diff -u -p -r1.18 ra-build.c
--- ra-build.c 8 Mar 2003 01:38:27 -0000 1.18
+++ ra-build.c 5 Jun 2003 12:14:07 -0000
@@ -1305,7 +1305,7 @@ init_one_web_common (web, reg)
AND_COMPL_HARD_REG_SET (web->usable_regs, never_use_colors);
prune_hardregs_for_mode (&web->usable_regs,
PSEUDO_REGNO_MODE (web->regno));
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (web->mode_changed)
AND_COMPL_HARD_REG_SET (web->usable_regs, invalid_mode_change_regs);
#endif
@@ -2370,7 +2370,7 @@ remember_web_was_spilled (web)
reg_class_contents[(int) GENERAL_REGS]);
AND_COMPL_HARD_REG_SET (web->usable_regs, never_use_colors);
prune_hardregs_for_mode (&web->usable_regs, PSEUDO_REGNO_MODE (web->regno));
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (web->mode_changed)
AND_COMPL_HARD_REG_SET (web->usable_regs, invalid_mode_change_regs);
#endif
Index: ra-colorize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ra-colorize.c,v
retrieving revision 1.11
diff -u -p -r1.11 ra-colorize.c
--- ra-colorize.c 15 Mar 2003 13:43:30 -0000 1.11
+++ ra-colorize.c 5 Jun 2003 12:14:19 -0000
@@ -1370,7 +1370,7 @@ colorize_one_web (web, hard)
else
COPY_HARD_REG_SET (colors,
usable_regs[reg_preferred_class (web->regno)]);
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (web->mode_changed)
AND_COMPL_HARD_REG_SET (colors, invalid_mode_change_regs);
#endif
@@ -1403,7 +1403,7 @@ colorize_one_web (web, hard)
else
IOR_HARD_REG_SET (colors, usable_regs
[reg_alternate_class (web->regno)]);
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CHANGE_MODE_CLASS_P
if (web->mode_changed)
AND_COMPL_HARD_REG_SET (colors, invalid_mode_change_regs);
#endif
Index: ra.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ra.c,v
retrieving revision 1.8
diff -u -p -r1.8 ra.c
--- ra.c 7 Mar 2003 22:06:16 -0000 1.8
+++ ra.c 5 Jun 2003 12:14:21 -0000
@@ -557,7 +557,7 @@ init_ra ()
}
CLEAR_HARD_REG_SET (invalid_mode_change_regs);
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (0)
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
Index: recog.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/recog.c,v
retrieving revision 1.177
diff -u -p -r1.177 recog.c
--- recog.c 18 Feb 2003 19:35:08 -0000 1.177
+++ recog.c 5 Jun 2003 12:14:34 -0000
@@ -1085,7 +1085,7 @@ register_operand (op, mode)
if (! reload_completed && GET_CODE (sub) == MEM)
return general_operand (op, mode);
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
if (GET_CODE (sub) == REG
&& REGNO (sub) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
Index: regclass.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regclass.c,v
retrieving revision 1.171
diff -u -p -r1.171 regclass.c
--- regclass.c 28 Feb 2003 10:11:47 -0000 1.171
+++ regclass.c 5 Jun 2003 12:14:42 -0000
@@ -231,7 +231,7 @@ static char *in_inc_dec;
#endif /* FORBIDDEN_INC_DEC_CLASSES */
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
/* All registers that have been subreged. Indexed by regno * MAX_MACHINE_MODE
+ mode. */
bitmap_head subregs_of_mode;
@@ -2627,7 +2627,8 @@ regset_release_memory ()
bitmap_release_memory ();
}
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
+
/* Set bits in *USED which correspond to registers which can't change
their mode from FROM to any mode in which REGNO was encountered. */
@@ -2651,6 +2652,10 @@ cannot_change_mode_set_regs (used, from,
SET_HARD_REG_BIT (*used, i);
);
}
+
+#endif /* REG_CANNOT_CHANGE_MODE_P */
+
+#ifdef CANNOT_CHANGE_MODE_CLASS
/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
mode. */
Index: regrename.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regrename.c,v
retrieving revision 1.66
diff -u -p -r1.66 regrename.c
--- regrename.c 10 Apr 2003 05:24:26 -0000 1.66
+++ regrename.c 5 Jun 2003 12:14:47 -0000
@@ -1318,7 +1318,7 @@ mode_change_ok (orig_mode, new_mode, reg
if (GET_MODE_SIZE (orig_mode) < GET_MODE_SIZE (new_mode))
return false;
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode, new_mode);
#endif
Index: reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.213
diff -u -p -r1.213 reload.c
--- reload.c 2 May 2003 00:53:45 -0000 1.213
+++ reload.c 5 Jun 2003 12:15:21 -0000
@@ -1023,7 +1023,7 @@ push_reload (in, out, inloc, outloc, cla
SUBREG_REG (in))
== NO_REGS))
#endif
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P
@@ -1120,7 +1120,7 @@ push_reload (in, out, inloc, outloc, cla
SUBREG_REG (out))
== NO_REGS))
#endif
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)),
Index: reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.394
diff -u -p -r1.394 reload1.c
--- reload1.c 11 May 2003 02:15:24 -0000 1.394
+++ reload1.c 5 Jun 2003 12:16:08 -0000
@@ -5505,14 +5505,14 @@ choose_reload_regs (chain)
GET_MODE_CLASS (mode));
if (
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
(!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg),
need_mode)
&&
#endif
(GET_MODE_SIZE (GET_MODE (last_reg))
>= GET_MODE_SIZE (need_mode))
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
)
#endif
&& reg_reloaded_contents[i] == regno
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.141
diff -u -p -r1.141 simplify-rtx.c
--- simplify-rtx.c 3 May 2003 23:12:41 -0000 1.141
+++ simplify-rtx.c 5 Jun 2003 12:16:37 -0000
@@ -2910,7 +2910,7 @@ simplify_subreg (outermode, op, innermod
&& (! REG_FUNCTION_VALUE_P (op)
|| ! rtx_equal_function_value_matters)
&& REGNO (op) < FIRST_PSEUDO_REGISTER
-#ifdef CANNOT_CHANGE_MODE_CLASS
+#ifdef REG_CANNOT_CHANGE_MODE_P
&& ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), innermode, outermode)
&& GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT)
Index: config/sparc/sparc.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.h,v
retrieving revision 1.227
diff -u -p -r1.227 sparc.h
--- config/sparc/sparc.h 4 Jun 2003 06:52:13 -0000 1.227
+++ config/sparc/sparc.h 5 Jun 2003 12:17:05 -0000
@@ -1049,6 +1049,28 @@ extern int sparc_mode_class[];
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
((hard_regno_mode_classes[REGNO] & sparc_mode_class[MODE]) != 0)
+/* Given a hard REGNO, a FROM mode and a TO mode, return nonzero if
+ REGNO cannot change modes between the specified modes.
+
+ For v9, double- and quad-word floating-point operations are not split
+ into single-word operations since they are supported by the hardware
+ for sufficiently aligned registers. Given that we have no constraints
+ describing these alignment requirements, the register allocator must
+ be taught to have them right at the first go. In particular, when
+ allocating a register that is paradoxically subreged, it must take into
+ account the alignment requirements of the first register overlapped by
+ the subreg, since SPARC is big-endian. */
+
+#define REG_CANNOT_CHANGE_MODE_P(REGNO, FROM, TO) \
+ (TARGET_V9 \
+ && (REGNO_REG_CLASS (REGNO) == FP_REGS \
+ || REGNO_REG_CLASS (REGNO) == EXTRA_FP_REGS) \
+ && GET_MODE_SIZE (TO) > GET_MODE_SIZE (FROM) \
+ && ((GET_MODE_SIZE (TO) == 8 && (REGNO % 2) != 1) \
+ || (GET_MODE_SIZE (TO) == 16 \
+ && ((GET_MODE_SIZE (FROM) == 4 && (REGNO % 4) != 3) \
+ || (GET_MODE_SIZE (FROM) == 8 && (REGNO % 4) != 2)))))
+
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.227
diff -u -p -r1.227 tm.texi
--- doc/tm.texi 4 Jun 2003 05:21:40 -0000 1.227
+++ doc/tm.texi 5 Jun 2003 12:18:09 -0000
@@ -2625,6 +2625,17 @@ as below:
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
? reg_classes_intersect_p (FLOAT_REGS, (CLASS)) : 0)
@end example
+
+@item REG_CANNOT_CHANGE_MODE_P(@var{num}, @var{from}, @var{to})
+If defined, a C expression that returns nonzero for register number
+@var{num} for which a change from mode @var{from} to mode @var{to} is
+invalid. This macro is a refinement of the previous one, so it need not
+be defined if the latter is defined and has the right granularity.
+
+For example, on the SPARC, even-numbered floating-point registers can hold
+32-bit or 64-bit objects whereas odd-numbered floating-point registers can
+only hold 32-bit objects. But they all belong to the same class so this
+macro is needed in order to differentiate them.
@end table
Three other special macros describe which operands fit which constraint
/* PR optimization/10904 */
/* Originator: <kminola@eng.umd.edu> */
/* Verify that SPARC64 properly aligns its DFmode
FP regs in the presence of paradoxical subregs. */
extern void abort(void);
volatile int k;
int foo2(int v)
{
k = v;
}
void foo(int n, int b)
{
int i, a;
a = (long)(b * ((double) 0.1));
for (i=0; i < n; i++) {
foo2(a);
}
}
int main(void)
{
foo(1, 10);
if (k != 1)
abort();
return 0;
}