Bug 58668 - [4.8/4.9 regression] internal compiler error: in cond_exec_process_insns, at ifcvt.c:339
Summary: [4.8/4.9 regression] internal compiler error: in cond_exec_process_insns, at ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 4.8.1
: P2 normal
Target Milestone: 4.8.3
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-10-09 15:41 UTC by Sébastien Villemot
Modified: 2014-01-07 16:52 UTC (History)
2 users (show)

See Also:
Host:
Target: arm-linux-gnueabihf, arm-none-eabi
Build:
Known to work: 4.7.4
Known to fail: 4.8.2, 4.9.0
Last reconfirmed: 2013-10-10 00:00:00


Attachments
Preprocessed source to replicate the ICE (94.81 KB, text/x-csrc)
2013-10-09 15:41 UTC, Sébastien Villemot
Details
gcc49-pr58668.patch (1.33 KB, patch)
2013-12-18 11:05 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sébastien Villemot 2013-10-09 15:41:11 UTC
Created attachment 30969 [details]
Preprocessed source to replicate the ICE

See the attached preprocessed source for replicating the ICE.

Here are the compiler specs:

COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.8/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Debian 4.8.1-10' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 4.8.1 (Debian 4.8.1-10) 


Note that I was also able to replicate the ICE with a GCC snapshot from Sept 17, 2013. On the contrary, GCC 4.7.3 is not affected.
Comment 1 ktkachov 2013-10-09 17:24:56 UTC
Hmmm... I can't seem to reproduce it with current trunk and 4.8.2
Comment 2 ktkachov 2013-10-10 09:33:11 UTC
After trying out some option combinations, I managed to reproduce it on 4.8 and trunk. For me it ICEs with -O2, but works with -O3 _unless_ I add -fPIC, in which case it ICEs.
Comment 3 Richard Earnshaw 2013-10-10 09:48:32 UTC
cond_exec_process_insns is throwing a wobbly, since it is not expecting to handle a jump insn (in this case a return).

(jump_insn 62 61 51 4 (parallel [
            (return)
            (set/f (reg/f:SI 13 sp)
                (plus:SI (reg/f:SI 13 sp)
                    (const_int 16 [0x10])))
            (set/f (reg:SI 3 r3)
                (mem/c:SI (reg/f:SI 13 sp) [25 S4 A32]))
            (set/f (reg:SI 4 r4)
                (mem/c:SI (plus:SI (reg/f:SI 13 sp)
                        (const_int 4 [0x4])) [25 S4 A32]))
            (set/f (reg:SI 5 r5)
                (mem/c:SI (plus:SI (reg/f:SI 13 sp)
                        (const_int 8 [0x8])) [25 S4 A32]))
            (set/f (reg:SI 15 pc)
                (mem/c:SI (plus:SI (reg/f:SI 13 sp)
                        (const_int 12 [0xc])) [25 S4 A32]))
        ]) image.c:1709 -1
     (expr_list:REG_UNUSED (reg:SI 15 pc)
        (expr_list:REG_UNUSED (reg:SI 3 r3)
            (expr_list:REG_CFA_RESTORE (reg:SI 5 r5)
                (expr_list:REG_CFA_RESTORE (reg:SI 4 r4)
                    (expr_list:REG_CFA_RESTORE (reg:SI 3 r3)
                        (nil))))))
 -> return)

Seems to work with 4.7, so a regression.
Comment 4 Jakub Jelinek 2013-12-17 20:01:59 UTC
Reduced testcase, ICEs with -march=armv7-a -mthumb -O2:

void *fn1 (void *);
void *fn2 (void *, const char *);
void fn3 (void *);
void fn4 (void *, int);

