diff options
author | David Malcolm <dmalcolm@redhat.com> | 2018-02-09 01:07:11 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2018-02-09 01:07:11 +0000 |
commit | 6d3aa24cd6535dcfc9f0701579eca53aa191768c (patch) | |
tree | f9732b16bca50b2d1c3b4ad86f5e65d8fe28c988 /gcc | |
parent | 7e64287b36bc9501cf8e214367b6d4dcfeeaae46 (diff) | |
download | gcc-6d3aa24cd6535dcfc9f0701579eca53aa191768c.zip gcc-6d3aa24cd6535dcfc9f0701579eca53aa191768c.tar.gz gcc-6d3aa24cd6535dcfc9f0701579eca53aa191768c.tar.bz2 |
Fix ICE in find_taken_edge_computed_goto (PR 84136)
PR 84136 reports an ICE within sccvn_dom_walker when handling a
C/C++ source file that overuses the labels-as-values extension.
The code in question stores a jump label into a global, and then
jumps to it from another function, which ICEs after inlining:
void* a;
void foo() {
if ((a = &&l))
return;
l:;
}
int main() {
foo();
goto *a;
return 0;
}
This appears to be far beyond what we claim to support in this
extension - but we shouldn't ICE.
What's happening is that, after inlining, we have usage of a *copy*
of the label, which optimizes away the if-return logic, turning it
into an infinite loop.
On entry to the sccvn_dom_walker we have this gimple:
main ()
{
void * a.0_1;
<bb 2> [count: 0]:
a = &l;
<bb 3> [count: 0]:
l:
a.0_1 = a;
goto a.0_1;
}
and:
edge taken = find_taken_edge (bb, vn_valueize (val));
reasonably valueizes the:
goto a.0_1;
after the:
a = &l;
a.0_1 = a;
as if it were:
goto *&l;
find_taken_edge_computed_goto then has:
2380 dest = label_to_block (val);
2381 if (dest)
2382 {
2383 e = find_edge (bb, dest);
2384 gcc_assert (e != NULL);
2385 }
which locates dest as a self-jump from block 3 back to itself.
However, the find_edge call returns NULL - it has a predecessor edge
from block 2, but no successor edges.
Hence the assertion fails and we ICE.
A successor edge from the computed goto could have been created by
make_edges if the label stmt had been in the function, but make_edges
only looks in the current function when handling computed gotos, and
the label only appeared after inlining.
The following patch removes the assertion, fixing the ICE.
gcc/testsuite/ChangeLog:
PR tree-optimization/84136
* gcc.c-torture/compile/pr84136.c: New test.
gcc/ChangeLog:
PR tree-optimization/84136
* tree-cfg.c (find_taken_edge_computed_goto): Remove assertion
that the result of find_edge is non-NULL.
From-SVN: r257509
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/pr84136.c | 15 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 12 |
4 files changed, 34 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dd78a34..8212952 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2018-02-08 David Malcolm <dmalcolm@redhat.com> + + PR tree-optimization/84136 + * tree-cfg.c (find_taken_edge_computed_goto): Remove assertion + that the result of find_edge is non-NULL. + 2018-02-08 Sergey Shalnov <sergey.shalnov@intel.com> PR target/83008 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d9ed50c..dfa8cb8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-02-08 David Malcolm <dmalcolm@redhat.com> + + PR tree-optimization/84136 + * gcc.c-torture/compile/pr84136.c: New test. + 2018-02-08 Sergey Shalnov <sergey.shalnov@intel.com> PR target/83008 diff --git a/gcc/testsuite/gcc.c-torture/compile/pr84136.c b/gcc/testsuite/gcc.c-torture/compile/pr84136.c new file mode 100644 index 0000000..0a70e4e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr84136.c @@ -0,0 +1,15 @@ +void* a; + +void foo() { + if ((a = &&l)) + return; + + l:; +} + +int main() { + foo(); + goto *a; + + return 0; +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index c5318b9..b87e48d 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -2379,10 +2379,14 @@ find_taken_edge_computed_goto (basic_block bb, tree val) dest = label_to_block (val); if (dest) - { - e = find_edge (bb, dest); - gcc_assert (e != NULL); - } + e = find_edge (bb, dest); + + /* It's possible for find_edge to return NULL here on invalid code + that abuses the labels-as-values extension (e.g. code that attempts to + jump *between* functions via stored labels-as-values; PR 84136). + If so, then we simply return that NULL for the edge. + We don't currently have a way of detecting such invalid code, so we + can't assert that it was the case when a NULL edge occurs here. */ return e; } |