This was something my tester was tripping over on h8-elf.  I was hoping
it was going to fix the similar ICEs for the SH port, but alas those are
different.

The fundamental problem is generic code generated something like this:

(set (temp) (plus (stack_pointer_rtx) (const_int))
(set (stack_pointer_rtx) (temp))  REG_ARGS_SIZE note


The backward propagation step in cse.c turns the first insn into:

(set (stack_pointer_rtx) (plus (stack_pointer_rtx) (const_int))

And the second insn gets deleted, losing the REG_ARGS_SIZE note.

We then cross jump the tail of that block with the tail of another block
which has REG_ARGS_SIZE notes that do not get deleted.

The net result is at the commonized tail we have two paths which
different notions of REG_ARGS_SIZE and thus different CFIs, triggering
the ICE.

The most sensible way to fix this is to move the REG_ARGS_SIZE note
during the backward propagation step in cse.c

That allows the H8 port to build libgcc/newlib across all its multilib
variants.

I've also bootstrapped and regression tested on x86_64-linux-gnu, though
I doubt it really got exercised there.

Installing on the trunk.  Now back to the SH, rx and mips problems with
maybe_record_trace_start.

Jeff

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5a264391268..d5913d0a7db 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2018-02-12  Jeff Law  <l...@redhat.com>
+
+       * cse.c (try_back_substitute_reg): Move any REG_ARGS_SIZE note when
+       successfully back substituting a reg.
+
 2018-02-12  Richard Biener  <rguent...@suse.de>
 
        PR tree-optimization/84037
diff --git a/gcc/cse.c b/gcc/cse.c
index 825b0bd8989..a73a771041a 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -4256,6 +4256,15 @@ try_back_substitute_reg (rtx set, rtx_insn *insn)
                  && (reg_mentioned_p (dest, XEXP (note, 0))
                      || rtx_equal_p (src, XEXP (note, 0))))
                remove_note (insn, note);
+
+             /* If INSN has a REG_ARGS_SIZE note, move it to PREV.  */
+             note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
+             if (note != 0)
+               {
+                 remove_note (insn, note);
+                 gcc_assert (!find_reg_note (prev, REG_ARGS_SIZE, NULL_RTX));
+                 set_unique_reg_note (prev, REG_ARGS_SIZE, XEXP (note, 0));
+               }
            }
        }
     }
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index dba0bedb7cf..8f22a65c7bb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2018-02-12  Jeff Law  <l...@redhat.com>
+
+       * gcc.c-torture/compile/reg-args-size.c: New test.
+
 2018-02-12  Carl Love  <c...@us.ibm.com>
 
        * gcc.target/powerpc/builtins-4-runnable.c (main): Move int128 and
diff --git a/gcc/testsuite/gcc.c-torture/compile/regs-arg-size.c 
b/gcc/testsuite/gcc.c-torture/compile/regs-arg-size.c
new file mode 100644
index 00000000000..0ca0b9f034b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/regs-arg-size.c
@@ -0,0 +1,36 @@
+int foo;
+typedef long unsigned int size_t;
+typedef short unsigned int wchar_t;
+struct tm
+{
+  int tm_mday;
+  int tm_mon;
+  int tm_year;
+};
+size_t
+__strftime (wchar_t * s, size_t maxsize, const wchar_t * format, const struct 
tm *tim_p)
+{
+  size_t count = 0;
+  int len = 0;
+  size_t i, ctloclen;
+  unsigned long width;
+  {
+    if (foo)
+      {
+       {
+         wchar_t *fmt = L"%s%.*d";
+         len = swprintf (&s[count], maxsize, fmt, "-", width, 0);
+       }
+       if ((count) >= maxsize)
+         return 0;
+      }
+    else
+      {
+       len =
+         swprintf (&s[count], maxsize - count, L"%.2d/%.2d/%.2d", 42, 99, 0);
+       if ((count) >= maxsize)
+         return 0;
+
+      }
+  }
+}

Reply via email to