Bug 94001 - [10 Regression] ICE: in fold_convert_loc, at fold-const.c:2435 at -O2
Summary: [10 Regression] ICE: in fold_convert_loc, at fold-const.c:2435 at -O2
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: 10.0
Assignee: Jakub Jelinek
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks:
 
Reported: 2020-03-02 11:48 UTC by Zdenek Sojka
Modified: 2020-03-17 18:56 UTC (History)
1 user (show)

See Also:
Host: x86_64-pc-linux-gnu
Target: {riscv64,sparc64,powerpc64,aarch64}-unknown-linux-gnu
Build:
Known to work:
Known to fail: 10.0
Last reconfirmed: 2020-03-02 00:00:00


Attachments
reduced testcase (125 bytes, text/plain)
2020-03-02 11:48 UTC, Zdenek Sojka
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Zdenek Sojka 2020-03-02 11:48:25 UTC
Created attachment 47945 [details]
reduced testcase

This affects several targets, but I failed to reproduce this on x86_64.

Compiler output:
$ riscv64-unknown-linux-gnu-gcc -O2 testcase.c
during GIMPLE pass: tailr
testcase.c: In function 'bar.isra':
testcase.c:4:1: internal compiler error: in fold_convert_loc, at fold-const.c:2435
    4 | bar (unsigned char e)
      | ^~~
0x631c58 fold_convert_loc(unsigned int, tree_node*, tree_node*)
        /repo/gcc-trunk/gcc/fold-const.c:2435
0x10e6d1c update_accumulator_with_ops
        /repo/gcc-trunk/gcc/tree-tailcall.c:832
0x10e9261 adjust_accumulator_values
        /repo/gcc-trunk/gcc/tree-tailcall.c:877
0x10e9261 eliminate_tail_call
        /repo/gcc-trunk/gcc/tree-tailcall.c:1018
0x10e9261 optimize_tail_call
        /repo/gcc-trunk/gcc/tree-tailcall.c:1041
0x10e9261 tree_optimize_tail_calls_1
        /repo/gcc-trunk/gcc/tree-tailcall.c:1178
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

$ riscv64-unknown-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=/repo/gcc-trunk/binary-latest-riscv64/bin/riscv64-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/repo/gcc-trunk/binary-trunk-20200301175845-g649e174102a-checking-yes-rtl-df-extra-riscv64/bin/../libexec/gcc/riscv64-unknown-linux-gnu/10.0.1/lto-wrapper
Target: riscv64-unknown-linux-gnu
Configured with: /repo/gcc-trunk//configure --enable-languages=c,c++ --enable-valgrind-annotations --disable-nls --enable-checking=yes,rtl,df,extra --with-cloog --with-ppl --with-isl --with-sysroot=/usr/riscv64-unknown-linux-gnu --build=x86_64-pc-linux-gnu --host=x86_64-pc-linux-gnu --target=riscv64-unknown-linux-gnu --with-ld=/usr/bin/riscv64-unknown-linux-gnu-ld --with-as=/usr/bin/riscv64-unknown-linux-gnu-as --disable-multilib --disable-libstdcxx-pch --prefix=/repo/gcc-trunk//binary-trunk-20200301175845-g649e174102a-checking-yes-rtl-df-extra-riscv64
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.0.1 20200302 (experimental) (GCC)
Comment 1 Martin Liška 2020-03-02 13:09:15 UTC
I'm bisecting that right now.
Comment 2 Martin Liška 2020-03-02 13:21:31 UTC
Started with r10-3542-g0b92cf305dcf34387a8e2564e55ca8948df3b47a, so it was probably a latent issue.
Comment 3 Jakub Jelinek 2020-03-03 18:37:22 UTC
Even
void
bar (unsigned char e)
{
  bar (3);
  unsigned char c;
  c = -e;
}
ICEs with -O2 -fno-tree-dce the same way.  So, the question is:
1) why on the #c0 testcase doesn't DCE do its job
2) why does the tailr pass consider it something that needs to be accumulated (in a void temporary)
Comment 4 Jakub Jelinek 2020-03-03 19:28:52 UTC
--- gcc/tree-tailcall.c.jj	2020-01-12 11:54:38.517381665 +0100
+++ gcc/tree-tailcall.c	2020-03-03 20:22:17.324133660 +0100
@@ -339,7 +339,8 @@ process_assignment (gassign *stmt,
 	   && (non_ass_var = independent_of_stmt_p (op1, stmt, call,
 						    to_move)))
     ;
