Hi all,

The ICE in this PR occurs when initialising the reginfo for the ira_costs for 
an instruction of the form:
(insn 6 15 16 2 (set (subreg:V2DI (reg/v:EI 111 [ b ]) 0)
        (const_vector:V2DI [
                (const_int 1 [0x1])
                (const_int 1 [0x1])
            ])) mycrash.c:10 861 {*neon_movv2di}
     (nil))

we're talking about (subreg:V2DI (reg/v:EI 111 [ b ]) 0).
EImode is a 24 byte arm-specific integer mode used to represent 3 D-registers.

record_subregs_of_mode in reginfo.c analyses not just the subreg at offset 0 as 
requested
but also the adjacent V2DI subreg i.e. at offset 16. However, there cannot be a 
second V2DI 16-byte
subreg because EImode is only 24 bytes wide, so we get an ICE in 
subreg_get_info to that effect.

I'm not familiar with the processes in that part of the code but my suspicion 
is that we should be
rejecting that invalid subreg somewhere and this patch does that in 
subreg_get_info a few lines before
the triggering assert. It rejects the subreg by setting info->representable_p 
to false.

This fixes the ICE for me on ARM (reproducible at -O3) and doesn't show any 
regressions on aarch64 and x86_64.

Is this the right way to go around fixing this?

Thanks,
Kyrill

2016-05-31  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    PR rtl-optimization/71295
    * rtlanal.c (subreg_get_info): If taking a subreg at the requested
    offset would go over the size of the inner mode reject it.

2016-05-31  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    PR rtl-optimization/71295
    * gcc.c-torture/compile/pr71295.c: New test.
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index bfefd968b47c530c77c50d72ce42f4a6d4955ea4..6ab96889408bc09815f5490532657ffcecf5c52e 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3657,6 +3657,16 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
 	  info->offset = offset / regsize_xmode;
 	  return;
 	}
+      /* It's not valid to extract a subreg of mode YMODE at OFFSET that
+	 would go outside of XMODE.  */
+      if (!rknown
+	  && GET_MODE_SIZE (ymode) + offset > GET_MODE_SIZE (xmode))
+	{
+	  info->representable_p = false;
+	  info->nregs = nregs_ymode;
+	  info->offset = offset / regsize_xmode;
+	  return;
+	}
       /* Quick exit for the simple and common case of extracting whole
 	 subregisters from a multiregister value.  */
       /* ??? It would be better to integrate this into the code below,
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr71295.c b/gcc/testsuite/gcc.c-torture/compile/pr71295.c
new file mode 100644
index 0000000000000000000000000000000000000000..d2ec852fd08b307da50bfd993a6c43d42f303037
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr71295.c
@@ -0,0 +1,12 @@
+extern void fn2 (long long);
+int a;
+
+void
+fn1 ()
+{
+  long long b[3];
+  a = 0;
+  for (; a < 3; a++)
+    b[a] = 1;
+  fn2 (b[1]);
+}

Reply via email to