This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Problems with sh mode switching code at -O0
- To: gcc-patches at gcc dot gnu dot org
- Subject: Problems with sh mode switching code at -O0
- From: Bernd Schmidt <bernds at redhat dot com>
- Date: Wed, 15 Nov 2000 13:00:30 +0000 (GMT)
The sh port fails to compile some files correctly at -O0. An example is
execute/930622-2.c; compilation flags to use are "-O0 -m4-single".
The problem is that we've started doing a bit of optimization even at -O0,
and this exposed a latent problem with the sh port. Floating point
instructions on the sh depend on the value of a certain control register.
At -O0, the functions emit_sf_insn and emit_df_insn wrap each floating point
insn (even moves) with a save/restore sequence for the control register.
At higher optimization levels, we use a more clever approach using the
optimize_mode_switching pass.
The problem is that the movsf pattern expands into a multi-insn sequence,
and the last insn in it does not set the target of the movsf. This causes
emit_libcall_block to emit bogus code. This was harmless until we started
doing some optimizations at -O0; now it means that sometimes a libcall will
be discarded due to the incorrect REG_RETVAL/REG_LIBCALL notes.
There are a couple of alternatives how to fix it. We could always run
optimize_mode_switching and get rid of emit_sf_insn/emit_df_insn. This
is my preferred solution and implemented by patch #1 below. However, I
don't know how fast that pass is; it may well be unacceptable at -O0.
Alternatively, we could try to make emit_libcall_block detect the situation.
This is patch #2. There are more possibilities (e.g. don't make libcall
blocks at -O0), but these two are IMO the only ones that make sense.
Bernd
Patch #1:
* toplev.c (rest_of_compilation): Run optimize_mode_switching even
if not optimizing.
* sh.c (emit_sf_insn, emit_df_insn): Just call emit_insn.
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.395
diff -u -p -r1.395 toplev.c
--- toplev.c 2000/11/10 11:43:42 1.395
+++ toplev.c 2000/11/14 14:09:07
@@ -3340,20 +3340,17 @@ rest_of_compilation (decl)
register_life_up_to_date = 0;
#ifdef OPTIMIZE_MODE_SWITCHING
- if (optimize)
- {
- timevar_push (TV_GCSE);
-
- if (optimize_mode_switching (NULL_PTR))
- {
- /* We did work, and so had to regenerate global life information.
- Take advantage of this and don't re-recompute register life
- information below. */
- register_life_up_to_date = 1;
- }
+ timevar_push (TV_GCSE);
- timevar_pop (TV_GCSE);
+ if (optimize_mode_switching (NULL_PTR))
+ {
+ /* We did work, and so had to regenerate global life information.
+ Take advantage of this and don't re-recompute register life
+ information below. */
+ register_life_up_to_date = 1;
}
+
+ timevar_pop (TV_GCSE);
#endif
#ifdef INSN_SCHEDULING
Index: config/sh/sh.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sh/sh.c,v
retrieving revision 1.70
diff -u -p -r1.70 sh.c
--- sh.c 2000/11/09 07:45:15 1.70
+++ sh.c 2000/11/14 14:09:09
@@ -5014,38 +5014,14 @@ void
emit_sf_insn (pat)
rtx pat;
{
- rtx addr;
- /* When generating reload insns, we must not create new registers. FPSCR
- should already have the correct value, so do nothing to change it. */
- if (! TARGET_FPU_SINGLE && ! reload_in_progress && optimize < 1)
- {
- addr = gen_reg_rtx (SImode);
- emit_insn (gen_fpu_switch0 (addr));
- }
emit_insn (pat);
- if (! TARGET_FPU_SINGLE && ! reload_in_progress && optimize < 1)
- {
- addr = gen_reg_rtx (SImode);
- emit_insn (gen_fpu_switch1 (addr));
- }
}
void
emit_df_insn (pat)
rtx pat;
{
- rtx addr;
- if (TARGET_FPU_SINGLE && ! reload_in_progress && optimize < 1)
- {
- addr = gen_reg_rtx (SImode);
- emit_insn (gen_fpu_switch0 (addr));
- }
emit_insn (pat);
- if (TARGET_FPU_SINGLE && ! reload_in_progress && optimize < 1)
- {
- addr = gen_reg_rtx (SImode);
- emit_insn (gen_fpu_switch1 (addr));
- }
}
void
Patch #2:
* optabs.c (emit_libcall_block): Try to detect if final move insn
doesn't set TARGET and avoid making libcall notes if so.
Index: optabs.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/optabs.c,v
retrieving revision 1.84
diff -u -p -r1.84 optabs.c
--- optabs.c 2000/10/18 21:33:40 1.84
+++ optabs.c 2000/11/14 14:15:57
@@ -2873,6 +2873,16 @@ emit_libcall_block (insns, target, resul
}
last = emit_move_insn (target, result);
+
+ if (final_dest != target)
+ emit_move_insn (final_dest, target);
+
+ /* If the final move insn doesn't copy the target register, something
+ funny is going on. Making a libcall block here would lead to
+ incorrect code. */
+ if (! reg_overlap_mentioned_p (target, PATTERN (last)))
+ return;
+
if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
!= CODE_FOR_nothing)
set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
@@ -2885,9 +2895,6 @@ emit_libcall_block (insns, target, resul
"last". */
remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
}
-
- if (final_dest != target)
- emit_move_insn (final_dest, target);
if (prev == 0)
first = get_insns ();