Patch http://gcc.gnu.org/ml/gcc-patches/2012-12/msg01229.html introduced
this ICE:
1. thumb1 estimate if far_jump is used based on function insn size
2. During reload, after stack layout finalized, it does reload_as_needed. It
however increases insn size that changes estimation result of far_jump,
which in return need to save lr and change stack layout again. While there
is not chance to change, GCC crashes.
Solution:
Do not change estimation result of far_jump if reload_in_progress or
reload_completed is true.
Not likely need to fix lra according to Vlad:
http://gcc.gnu.org/ml/gcc/2014-02/msg00355.html
ChangeLog:
* config/arm/arm.c (thumb_far_jump_used_p): Don't change
if reload in progress or completed.
* gcc.target/arm/thumb1-far-jump-3.c: New case.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index b562986..2cf362c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -26255,6 +26255,11 @@ thumb_far_jump_used_p (void)
return 0;
}
+ /* We should not change far_jump_used during or after reload, as there is
+ no chance to change stack frame layout. */
+ if (reload_in_progress || reload_completed)
+ return 0;
+
/* Check to see if the function contains a branch
insn with the far jump attribute set. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
diff --git a/gcc/testsuite/gcc.target/arm/thumb1-far-jump-3.c
b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-3.c
new file mode 100644
index 0000000..90559ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-3.c
@@ -0,0 +1,108 @@
+/* Catch reload ICE on target thumb1 with far jump optimization.
+ * It is also a valid case for non-thumb1 target. */
+
+/* Add -mno-lra option as it is only reproducable with reload. It will
+ be removed after reload is completely removed. */
+/* { dg-options "-mno-lra -fomit-frame-pointer" } */
+/* { dg-do compile } */
+
+#define C 2
+#define A 4
+#define RGB (C | A)
+#define GRAY (A)
+
+typedef unsigned long uint_32;
+typedef unsigned char byte;
+typedef byte * bytep;
+
+typedef struct ss
+{
+ uint_32 w;
+ uint_32 r;
+ byte c;
+ byte b;
+ byte p;
+} info;
+
+typedef info * infop;
+
+void
+foo(infop info, bytep row)
+{
+ uint_32 iw = info->w;
+ if (info->c == RGB)
+ {
+ if (info->b == 8)
+ {
+ bytep sp = row + info->r;
+ bytep dp = sp;
+ byte save;
+ uint_32 i;
+
+ for (i = 0; i < iw; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+
+ else
+ {
+ bytep sp = row + info->r;
+ bytep dp = sp;
+ byte save[2];
+ uint_32 i;
+
+ for (i = 0; i < iw; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ else if (info->c == GRAY)
+ {
+ if (info->b == 8)
+ {
+ bytep sp = row + info->r;
+ bytep dp = sp;
+ byte save;
+ uint_32 i;
+
+ for (i = 0; i < iw; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ else
+ {
+ bytep sp = row + info->r;
+ bytep dp = sp;
+ byte save[2];
+ uint_32 i;
+
+ for (i = 0; i < iw; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+}