void *
test (void *x)
{
  void *a, *b;
  if (!(a = fn1 (x)))
    return (void *) 0;
  if (!(b = fn2 (a, "w")))
    {
      fn3 (a);
      return (void *) 0;
    }
  fn3 (a);
  fn4 (b, 1);
  return b;
}
Comment 5 Jakub Jelinek 2013-12-17 21:14:00 UTC
I think the problem is that ifcvt relies on consistent counting of insns, but the various functions count different things.
- count_bb_insns counts CALL_INSN and INSN
- flow_find_cross_jump counts in some cases the jump insn (quite complicated test whether it counts it or not), and doesn't count insns with USE or CLOBBER PATTERNs
- flow_find_head_matching_sequence counts all CALL_INSN/INSN, including USE and CLOBBER
- first_active_insn finds what count_bb_insns counts
- last_active_insn (..., TRUE) finds what count_bb_insns except it skips over USE patterns

I guess best would be to count/skip/etc. the same things consistently, the problem is that some of the functions have other uses etc.

So, perhaps
1) let count_bb_insns not count insns with USE or CLOBBER PATTERNs
2) perhaps not count any JUMP_INSNs in flow_find_cross_jump if dir_p == NULL (i.e.
when called from ifcvt)?
3) perhaps not count USE/CLOBBER insns in flow_find_head_matching_sequence if
stop_after is non-zero?
4) perhaps add also skip_use argument to first_active_insn and if TRUE, ignore USE insns and for both {first,last}_active_insn if skip_use is TRUE, also
ignore CLOBBER insns
5) in find_active_insn_{before,after} ignore USE/CLOBBER insns
and document this properly?
Comment 6 Eric Botcazou 2013-12-18 09:39:35 UTC
> I think the problem is that ifcvt relies on consistent counting of insns,
> but the various functions count different things.

What kind of insns is responsible for the discrepancy that leads to the ICE?

> I guess best would be to count/skip/etc. the same things consistently, the
> problem is that some of the functions have other uses etc.

In any case, this would be a sensible approach.

> 1) let count_bb_insns not count insns with USE or CLOBBER PATTERNs

Agreed.

> 2) perhaps not count any JUMP_INSNs in flow_find_cross_jump if dir_p == NULL
> (i.e.
> when called from ifcvt)?
> 3) perhaps not count USE/CLOBBER insns in flow_find_head_matching_sequence if
> stop_after is non-zero?

I'd first make the functions behave the same wrt USE and CLOBBER insns.

> 4) perhaps add also skip_use argument to first_active_insn and if TRUE,
> ignore USE insns and for both {first,last}_active_insn if skip_use is TRUE,
> also ignore CLOBBER insns
>
> 5) in find_active_insn_{before,after} ignore USE/CLOBBER insns
> and document this properly?

I'm less sure about these ones: does their behavior need to be in keeping with the insns counting?
Comment 7 Jakub Jelinek 2013-12-18 09:51:56 UTC
(In reply to Eric Botcazou from comment #6)
> > I think the problem is that ifcvt relies on consistent counting of insns,
> > but the various functions count different things.
> 
> What kind of insns is responsible for the discrepancy that leads to the ICE?

On the given testcase the JUMP_INSN at the end of bb is returnjump_p (without additional side effects), so it isn't counted and thus that problem isn't present.  But the problem on the testcase is insn with USE pattern right before the jump, count_bb_insns counts it as active insn, flow_find_cross_jump doesn't, and we subtract from the former the latter to see how many insns we should allow at most for flow_find_head_matching_sequence, and because of the discrepancy it is one bigger than it should and we end up with
then_last_head being after then_end, which violates the assumptions the code makes.

> > 3) perhaps not count USE/CLOBBER insns in flow_find_head_matching_sequence if
> > stop_after is non-zero?
> 
> I'd first make the functions behave the same wrt USE and CLOBBER insns.

Perhaps we can ignore those always in flow_find_head_matching_sequence?
 
> > 4) perhaps add also skip_use argument to first_active_insn and if TRUE,
> > ignore USE insns and for both {first,last}_active_insn if skip_use is TRUE,
> > also ignore CLOBBER insns
> >
> > 5) in find_active_insn_{before,after} ignore USE/CLOBBER insns
> > and document this properly?
> 
> I'm less sure about these ones: does their behavior need to be in keeping
> with the insns counting?

