There's a subtle bug in reorg.c's relax_delay_slots that my tester tripped this weekend. Not sure what changed code generation wise as the affected port built just fine last week. But it is what is is.



Assume before this code we've set TARGET_LABEL to the code_label associated with DELAY_JUMP_INSN (which is what we want)...



     /* If the first insn at TARGET_LABEL is redundant with a previous
         insn, redirect the jump to the following insn and process again.
         We use next_real_insn instead of next_active_insn so we
         don't skip USE-markers, or we'll end up with incorrect
         liveness info.  */

[ ... ]

     /* Similarly, if it is an unconditional jump with one insn in its
         delay list and that insn is redundant, thread the jump.  */
      rtx_sequence *trial_seq =
        trial ? dyn_cast <rtx_sequence *> (PATTERN (trial)) : NULL;
      if (trial_seq
          && trial_seq->len () == 2
          && JUMP_P (trial_seq->insn (0))
          && simplejump_or_return_p (trial_seq->insn (0))
          && redundant_insn (trial_seq->insn (1), insn, vNULL))
        {
          target_label = JUMP_LABEL (trial_seq->insn (0));
          if (ANY_RETURN_P (target_label))
            target_label = find_end_label (target_label);

          if (target_label
              && redirect_with_delay_slots_safe_p (delay_jump_insn,
                                                   target_label, insn))
            {
              update_block (trial_seq->insn (1), insn);
              reorg_redirect_jump (delay_jump_insn, target_label);
              next = insn;
              continue;
            }
        }

      /* See if we have a simple (conditional) jump that is useless.  */
      if (! INSN_ANNULLED_BRANCH_P (delay_jump_insn)
          && ! condjump_in_parallel_p (delay_jump_insn)
          && prev_active_insn (as_a<rtx_insn *> (target_label)) == insn

Now assume that we get into the TRUE arm of that first conditional which sets a new value for TARGET_LABEL. Normally when this happens in relax_delay_slots we're going to unconditionally continue. But as we can see there's an inner conditional and if we don't get into its true arm, then we'll pop out a nesting level and execute the second outer IF.

That second outer IF assumes that TARGET_LABEL still points to the code label associated with DELAY_JUMP_INSN. Opps. In my particular case it was NULL and caused an ICE. But I could probably construct a case where it pointed to a real label and could result in incorrect code generation.

The fix is pretty simple. Just creating a new variable (to avoid -Wshadow) inside that first outer IF is sufficient.

Tested by building the affected target (mipsisa64r2el-elf) through newlib.

Installed on the trunk.

jeff
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8cceb247a85..18b6ed59c73 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,8 @@
 2017-05-15  Jeff Law  <l...@redhat.com>
 
+       * reorg.c (relax_delay_slots): Create a new variable to hold
+       the temporary target rather than clobbering TARGET_LABEL.
+
        * config/tilegx/tilegx.c (tilegx_expand_unaligned_load): Add
        missing argument to extract_bit_field call.
        * config/tilepro/tilepro.c (tilepro_expand_unaligned_load): Likewise.
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 85ef7d6880c..1a6fd86e286 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -3351,16 +3351,16 @@ relax_delay_slots (rtx_insn *first)
          && simplejump_or_return_p (trial_seq->insn (0))
          && redundant_insn (trial_seq->insn (1), insn, vNULL))
        {
-         target_label = JUMP_LABEL (trial_seq->insn (0));
-         if (ANY_RETURN_P (target_label))
-           target_label = find_end_label (target_label);
+         rtx temp_label = JUMP_LABEL (trial_seq->insn (0));
+         if (ANY_RETURN_P (temp_label))
+           temp_label = find_end_label (temp_label);
          
-         if (target_label
+         if (temp_label
              && redirect_with_delay_slots_safe_p (delay_jump_insn,
-                                                  target_label, insn))
+                                                  temp_label, insn))
            {
              update_block (trial_seq->insn (1), insn);
-             reorg_redirect_jump (delay_jump_insn, target_label);
+             reorg_redirect_jump (delay_jump_insn, temp_label);
              next = insn;
              continue;
            }
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f198fc6b42b..9fb8c8598b8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2017-05-15  Jeff Law  <l...@redhat.com>
+
+       * gcc.target/mips/reorgbug-1.c: New test.
+
 2017-05-15  Pierre-Marie de Rodat  <dero...@adacore.com>
 
        * gnat.dg/specs/pack13.ads: New test.
diff --git a/gcc/testsuite/gcc.target/mips/reorgbug-1.c 
b/gcc/testsuite/gcc.target/mips/reorgbug-1.c
new file mode 100644
index 00000000000..b820a2b5df1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/reorgbug-1.c
@@ -0,0 +1,39 @@
+/* { dg-options "-O2 -msoft-float -mips2" } */
+
+typedef long int __int32_t;
+typedef long unsigned int __uint32_t;
+typedef union
+{
+  double value;
+  struct
+  {
+    __uint32_t msw;
+    __uint32_t lsw;
+  }
+  parts;
+}
+ieee_double_shape_type;
+double
+__ieee754_fmod (double x, double y, int z, int xx)
+{
+  __int32_t n, hx, hy, hz, ix, iy, sx, i;
+  __uint32_t lx, ly, lz;
+  ieee_double_shape_type ew_u;
+  ew_u.value = (x);
+  (lx) = ew_u.parts.lsw;
+  ew_u.value = (y);
+  (hy) = ew_u.parts.msw;
+  (ly) = ew_u.parts.lsw;
+  if (hy == 0 || hx >= 0x7ff00000)
+    return (x * y);
+  if (z)
+    {
+      if ((hx < hy) || (lx < ly))
+       return x;
+      lz = lx - ly;
+      lx = lz + lz;
+    }
+  ieee_double_shape_type iw_u;
+  iw_u.parts.lsw = (lx);
+  return iw_u.value;
+}

Reply via email to