-  else if (op1 == *ass_var
+  else if (*ass_var
+	   && op1 == *ass_var
 	   && (non_ass_var = independent_of_stmt_p (op0, stmt, call,
 						    to_move)))
     ;

For the void calls *ass_var is NULL and if we have an UNARY_RHS assignment, op1 is also NULL and so will appear to match, while it shouldn't.
Comment 5 GCC Commits 2020-03-04 08:03:29 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:8e480ec1ddb307150cb36cf610b9eeab591de216

commit r10-7009-g8e480ec1ddb307150cb36cf610b9eeab591de216
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Mar 4 09:01:59 2020 +0100

    tailcall: Fix up process_assignment [PR94001]
    
    When a function returns void or the return value is ignored, ass_var
    is NULL_TREE.  The tail recursion handling generally assumes DCE has been
    performed and so doesn't expect to encounter useless assignments after the
    call and expects them to be part of the return value adjustment that need
    to be changed into tail recursion additions/multiplications.
    process_assignment does some verification and has a way to tell the caller
    to try to move dead or whatever other stmts that don't participate in the
    return value modifications before it is returned.
    For binary rhs assignments it is just fine, neither op0 nor op1 will be
    NULL_TREE and thus if *ass_var is NULL_TREE, it will not match, but unary
    rhs is handled by only setting op0 to rhs1 and setting op1 to NULL_TREE.
    And at this point, NULL_TREE == NULL_TREE and thus we think e.g. the
      c_2 = -e_3(D);
    dead stmt is actually a return value modification, so we queue it as
    multiplication and then create a void type SSA_NAME accumulator for it
    and ICE shortly after.
    
    Fixed by making sure op1 == *ass_var comparison is done only if *ass_var.
    
    2020-03-04  Jakub Jelinek  <jakub@redhat.com>
    
    	PR tree-optimization/94001
    	* tree-tailcall.c (process_assignment): Before comparing op1 to
    	*ass_var, verify *ass_var is non-NULL.
    
    	* gcc.dg/pr94001.c: New test.
Comment 6 Jakub Jelinek 2020-03-04 08:05:46 UTC
Fixed.
Comment 7 GCC Commits 2020-03-17 18:56:49 UTC
The releases/gcc-9 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:5de0dc84c75a43f78a03c7cdb7e7c443c641a7fa

commit r9-8385-g5de0dc84c75a43f78a03c7cdb7e7c443c641a7fa
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Mar 4 09:01:59 2020 +0100

    tailcall: Fix up process_assignment [PR94001]
    
    When a function returns void or the return value is ignored, ass_var
    is NULL_TREE.  The tail recursion handling generally assumes DCE has been
    performed and so doesn't expect to encounter useless assignments after the
    call and expects them to be part of the return value adjustment that need
    to be changed into tail recursion additions/multiplications.
    process_assignment does some verification and has a way to tell the caller
    to try to move dead or whatever other stmts that don't participate in the
    return value modifications before it is returned.
    For binary rhs assignments it is just fine, neither op0 nor op1 will be
    NULL_TREE and thus if *ass_var is NULL_TREE, it will not match, but unary
    rhs is handled by only setting op0 to rhs1 and setting op1 to NULL_TREE.
    And at this point, NULL_TREE == NULL_TREE and thus we think e.g. the
      c_2 = -e_3(D);
    dead stmt is actually a return value modification, so we queue it as
    multiplication and then create a void type SSA_NAME accumulator for it
    and ICE shortly after.
    
    Fixed by making sure op1 == *ass_var comparison is done only if *ass_var.
    
    2020-03-04  Jakub Jelinek  <jakub@redhat.com>
    
            PR tree-optimization/94001
            * tree-tailcall.c (process_assignment): Before comparing op1 to
            *ass_var, verify *ass_var is non-NULL.
    
            * gcc.dg/pr94001.c: New test.