Perhaps, though I'd say it might be a ticking bomb.
Comment 8 Eric Botcazou 2013-12-18 10:07:17 UTC
> Perhaps we can ignore those always in flow_find_head_matching_sequence?

Yes, that seems to be the most sensible thing to do, so that count_bb_insns, flow_find_cross_jump and flow_find_head_matching_sequence agree about them.

> Perhaps, though I'd say it might be a ticking bomb.

If the bomb would be an ICE, that's good enough for now in my opinion.
Comment 9 Jakub Jelinek 2013-12-18 11:05:25 UTC
Created attachment 31466 [details]
gcc49-pr58668.patch

So like this?  Note, the USE/CLOBBER change for flow_find_cross_jump
has been added in 2011 for 4.7 as PR43920 fix: http://gcc.gnu.org/ml/gcc-patches/2011-03/msg02246.html
Comment 10 Eric Botcazou 2013-12-18 11:20:05 UTC
> So like this?  Note, the USE/CLOBBER change for flow_find_cross_jump
> has been added in 2011 for 4.7 as PR43920 fix:
> http://gcc.gnu.org/ml/gcc-patches/2011-03/msg02246.html

Yes, let's try that, but use the same idiom in flow_find_cross_jump as yours (i.e. remove the useless p1) added by the above fix so that your patch will
have an explicit link to the above fix.
Comment 11 Jakub Jelinek 2014-01-07 07:54:50 UTC
Author: jakub
Date: Tue Jan  7 07:54:47 2014
New Revision: 206385

URL: http://gcc.gnu.org/viewcvs?rev=206385&root=gcc&view=rev
Log:
	PR rtl-optimization/58668
	* cfgcleanup.c (flow_find_cross_jump): Don't count
	any jumps if dir_p is NULL.  Remove p1 variable, use active_insn_p
	to determine what is counted.
	(flow_find_head_matching_sequence): Use active_insn_p to determine
	what is counted.
	(try_head_merge_bb): Adjust for the flow_find_head_matching_sequence
	counting change.
	* ifcvt.c (count_bb_insns): Use active_insn_p && !JUMP_P to
	determine what is counted.

	* gcc.dg/pr58668.c: New test.

Added:
    trunk/gcc/testsuite/gcc.dg/pr58668.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/cfgcleanup.c
    trunk/gcc/ifcvt.c
    trunk/gcc/testsuite/ChangeLog
Comment 12 Jakub Jelinek 2014-01-07 16:51:19 UTC
Author: jakub
Date: Tue Jan  7 16:51:16 2014
New Revision: 206398

URL: http://gcc.gnu.org/viewcvs?rev=206398&root=gcc&view=rev
Log:
	PR rtl-optimization/58668
	* cfgcleanup.c (flow_find_cross_jump): Don't count
	any jumps if dir_p is NULL.  Remove p1 variable and make USE/CLOBBER
	check consistent with other places.
	(flow_find_head_matching_sequence): Don't count USE or CLOBBER insns.
	(try_head_merge_bb): Adjust for the flow_find_head_matching_sequence
	counting change.
	* ifcvt.c (count_bb_insns): Don't count USE or CLOBBER insns.

	* gcc.dg/pr58668.c: New test.

Added:
    branches/gcc-4_8-branch/gcc/testsuite/gcc.dg/pr58668.c
Modified:
    branches/gcc-4_8-branch/gcc/ChangeLog
    branches/gcc-4_8-branch/gcc/cfgcleanup.c
    branches/gcc-4_8-branch/gcc/ifcvt.c
    branches/gcc-4_8-branch/gcc/testsuite/ChangeLog
Comment 13 Jakub Jelinek 2014-01-07 16:52:53 UTC
Hopefully fixed.