aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryroux <yroux@138bc75d-0d04-0410-961f-82ee72b054a4>2015-03-05 14:28:05 +0000
committeryroux <yroux@138bc75d-0d04-0410-961f-82ee72b054a4>2015-03-05 14:28:05 +0000
commit984a1f8a9b9b2e3c1a81588353b46930f49409fc (patch)
tree5005d3a84c488437fd79790ad6316f6c0146e152
parent1d1384dd7748a6c2f6eaf36d348eaa5194ed08f2 (diff)
gcc/
2015-03-05 Yvan Roux <yvan.roux@linaro.org> Backport from trunk r212011, r214942, r214957, r215012, r215016, r218115, r218733, r218746, r220491. 2015-02-06 Sebastian Pop <s.pop@samsung.com> Brian Rzycki <b.rzycki@samsung.com> PR tree-optimization/64878 * tree-ssa-threadedge.c: Include tree-ssa-loop.h. (fsm_find_control_statement_thread_paths): Add parameter seen_loop_phi. Stop recursion at loop phi nodes after having visited a loop phi node. 2014-12-15 Richard Biener <rguenther@suse.de> PR middle-end/64246 * cfgloop.c (mark_loop_for_removal): Make safe against multiple invocations on the same loop. 2014-12-15 Richard Biener <rguenther@suse.de> PR tree-optimization/64284 * tree-ssa-threadupdate.c (duplicate_seme_region): Mark the loop for removal if we copied the loop header. 2014-11-27 Richard Biener <rguenther@suse.de> PR tree-optimization/64083 * tree-ssa-threadupdate.c (thread_through_all_blocks): Do not forcibly mark loop for removal the wrong way. 2014-09-08 Richard Biener <rguenther@suse.de> PR ipa/63196 * tree-inline.c (copy_loops): The source loop header should always be non-NULL. (tree_function_versioning): If loops need fixup after removing unreachable blocks fix them. * omp-low.c (simd_clone_adjust): Do not add incr block to loop under construction. 2014-09-08 Richard Biener <rguenther@suse.de> PR bootstrap/63204 * cfgloop.c (mark_loop_for_removal): Track former header unconditionally. * cfgloop.h (struct loop): Add former_header member unconditionally. * loop-init.c (fix_loop_structure): Enable bogus loop removal diagnostic unconditionally. 2014-09-05 Richard Biener <rguenther@suse.de> * cfgloop.c (mark_loop_for_removal): Record former header when ENABLE_CHECKING. * cfgloop.h (strut loop): Add former_header member when ENABLE_CHECKING. * loop-init.c (fix_loop_structure): Sanity check loops marked for removal if they re-appeared. 2014-09-05 Richard Biener <rguenther@suse.de> * cfgloop.c (mark_loop_for_removal): New function. * cfgloop.h (mark_loop_for_removal): Declare. * cfghooks.c (delete_basic_block): Use mark_loop_for_removal. (merge_blocks): Likewise. (duplicate_block): Likewise. * except.c (sjlj_emit_dispatch_table): Likewise. * tree-eh.c (cleanup_empty_eh_merge_phis): Likewise. * tree-ssa-threadupdate.c (ssa_redirect_edges): Likewise. (thread_through_loop_header): Likewise. 2014-06-26 Richard Biener <rguenther@suse.de> PR tree-optimization/61607 * tree-ssa-threadupdate.c (ssa_redirect_edges): Cancel the loop if we redirected its latch edge. (thread_block_1): Do not cancel loops prematurely. gcc/testsuite/ 2015-03-05 Yvan Roux <yvan.roux@linaro.org> Backport from trunk r218115, r218733, r218746, r220491. 2015-02-06 Sebastian Pop <s.pop@samsung.com> Brian Rzycki <b.rzycki@samsung.com> PR tree-optimization/64878 * testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c: New. 2014-12-15 Richard Biener <rguenther@suse.de> PR middle-end/64246 * gnat.dg/opt46.adb: New testcase. * gnat.dg/opt46.ads: Likewise. * gnat.dg/opt46_pkg.adb: Likewise. * gnat.dg/opt46_pkg.ads: Likewise. 2014-12-15 Richard Biener <rguenther@suse.de> PR tree-optimization/64284 * gcc.dg/torture/pr64284.c: New testcase. 2014-11-27 Richard Biener <rguenther@suse.de> PR tree-optimization/64083 * gcc.dg/torture/pr64083.c: New testcase. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/linaro/gcc-4_9-branch@221216 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog.linaro77
-rw-r--r--gcc/cfghooks.c18
-rw-r--r--gcc/cfgloop.c13
-rw-r--r--gcc/cfgloop.h8
-rw-r--r--gcc/except.c5
-rw-r--r--gcc/loop-init.c31
-rw-r--r--gcc/omp-low.c4
-rw-r--r--gcc/testsuite/ChangeLog.linaro27
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr64083.c17
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr64284.c21
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c440
-rw-r--r--gcc/testsuite/gnat.dg/opt46.adb45
-rw-r--r--gcc/testsuite/gnat.dg/opt46.ads16
-rw-r--r--gcc/testsuite/gnat.dg/opt46_pkg.adb8
-rw-r--r--gcc/testsuite/gnat.dg/opt46_pkg.ads31
-rw-r--r--gcc/tree-eh.c5
-rw-r--r--gcc/tree-inline.c12
-rw-r--r--gcc/tree-ssa-threadedge.c19
-rw-r--r--gcc/tree-ssa-threadupdate.c54
19 files changed, 776 insertions, 75 deletions
diff --git a/gcc/ChangeLog.linaro b/gcc/ChangeLog.linaro
index ee9ef6ac71e..6801455023b 100644
--- a/gcc/ChangeLog.linaro
+++ b/gcc/ChangeLog.linaro
@@ -1,5 +1,82 @@
2015-03-05 Yvan Roux <yvan.roux@linaro.org>
+ Backport from trunk r212011, r214942, r214957, r215012, r215016, r218115,
+ r218733, r218746, r220491.
+ 2015-02-06 Sebastian Pop <s.pop@samsung.com>
+ Brian Rzycki <b.rzycki@samsung.com>
+
+ PR tree-optimization/64878
+ * tree-ssa-threadedge.c: Include tree-ssa-loop.h.
+ (fsm_find_control_statement_thread_paths): Add parameter seen_loop_phi.
+ Stop recursion at loop phi nodes after having visited a loop phi node.
+
+ 2014-12-15 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/64246
+ * cfgloop.c (mark_loop_for_removal): Make safe against multiple
+ invocations on the same loop.
+
+ 2014-12-15 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/64284
+ * tree-ssa-threadupdate.c (duplicate_seme_region): Mark
+ the loop for removal if we copied the loop header.
+
+ 2014-11-27 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/64083
+ * tree-ssa-threadupdate.c (thread_through_all_blocks): Do not
+ forcibly mark loop for removal the wrong way.
+
+ 2014-09-08 Richard Biener <rguenther@suse.de>
+
+ PR ipa/63196
+ * tree-inline.c (copy_loops): The source loop header should
+ always be non-NULL.
+ (tree_function_versioning): If loops need fixup after removing
+ unreachable blocks fix them.
+ * omp-low.c (simd_clone_adjust): Do not add incr block to
+ loop under construction.
+
+ 2014-09-08 Richard Biener <rguenther@suse.de>
+
+ PR bootstrap/63204
+ * cfgloop.c (mark_loop_for_removal): Track former header
+ unconditionally.
+ * cfgloop.h (struct loop): Add former_header member unconditionally.
+ * loop-init.c (fix_loop_structure): Enable bogus loop removal
+ diagnostic unconditionally.
+
+ 2014-09-05 Richard Biener <rguenther@suse.de>
+
+ * cfgloop.c (mark_loop_for_removal): Record former header
+ when ENABLE_CHECKING.
+ * cfgloop.h (strut loop): Add former_header member when
+ ENABLE_CHECKING.
+ * loop-init.c (fix_loop_structure): Sanity check loops
+ marked for removal if they re-appeared.
+
+ 2014-09-05 Richard Biener <rguenther@suse.de>
+
+ * cfgloop.c (mark_loop_for_removal): New function.
+ * cfgloop.h (mark_loop_for_removal): Declare.
+ * cfghooks.c (delete_basic_block): Use mark_loop_for_removal.
+ (merge_blocks): Likewise.
+ (duplicate_block): Likewise.
+ * except.c (sjlj_emit_dispatch_table): Likewise.
+ * tree-eh.c (cleanup_empty_eh_merge_phis): Likewise.
+ * tree-ssa-threadupdate.c (ssa_redirect_edges): Likewise.
+ (thread_through_loop_header): Likewise.
+
+ 2014-06-26 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/61607
+ * tree-ssa-threadupdate.c (ssa_redirect_edges): Cancel the
+ loop if we redirected its latch edge.
+ (thread_block_1): Do not cancel loops prematurely.
+
+2015-03-05 Yvan Roux <yvan.roux@linaro.org>
+
Backport from trunk r220860.
2015-02-20 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c
index bc1634aac87..53da0d9a9f0 100644
--- a/gcc/cfghooks.c
+++ b/gcc/cfghooks.c
@@ -569,14 +569,10 @@ delete_basic_block (basic_block bb)
struct loop *loop = bb->loop_father;
/* If we remove the header or the latch of a loop, mark the loop for
- removal by setting its header and latch to NULL. */
+ removal. */
if (loop->latch == bb
|| loop->header == bb)
- {
- loop->header = NULL;
- loop->latch = NULL;
- loops_state_set (LOOPS_NEED_FIXUP);
- }
+ mark_loop_for_removal (loop);
remove_bb_from_loops (bb);
}
@@ -760,11 +756,7 @@ merge_blocks (basic_block a, basic_block b)
/* ... we merge two loop headers, in which case we kill
the inner loop. */
if (b->loop_father->header == b)
- {
- b->loop_father->header = NULL;
- b->loop_father->latch = NULL;
- loops_state_set (LOOPS_NEED_FIXUP);
- }
+ mark_loop_for_removal (b->loop_father);
}
/* If we merge a loop header into its predecessor, update the loop
structure. */
@@ -1103,9 +1095,7 @@ duplicate_block (basic_block bb, edge e, basic_block after)
&& cloop->header == bb)
{
add_bb_to_loop (new_bb, loop_outer (cloop));
- cloop->header = NULL;
- cloop->latch = NULL;
- loops_state_set (LOOPS_NEED_FIXUP);
+ mark_loop_for_removal (cloop);
}
else
{
diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index 70744d83d19..ff25e012dbe 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -1919,3 +1919,16 @@ bb_loop_depth (const_basic_block bb)
{
return bb->loop_father ? loop_depth (bb->loop_father) : 0;
}
+
+/* Marks LOOP for removal and sets LOOPS_NEED_FIXUP. */
+
+void
+mark_loop_for_removal (loop_p loop)
+{
+ if (loop->header == NULL)
+ return;
+ loop->former_header = loop->header;
+ loop->header = NULL;
+ loop->latch = NULL;
+ loops_state_set (LOOPS_NEED_FIXUP);
+}
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 4b7c3d3985a..5a94fe7217d 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -192,6 +192,12 @@ struct GTY ((chain_next ("%h.next"))) loop {
/* Number of iteration analysis data for RTL. */
struct niter_desc *simple_loop_desc;
+
+ /* For sanity checking during loop fixup we record here the former
+ loop header for loops marked for removal. Note that this prevents
+ the basic-block from being collected but its index can still be
+ reused. */
+ basic_block former_header;
};
/* Flags for state of loop structure. */
@@ -335,6 +341,8 @@ struct loop * loop_version (struct loop *, void *,
extern bool remove_path (edge);
extern void unloop (struct loop *, bool *, bitmap);
extern void scale_loop_frequencies (struct loop *, int, int);
+void mark_loop_for_removal (loop_p);
+
/* Induction variable analysis. */
diff --git a/gcc/except.c b/gcc/except.c
index 908954cbbbf..9ea813bdef1 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -1394,10 +1394,7 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
{
for (loop = bb->loop_father;
loop_outer (loop); loop = loop_outer (loop))
- {
- loop->header = NULL;
- loop->latch = NULL;
- }
+ mark_loop_for_removal (loop);
}
}
diff --git a/gcc/loop-init.c b/gcc/loop-init.c
index 4cc561c2e7a..5f6e3db1327 100644
--- a/gcc/loop-init.c
+++ b/gcc/loop-init.c
@@ -245,6 +245,10 @@ fix_loop_structure (bitmap changed_bbs)
}
/* Remove the loop. */
+ if (loop->header)
+ loop->former_header = loop->header;
+ else
+ gcc_assert (loop->former_header != NULL);
loop->header = NULL;
flow_loop_tree_node_remove (loop);
}
@@ -272,6 +276,33 @@ fix_loop_structure (bitmap changed_bbs)
FOR_EACH_VEC_ELT (*get_loops (cfun), i, loop)
if (loop && loop->header == NULL)
{
+ if (dump_file
+ && ((unsigned) loop->former_header->index
+ < basic_block_info_for_fn (cfun)->length ()))
+ {
+ basic_block former_header
+ = BASIC_BLOCK_FOR_FN (cfun, loop->former_header->index);
+ /* If the old header still exists we want to check if the
+ original loop is re-discovered or the old header is now
+ part of a newly discovered loop.
+ In both cases we should have avoided removing the loop. */
+ if (former_header == loop->former_header)
+ {
+ if (former_header->loop_father->header == former_header)
+ fprintf (dump_file, "fix_loop_structure: rediscovered "
+ "removed loop %d as loop %d with old header %d\n",
+ loop->num, former_header->loop_father->num,
+ former_header->index);
+ else if ((unsigned) former_header->loop_father->num
+ >= old_nloops)
+ fprintf (dump_file, "fix_loop_structure: header %d of "
+ "removed loop %d is part of the newly "
+ "discovered loop %d with header %d\n",
+ former_header->index, loop->num,
+ former_header->loop_father->num,
+ former_header->loop_father->header->index);
+ }
+ }
(*get_loops (cfun))[i] = NULL;
flow_loop_free (loop);
}
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index f0059be6b5d..4b9c827eea9 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -11707,6 +11707,7 @@ simd_clone_adjust (struct cgraph_node *node)
iteration increment and the condition/branch. */
basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
basic_block incr_bb = create_empty_bb (orig_exit);
+ add_bb_to_loop (incr_bb, body_bb->loop_father);
/* The succ of orig_exit was EXIT_BLOCK_PTR_FOR_FN (cfun), with an empty
flag. Set it now to be a FALLTHRU_EDGE. */
gcc_assert (EDGE_COUNT (orig_exit->succs) == 1);
@@ -11731,7 +11732,6 @@ simd_clone_adjust (struct cgraph_node *node)
loop->safelen = node->simdclone->simdlen;
loop->force_vect = true;
loop->header = body_bb;
- add_bb_to_loop (incr_bb, loop);
/* Branch around the body if the mask applies. */
if (node->simdclone->inbranch)
@@ -11772,7 +11772,7 @@ simd_clone_adjust (struct cgraph_node *node)
gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
e = split_block (incr_bb, gsi_stmt (gsi));
basic_block latch_bb = e->dest;
- basic_block new_exit_bb = e->dest;
+ basic_block new_exit_bb;
new_exit_bb = split_block (latch_bb, NULL)->dest;
loop->latch = latch_bb;
diff --git a/gcc/testsuite/ChangeLog.linaro b/gcc/testsuite/ChangeLog.linaro
index 19ab7f1beb2..85e8a720aef 100644
--- a/gcc/testsuite/ChangeLog.linaro
+++ b/gcc/testsuite/ChangeLog.linaro
@@ -1,5 +1,32 @@
2015-03-05 Yvan Roux <yvan.roux@linaro.org>
+ Backport from trunk r218115, r218733, r218746, r220491.
+ 2015-02-06 Sebastian Pop <s.pop@samsung.com>
+ Brian Rzycki <b.rzycki@samsung.com>
+
+ PR tree-optimization/64878
+ * testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c: New.
+
+ 2014-12-15 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/64246
+ * gnat.dg/opt46.adb: New testcase.
+ * gnat.dg/opt46.ads: Likewise.
+ * gnat.dg/opt46_pkg.adb: Likewise.
+ * gnat.dg/opt46_pkg.ads: Likewise.
+
+ 2014-12-15 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/64284
+ * gcc.dg/torture/pr64284.c: New testcase.
+
+ 2014-11-27 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/64083
+ * gcc.dg/torture/pr64083.c: New testcase.
+
+2015-03-05 Yvan Roux <yvan.roux@linaro.org>
+
Backport from trunk r220860.
2015-02-20 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
diff --git a/gcc/testsuite/gcc.dg/torture/pr64083.c b/gcc/testsuite/gcc.dg/torture/pr64083.c
new file mode 100644
index 00000000000..3c3e5a6087a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr64083.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+
+int a, b;
+void
+fn1 ()
+{
+ int c = 0;
+ while (b)
+ {
+ switch (c)
+ case 1:
+ fn1 ();
+ if (a)
+ c = 1;
+ b = 0;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr64284.c b/gcc/testsuite/gcc.dg/torture/pr64284.c
new file mode 100644
index 00000000000..425438116eb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr64284.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+int *a;
+int b;
+int
+fn1() {
+ enum { QSTRING } c = 0;
+ while (1) {
+ switch (*a) {
+ case '\'':
+ c = 0;
+ default:
+ switch (c)
+ case 0:
+ if (b)
+ return 0;
+ c = 1;
+ }
+ a++;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c
new file mode 100644
index 00000000000..9be75aaf21d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c
@@ -0,0 +1,440 @@
+/* PR 64878 */
+/* { dg-options "-O2" } */
+/* { dg-do run } */
+
+struct A { int a1; };
+struct B { char *b1; int b2; int b3; };
+struct C { char *c1; int c2; struct B *c3; };
+extern struct A *f1 (char *s);
+static struct A *f2 (struct C *x);
+__attribute__ ((noinline, noclone)) int f3 (struct A *x, struct A *z) { asm volatile ("" : : "g" (x), "g" (z) : "memory"); return 0; }
+__attribute__ ((noinline, noclone)) void f4 (struct A *x, char *y, struct A *z) { asm volatile ("" : : "g" (x), "g" (z), "g" (y) : "memory"); }
+__attribute__ ((noinline, noclone)) struct B *f5 (void) { static char b[32]; static struct B f3 = { b, 0, 32 }; return &f3; }
+__attribute__ ((noinline, noclone)) int f6 (struct B *p, char *w, int z) { asm volatile ("" : : "g" (p), "g" (w), "g" (z) : "memory"); return 0; }
+__attribute__ ((noinline, noclone)) void f7 (struct B *p) { asm volatile ("" : : "g" (p) : "memory"); }
+__attribute__ ((noinline, noclone)) void f8 (struct B *p) { asm volatile ("" : : "g" (p) : "memory"); }
+__attribute__ ((noinline, noclone)) void f9 (struct A *x) { asm volatile ("" : : "g" (x) : "memory"); }
+__attribute__ ((noinline, noclone)) struct A *f10 (void) { static struct A j; asm volatile ("" : : : "memory"); return &j; }
+__attribute__ ((noinline, noclone)) struct A *f11 (void) { static struct A j; asm volatile ("" : : : "memory"); return &j; }
+__attribute__ ((noinline, noclone)) struct A *f12 (int b) { static struct A j; asm volatile ("" : : "g" (b) : "memory"); return &j; }
+__attribute__ ((noinline, noclone)) struct A *f13 (int i) { static struct A j; asm volatile ("" : : "g" (i) : "memory"); return &j; }
+__attribute__ ((noinline, noclone)) struct A *f14 (double d) { static struct A j; asm volatile ("" : : "g" (&d) : "memory"); return &j; }
+__attribute__ ((noinline, noclone)) struct A *f15 (char *s) { static struct A j; asm volatile ("" : : "g" (s) : "memory"); return &j; }
+char *t = "0123456789abcdef";
+char *u = "0123456789.+-e";
+
+__attribute__ ((noinline, noclone)) struct A *
+f1 (char *s)
+{
+ struct C f;
+ struct A *o;
+ f.c1 = s;
+ f.c2 = 0;
+ f.c3 = f5 ();
+ o = f2 (&f);
+ f8 (f.c3);
+ return o;
+}
+
+static struct A *
+f2 (struct C *x)
+{
+ int a, b, e = 0;
+ struct A *f = 0, *o;
+ char *g = 0;
+ char h = '\0';
+ int i = 0, j = 0;
+ a = 0;
+ b = 1;
+ char c;
+ do
+ {
+ c = x->c1[x->c2];
+ switch (a)
+ {
+ case 0:
+ if (c == ' ')
+ x->c2++;
+ else if (c == '/')
+ {
+ a = 4;
+ j = x->c2++;
+ }
+ else
+ a = b;
+ break;
+ case 1:
+ switch (c)
+ {
+ case '{':
+ a = 0;
+ b = 15;
+ f = f10 ();
+ x->c2++;
+ break;
+ case '[':
+ a = 0;
+ b = 13;
+ f = f11 ();
+ x->c2++;
+ break;
+ case 'N':
+ case 'n':
+ a = 3;
+ j = x->c2++;
+ break;
+ case '"':
+ case '\'':
+ h = c;
+ f7 (x->c3);
+ a = 8;
+ j = ++x->c2;
+ break;
+ case 'T':
+ case 't':
+ case 'F':
+ case 'f':
+ a = 11;
+ j = x->c2++;
+ break;
+ case '0' ... '9':
+ case '-':
+ i = 0;
+ a = 12;
+ j = x->c2++;
+ break;
+ default:
+ e = 1;
+ goto out;
+ }
+ break;
+ case 2:
+ goto out;
+ case 3:
+ if (__builtin_strncmp ("null", x->c1 + j, x->c2 - j))
+ {
+ e = 2;
+ goto out;
+ }
+ if (x->c2 - j == 4)
+ {
+ f = 0;
+ b = 2;
+ a = 0;
+ }
+ else
+ x->c2++;
+ break;
+ case 4:
+ if (c == '*')
+ a = 5;
+ else if (c == '/')
+ a = 6;
+ else
+ {
+ e = 8;
+ goto out;
+ }
+ x->c2++;
+ break;
+ case 5:
+ if (c == '*')
+ a = 7;
+ x->c2++;
+ break;
+ case 6:
+ if (c == '\n')
+ a = 0;
+ x->c2++;
+ break;
+ case 7:
+ if (c == '/')
+ a = 0;
+ else
+ a = 5;
+ x->c2++;
+ break;
+ case 8:
+ if (c == h)
+ {
+ f6 (x->c3, x->c1 + j, x->c2 - j);
+ f = f15 (x->c3->b1);
+ b = 2;
+ a = 0;
+ }
+ else if (c == '\\')
+ {
+ b = 8;
+ a = 9;
+ }
+ x->c2++;
+ break;
+ case 9:
+ switch (c)
+ {
+ case '"':
+ case '\\':
+ f6 (x->c3, x->c1 + j, x->c2 - j - 1);
+ j = x->c2++;
+ a = b;
+ break;
+ case 'b':
+ case 'n':
+ case 'r':
+ case 't':
+ f6 (x->c3, x->c1 + j, x->c2 - j - 1);
+ if (c == 'b')
+ f6 (x->c3, "\b", 1);
+ else if (c == 'n')
+ f6 (x->c3, "\n", 1);
+ else if (c == 'r')
+ f6 (x->c3, "\r", 1);
+ else if (c == 't')
+ f6 (x->c3, "\t", 1);
+ j = ++x->c2;
+ a = b;
+ break;
+ case 'u':
+ f6 (x->c3, x->c1 + j, x->c2 - j - 1);
+ j = ++x->c2;
+ a = 10;
+ break;
+ default:
+ e = 7;
+ goto out;
+ }
+ break;
+ case 10:
+ if (__builtin_strchr (t, c))
+ {
+ x->c2++;
+ if (x->c2 - j == 4)
+ {
+ unsigned char w[3];
+ unsigned int s =
+ (((x->c1[j] <= '9') ? x->c1[j] - '0' : (x->c1[j] & 7) + 9) << 12)
+ + (((x->c1[j + 1] <= '9') ? x->c1[j + 1] - '0' : (x->c1[j + 1] & 7) + 9) << 8)
+ + (((x->c1[j + 2] <= '9') ? x->c1[j + 2] - '0' : (x->c1[j + 2] & 7) + 9) << 4)
+ + ((x->c1[j + 3] <= '9') ? x->c1[j + 3] - '0' : (x->c1[j + 3] & 7) + 9);
+ if (s < 0x80)
+ {
+ w[0] = s;
+ f6 (x->c3, (char *) w, 1);
+ }
+ else if (s < 0x800)
+ {
+ w[0] = 0xc0 | (s >> 6);
+ w[1] = 0x80 | (s & 0x3f);
+ f6 (x->c3, (char *) w, 2);
+ }
+ else
+ {
+ w[0] = 0x0 | (s >> 12);
+ w[1] = 0x80 | ((s >> 6) & 0x3f);
+ w[2] = 0x80 | (s & 0x3f);
+ f6 (x->c3, (char *) w, 3);
+ }
+ j = x->c2;
+ a = b;
+ }
+ }
+ else
+ {
+ e = 7;
+ goto out;
+ }
+ break;
+ case 11:
+ if (__builtin_strncmp ("true", x->c1 + j, x->c2 - j) == 0)
+ {
+ if (x->c2 - j == 4)
+ {
+ f = f12 (1);
+ b = 2;
+ a = 0;
+ }
+ else
+ x->c2++;
+ }
+ else if (__builtin_strncmp ("false", x->c1 + j, x->c2 - j) == 0)
+ {
+ if (x->c2 - j == 5)
+ {
+ f = f12 (0);
+ b = 2;
+ a = 0;
+ }
+ else
+ x->c2++;
+ }
+ else
+ {
+ e = 3;
+ goto out;
+ }
+ break;
+ case 12:
+ if (!c || !__builtin_strchr (u, c))
+ {
+ if (!i)
+ f = f13 (0);
+ else
+ f = f14 (0.0);
+ b = 2;
+ a = 0;
+ }
+ else
+ {
+ if (c == '.' || c == 'e')
+ i = 1;
+ x->c2++;
+ }
+ break;
+ case 13:
+ if (c == ']')
+ {
+ x->c2++;
+ b = 2;
+ a = 0;
+ }
+ else
+ {
+ o = f2 (x);
+ if (((unsigned long) o > (unsigned long) -4000L))
+ {
+ e = 5;
+ goto out;
+ }
+ f3 (f, o);
+ b = 14;
+ a = 0;
+ }
+ break;
+ case 14:
+ if (c == ']')
+ {
+ x->c2++;
+ b = 2;
+ a = 0;
+ }
+ else if (c == ',')
+ {
+ x->c2++;
+ b = 13;
+ a = 0;
+ }
+ else
+ {
+ f9 (f);
+ e = 5;
+ goto out;
+ }
+ break;
+ case 15:
+ a = 16;
+ j = x->c2;
+ break;
+ case 16:
+ if (c == '}')
+ {
+ x->c2++;
+ b = 2;
+ a = 0;
+ }
+ else if (c == '"' || c == '\'')
+ {
+ h = c;
+ f7 (x->c3);
+ a = 17;
+ j = ++x->c2;
+ }
+ else
+ {
+ e = 6;
+ goto out;
+ }
+ break;
+ case 17:
+ if (c == h)
+ {
+ f6 (x->c3, x->c1 + j, x->c2 - j);
+ g = __builtin_strdup (x->c3->b1);
+ b = 18;
+ a = 0;
+ }
+ else if (c == '\\')
+ {
+ b = 17;
+ a = 9;
+ }
+ x->c2++;
+ break;
+ case 18:
+ if (c == ':')
+ {
+ x->c2++;
+ b = 19;
+ a = 0;
+ }
+ else
+ {
+ e = -6;
+ goto out;
+ }
+ break;
+ case 19:
+ o = f2 (x);
+ if (((unsigned long) o > (unsigned long) -4000L))
+ {
+ e = 6;
+ goto out;
+ }
+ f4 (f, g, o);
+ __builtin_free (g);
+ g = 0;
+ b = 20;
+ a = 0;
+ break;
+ case 20:
+ if (c == '}')
+ {
+ x->c2++;
+ b = 2;
+ a = 0;
+ }
+ else if (c == ',')
+ {
+ x->c2++;
+ b = 15;
+ a = 0;
+ }
+ else
+ {
+ e = 6;
+ goto out;
+ }
+ break;
+ }
+ }
+ while (c);
+ if (a != 2 && b != 2)
+ e = 9;
+out:
+ __builtin_free (g);
+ if (e == 0)
+ return f;
+ f9 (f);
+ return 0;
+}
+
+int
+main ()
+{
+ asm volatile ("" : : : "memory");
+ struct A *r = f1 ("{ \"id\": null, \"blahah\": \"foobarbazbar\", \"barbar\": { \"barbarbarba\":"
+ "\"abcdefgh\", \"ijklmnopqr\": \"stuvwxyzabcdefghijklmnopqrstuv\", \"xyzxyz\":"
+ " [ \"1\" ] } }");
+ if (!r)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gnat.dg/opt46.adb b/gcc/testsuite/gnat.dg/opt46.adb
new file mode 100644
index 00000000000..64e0b632e3a
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt46.adb
@@ -0,0 +1,45 @@
+-- { dg-do compile }
+-- { dg-options "-O" }
+
+with Ada.Unchecked_Deallocation;
+
+with Opt46_Pkg;
+
+package body Opt46 is
+
+ type Pattern is abstract tagged null record;
+
+ type Pattern_Access is access Pattern'Class;
+
+ procedure Free is new Ada.Unchecked_Deallocation
+ (Pattern'Class, Pattern_Access);
+
+ type Action is abstract tagged null record;
+
+ type Action_Access is access Action'Class;
+
+ procedure Free is new Ada.Unchecked_Deallocation
+ (Action'Class, Action_Access);
+
+ type Pattern_Action is record
+ Pattern : Pattern_Access;
+ Action : Action_Access;
+ end record;
+
+ package Pattern_Action_Table is new Opt46_Pkg (Pattern_Action, Natural, 1);
+
+ type Session_Data is record
+ Filters : Pattern_Action_Table.Instance;
+ end record;
+
+ procedure Close (Session : Session_Type) is
+ Filters : Pattern_Action_Table.Instance renames Session.Data.Filters;
+ begin
+ for F in 1 .. Pattern_Action_Table.Last (Filters) loop
+ Free (Filters.Table (F).Pattern);
+ Free (Filters.Table (F).Action);
+ end loop;
+
+ end Close;
+
+end Opt46;
diff --git a/gcc/testsuite/gnat.dg/opt46.ads b/gcc/testsuite/gnat.dg/opt46.ads
new file mode 100644
index 00000000000..5a5175d0936
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt46.ads
@@ -0,0 +1,16 @@
+package Opt46 is
+
+ type Session_Type is limited private;
+
+ procedure Close (Session : Session_Type);
+
+private
+
+ type Session_Data;
+ type Session_Data_Access is access Session_Data;
+
+ type Session_Type is record
+ Data : Session_Data_Access;
+ end record;
+
+end Opt46;
diff --git a/gcc/testsuite/gnat.dg/opt46_pkg.adb b/gcc/testsuite/gnat.dg/opt46_pkg.adb
new file mode 100644
index 00000000000..26f67cc90ec
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt46_pkg.adb
@@ -0,0 +1,8 @@
+package body Opt46_Pkg is
+
+ function Last (T : Instance) return Table_Index_Type is
+ begin
+ return Table_Index_Type (T.P.Last_Val);
+ end Last;
+
+end Opt46_Pkg;
diff --git a/gcc/testsuite/gnat.dg/opt46_pkg.ads b/gcc/testsuite/gnat.dg/opt46_pkg.ads
new file mode 100644
index 00000000000..1309315378f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt46_pkg.ads
@@ -0,0 +1,31 @@
+generic
+ type Table_Component_Type is private;
+ type Table_Index_Type is range <>;
+
+ Table_Low_Bound : Table_Index_Type;
+
+package Opt46_Pkg is
+
+ type Table_Type is
+ array (Table_Index_Type range <>) of Table_Component_Type;
+ subtype Big_Table_Type is
+ Table_Type (Table_Low_Bound .. Table_Index_Type'Last);
+
+ type Table_Ptr is access all Big_Table_Type;
+
+ type Table_Private is private;
+
+ type Instance is record
+ Table : aliased Table_Ptr := null;
+ P : Table_Private;
+ end record;
+
+ function Last (T : Instance) return Table_Index_Type;
+
+private
+
+ type Table_Private is record
+ Last_Val : Integer;
+ end record;
+
+end Opt46_Pkg;
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 14ed52a007a..dc3b4191bb5 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -4236,10 +4236,9 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
if (current_loops
&& e->dest == e->dest->loop_father->header)
{
- e->dest->loop_father->header = NULL;
- e->dest->loop_father->latch = NULL;
+ mark_loop_for_removal (e->dest->loop_father);
new_bb->loop_father->latch = NULL;
- loops_state_set (LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
+ loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
}
redirect_eh_edge_1 (e, new_bb, change_region);
redirect_edge_succ (e, new_bb);
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index f757bdfaa2f..288645b5904 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -2336,11 +2336,8 @@ copy_loops (copy_body_data *id,
/* Assign the new loop its header and latch and associate
those with the new loop. */
- if (src_loop->header != NULL)
- {
- dest_loop->header = (basic_block)src_loop->header->aux;
- dest_loop->header->loop_father = dest_loop;
- }
+ dest_loop->header = (basic_block)src_loop->header->aux;
+ dest_loop->header->loop_father = dest_loop;
if (src_loop->latch != NULL)
{
dest_loop->latch = (basic_block)src_loop->latch->aux;
@@ -5505,6 +5502,11 @@ tree_function_versioning (tree old_decl, tree new_decl,
delete_unreachable_blocks_update_callgraph (&id);
if (id.dst_node->definition)
cgraph_rebuild_references ();
+ if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+ {
+ calculate_dominance_info (CDI_DOMINATORS);
+ fix_loop_structure (NULL);
+ }
update_ssa (TODO_update_ssa);
/* After partial cloning we need to rescale frequencies, so they are
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index d3fe4afab71..cad91ef667c 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "params.h"
#include "tree-ssa-threadedge.h"
+#include "tree-ssa-loop.h"
/* To avoid code explosion due to jump threading, we limit the
number of statements we are going to copy. This variable
@@ -947,7 +948,8 @@ static int max_threaded_paths;
static void
fsm_find_control_statement_thread_paths (tree expr,
pointer_set_t *visited_phis,
- vec<basic_block, va_gc> *&path)
+ vec<basic_block, va_gc> *&path,
+ bool seen_loop_phi)
{
tree var = SSA_NAME_VAR (expr);
gimple def_stmt = SSA_NAME_DEF_STMT (expr);
@@ -970,6 +972,14 @@ fsm_find_control_statement_thread_paths (tree expr,
int next_path_length = 0;
basic_block last_bb_in_path = path->last ();
+ if (loop_containing_stmt (def_stmt)->header == gimple_bb (def_stmt))
+ {
+ /* Do not walk through more than one loop PHI node. */
+ if (seen_loop_phi)
+ return;
+ seen_loop_phi = true;
+ }
+
/* Following the chain of SSA_NAME definitions, we jumped from a definition in
LAST_BB_IN_PATH to a definition in VAR_BB. When these basic blocks are
different, append to PATH the blocks from LAST_BB_IN_PATH to VAR_BB. */
@@ -1030,7 +1040,9 @@ fsm_find_control_statement_thread_paths (tree expr,
{
vec_safe_push (path, bbi);
/* Recursively follow SSA_NAMEs looking for a constant definition. */
- fsm_find_control_statement_thread_paths (arg, visited_phis, path);
+ fsm_find_control_statement_thread_paths (arg, visited_phis, path,
+ seen_loop_phi);
+
path->pop ();
continue;
}
@@ -1297,7 +1309,8 @@ thread_through_normal_block (edge e,
pointer_set_t *visited_phis = pointer_set_create ();
max_threaded_paths = PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATHS);
- fsm_find_control_statement_thread_paths (cond, visited_phis, bb_path);
+ fsm_find_control_statement_thread_paths (cond, visited_phis, bb_path,
+ false);
pointer_set_destroy (visited_phis);
vec_free (bb_path);
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index d1b289ffa68..6ae071ea083 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -700,6 +700,10 @@ ssa_redirect_edges (struct redirection_data **slot,
if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK)
EDGE_SUCC (rd->dup_blocks[0], 0)->count += e->count;
+ /* If we redirect a loop latch edge cancel its loop. */
+ if (e->src == e->src->loop_father->latch)
+ mark_loop_for_removal (e->src->loop_father);
+
/* Redirect the incoming edge (possibly to the joiner block) to the
appropriate duplicate block. */
e2 = redirect_edge_and_branch (e, rd->dup_blocks[0]);
@@ -780,7 +784,6 @@ thread_block_1 (basic_block bb, bool noloop_only, bool joiners)
edge e, e2;
edge_iterator ei;
ssa_local_info_t local_info;
- struct loop *loop = bb->loop_father;
/* To avoid scanning a linear array for the element we need we instead
use a hash table. For normal code there should be no noticeable
@@ -788,32 +791,6 @@ thread_block_1 (basic_block bb, bool noloop_only, bool joiners)
incoming and outgoing edges such linear searches can get expensive. */
redirection_data.create (EDGE_COUNT (bb->succs));
- /* If we thread the latch of the loop to its exit, the loop ceases to
- exist. Make sure we do not restrict ourselves in order to preserve
- this loop. */
- if (loop->header == bb)
- {
- e = loop_latch_edge (loop);
- vec<jump_thread_edge *> *path = THREAD_PATH (e);
-
- if (path
- && (((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK && joiners)
- || ((*path)[1]->type == EDGE_COPY_SRC_BLOCK && !joiners)))
- {
- for (unsigned int i = 1; i < path->length (); i++)
- {
- edge e2 = (*path)[i]->e;
-
- if (loop_exit_edge_p (loop, e2))
- {
- loop->header = NULL;
- loop->latch = NULL;
- loops_state_set (LOOPS_NEED_FIXUP);
- }
- }
- }
- }
-
/* Record each unique threaded destination into a hash table for
efficient lookups. */
FOR_EACH_EDGE (e, ei, bb->preds)
@@ -1257,9 +1234,7 @@ thread_through_loop_header (struct loop *loop, bool may_peel_loop_headers)
{
/* If the loop ceased to exist, mark it as such, and thread through its
original header. */
- loop->header = NULL;
- loop->latch = NULL;
- loops_state_set (LOOPS_NEED_FIXUP);
+ mark_loop_for_removal (loop);
return thread_block (header, false);
}
@@ -1669,7 +1644,7 @@ duplicate_seme_region (edge entry, edge exit,
basic_block *region_copy)
{
unsigned i;
- bool free_region_copy = false, copying_header = false;
+ bool free_region_copy = false;
struct loop *loop = entry->dest->loop_father;
edge exit_copy;
edge redirected;
@@ -1693,10 +1668,7 @@ duplicate_seme_region (edge entry, edge exit,
initialize_original_copy_tables ();
- if (copying_header)
- set_loop_copy (loop, loop_outer (loop));
- else
- set_loop_copy (loop, loop);
+ set_loop_copy (loop, loop);
if (!region_copy)
{
@@ -1758,6 +1730,8 @@ duplicate_seme_region (edge entry, edge exit,
}
/* Redirect the entry and add the phi node arguments. */
+ if (entry->dest == loop->header)
+ mark_loop_for_removal (loop);
redirected = redirect_edge_and_branch (entry, get_bb_copy (entry->dest));
gcc_assert (redirected != NULL);
flush_pending_stmts (entry);
@@ -1937,16 +1911,8 @@ thread_through_all_blocks (bool may_peel_loop_headers)
/* Our path is still valid, thread it. */
if (e->aux)
{
- struct loop *loop = (*path)[0]->e->dest->loop_father;
-
if (thread_block ((*path)[0]->e->dest, false))
- {
- /* This jump thread likely totally scrambled this loop.
- So arrange for it to be fixed up. */
- loop->header = NULL;
- loop->latch = NULL;
- e->aux = NULL;
- }
+ e->aux = NULL;
else
{
delete_jump_thread_path (path);