LTO streaming does not preserve the order of incoming edges and
thus the order of PHI operands, disturbing the IPA ICF IPA reference
comparison.  The following rectifies this by streaming predecessor
edges instead of successor edges (which leaves outgoing edge order
not preserved)

LTO bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

I'll push this to trunk soon until you have comments very quickly.

Richard.

        PR ipa/127479
        * lto-streamer-out.cc (output_cfg): Output predecessor edges.
        * lto-streamer-in.cc (input_cfg): Input predecessor edges.

        * gcc.dg/lto/pr127479_0.c: New testcase.
---
 gcc/lto-streamer-in.cc                | 12 +++----
 gcc/lto-streamer-out.cc               | 11 ++++---
 gcc/testsuite/gcc.dg/lto/pr127479_0.c | 45 +++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr127479_0.c

diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc
index 901c3212656..668a5d3065b 100644
--- a/gcc/lto-streamer-in.cc
+++ b/gcc/lto-streamer-in.cc
@@ -1113,25 +1113,25 @@ input_cfg (class lto_input_block *ib, class data_in 
*data_in,
        bb = make_new_block (fn, index);
 
       edge_count = streamer_read_uhwi (ib);
+      vec_safe_reserve (bb->preds, edge_count);
 
       /* Connect up the CFG.  */
       for (i = 0; i < edge_count; i++)
        {
          bitpack_d bp = streamer_read_bitpack (ib);
-         unsigned int dest_index = bp_unpack_var_len_unsigned (&bp);
+         unsigned int src_index = bp_unpack_var_len_unsigned (&bp);
          unsigned int edge_flags = bp_unpack_var_len_unsigned (&bp);
-         basic_block dest = BASIC_BLOCK_FOR_FN (fn, dest_index);
+         basic_block src = BASIC_BLOCK_FOR_FN (fn, src_index);
 
-         if (dest == NULL)
-           dest = make_new_block (fn, dest_index);
+         if (src == NULL)
+           src = make_new_block (fn, src_index);
 
-         edge e = make_edge (bb, dest, edge_flags);
+         edge e = make_edge (src, bb, edge_flags);
          data_in->location_cache.input_location_and_block (&e->goto_locus,
                                                            &bp, ib, data_in);
          e->probability = profile_probability::stream_in (ib);
          if (!e->probability.initialized_p ())
            full_profile = false;
-
        }
 
       index = streamer_read_hwi (ib);
diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index 7afc2673ea2..6e34d4bea90 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -2334,12 +2334,15 @@ output_cfg (struct output_block *ob, struct function 
*fn)
 
       streamer_write_hwi (ob, bb->index);
 
-      /* Output the successors and the edge flags.  */
-      streamer_write_uhwi (ob, EDGE_COUNT (bb->succs));
-      FOR_EACH_EDGE (e, ei, bb->succs)
+      /* Output the predecessors and the edge flags.  We output
+        predecessors instead of successors so PHI argument order
+        is preserved when we reconstruct the CFG greedily in
+        input_cfg.  */
+      streamer_write_uhwi (ob, EDGE_COUNT (bb->preds));
+      FOR_EACH_EDGE (e, ei, bb->preds)
        {
          bitpack_d bp = bitpack_create (ob->main_stream);
-         bp_pack_var_len_unsigned (&bp, e->dest->index);
+         bp_pack_var_len_unsigned (&bp, e->src->index);
          bp_pack_var_len_unsigned (&bp, e->flags);
          stream_output_location_and_block (ob, &bp, e->goto_locus);
          e->probability.stream_out (ob);
diff --git a/gcc/testsuite/gcc.dg/lto/pr127479_0.c 
b/gcc/testsuite/gcc.dg/lto/pr127479_0.c
new file mode 100644
index 00000000000..d96dedabd4d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr127479_0.c
@@ -0,0 +1,45 @@
+/* { dg-lto-do run } */
+/* { dg-lto-options { { -O2 -flto } } } */
+
+static char false_object;
+static char true_object;
+
+__attribute__((noinline))
+static
+char *less_equal(long comparison) {
+    if (comparison == 0) goto return_true;
+    if (comparison < 0) goto return_true;
+    goto return_false;
+
+return_true:
+    return &true_object;
+
+return_false:
+    return &false_object;
+}
+
+__attribute__((noinline))
+static
+char *greater_equal(long comparison) {
+    if (comparison == 0) goto return_true;
+    if (comparison < 0) goto return_false;
+    goto return_true;
+
+return_true:
+    return &true_object;
+
+return_false:
+    return &false_object;
+}
+
+int main(void) {
+    volatile long negative = -1;
+
+    int correct =
+        less_equal(negative) == &true_object &&
+        greater_equal(negative) == &false_object;
+
+    if (!correct)
+      __builtin_abort ();
+    return 0;
+}
-- 
2.51.0

Reply via email to