public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR rtl-optimization/66790: uninitialized registers handling in REE
@ 2015-07-19  6:40 Pierre-Marie de Rodat
  2015-07-27  9:05 ` [PATCH, PING] " Pierre-Marie de Rodat
  0 siblings, 1 reply; 11+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-19  6:40 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 2546 bytes --]

Hello,

This patch is an attempt to fix PR rtl-optimization/66790: please see 
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790> for the context. 
This adds a new dataflow problem (MIR for Must-Initialized Registers) 
and use it in the REE pass to remove oversights, fixing the original issue.

I would also like to draw your attention to the use of the 
"must-initialized" term. Being new to dataflow problems, I understand it 
as "registers that are always initialized whatever the path leading to 
its use" and this seems to be confirmed by the current "LIVE AND 
MUST-INITIALIZED REGISTERS" comment in df-problems.c. However, it feels 
like what is currently called "must-initialized" in this source file is 
actually registers that *may* be initialized: see in particular the use 
of the bitmap_ior_into operation in df_live_confluence_n.

Can someone confirm this, please? If I'm right, I will update the 
attached patch to reword the corresponding comments.

This patch bootstraps and yields no regression on x86_64-linux. I'm 
still trying to fiddle the build system to actually see how assemblies 
from the bootstrap are affected. Thank you in advance for the review! :-)

gcc/ChangeLog:

         PR rtl-optimization/66790
         * df.h (DF_MIR): New macro.
         (DF_LAST_PROBLEM_PLUS1): Update to be past DF_MIR
         (DF_MIR_INFO_BB): New macro.
         (DF_MIR_IN, DF_MIR_OUT): New macros.
         (struct df_mir_bb_info): New.
         (df_mir): New macro.
         (df_mir_add_problem, df_mir_simulate_one_insn): New forward
         declarations.
         (df_mir_get_bb_info): New.
         * df-problems.c (struct df_mir_problem_data): New.
         (df_mir_free_bb_info, df_mir_alloc, df_mir_reset,
         df_mir_bb_local_compute, df_mir_local_compute, df_mir_init,
         df_mir_confluence_n, df_mir_transfer_function, df_mir_free,
         df_mir_top_dump, df_mir_bottom_dump,
         df_mir_verify_solution_start, df_mir_verify_solution_end): New.
         (problem_MIR): New.
         (df_mir_add_problem, df_mir_simulate_one_insn): New.
         * timevar.def (TV_DF_MIR): New.
         * ree.c: Include bitmap.h
         (add_removable_extension): Add an INIT_REGS parameter.  Use it
         to skip extensions that may get an uninitialized register.
         (find_removable_extensions): Compute must-initialized registers
         using the MIR dataflow problem. Update the call to
         add_removable_extension.
         (find_and_remove_re): Call df_mir_add_problem.

-- 
Pierre-Marie de Rodat

[-- Attachment #2: 0001-REE-fix-uninitialized-registers-handling.patch --]
[-- Type: text/x-patch, Size: 21688 bytes --]

From 2b0fe78644c3c3b16555b69d0b787dbad4a434a4 Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Sat, 18 Jul 2015 13:10:45 +0200
Subject: [PATCH] REE: fix uninitialized registers handling

gcc/ChangeLog:

	PR rtl-optimization/66790
	* df.h (DF_MIR): New macro.
	(DF_LAST_PROBLEM_PLUS1): Update to be past DF_MIR
	(DF_MIR_INFO_BB): New macro.
	(DF_MIR_IN, DF_MIR_OUT): New macros.
	(struct df_mir_bb_info): New.
	(df_mir): New macro.
	(df_mir_add_problem, df_mir_simulate_one_insn): New forward
	declarations.
	(df_mir_get_bb_info): New.
	* df-problems.c (struct df_mir_problem_data): New.
	(df_mir_free_bb_info, df_mir_alloc, df_mir_reset,
	df_mir_bb_local_compute, df_mir_local_compute, df_mir_init,
	df_mir_confluence_n, df_mir_transfer_function, df_mir_free,
	df_mir_top_dump, df_mir_bottom_dump,
	df_mir_verify_solution_start, df_mir_verify_solution_end): New.
	(problem_MIR): New.
	(df_mir_add_problem, df_mir_simulate_one_insn): New.
	* timevar.def (TV_DF_MIR): New.
	* ree.c: Include bitmap.h
	(add_removable_extension): Add an INIT_REGS parameter.  Use it
	to skip extensions that may get an uninitialized register.
	(find_removable_extensions): Compute must-initialized registers
	using the MIR dataflow problem. Update the call to
	add_removable_extension.
	(find_and_remove_re): Call df_mir_add_problem.
---
 gcc/df-problems.c | 411 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/df.h          |  37 ++++-
 gcc/ree.c         |  61 ++++++--
 gcc/timevar.def   |   1 +
 4 files changed, 496 insertions(+), 14 deletions(-)

diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index d4b5d76..fdb067d 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -1848,6 +1848,417 @@ df_live_verify_transfer_functions (void)
 }
 \f
 /*----------------------------------------------------------------------------
+   MUST-INITIALIZED REGISTERS.
+----------------------------------------------------------------------------*/
+
+/* Private data used to verify the solution for this problem.  */
+struct df_mir_problem_data
+{
+  bitmap_head *in;
+  bitmap_head *out;
+  /* An obstack for the bitmaps we need for this problem.  */
+  bitmap_obstack mir_bitmaps;
+};
+
+
+/* Free basic block info.  */
+
+static void
+df_mir_free_bb_info (basic_block bb ATTRIBUTE_UNUSED,
+		     void *vbb_info)
+{
+  struct df_mir_bb_info *bb_info = (struct df_mir_bb_info *) vbb_info;
+  if (bb_info)
+    {
+      bitmap_clear (&bb_info->gen);
+      bitmap_clear (&bb_info->kill);
+      bitmap_clear (&bb_info->in);
+      bitmap_clear (&bb_info->out);
+    }
+}
+
+
+/* Allocate or reset bitmaps for DF_MIR blocks. The solution bits are
+   not touched unless the block is new.  */
+
+static void
+df_mir_alloc (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+  struct df_mir_problem_data *problem_data;
+
+  if (df_mir->problem_data)
+    problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  else
+    {
+      problem_data = XNEW (struct df_mir_problem_data);
+      df_mir->problem_data = problem_data;
+
+      problem_data->out = NULL;
+      problem_data->in = NULL;
+      bitmap_obstack_initialize (&problem_data->mir_bitmaps);
+    }
+
+  df_grow_bb_info (df_mir);
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+
+      /* When bitmaps are already initialized, just clear them.  */
+      if (bb_info->kill.obstack)
+	{
+	  bitmap_clear (&bb_info->kill);
+	  bitmap_clear (&bb_info->gen);
+	}
+      else
+	{
+	  bitmap_initialize (&bb_info->kill, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->gen, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->in, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->out, &problem_data->mir_bitmaps);
+	}
+    }
+  df_mir->optional_p = 1;
+}
+
+
+/* Reset the global solution for recalculation.  */
+
+static void
+df_mir_reset (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+      gcc_assert (bb_info);
+      bb_info->visited = false;
+      bitmap_clear (&bb_info->in);
+      bitmap_clear (&bb_info->out);
+    }
+}
+
+
+/* Compute local uninitialized register info for basic block BB.  */
+
+static void
+df_mir_bb_local_compute (unsigned int bb_index)
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+  rtx_insn *insn;
+  df_ref def;
+  int luid = 0;
+
+  FOR_BB_INSNS (bb, insn)
+    {
+      unsigned int uid = INSN_UID (insn);
+      struct df_insn_info *insn_info = DF_INSN_UID_GET (uid);
+
+      /* Inserting labels does not always trigger the incremental
+	 rescanning.  */
+      if (!insn_info)
+	{
+	  gcc_assert (!INSN_P (insn));
+	  insn_info = df_insn_create_insn_record (insn);
+	}
+
+      DF_INSN_INFO_LUID (insn_info) = luid;
+      if (!INSN_P (insn))
+	continue;
+
+      luid++;
+      df_mir_simulate_one_insn (bb, insn, &bb_info->kill, &bb_info->gen);
+    }
+
+  FOR_EACH_ARTIFICIAL_DEF (def, bb_index)
+    bitmap_set_bit (&bb_info->gen, DF_REF_REGNO (def));
+}
+
+
+/* Compute local uninitialized register info.  */
+
+static void
+df_mir_local_compute (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+
+  df_grow_insn_info ();
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      df_mir_bb_local_compute (bb_index);
+    }
+}
+
+
+/* Initialize the solution vectors.  */
+
+static void
+df_mir_init (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+
+      bb_info->visited = false;
+      bitmap_clear (&bb_info->in);
+      bitmap_clear (&bb_info->out);
+    }
+}
+
+
+/* Forward confluence function that ignores fake edges.  */
+
+static bool
+df_mir_confluence_n (edge e)
+{
+  bitmap op1 = &df_mir_get_bb_info (e->dest->index)->in;
+  bitmap op2 = &df_mir_get_bb_info (e->src->index)->out;
+
+  if (e->flags & EDGE_FAKE)
+    return false;
+
+  /* A register is must-initialized at the entry of a basic block iff it is
+     must-initialized at the exit of all the predecessors.
+
+     This problem determines which registers may be uninitialized. It first
+     assumes these are all initialized and then it eliminates the ones reached
+     by paths without crossing a definition.  The IN bitmap is clear at first
+     (i.e. all registers are assumed not to be initialized) so don't consider
+     its value the first time.  */
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (e->dest->index);
+  if (bb_info->visited)
+    return bitmap_and_into (op1, op2);
+  else
+    {
+      bb_info->visited = true;
+      bitmap_copy (op1, op2);
+      return true;
+    }
+}
+
+
+/* Transfer function for the forwards must-initialized problem.  */
+
+static bool
+df_mir_transfer_function (int bb_index)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+  bitmap in = &bb_info->in;
+  bitmap out = &bb_info->out;
+  bitmap gen = &bb_info->gen;
+  bitmap kill = &bb_info->kill;
+
+  return bitmap_ior_and_compl (out, gen, in, kill);
+}
+
+
+/* Free all storage associated with the problem.  */
+
+static void
+df_mir_free (void)
+{
+  struct df_mir_problem_data *problem_data
+    = (struct df_mir_problem_data *) df_mir->problem_data;
+  if (df_mir->block_info)
+    {
+      df_mir->block_info_size = 0;
+      free (df_mir->block_info);
+      df_mir->block_info = NULL;
+      bitmap_obstack_release (&problem_data->mir_bitmaps);
+      free (problem_data);
+      df_mir->problem_data = NULL;
+    }
+  free (df_mir);
+}
+
+
+/* Debugging info at top of bb.  */
+
+static void
+df_mir_top_dump (basic_block bb, FILE *file)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  if (!bb_info)
+    return;
+
+  fprintf (file, ";; mir   in  \t");
+  df_print_regset (file, &bb_info->in);
+  fprintf (file, ";; mir   kill\t");
+  df_print_regset (file, &bb_info->kill);
+  fprintf (file, ";; mir   gen \t");
+  df_print_regset (file, &bb_info->gen);
+}
+
+/* Debugging info at bottom of bb.  */
+
+static void
+df_mir_bottom_dump (basic_block bb, FILE *file)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  if (!bb_info)
+    return;
+
+  fprintf (file, ";; mir   out \t");
+  df_print_regset (file, &bb_info->out);
+}
+
+
+/* Build the datastructure to verify that the solution to the dataflow
+   equations is not dirty.  */
+
+static void
+df_mir_verify_solution_start (void)
+{
+  basic_block bb;
+  struct df_mir_problem_data *problem_data;
+  if (df_mir->solutions_dirty)
+    return;
+
+  /* Set it true so that the solution is recomputed.  */
+  df_mir->solutions_dirty = true;
+
+  problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  problem_data->in = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+  problem_data->out = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+  bitmap_obstack_initialize (&problem_data->mir_bitmaps);
+
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      bitmap_initialize (&problem_data->in[bb->index], &problem_data->mir_bitmaps);
+      bitmap_initialize (&problem_data->out[bb->index], &problem_data->mir_bitmaps);
+      bitmap_copy (&problem_data->in[bb->index], DF_MIR_IN (bb));
+      bitmap_copy (&problem_data->out[bb->index], DF_MIR_OUT (bb));
+    }
+}
+
+
+/* Compare the saved datastructure and the new solution to the dataflow
+   equations.  */
+
+static void
+df_mir_verify_solution_end (void)
+{
+  struct df_mir_problem_data *problem_data;
+  basic_block bb;
+
+  problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  if (!problem_data->out)
+    return;
+
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      if ((!bitmap_equal_p (&problem_data->in[bb->index], DF_MIR_IN (bb)))
+	  || (!bitmap_equal_p (&problem_data->out[bb->index], DF_MIR_OUT (bb))))
+	{
+	  /*df_dump (stderr);*/
+	  gcc_unreachable ();
+	}
+    }
+
+  /* Cannot delete them immediately because you may want to dump them
+     if the comparison fails.  */
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      bitmap_clear (&problem_data->in[bb->index]);
+      bitmap_clear (&problem_data->out[bb->index]);
+    }
+
+  free (problem_data->in);
+  free (problem_data->out);
+  bitmap_obstack_release (&problem_data->mir_bitmaps);
+  free (problem_data);
+  df_mir->problem_data = NULL;
+}
+
+
+/* All of the information associated with every instance of the problem.  */
+
+static struct df_problem problem_MIR =
+{
+  DF_MIR,                       /* Problem id.  */
+  DF_FORWARD,                   /* Direction.  */
+  df_mir_alloc,                 /* Allocate the problem specific data.  */
+  df_mir_reset,                 /* Reset global information.  */
+  df_mir_free_bb_info,          /* Free basic block info.  */
+  df_mir_local_compute,         /* Local compute function.  */
+  df_mir_init,                  /* Init the solution specific data.  */
+  df_worklist_dataflow,         /* Worklist solver.  */
+  NULL,                         /* Confluence operator 0.  */
+  df_mir_confluence_n,          /* Confluence operator n.  */
+  df_mir_transfer_function,     /* Transfer function.  */
+  NULL,                         /* Finalize function.  */
+  df_mir_free,                  /* Free all of the problem information.  */
+  df_mir_free,                  /* Remove this problem from the stack of dataflow problems.  */
+  NULL,                         /* Debugging.  */
+  df_mir_top_dump,              /* Debugging start block.  */
+  df_mir_bottom_dump,           /* Debugging end block.  */
+  NULL,                         /* Debugging start insn.  */
+  NULL,                         /* Debugging end insn.  */
+  df_mir_verify_solution_start, /* Incremental solution verify start.  */
+  df_mir_verify_solution_end,   /* Incremental solution verify end.  */
+  NULL,                         /* Dependent problem.  */
+  sizeof (struct df_mir_bb_info),/* Size of entry of block_info array.  */
+  TV_DF_MIR,                    /* Timing variable.  */
+  false                         /* Reset blocks on dropping out of blocks_to_analyze.  */
+};
+
+
+/* Create a new DATAFLOW instance and add it to an existing instance
+   of DF.  */
+
+void
+df_mir_add_problem (void)
+{
+  df_add_problem (&problem_MIR);
+  /* These will be initialized when df_scan_blocks processes each
+     block.  */
+  df_mir->out_of_date_transfer_functions = BITMAP_ALLOC (&df_bitmap_obstack);
+}
+
+
+/* Apply the effects of the gen/kills in INSN to the corresponding bitmaps.  */
+
+void
+df_mir_simulate_one_insn (basic_block bb ATTRIBUTE_UNUSED, rtx_insn *insn,
+			  bitmap kill, bitmap gen)
+{
+  df_ref def;
+
+  FOR_EACH_INSN_DEF (def, insn)
+    {
+      unsigned int regno = DF_REF_REGNO (def);
+
+      if (DF_REF_FLAGS_IS_SET (def,
+			       DF_REF_PARTIAL | DF_REF_CONDITIONAL))
+	/* All partial or conditional def
+	   seen are included in the gen set. */
+	bitmap_set_bit (gen, regno);
+      else if (DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
+	{
+	  /* Only must clobbers for the entire reg destroy the value.  Note
+	     that if this instruction clobbers the register, previous defs are
+	     out of interest.  */
+	  bitmap_set_bit (kill, regno);
+	  bitmap_clear_bit (gen, regno);
+	}
+      else if (! DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER))
+	bitmap_set_bit (gen, regno);
+    }
+}
+\f
+/*----------------------------------------------------------------------------
    CREATE DEF_USE (DU) and / or USE_DEF (UD) CHAINS
 
    Link either the defs to the uses and / or the uses to the defs.
diff --git a/gcc/df.h b/gcc/df.h
index 44e5fdb..d83eaaf 100644
--- a/gcc/df.h
+++ b/gcc/df.h
@@ -51,8 +51,9 @@ union df_ref_d;
 #define DF_WORD_LR 5      /* Subreg tracking lr.  */
 #define DF_NOTE    6      /* REG_DEAD and REG_UNUSED notes.  */
 #define DF_MD      7      /* Multiple Definitions. */
+#define DF_MIR     8      /* Must-initialized Registers.  */
 
-#define DF_LAST_PROBLEM_PLUS1 (DF_MD + 1)
+#define DF_LAST_PROBLEM_PLUS1 (DF_MIR + 1)
 
 /* Dataflow direction.  */
 enum df_flow_dir
@@ -612,12 +613,16 @@ struct df_d
 #define DF_LIVE_BB_INFO(BB) (df_live_get_bb_info ((BB)->index))
 #define DF_WORD_LR_BB_INFO(BB) (df_word_lr_get_bb_info ((BB)->index))
 #define DF_MD_BB_INFO(BB) (df_md_get_bb_info ((BB)->index))
+#define DF_MIR_BB_INFO(BB) (df_mir_get_bb_info ((BB)->index))
 
 /* Most transformations that wish to use live register analysis will
    use these macros.  This info is the and of the lr and live sets.  */
 #define DF_LIVE_IN(BB) (&DF_LIVE_BB_INFO (BB)->in)
 #define DF_LIVE_OUT(BB) (&DF_LIVE_BB_INFO (BB)->out)
 
+#define DF_MIR_IN(BB) (&DF_MIR_BB_INFO (BB)->in)
+#define DF_MIR_OUT(BB) (&DF_MIR_BB_INFO (BB)->out)
+
 /* These macros are used by passes that are not tolerant of
    uninitialized variables.  This intolerance should eventually
    be fixed.  */
@@ -896,6 +901,24 @@ struct df_word_lr_bb_info
   bitmap_head out;   /* At the bottom of the block.  */
 };
 
+/* Must-initialized registers.  All bitmaps are referenced by the
+   register number.  */
+struct df_mir_bb_info
+{
+  /* Local sets to describe the basic blocks.  */
+  bitmap_head kill;  /* The set of registers unset in this block.  Calls,
+		        for instance, unset registers.  */
+  bitmap_head gen;   /* The set of registers set in this block, excluding the
+			ones killed later on in this block.  */
+
+  bool visited;      /* Whether dataflow problem solving visited this block.
+			Used only during problem solving.  */
+
+  /* The results of the dataflow problem.  */
+  bitmap_head in;    /* At the top of the block.  */
+  bitmap_head out;   /* At the bottom of the block.  */
+};
+
 
 /* This is used for debugging and for the dumpers to find the latest
    instance so that the df info can be added to the dumps.  This
@@ -909,6 +932,7 @@ extern struct df_d *df;
 #define df_word_lr (df->problems_by_index[DF_WORD_LR])
 #define df_note    (df->problems_by_index[DF_NOTE])
 #define df_md      (df->problems_by_index[DF_MD])
+#define df_mir     (df->problems_by_index[DF_MIR])
 
 /* This symbol turns on checking that each modification of the cfg has
   been identified to the appropriate df routines.  It is not part of
@@ -1005,6 +1029,8 @@ extern void df_note_add_problem (void);
 extern void df_md_add_problem (void);
 extern void df_md_simulate_artificial_defs_at_top (basic_block, bitmap);
 extern void df_md_simulate_one_insn (basic_block, rtx_insn *, bitmap);
+extern void df_mir_add_problem (void);
+extern void df_mir_simulate_one_insn (basic_block, rtx_insn *, bitmap, bitmap);
 extern void df_simulate_find_noclobber_defs (rtx_insn *, bitmap);
 extern void df_simulate_find_defs (rtx_insn *, bitmap);
 extern void df_simulate_defs (rtx_insn *, bitmap);
@@ -1111,6 +1137,15 @@ df_word_lr_get_bb_info (unsigned int index)
     return NULL;
 }
 
+static inline struct df_mir_bb_info *
+df_mir_get_bb_info (unsigned int index)
+{
+  if (index < df_mir->block_info_size)
+    return &((struct df_mir_bb_info *) df_mir->block_info)[index];
+  else
+    return NULL;
+}
+
 /* Get the live at out set for BB no matter what problem happens to be
    defined.  This function is used by the register allocators who
    choose different dataflow problems depending on the optimization
diff --git a/gcc/ree.c b/gcc/ree.c
index 016659c..aec98a8 100644
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -246,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "tree-pass.h"
 #include "cgraph.h"
+#include "bitmap.h"
 
 /* This structure represents a candidate for elimination.  */
 
@@ -973,7 +974,8 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
 static void
 add_removable_extension (const_rtx expr, rtx_insn *insn,
 			 vec<ext_cand> *insn_list,
-			 unsigned *def_map)
+			 unsigned *def_map,
+			 bitmap init_regs)
 {
   enum rtx_code code;
   machine_mode mode;
@@ -993,11 +995,28 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
       && (code == SIGN_EXTEND || code == ZERO_EXTEND)
       && REG_P (XEXP (src, 0)))
     {
+      const rtx reg = XEXP (src, 0);
       struct df_link *defs, *def;
       ext_cand *cand;
 
-      /* First, make sure we can get all the reaching definitions.  */
-      defs = get_defs (insn, XEXP (src, 0), NULL);
+      /* If there exists a path from the entry to this instruction that
+	 leaves this register uninitialized, removing the extension could
+	 change the behavior of correct programs.  So first, check it is not
+	 the case.  */
+      if (!bitmap_bit_p (init_regs, REGNO (reg)))
+	{
+	  if (dump_file)
+	    {
+	      fprintf (dump_file, "Cannot eliminate extension:\n");
+	      print_rtl_single (dump_file, insn);
+	      fprintf (dump_file, " because it can operate on uninitialized"
+			          " data\n");
+	    }
+	  return;
+	}
+
+      /* Second, make sure we can get all the reaching definitions.  */
+      defs = get_defs (insn, reg, NULL);
       if (!defs)
 	{
 	  if (dump_file)
@@ -1009,7 +1028,7 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
 	  return;
 	}
 
-      /* Second, make sure the reaching definitions don't feed another and
+      /* Third, make sure the reaching definitions don't feed another and
 	 different extension.  FIXME: this obviously can be improved.  */
       for (def = defs; def; def = def->next)
 	if ((idx = def_map[INSN_UID (DF_REF_INSN (def->ref))])
@@ -1099,18 +1118,33 @@ find_removable_extensions (void)
   rtx_insn *insn;
   rtx set;
   unsigned *def_map = XCNEWVEC (unsigned, max_insn_uid);
+  bitmap_head init, kill, gen, tmp;
+
+  bitmap_initialize (&init, NULL);
+  bitmap_initialize (&kill, NULL);
+  bitmap_initialize (&gen, NULL);
+  bitmap_initialize (&tmp, NULL);
 
   FOR_EACH_BB_FN (bb, cfun)
-    FOR_BB_INSNS (bb, insn)
-      {
-	if (!NONDEBUG_INSN_P (insn))
-	  continue;
+    {
+      bitmap_copy (&init, DF_MIR_IN (bb));
+      bitmap_clear (&kill);
+      bitmap_clear (&gen);
 
-	set = single_set (insn);
-	if (set == NULL_RTX)
-	  continue;
-	add_removable_extension (set, insn, &insn_list, def_map);
-      }
+      FOR_BB_INSNS (bb, insn)
+	{
+	  if (NONDEBUG_INSN_P (insn))
+	    {
+	      set = single_set (insn);
+	      if (set != NULL_RTX)
+		add_removable_extension (set, insn, &insn_list, def_map,
+					 &init);
+	      df_mir_simulate_one_insn (bb, insn, &kill, &gen);
+	      bitmap_ior_and_compl (&tmp, &gen, &init, &kill);
+	      bitmap_copy (&init, &tmp);
+	    }
+	}
+    }
 
   XDELETEVEC (def_map);
 
@@ -1135,6 +1169,7 @@ find_and_remove_re (void)
      extension instruction.  */
   df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
   df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
+  df_mir_add_problem ();
   df_analyze ();
   df_set_flags (DF_DEFER_INSN_RESCAN);
 
diff --git a/gcc/timevar.def b/gcc/timevar.def
index aee36e6..6066987 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -115,6 +115,7 @@ DEFTIMEVAR (TV_DF_MD		     , "df multiple defs")
 DEFTIMEVAR (TV_DF_RD		     , "df reaching defs")
 DEFTIMEVAR (TV_DF_LR		     , "df live regs")
 DEFTIMEVAR (TV_DF_LIVE		     , "df live&initialized regs")
+DEFTIMEVAR (TV_DF_MIR		     , "df must-initialized regs")
 DEFTIMEVAR (TV_DF_CHAIN		     , "df use-def / def-use chains")
 DEFTIMEVAR (TV_DF_WORD_LR	     , "df live reg subwords")
 DEFTIMEVAR (TV_DF_NOTE		     , "df reg dead/unused notes")
-- 
2.4.5


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH, PING] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-07-19  6:40 [PATCH] PR rtl-optimization/66790: uninitialized registers handling in REE Pierre-Marie de Rodat
@ 2015-07-27  9:05 ` Pierre-Marie de Rodat
  2015-08-08  8:58   ` [PATCH, PING*2] " Pierre-Marie de Rodat
  0 siblings, 1 reply; 11+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-27  9:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jeff Law

On 07/19/2015 12:14 AM, Pierre-Marie de Rodat wrote:
> This patch is an attempt to fix PR rtl-optimization/66790: please see
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790> for the context.
> This adds a new dataflow problem (MIR for Must-Initialized Registers)
> and use it in the REE pass to remove oversights, fixing the original issue.

Ping for the patch submitted in 
<https://gcc.gnu.org/ml/gcc-patches/2015-07/msg01604.html>.

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH, PING*2] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-07-27  9:05 ` [PATCH, PING] " Pierre-Marie de Rodat
@ 2015-08-08  8:58   ` Pierre-Marie de Rodat
  2015-08-31  7:26     ` [PATCH, PING*3] " Pierre-Marie de Rodat
  0 siblings, 1 reply; 11+ messages in thread
From: Pierre-Marie de Rodat @ 2015-08-08  8:58 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jeff Law

On 07/19/2015 12:14 AM, Pierre-Marie de Rodat wrote:
> This patch is an attempt to fix PR rtl-optimization/66790: please see
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790> for the context.
> This adds a new dataflow problem (MIR for Must-Initialized Registers)
> and use it in the REE pass to remove oversights, fixing the original
> issue.

Ping for the discussion on Bugzilla. Thanks in advance! :-)

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH, PING*3] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-08-08  8:58   ` [PATCH, PING*2] " Pierre-Marie de Rodat
@ 2015-08-31  7:26     ` Pierre-Marie de Rodat
  2015-10-13 15:17       ` [PATCH v2] " Pierre-Marie de Rodat
  0 siblings, 1 reply; 11+ messages in thread
From: Pierre-Marie de Rodat @ 2015-08-31  7:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jeff Law

On 07/19/2015 12:14 AM, Pierre-Marie de Rodat wrote:
> This patch is an attempt to fix PR rtl-optimization/66790: please see
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790> for the context.
> This adds a new dataflow problem (MIR for Must-Initialized Registers)
> and use it in the REE pass to remove oversights, fixing the original
> issue.

Ping for the discussion on Bugzilla. Thanks in advance!

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-08-31  7:26     ` [PATCH, PING*3] " Pierre-Marie de Rodat
@ 2015-10-13 15:17       ` Pierre-Marie de Rodat
  2015-10-14 13:41         ` Bernd Schmidt
  2015-10-23 11:31         ` Bernd Schmidt
  0 siblings, 2 replies; 11+ messages in thread
From: Pierre-Marie de Rodat @ 2015-10-13 15:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Jeff Law, Bernd Schmidt

[-- Attachment #1: Type: text/plain, Size: 2217 bytes --]

Hello,

The first attached patch is the second attempt to fix PR 
rtl-optimization/66790 (see 
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790>).

The second one is a fix for some inconsistency noticed while working on 
the original bug. This specific patch fixes no known bug, but anyway…

Both were bootstrapped and regtested on x86_64-linux. Ok to commit? 
Thank you in advance!

[PATCH 1/2] REE: fix uninitialized registers handling

gcc/ChangeLog:

         PR rtl-optimization/66790
         * df.h (DF_MIR): New macro.
         (DF_LAST_PROBLEM_PLUS1): Update to be past DF_MIR
         (DF_MIR_INFO_BB): New macro.
         (DF_MIR_IN, DF_MIR_OUT): New macros.
         (struct df_mir_bb_info): New.
         (df_mir): New macro.
         (df_mir_add_problem, df_mir_simulate_one_insn): New forward
         declarations.
         (df_mir_get_bb_info): New.
         * df-problems.c (struct df_mir_problem_data): New.
         (df_mir_free_bb_info, df_mir_alloc, df_mir_reset,
         df_mir_bb_local_compute, df_mir_local_compute, df_mir_init,
         df_mir_confluence_0, df_mir_confluence_n,
         df_mir_transfer_function, df_mir_free, df_mir_top_dump,
         df_mir_bottom_dump, df_mir_verify_solution_start,
         df_mir_verify_solution_end): New.
         (problem_MIR): New.
         (df_mir_add_problem, df_mir_simulate_one_insn): New.
         * timevar.def (TV_DF_MIR): New.
         * ree.c: Include bitmap.h
         (add_removable_extension): Add an INIT_REGS parameter.  Use it
         to skip zero-extensions that may get an uninitialized register.
         (find_removable_extensions): Compute must-initialized registers
         using the MIR dataflow problem. Update the call to
         add_removable_extension.
         (find_and_remove_re): Call df_mir_add_problem.

gcc/testsuite/ChangeLog:

         * gnat.dg/opt50.adb: New test.
         * gnat.dg/opt50_pkg.adb: New helper.
         * gnat.dg/opt50_pkg.ads: New helper.

[PATCH 2/2] DF_LIVE: make clobbers cancel effect of previous GENs in
  the same BBs

gcc/ChangeLog:

         * df-problems.c (df_live_bb_local_compute): Clear GEN bits for
         DF_REF_MUST_CLOBBER references.

-- 
Pierre-Marie de Rodat

[-- Attachment #2: 0001-REE-fix-uninitialized-registers-handling.patch --]
[-- Type: text/x-diff, Size: 24908 bytes --]

From d7bf6e8c194f66e6b7e1823ad3d118115e4406bc Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Sat, 18 Jul 2015 13:10:45 +0200
Subject: [PATCH 1/2] REE: fix uninitialized registers handling

gcc/ChangeLog:

	PR rtl-optimization/66790
	* df.h (DF_MIR): New macro.
	(DF_LAST_PROBLEM_PLUS1): Update to be past DF_MIR
	(DF_MIR_INFO_BB): New macro.
	(DF_MIR_IN, DF_MIR_OUT): New macros.
	(struct df_mir_bb_info): New.
	(df_mir): New macro.
	(df_mir_add_problem, df_mir_simulate_one_insn): New forward
	declarations.
	(df_mir_get_bb_info): New.
	* df-problems.c (struct df_mir_problem_data): New.
	(df_mir_free_bb_info, df_mir_alloc, df_mir_reset,
	df_mir_bb_local_compute, df_mir_local_compute, df_mir_init,
	df_mir_confluence_0, df_mir_confluence_n,
	df_mir_transfer_function, df_mir_free, df_mir_top_dump,
	df_mir_bottom_dump, df_mir_verify_solution_start,
	df_mir_verify_solution_end): New.
	(problem_MIR): New.
	(df_mir_add_problem, df_mir_simulate_one_insn): New.
	* timevar.def (TV_DF_MIR): New.
	* ree.c: Include bitmap.h
	(add_removable_extension): Add an INIT_REGS parameter.  Use it
	to skip zero-extensions that may get an uninitialized register.
	(find_removable_extensions): Compute must-initialized registers
	using the MIR dataflow problem. Update the call to
	add_removable_extension.
	(find_and_remove_re): Call df_mir_add_problem.

gcc/testsuite/ChangeLog:

	* gnat.dg/opt50.adb: New test.
	* gnat.dg/opt50_pkg.adb: New helper.
	* gnat.dg/opt50_pkg.ads: New helper.
---
 gcc/df-problems.c                   | 406 ++++++++++++++++++++++++++++++++++++
 gcc/df.h                            |  34 ++-
 gcc/ree.c                           |  62 ++++--
 gcc/testsuite/gnat.dg/opt50.adb     |  23 ++
 gcc/testsuite/gnat.dg/opt50_pkg.adb |  48 +++++
 gcc/testsuite/gnat.dg/opt50_pkg.ads |  12 ++
 gcc/timevar.def                     |   1 +
 7 files changed, 572 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gnat.dg/opt50.adb
 create mode 100644 gcc/testsuite/gnat.dg/opt50_pkg.adb
 create mode 100644 gcc/testsuite/gnat.dg/opt50_pkg.ads

diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index 153732a..c08ae36 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -1849,6 +1849,412 @@ df_live_verify_transfer_functions (void)
 }
 \f
 /*----------------------------------------------------------------------------
+   MUST-INITIALIZED REGISTERS.
+----------------------------------------------------------------------------*/
+
+/* Private data used to verify the solution for this problem.  */
+struct df_mir_problem_data
+{
+  bitmap_head *in;
+  bitmap_head *out;
+  /* An obstack for the bitmaps we need for this problem.  */
+  bitmap_obstack mir_bitmaps;
+};
+
+
+/* Free basic block info.  */
+
+static void
+df_mir_free_bb_info (basic_block bb ATTRIBUTE_UNUSED,
+		     void *vbb_info)
+{
+  struct df_mir_bb_info *bb_info = (struct df_mir_bb_info *) vbb_info;
+  if (bb_info)
+    {
+      bitmap_clear (&bb_info->gen);
+      bitmap_clear (&bb_info->kill);
+      bitmap_clear (&bb_info->in);
+      bitmap_clear (&bb_info->out);
+    }
+}
+
+
+/* Allocate or reset bitmaps for DF_MIR blocks. The solution bits are
+   not touched unless the block is new.  */
+
+static void
+df_mir_alloc (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+  struct df_mir_problem_data *problem_data;
+
+  if (df_mir->problem_data)
+    problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  else
+    {
+      problem_data = XNEW (struct df_mir_problem_data);
+      df_mir->problem_data = problem_data;
+
+      problem_data->out = NULL;
+      problem_data->in = NULL;
+      bitmap_obstack_initialize (&problem_data->mir_bitmaps);
+    }
+
+  df_grow_bb_info (df_mir);
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+
+      /* When bitmaps are already initialized, just clear them.  */
+      if (bb_info->kill.obstack)
+	{
+	  bitmap_clear (&bb_info->kill);
+	  bitmap_clear (&bb_info->gen);
+	}
+      else
+	{
+	  bitmap_initialize (&bb_info->kill, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->gen, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->in, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->out, &problem_data->mir_bitmaps);
+	  bitmap_set_range (&bb_info->in, 0, DF_REG_SIZE (df));
+	  bitmap_set_range (&bb_info->out, 0, DF_REG_SIZE (df));
+	}
+    }
+
+  df_mir->optional_p = 1;
+}
+
+
+/* Reset the global solution for recalculation.  */
+
+static void
+df_mir_reset (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+
+      gcc_assert (bb_info);
+
+      bitmap_clear (&bb_info->in);
+      bitmap_set_range (&bb_info->in, 0, DF_REG_SIZE (df));
+      bitmap_clear (&bb_info->out);
+      bitmap_set_range (&bb_info->out, 0, DF_REG_SIZE (df));
+    }
+}
+
+
+/* Compute local uninitialized register info for basic block BB.  */
+
+static void
+df_mir_bb_local_compute (unsigned int bb_index)
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+  rtx_insn *insn;
+  int luid = 0;
+
+  /* Ignoring artificial defs is intentionnal: these often pretend that some
+     registers carry incoming arguments (when they are FUNCTION_ARG_REGNO) even
+     though they are not used for that.  As a result, conservatively assume
+     they may be uninitialized.  */
+
+  FOR_BB_INSNS (bb, insn)
+    {
+      unsigned int uid = INSN_UID (insn);
+      struct df_insn_info *insn_info = DF_INSN_UID_GET (uid);
+
+      /* Inserting labels does not always trigger the incremental
+	 rescanning.  */
+      if (!insn_info)
+	{
+	  gcc_assert (!INSN_P (insn));
+	  insn_info = df_insn_create_insn_record (insn);
+	}
+
+      DF_INSN_INFO_LUID (insn_info) = luid;
+      if (!INSN_P (insn))
+	continue;
+
+      luid++;
+      df_mir_simulate_one_insn (bb, insn, &bb_info->kill, &bb_info->gen);
+    }
+}
+
+
+/* Compute local uninitialized register info.  */
+
+static void
+df_mir_local_compute (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+
+  df_grow_insn_info ();
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      df_mir_bb_local_compute (bb_index);
+    }
+}
+
+
+/* Initialize the solution vectors.  */
+
+static void
+df_mir_init (bitmap all_blocks)
+{
+  df_mir_reset (all_blocks);
+}
+
+
+/* Initialize IN sets for blocks with no predecessors: when landing on such
+   blocks, assume all registers are uninitialized.  */
+
+static void
+df_mir_confluence_0 (basic_block bb)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  bitmap_clear (&bb_info->in);
+}
+
+
+/* Forward confluence function that ignores fake edges.  */
+
+static bool
+df_mir_confluence_n (edge e)
+{
+  bitmap op1 = &df_mir_get_bb_info (e->dest->index)->in;
+  bitmap op2 = &df_mir_get_bb_info (e->src->index)->out;
+
+  if (e->flags & EDGE_FAKE)
+    return false;
+
+  /* A register is must-initialized at the entry of a basic block iff it is
+     must-initialized at the exit of all the predecessors.  */
+  return bitmap_and_into (op1, op2);
+}
+
+
+/* Transfer function for the forwards must-initialized problem.  */
+
+static bool
+df_mir_transfer_function (int bb_index)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+  bitmap in = &bb_info->in;
+  bitmap out = &bb_info->out;
+  bitmap gen = &bb_info->gen;
+  bitmap kill = &bb_info->kill;
+
+  return bitmap_ior_and_compl (out, gen, in, kill);
+}
+
+
+/* Free all storage associated with the problem.  */
+
+static void
+df_mir_free (void)
+{
+  struct df_mir_problem_data *problem_data
+    = (struct df_mir_problem_data *) df_mir->problem_data;
+  if (df_mir->block_info)
+    {
+      df_mir->block_info_size = 0;
+      free (df_mir->block_info);
+      df_mir->block_info = NULL;
+      bitmap_obstack_release (&problem_data->mir_bitmaps);
+      free (problem_data);
+      df_mir->problem_data = NULL;
+    }
+  free (df_mir);
+}
+
+
+/* Debugging info at top of bb.  */
+
+static void
+df_mir_top_dump (basic_block bb, FILE *file)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  if (!bb_info)
+    return;
+
+  fprintf (file, ";; mir   in  \t");
+  df_print_regset (file, &bb_info->in);
+  fprintf (file, ";; mir   kill\t");
+  df_print_regset (file, &bb_info->kill);
+  fprintf (file, ";; mir   gen \t");
+  df_print_regset (file, &bb_info->gen);
+}
+
+/* Debugging info at bottom of bb.  */
+
+static void
+df_mir_bottom_dump (basic_block bb, FILE *file)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  if (!bb_info)
+    return;
+
+  fprintf (file, ";; mir   out \t");
+  df_print_regset (file, &bb_info->out);
+}
+
+
+/* Build the datastructure to verify that the solution to the dataflow
+   equations is not dirty.  */
+
+static void
+df_mir_verify_solution_start (void)
+{
+  basic_block bb;
+  struct df_mir_problem_data *problem_data;
+  if (df_mir->solutions_dirty)
+    return;
+
+  /* Set it true so that the solution is recomputed.  */
+  df_mir->solutions_dirty = true;
+
+  problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  problem_data->in = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+  problem_data->out = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+  bitmap_obstack_initialize (&problem_data->mir_bitmaps);
+
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      bitmap_initialize (&problem_data->in[bb->index], &problem_data->mir_bitmaps);
+      bitmap_initialize (&problem_data->out[bb->index], &problem_data->mir_bitmaps);
+      bitmap_copy (&problem_data->in[bb->index], DF_MIR_IN (bb));
+      bitmap_copy (&problem_data->out[bb->index], DF_MIR_OUT (bb));
+    }
+}
+
+
+/* Compare the saved datastructure and the new solution to the dataflow
+   equations.  */
+
+static void
+df_mir_verify_solution_end (void)
+{
+  struct df_mir_problem_data *problem_data;
+  basic_block bb;
+
+  problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  if (!problem_data->out)
+    return;
+
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      if ((!bitmap_equal_p (&problem_data->in[bb->index], DF_MIR_IN (bb)))
+	  || (!bitmap_equal_p (&problem_data->out[bb->index], DF_MIR_OUT (bb))))
+	{
+	  /*df_dump (stderr);*/
+	  gcc_unreachable ();
+	}
+    }
+
+  /* Cannot delete them immediately because you may want to dump them
+     if the comparison fails.  */
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      bitmap_clear (&problem_data->in[bb->index]);
+      bitmap_clear (&problem_data->out[bb->index]);
+    }
+
+  free (problem_data->in);
+  free (problem_data->out);
+  bitmap_obstack_release (&problem_data->mir_bitmaps);
+  free (problem_data);
+  df_mir->problem_data = NULL;
+}
+
+
+/* All of the information associated with every instance of the problem.  */
+
+static struct df_problem problem_MIR =
+{
+  DF_MIR,                       /* Problem id.  */
+  DF_FORWARD,                   /* Direction.  */
+  df_mir_alloc,                 /* Allocate the problem specific data.  */
+  df_mir_reset,                 /* Reset global information.  */
+  df_mir_free_bb_info,          /* Free basic block info.  */
+  df_mir_local_compute,         /* Local compute function.  */
+  df_mir_init,                  /* Init the solution specific data.  */
+  df_worklist_dataflow,         /* Worklist solver.  */
+  df_mir_confluence_0,          /* Confluence operator 0.  */
+  df_mir_confluence_n,          /* Confluence operator n.  */
+  df_mir_transfer_function,     /* Transfer function.  */
+  NULL,                         /* Finalize function.  */
+  df_mir_free,                  /* Free all of the problem information.  */
+  df_mir_free,                  /* Remove this problem from the stack of dataflow problems.  */
+  NULL,                         /* Debugging.  */
+  df_mir_top_dump,              /* Debugging start block.  */
+  df_mir_bottom_dump,           /* Debugging end block.  */
+  NULL,                         /* Debugging start insn.  */
+  NULL,                         /* Debugging end insn.  */
+  df_mir_verify_solution_start, /* Incremental solution verify start.  */
+  df_mir_verify_solution_end,   /* Incremental solution verify end.  */
+  NULL,                         /* Dependent problem.  */
+  sizeof (struct df_mir_bb_info),/* Size of entry of block_info array.  */
+  TV_DF_MIR,                    /* Timing variable.  */
+  false                         /* Reset blocks on dropping out of blocks_to_analyze.  */
+};
+
+
+/* Create a new DATAFLOW instance and add it to an existing instance
+   of DF.  */
+
+void
+df_mir_add_problem (void)
+{
+  df_add_problem (&problem_MIR);
+  /* These will be initialized when df_scan_blocks processes each
+     block.  */
+  df_mir->out_of_date_transfer_functions = BITMAP_ALLOC (&df_bitmap_obstack);
+}
+
+
+/* Apply the effects of the gen/kills in INSN to the corresponding bitmaps.  */
+
+void
+df_mir_simulate_one_insn (basic_block bb ATTRIBUTE_UNUSED, rtx_insn *insn,
+			  bitmap kill, bitmap gen)
+{
+  df_ref def;
+
+  FOR_EACH_INSN_DEF (def, insn)
+    {
+      unsigned int regno = DF_REF_REGNO (def);
+
+      /* The order of GENs/KILLs matters, so if this def clobbers a reg, any
+	 previous gen is irrelevant (and reciprocally).  Also, claim that a
+	 register is GEN only if it is in all cases.  */
+      if (DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))
+	{
+	  bitmap_set_bit (kill, regno);
+	  bitmap_clear_bit (gen, regno);
+	}
+      /* In the worst case, partial and conditional defs can leave bits
+	 uninitialized, so assume they do not change anything.  */
+      else if (!DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL | DF_REF_CONDITIONAL))
+	{
+	  bitmap_set_bit (gen, regno);
+	  bitmap_clear_bit (kill, regno);
+	}
+    }
+}
+\f
+/*----------------------------------------------------------------------------
    CREATE DEF_USE (DU) and / or USE_DEF (UD) CHAINS
 
    Link either the defs to the uses and / or the uses to the defs.
diff --git a/gcc/df.h b/gcc/df.h
index 44e5fdb..54b9abb 100644
--- a/gcc/df.h
+++ b/gcc/df.h
@@ -51,8 +51,9 @@ union df_ref_d;
 #define DF_WORD_LR 5      /* Subreg tracking lr.  */
 #define DF_NOTE    6      /* REG_DEAD and REG_UNUSED notes.  */
 #define DF_MD      7      /* Multiple Definitions. */
+#define DF_MIR     8      /* Must-initialized Registers.  */
 
-#define DF_LAST_PROBLEM_PLUS1 (DF_MD + 1)
+#define DF_LAST_PROBLEM_PLUS1 (DF_MIR + 1)
 
 /* Dataflow direction.  */
 enum df_flow_dir
@@ -612,12 +613,16 @@ struct df_d
 #define DF_LIVE_BB_INFO(BB) (df_live_get_bb_info ((BB)->index))
 #define DF_WORD_LR_BB_INFO(BB) (df_word_lr_get_bb_info ((BB)->index))
 #define DF_MD_BB_INFO(BB) (df_md_get_bb_info ((BB)->index))
+#define DF_MIR_BB_INFO(BB) (df_mir_get_bb_info ((BB)->index))
 
 /* Most transformations that wish to use live register analysis will
    use these macros.  This info is the and of the lr and live sets.  */
 #define DF_LIVE_IN(BB) (&DF_LIVE_BB_INFO (BB)->in)
 #define DF_LIVE_OUT(BB) (&DF_LIVE_BB_INFO (BB)->out)
 
+#define DF_MIR_IN(BB) (&DF_MIR_BB_INFO (BB)->in)
+#define DF_MIR_OUT(BB) (&DF_MIR_BB_INFO (BB)->out)
+
 /* These macros are used by passes that are not tolerant of
    uninitialized variables.  This intolerance should eventually
    be fixed.  */
@@ -896,6 +901,21 @@ struct df_word_lr_bb_info
   bitmap_head out;   /* At the bottom of the block.  */
 };
 
+/* Must-initialized registers.  All bitmaps are referenced by the
+   register number.  */
+struct df_mir_bb_info
+{
+  /* Local sets to describe the basic blocks.  */
+  bitmap_head kill;  /* The set of registers unset in this block.  Calls,
+		        for instance, unset registers.  */
+  bitmap_head gen;   /* The set of registers set in this block, excluding the
+			ones killed later on in this block.  */
+
+  /* The results of the dataflow problem.  */
+  bitmap_head in;    /* At the top of the block.  */
+  bitmap_head out;   /* At the bottom of the block.  */
+};
+
 
 /* This is used for debugging and for the dumpers to find the latest
    instance so that the df info can be added to the dumps.  This
@@ -909,6 +929,7 @@ extern struct df_d *df;
 #define df_word_lr (df->problems_by_index[DF_WORD_LR])
 #define df_note    (df->problems_by_index[DF_NOTE])
 #define df_md      (df->problems_by_index[DF_MD])
+#define df_mir     (df->problems_by_index[DF_MIR])
 
 /* This symbol turns on checking that each modification of the cfg has
   been identified to the appropriate df routines.  It is not part of
@@ -1005,6 +1026,8 @@ extern void df_note_add_problem (void);
 extern void df_md_add_problem (void);
 extern void df_md_simulate_artificial_defs_at_top (basic_block, bitmap);
 extern void df_md_simulate_one_insn (basic_block, rtx_insn *, bitmap);
+extern void df_mir_add_problem (void);
+extern void df_mir_simulate_one_insn (basic_block, rtx_insn *, bitmap, bitmap);
 extern void df_simulate_find_noclobber_defs (rtx_insn *, bitmap);
 extern void df_simulate_find_defs (rtx_insn *, bitmap);
 extern void df_simulate_defs (rtx_insn *, bitmap);
@@ -1111,6 +1134,15 @@ df_word_lr_get_bb_info (unsigned int index)
     return NULL;
 }
 
+static inline struct df_mir_bb_info *
+df_mir_get_bb_info (unsigned int index)
+{
+  if (index < df_mir->block_info_size)
+    return &((struct df_mir_bb_info *) df_mir->block_info)[index];
+  else
+    return NULL;
+}
+
 /* Get the live at out set for BB no matter what problem happens to be
    defined.  This function is used by the register allocators who
    choose different dataflow problems depending on the optimization
diff --git a/gcc/ree.c b/gcc/ree.c
index 6156eec..0ca526f 100644
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -246,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "tree-pass.h"
 #include "cgraph.h"
+#include "bitmap.h"
 
 /* This structure represents a candidate for elimination.  */
 
@@ -973,7 +974,8 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
 static void
 add_removable_extension (const_rtx expr, rtx_insn *insn,
 			 vec<ext_cand> *insn_list,
-			 unsigned *def_map)
+			 unsigned *def_map,
+			 bitmap init_regs)
 {
   enum rtx_code code;
   machine_mode mode;
@@ -993,11 +995,29 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
       && (code == SIGN_EXTEND || code == ZERO_EXTEND)
       && REG_P (XEXP (src, 0)))
     {
+      const rtx reg = XEXP (src, 0);
       struct df_link *defs, *def;
       ext_cand *cand;
 
-      /* First, make sure we can get all the reaching definitions.  */
-      defs = get_defs (insn, XEXP (src, 0), NULL);
+      /* Zero-extension of an undefined value is partly defined (it's
+	 completely undefined for sign-extension, though).  So if there exists
+	 a path from the entry to this zero-extension that leaves this register
+	 uninitialized, removing the extension could change the behavior of
+	 correct programs.  So first, check it is not the case.  */
+      if (code == ZERO_EXTEND && !bitmap_bit_p (init_regs, REGNO (reg)))
+	{
+	  if (dump_file)
+	    {
+	      fprintf (dump_file, "Cannot eliminate extension:\n");
+	      print_rtl_single (dump_file, insn);
+	      fprintf (dump_file, " because it can operate on uninitialized"
+			          " data\n");
+	    }
+	  return;
+	}
+
+      /* Second, make sure we can get all the reaching definitions.  */
+      defs = get_defs (insn, reg, NULL);
       if (!defs)
 	{
 	  if (dump_file)
@@ -1009,7 +1029,7 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
 	  return;
 	}
 
-      /* Second, make sure the reaching definitions don't feed another and
+      /* Third, make sure the reaching definitions don't feed another and
 	 different extension.  FIXME: this obviously can be improved.  */
       for (def = defs; def; def = def->next)
 	if ((idx = def_map[INSN_UID (DF_REF_INSN (def->ref))])
@@ -1099,18 +1119,33 @@ find_removable_extensions (void)
   rtx_insn *insn;
   rtx set;
   unsigned *def_map = XCNEWVEC (unsigned, max_insn_uid);
+  bitmap_head init, kill, gen, tmp;
+
+  bitmap_initialize (&init, NULL);
+  bitmap_initialize (&kill, NULL);
+  bitmap_initialize (&gen, NULL);
+  bitmap_initialize (&tmp, NULL);
 
   FOR_EACH_BB_FN (bb, cfun)
-    FOR_BB_INSNS (bb, insn)
-      {
-	if (!NONDEBUG_INSN_P (insn))
-	  continue;
+    {
+      bitmap_copy (&init, DF_MIR_IN (bb));
+      bitmap_clear (&kill);
+      bitmap_clear (&gen);
 
-	set = single_set (insn);
-	if (set == NULL_RTX)
-	  continue;
-	add_removable_extension (set, insn, &insn_list, def_map);
-      }
+      FOR_BB_INSNS (bb, insn)
+	{
+	  if (NONDEBUG_INSN_P (insn))
+	    {
+	      set = single_set (insn);
+	      if (set != NULL_RTX)
+		add_removable_extension (set, insn, &insn_list, def_map,
+					 &init);
+	      df_mir_simulate_one_insn (bb, insn, &kill, &gen);
+	      bitmap_ior_and_compl (&tmp, &gen, &init, &kill);
+	      bitmap_copy (&init, &tmp);
+	    }
+	}
+    }
 
   XDELETEVEC (def_map);
 
@@ -1135,6 +1170,7 @@ find_and_remove_re (void)
      extension instruction.  */
   df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
   df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
+  df_mir_add_problem ();
   df_analyze ();
   df_set_flags (DF_DEFER_INSN_RESCAN);
 
diff --git a/gcc/testsuite/gnat.dg/opt50.adb b/gcc/testsuite/gnat.dg/opt50.adb
new file mode 100644
index 0000000..f930d09
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt50.adb
@@ -0,0 +1,23 @@
+-- { dg-do run }
+-- { dg-options "-O3 -gnatn" }
+
+with Opt50_Pkg; use Opt50_Pkg;
+
+procedure Opt50 is
+  B : Boolean;
+  E : Enum;
+begin
+  Get ("four", E, B);
+  if B = True then
+    raise Program_Error;
+  end if;
+  Get ("three", E, B);
+  if B = False then
+    raise Program_Error;
+  end if;
+  declare
+    A : Enum_Boolean_Array (One .. E) := (others => True);
+  begin
+    Set (A);
+  end;
+end Opt50;
diff --git a/gcc/testsuite/gnat.dg/opt50_pkg.adb b/gcc/testsuite/gnat.dg/opt50_pkg.adb
new file mode 100644
index 0000000..0f92f7d
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt50_pkg.adb
@@ -0,0 +1,48 @@
+with Ada.Characters.Handling;
+with Ada.Containers;
+with Ada.Containers.Indefinite_Hashed_Maps;
+with Ada.Strings.Hash;
+
+package body Opt50_Pkg is
+
+   type Enum_Name is array (Enum) of access constant String;
+
+   Enum_Name_Table : constant Enum_Name := (
+      One   => new String'("one"),
+      Two   => new String'("two"),
+      Three => new String'("three"));
+
+   package String_To_Enum_Map is new Ada.Containers.Indefinite_Hashed_Maps
+      (Key_Type => String, Element_Type => Enum,
+       Hash => Ada.Strings.Hash, Equivalent_Keys => "=");
+
+   function Fill_Hashed_Map return String_To_Enum_Map.Map is
+      Res : String_To_Enum_Map.Map;
+      use String_To_Enum_Map;
+   begin
+      for I in Enum_Name_Table'Range loop
+         declare
+            Kind : constant String := Enum_Name_Table (I).all;
+         begin
+            Res.Insert(Key => Kind, New_Item => I);
+         end;
+      end loop;
+      return Res;
+   end;
+
+   String_To_Enum : constant String_To_Enum_Map.Map := Fill_Hashed_Map;
+
+   procedure Get (Kind : String; Result : out Enum; Success : out Boolean) is
+      X : constant String := Ada.Characters.Handling.To_Lower (Kind);
+      use String_To_Enum_Map;
+      Curs : constant Cursor := String_To_Enum.Find (X);
+   begin
+      Success := Curs /= No_Element;
+      if Success then
+         Result := Element(Curs);
+      end if;
+   end;
+
+   procedure Set (A : Enum_Boolean_Array) is null;
+
+end Opt50_Pkg;
diff --git a/gcc/testsuite/gnat.dg/opt50_pkg.ads b/gcc/testsuite/gnat.dg/opt50_pkg.ads
new file mode 100644
index 0000000..9faea54
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt50_pkg.ads
@@ -0,0 +1,12 @@
+package Opt50_Pkg is
+
+   type Enum is (One, Two, Three);
+   for Enum'Size use 16;
+
+   type Enum_Boolean_Array is array (Enum range <>) of Boolean;
+
+   procedure Get (Kind : String; Result : out Enum; Success : out Boolean);
+
+   procedure Set (A : Enum_Boolean_Array);
+
+end Opt50_Pkg;
diff --git a/gcc/timevar.def b/gcc/timevar.def
index ac41075..2fbfb17 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -115,6 +115,7 @@ DEFTIMEVAR (TV_DF_MD		     , "df multiple defs")
 DEFTIMEVAR (TV_DF_RD		     , "df reaching defs")
 DEFTIMEVAR (TV_DF_LR		     , "df live regs")
 DEFTIMEVAR (TV_DF_LIVE		     , "df live&initialized regs")
+DEFTIMEVAR (TV_DF_MIR		     , "df must-initialized regs")
 DEFTIMEVAR (TV_DF_CHAIN		     , "df use-def / def-use chains")
 DEFTIMEVAR (TV_DF_WORD_LR	     , "df live reg subwords")
 DEFTIMEVAR (TV_DF_NOTE		     , "df reg dead/unused notes")
-- 
2.6.0


[-- Attachment #3: 0002-DF_LIVE-make-clobbers-cancel-effect-of-previous-GENs.patch --]
[-- Type: text/x-diff, Size: 1241 bytes --]

From ff694bf70e0b1ebd336c684713ce6153cc26b3d6 Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Tue, 22 Sep 2015 16:02:41 +0200
Subject: [PATCH 2/2] DF_LIVE: make clobbers cancel effect of previous GENs in
 the same BBs

gcc/ChangeLog:

	* df-problems.c (df_live_bb_local_compute): Clear GEN bits for
	DF_REF_MUST_CLOBBER references.
---
 gcc/df-problems.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index c08ae36..56e1cf5 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -1464,9 +1464,12 @@ df_live_bb_local_compute (unsigned int bb_index)
 	       seen are included in the gen set. */
 	    bitmap_set_bit (&bb_info->gen, regno);
 	  else if (DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
-	    /* Only must clobbers for the entire reg destroy the
-	       value.  */
-	    bitmap_set_bit (&bb_info->kill, regno);
+	    {
+	      /* Only must clobbers for the entire reg destroy the
+		 value.  */
+	      bitmap_set_bit (&bb_info->kill, regno);
+	      bitmap_clear_bit (&bb_info->gen, regno);
+	    }
 	  else if (! DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER))
 	    bitmap_set_bit (&bb_info->gen, regno);
 	}
-- 
2.6.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-10-13 15:17       ` [PATCH v2] " Pierre-Marie de Rodat
@ 2015-10-14 13:41         ` Bernd Schmidt
  2015-10-19 23:51           ` Pierre-Marie de Rodat
  2015-10-23 11:31         ` Bernd Schmidt
  1 sibling, 1 reply; 11+ messages in thread
From: Bernd Schmidt @ 2015-10-14 13:41 UTC (permalink / raw)
  To: Pierre-Marie de Rodat, gcc-patches
  Cc: Richard Biener, Jeff Law, Bernd Schmidt

On 10/13/2015 05:17 PM, Pierre-Marie de Rodat wrote:
> The first attached patch is the second attempt to fix PR
> rtl-optimization/66790 (see
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790>).
>
> The second one is a fix for some inconsistency noticed while working on
> the original bug. This specific patch fixes no known bug, but anyway…
>
> Both were bootstrapped and regtested on x86_64-linux. Ok to commit?
> Thank you in advance!
>
> [PATCH 1/2] REE: fix uninitialized registers handling

This one is OK with minor changes. I ran some tests with it, and the mir 
sets look good this time. Code generation still seems unaffected by it 
on all my example code (which is as expected).

> +
> +  /* Ignoring artificial defs is intentionnal: these often pretend that some

"intentional".

> +      if ((!bitmap_equal_p (&problem_data->in[bb->index], DF_MIR_IN (bb)))
> +	  || (!bitmap_equal_p (&problem_data->out[bb->index], DF_MIR_OUT (bb))))
> +	{
> +	  /*df_dump (stderr);*/
> +	  gcc_unreachable ();
> +	}

Please remove the commented out code and then also the unnecessary 
braces. In general we avoid commented out code in gcc, but when doing 
it, #if 0 is generally a better method.

> +      const rtx reg = XEXP (src, 0);

Drop the const maybe? It doesn't seem to add much and the idiom is to 
just use rtx.

>From ff694bf70e0b1ebd336c684713ce6153cc26b3d6 Mon Sep 17 00:00:00 2001
> From: Pierre-Marie de Rodat<derodat@adacore.com>
> Date: Tue, 22 Sep 2015 16:02:41 +0200
> Subject: [PATCH 2/2] DF_LIVE: make clobbers cancel effect of previous GENs in
>   the same BBs
>
> gcc/ChangeLog:
>
> 	* df-problems.c (df_live_bb_local_compute): Clear GEN bits for
> 	DF_REF_MUST_CLOBBER references.

This one is probably ok too; I still want to experiment with it a little.


Bernd

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-10-14 13:41         ` Bernd Schmidt
@ 2015-10-19 23:51           ` Pierre-Marie de Rodat
  0 siblings, 0 replies; 11+ messages in thread
From: Pierre-Marie de Rodat @ 2015-10-19 23:51 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: Richard Biener, Jeff Law

[-- Attachment #1: Type: text/plain, Size: 1166 bytes --]

On 10/14/2015 09:41 AM, Bernd Schmidt wrote:
> This one is OK with minor changes. I ran some tests with it, and the mir
> sets look good this time. Code generation still seems unaffected by it
> on all my example code (which is as expected).

Thank you very much for your help on this and for double-checking!

>> +  /* Ignoring artificial defs is intentionnal: these often pretend
>> that some
>
> "intentional".

Fixed.

> Please remove the commented out code and then also the unnecessary
> braces. In general we avoid commented out code in gcc, but when doing
> it, #if 0 is generally a better method.

Ok, this is removed.

>> +      const rtx reg = XEXP (src, 0);
>
> Drop the const maybe? It doesn't seem to add much and the idiom is to
> just use rtx.

Done.

>> Subject: [PATCH 2/2] DF_LIVE: make clobbers cancel effect of previous
>> GENs in
>>   the same BBs
>>
>> gcc/ChangeLog:
>>
>>     * df-problems.c (df_live_bb_local_compute): Clear GEN bits for
>>     DF_REF_MUST_CLOBBER references.
>
> This one is probably ok too; I still want to experiment with it a little.

Sure, I only committed the attached updated first patch.

-- 
Pierre-Marie de Rodat

[-- Attachment #2: 0001-REE-fix-uninitialized-registers-handling.patch --]
[-- Type: text/x-diff, Size: 26829 bytes --]

From 0275c4a20a4b9daaefbbddd5306e9214e7d5d673 Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Sat, 18 Jul 2015 13:10:45 +0200
Subject: [PATCH] REE: fix uninitialized registers handling

gcc/ChangeLog:

	PR rtl-optimization/66790
	* df.h (DF_MIR): New macro.
	(DF_LAST_PROBLEM_PLUS1): Update to be past DF_MIR
	(DF_MIR_INFO_BB): New macro.
	(DF_MIR_IN, DF_MIR_OUT): New macros.
	(struct df_mir_bb_info): New.
	(df_mir): New macro.
	(df_mir_add_problem, df_mir_simulate_one_insn): New forward
	declarations.
	(df_mir_get_bb_info): New.
	* df-problems.c (struct df_mir_problem_data): New.
	(df_mir_free_bb_info, df_mir_alloc, df_mir_reset,
	df_mir_bb_local_compute, df_mir_local_compute, df_mir_init,
	df_mir_confluence_0, df_mir_confluence_n,
	df_mir_transfer_function, df_mir_free, df_mir_top_dump,
	df_mir_bottom_dump, df_mir_verify_solution_start,
	df_mir_verify_solution_end): New.
	(problem_MIR): New.
	(df_mir_add_problem, df_mir_simulate_one_insn): New.
	* timevar.def (TV_DF_MIR): New.
	* ree.c: Include bitmap.h
	(add_removable_extension): Add an INIT_REGS parameter.  Use it
	to skip zero-extensions that may get an uninitialized register.
	(find_removable_extensions): Compute must-initialized registers
	using the MIR dataflow problem. Update the call to
	add_removable_extension.
	(find_and_remove_re): Call df_mir_add_problem.

gcc/testsuite/ChangeLog:

	* gnat.dg/opt50.adb: New test.
	* gnat.dg/opt50_pkg.adb: New helper.
	* gnat.dg/opt50_pkg.ads: New helper.
---
 gcc/ChangeLog                       |  30 +++
 gcc/df-problems.c                   | 403 ++++++++++++++++++++++++++++++++++++
 gcc/df.h                            |  34 ++-
 gcc/ree.c                           |  62 ++++--
 gcc/testsuite/ChangeLog             |   6 +
 gcc/testsuite/gnat.dg/opt50.adb     |  23 ++
 gcc/testsuite/gnat.dg/opt50_pkg.adb |  48 +++++
 gcc/testsuite/gnat.dg/opt50_pkg.ads |  12 ++
 gcc/timevar.def                     |   1 +
 9 files changed, 605 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gnat.dg/opt50.adb
 create mode 100644 gcc/testsuite/gnat.dg/opt50_pkg.adb
 create mode 100644 gcc/testsuite/gnat.dg/opt50_pkg.ads

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6255b76..4279557 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,33 @@
+2015-10-19  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+	PR rtl-optimization/66790
+	* df.h (DF_MIR): New macro.
+	(DF_LAST_PROBLEM_PLUS1): Update to be past DF_MIR
+	(DF_MIR_INFO_BB): New macro.
+	(DF_MIR_IN, DF_MIR_OUT): New macros.
+	(struct df_mir_bb_info): New.
+	(df_mir): New macro.
+	(df_mir_add_problem, df_mir_simulate_one_insn): New forward
+	declarations.
+	(df_mir_get_bb_info): New.
+	* df-problems.c (struct df_mir_problem_data): New.
+	(df_mir_free_bb_info, df_mir_alloc, df_mir_reset,
+	df_mir_bb_local_compute, df_mir_local_compute, df_mir_init,
+	df_mir_confluence_0, df_mir_confluence_n,
+	df_mir_transfer_function, df_mir_free, df_mir_top_dump,
+	df_mir_bottom_dump, df_mir_verify_solution_start,
+	df_mir_verify_solution_end): New.
+	(problem_MIR): New.
+	(df_mir_add_problem, df_mir_simulate_one_insn): New.
+	* timevar.def (TV_DF_MIR): New.
+	* ree.c: Include bitmap.h
+	(add_removable_extension): Add an INIT_REGS parameter.  Use it
+	to skip zero-extensions that may get an uninitialized register.
+	(find_removable_extensions): Compute must-initialized registers
+	using the MIR dataflow problem. Update the call to
+	add_removable_extension.
+	(find_and_remove_re): Call df_mir_add_problem.
+
 2015-10-19  Segher Boessenkool  <segher@kernel.crashing.org>
 
 	* common/config/mn10300/mn10300-common.c
diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index 153732a..331fd87 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -1849,6 +1849,409 @@ df_live_verify_transfer_functions (void)
 }
 \f
 /*----------------------------------------------------------------------------
+   MUST-INITIALIZED REGISTERS.
+----------------------------------------------------------------------------*/
+
+/* Private data used to verify the solution for this problem.  */
+struct df_mir_problem_data
+{
+  bitmap_head *in;
+  bitmap_head *out;
+  /* An obstack for the bitmaps we need for this problem.  */
+  bitmap_obstack mir_bitmaps;
+};
+
+
+/* Free basic block info.  */
+
+static void
+df_mir_free_bb_info (basic_block bb ATTRIBUTE_UNUSED,
+		     void *vbb_info)
+{
+  struct df_mir_bb_info *bb_info = (struct df_mir_bb_info *) vbb_info;
+  if (bb_info)
+    {
+      bitmap_clear (&bb_info->gen);
+      bitmap_clear (&bb_info->kill);
+      bitmap_clear (&bb_info->in);
+      bitmap_clear (&bb_info->out);
+    }
+}
+
+
+/* Allocate or reset bitmaps for DF_MIR blocks. The solution bits are
+   not touched unless the block is new.  */
+
+static void
+df_mir_alloc (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+  struct df_mir_problem_data *problem_data;
+
+  if (df_mir->problem_data)
+    problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  else
+    {
+      problem_data = XNEW (struct df_mir_problem_data);
+      df_mir->problem_data = problem_data;
+
+      problem_data->out = NULL;
+      problem_data->in = NULL;
+      bitmap_obstack_initialize (&problem_data->mir_bitmaps);
+    }
+
+  df_grow_bb_info (df_mir);
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+
+      /* When bitmaps are already initialized, just clear them.  */
+      if (bb_info->kill.obstack)
+	{
+	  bitmap_clear (&bb_info->kill);
+	  bitmap_clear (&bb_info->gen);
+	}
+      else
+	{
+	  bitmap_initialize (&bb_info->kill, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->gen, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->in, &problem_data->mir_bitmaps);
+	  bitmap_initialize (&bb_info->out, &problem_data->mir_bitmaps);
+	  bitmap_set_range (&bb_info->in, 0, DF_REG_SIZE (df));
+	  bitmap_set_range (&bb_info->out, 0, DF_REG_SIZE (df));
+	}
+    }
+
+  df_mir->optional_p = 1;
+}
+
+
+/* Reset the global solution for recalculation.  */
+
+static void
+df_mir_reset (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+
+      gcc_assert (bb_info);
+
+      bitmap_clear (&bb_info->in);
+      bitmap_set_range (&bb_info->in, 0, DF_REG_SIZE (df));
+      bitmap_clear (&bb_info->out);
+      bitmap_set_range (&bb_info->out, 0, DF_REG_SIZE (df));
+    }
+}
+
+
+/* Compute local uninitialized register info for basic block BB.  */
+
+static void
+df_mir_bb_local_compute (unsigned int bb_index)
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+  rtx_insn *insn;
+  int luid = 0;
+
+  /* Ignoring artificial defs is intentional: these often pretend that some
+     registers carry incoming arguments (when they are FUNCTION_ARG_REGNO) even
+     though they are not used for that.  As a result, conservatively assume
+     they may be uninitialized.  */
+
+  FOR_BB_INSNS (bb, insn)
+    {
+      unsigned int uid = INSN_UID (insn);
+      struct df_insn_info *insn_info = DF_INSN_UID_GET (uid);
+
+      /* Inserting labels does not always trigger the incremental
+	 rescanning.  */
+      if (!insn_info)
+	{
+	  gcc_assert (!INSN_P (insn));
+	  insn_info = df_insn_create_insn_record (insn);
+	}
+
+      DF_INSN_INFO_LUID (insn_info) = luid;
+      if (!INSN_P (insn))
+	continue;
+
+      luid++;
+      df_mir_simulate_one_insn (bb, insn, &bb_info->kill, &bb_info->gen);
+    }
+}
+
+
+/* Compute local uninitialized register info.  */
+
+static void
+df_mir_local_compute (bitmap all_blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+
+  df_grow_insn_info ();
+
+  EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
+    {
+      df_mir_bb_local_compute (bb_index);
+    }
+}
+
+
+/* Initialize the solution vectors.  */
+
+static void
+df_mir_init (bitmap all_blocks)
+{
+  df_mir_reset (all_blocks);
+}
+
+
+/* Initialize IN sets for blocks with no predecessors: when landing on such
+   blocks, assume all registers are uninitialized.  */
+
+static void
+df_mir_confluence_0 (basic_block bb)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  bitmap_clear (&bb_info->in);
+}
+
+
+/* Forward confluence function that ignores fake edges.  */
+
+static bool
+df_mir_confluence_n (edge e)
+{
+  bitmap op1 = &df_mir_get_bb_info (e->dest->index)->in;
+  bitmap op2 = &df_mir_get_bb_info (e->src->index)->out;
+
+  if (e->flags & EDGE_FAKE)
+    return false;
+
+  /* A register is must-initialized at the entry of a basic block iff it is
+     must-initialized at the exit of all the predecessors.  */
+  return bitmap_and_into (op1, op2);
+}
+
+
+/* Transfer function for the forwards must-initialized problem.  */
+
+static bool
+df_mir_transfer_function (int bb_index)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb_index);
+  bitmap in = &bb_info->in;
+  bitmap out = &bb_info->out;
+  bitmap gen = &bb_info->gen;
+  bitmap kill = &bb_info->kill;
+
+  return bitmap_ior_and_compl (out, gen, in, kill);
+}
+
+
+/* Free all storage associated with the problem.  */
+
+static void
+df_mir_free (void)
+{
+  struct df_mir_problem_data *problem_data
+    = (struct df_mir_problem_data *) df_mir->problem_data;
+  if (df_mir->block_info)
+    {
+      df_mir->block_info_size = 0;
+      free (df_mir->block_info);
+      df_mir->block_info = NULL;
+      bitmap_obstack_release (&problem_data->mir_bitmaps);
+      free (problem_data);
+      df_mir->problem_data = NULL;
+    }
+  free (df_mir);
+}
+
+
+/* Debugging info at top of bb.  */
+
+static void
+df_mir_top_dump (basic_block bb, FILE *file)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  if (!bb_info)
+    return;
+
+  fprintf (file, ";; mir   in  \t");
+  df_print_regset (file, &bb_info->in);
+  fprintf (file, ";; mir   kill\t");
+  df_print_regset (file, &bb_info->kill);
+  fprintf (file, ";; mir   gen \t");
+  df_print_regset (file, &bb_info->gen);
+}
+
+/* Debugging info at bottom of bb.  */
+
+static void
+df_mir_bottom_dump (basic_block bb, FILE *file)
+{
+  struct df_mir_bb_info *bb_info = df_mir_get_bb_info (bb->index);
+
+  if (!bb_info)
+    return;
+
+  fprintf (file, ";; mir   out \t");
+  df_print_regset (file, &bb_info->out);
+}
+
+
+/* Build the datastructure to verify that the solution to the dataflow
+   equations is not dirty.  */
+
+static void
+df_mir_verify_solution_start (void)
+{
+  basic_block bb;
+  struct df_mir_problem_data *problem_data;
+  if (df_mir->solutions_dirty)
+    return;
+
+  /* Set it true so that the solution is recomputed.  */
+  df_mir->solutions_dirty = true;
+
+  problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  problem_data->in = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+  problem_data->out = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+  bitmap_obstack_initialize (&problem_data->mir_bitmaps);
+
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      bitmap_initialize (&problem_data->in[bb->index], &problem_data->mir_bitmaps);
+      bitmap_initialize (&problem_data->out[bb->index], &problem_data->mir_bitmaps);
+      bitmap_copy (&problem_data->in[bb->index], DF_MIR_IN (bb));
+      bitmap_copy (&problem_data->out[bb->index], DF_MIR_OUT (bb));
+    }
+}
+
+
+/* Compare the saved datastructure and the new solution to the dataflow
+   equations.  */
+
+static void
+df_mir_verify_solution_end (void)
+{
+  struct df_mir_problem_data *problem_data;
+  basic_block bb;
+
+  problem_data = (struct df_mir_problem_data *) df_mir->problem_data;
+  if (!problem_data->out)
+    return;
+
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      if ((!bitmap_equal_p (&problem_data->in[bb->index], DF_MIR_IN (bb)))
+	  || (!bitmap_equal_p (&problem_data->out[bb->index], DF_MIR_OUT (bb))))
+	gcc_unreachable ();
+    }
+
+  /* Cannot delete them immediately because you may want to dump them
+     if the comparison fails.  */
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      bitmap_clear (&problem_data->in[bb->index]);
+      bitmap_clear (&problem_data->out[bb->index]);
+    }
+
+  free (problem_data->in);
+  free (problem_data->out);
+  bitmap_obstack_release (&problem_data->mir_bitmaps);
+  free (problem_data);
+  df_mir->problem_data = NULL;
+}
+
+
+/* All of the information associated with every instance of the problem.  */
+
+static struct df_problem problem_MIR =
+{
+  DF_MIR,                       /* Problem id.  */
+  DF_FORWARD,                   /* Direction.  */
+  df_mir_alloc,                 /* Allocate the problem specific data.  */
+  df_mir_reset,                 /* Reset global information.  */
+  df_mir_free_bb_info,          /* Free basic block info.  */
+  df_mir_local_compute,         /* Local compute function.  */
+  df_mir_init,                  /* Init the solution specific data.  */
+  df_worklist_dataflow,         /* Worklist solver.  */
+  df_mir_confluence_0,          /* Confluence operator 0.  */
+  df_mir_confluence_n,          /* Confluence operator n.  */
+  df_mir_transfer_function,     /* Transfer function.  */
+  NULL,                         /* Finalize function.  */
+  df_mir_free,                  /* Free all of the problem information.  */
+  df_mir_free,                  /* Remove this problem from the stack of dataflow problems.  */
+  NULL,                         /* Debugging.  */
+  df_mir_top_dump,              /* Debugging start block.  */
+  df_mir_bottom_dump,           /* Debugging end block.  */
+  NULL,                         /* Debugging start insn.  */
+  NULL,                         /* Debugging end insn.  */
+  df_mir_verify_solution_start, /* Incremental solution verify start.  */
+  df_mir_verify_solution_end,   /* Incremental solution verify end.  */
+  NULL,                         /* Dependent problem.  */
+  sizeof (struct df_mir_bb_info),/* Size of entry of block_info array.  */
+  TV_DF_MIR,                    /* Timing variable.  */
+  false                         /* Reset blocks on dropping out of blocks_to_analyze.  */
+};
+
+
+/* Create a new DATAFLOW instance and add it to an existing instance
+   of DF.  */
+
+void
+df_mir_add_problem (void)
+{
+  df_add_problem (&problem_MIR);
+  /* These will be initialized when df_scan_blocks processes each
+     block.  */
+  df_mir->out_of_date_transfer_functions = BITMAP_ALLOC (&df_bitmap_obstack);
+}
+
+
+/* Apply the effects of the gen/kills in INSN to the corresponding bitmaps.  */
+
+void
+df_mir_simulate_one_insn (basic_block bb ATTRIBUTE_UNUSED, rtx_insn *insn,
+			  bitmap kill, bitmap gen)
+{
+  df_ref def;
+
+  FOR_EACH_INSN_DEF (def, insn)
+    {
+      unsigned int regno = DF_REF_REGNO (def);
+
+      /* The order of GENs/KILLs matters, so if this def clobbers a reg, any
+	 previous gen is irrelevant (and reciprocally).  Also, claim that a
+	 register is GEN only if it is in all cases.  */
+      if (DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))
+	{
+	  bitmap_set_bit (kill, regno);
+	  bitmap_clear_bit (gen, regno);
+	}
+      /* In the worst case, partial and conditional defs can leave bits
+	 uninitialized, so assume they do not change anything.  */
+      else if (!DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL | DF_REF_CONDITIONAL))
+	{
+	  bitmap_set_bit (gen, regno);
+	  bitmap_clear_bit (kill, regno);
+	}
+    }
+}
+\f
+/*----------------------------------------------------------------------------
    CREATE DEF_USE (DU) and / or USE_DEF (UD) CHAINS
 
    Link either the defs to the uses and / or the uses to the defs.
diff --git a/gcc/df.h b/gcc/df.h
index 44e5fdb..54b9abb 100644
--- a/gcc/df.h
+++ b/gcc/df.h
@@ -51,8 +51,9 @@ union df_ref_d;
 #define DF_WORD_LR 5      /* Subreg tracking lr.  */
 #define DF_NOTE    6      /* REG_DEAD and REG_UNUSED notes.  */
 #define DF_MD      7      /* Multiple Definitions. */
+#define DF_MIR     8      /* Must-initialized Registers.  */
 
-#define DF_LAST_PROBLEM_PLUS1 (DF_MD + 1)
+#define DF_LAST_PROBLEM_PLUS1 (DF_MIR + 1)
 
 /* Dataflow direction.  */
 enum df_flow_dir
@@ -612,12 +613,16 @@ struct df_d
 #define DF_LIVE_BB_INFO(BB) (df_live_get_bb_info ((BB)->index))
 #define DF_WORD_LR_BB_INFO(BB) (df_word_lr_get_bb_info ((BB)->index))
 #define DF_MD_BB_INFO(BB) (df_md_get_bb_info ((BB)->index))
+#define DF_MIR_BB_INFO(BB) (df_mir_get_bb_info ((BB)->index))
 
 /* Most transformations that wish to use live register analysis will
    use these macros.  This info is the and of the lr and live sets.  */
 #define DF_LIVE_IN(BB) (&DF_LIVE_BB_INFO (BB)->in)
 #define DF_LIVE_OUT(BB) (&DF_LIVE_BB_INFO (BB)->out)
 
+#define DF_MIR_IN(BB) (&DF_MIR_BB_INFO (BB)->in)
+#define DF_MIR_OUT(BB) (&DF_MIR_BB_INFO (BB)->out)
+
 /* These macros are used by passes that are not tolerant of
    uninitialized variables.  This intolerance should eventually
    be fixed.  */
@@ -896,6 +901,21 @@ struct df_word_lr_bb_info
   bitmap_head out;   /* At the bottom of the block.  */
 };
 
+/* Must-initialized registers.  All bitmaps are referenced by the
+   register number.  */
+struct df_mir_bb_info
+{
+  /* Local sets to describe the basic blocks.  */
+  bitmap_head kill;  /* The set of registers unset in this block.  Calls,
+		        for instance, unset registers.  */
+  bitmap_head gen;   /* The set of registers set in this block, excluding the
+			ones killed later on in this block.  */
+
+  /* The results of the dataflow problem.  */
+  bitmap_head in;    /* At the top of the block.  */
+  bitmap_head out;   /* At the bottom of the block.  */
+};
+
 
 /* This is used for debugging and for the dumpers to find the latest
    instance so that the df info can be added to the dumps.  This
@@ -909,6 +929,7 @@ extern struct df_d *df;
 #define df_word_lr (df->problems_by_index[DF_WORD_LR])
 #define df_note    (df->problems_by_index[DF_NOTE])
 #define df_md      (df->problems_by_index[DF_MD])
+#define df_mir     (df->problems_by_index[DF_MIR])
 
 /* This symbol turns on checking that each modification of the cfg has
   been identified to the appropriate df routines.  It is not part of
@@ -1005,6 +1026,8 @@ extern void df_note_add_problem (void);
 extern void df_md_add_problem (void);
 extern void df_md_simulate_artificial_defs_at_top (basic_block, bitmap);
 extern void df_md_simulate_one_insn (basic_block, rtx_insn *, bitmap);
+extern void df_mir_add_problem (void);
+extern void df_mir_simulate_one_insn (basic_block, rtx_insn *, bitmap, bitmap);
 extern void df_simulate_find_noclobber_defs (rtx_insn *, bitmap);
 extern void df_simulate_find_defs (rtx_insn *, bitmap);
 extern void df_simulate_defs (rtx_insn *, bitmap);
@@ -1111,6 +1134,15 @@ df_word_lr_get_bb_info (unsigned int index)
     return NULL;
 }
 
+static inline struct df_mir_bb_info *
+df_mir_get_bb_info (unsigned int index)
+{
+  if (index < df_mir->block_info_size)
+    return &((struct df_mir_bb_info *) df_mir->block_info)[index];
+  else
+    return NULL;
+}
+
 /* Get the live at out set for BB no matter what problem happens to be
    defined.  This function is used by the register allocators who
    choose different dataflow problems depending on the optimization
diff --git a/gcc/ree.c b/gcc/ree.c
index 6156eec..a75c732 100644
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -246,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "tree-pass.h"
 #include "cgraph.h"
+#include "bitmap.h"
 
 /* This structure represents a candidate for elimination.  */
 
@@ -973,7 +974,8 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
 static void
 add_removable_extension (const_rtx expr, rtx_insn *insn,
 			 vec<ext_cand> *insn_list,
-			 unsigned *def_map)
+			 unsigned *def_map,
+			 bitmap init_regs)
 {
   enum rtx_code code;
   machine_mode mode;
@@ -993,11 +995,29 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
       && (code == SIGN_EXTEND || code == ZERO_EXTEND)
       && REG_P (XEXP (src, 0)))
     {
+      rtx reg = XEXP (src, 0);
       struct df_link *defs, *def;
       ext_cand *cand;
 
-      /* First, make sure we can get all the reaching definitions.  */
-      defs = get_defs (insn, XEXP (src, 0), NULL);
+      /* Zero-extension of an undefined value is partly defined (it's
+	 completely undefined for sign-extension, though).  So if there exists
+	 a path from the entry to this zero-extension that leaves this register
+	 uninitialized, removing the extension could change the behavior of
+	 correct programs.  So first, check it is not the case.  */
+      if (code == ZERO_EXTEND && !bitmap_bit_p (init_regs, REGNO (reg)))
+	{
+	  if (dump_file)
+	    {
+	      fprintf (dump_file, "Cannot eliminate extension:\n");
+	      print_rtl_single (dump_file, insn);
+	      fprintf (dump_file, " because it can operate on uninitialized"
+			          " data\n");
+	    }
+	  return;
+	}
+
+      /* Second, make sure we can get all the reaching definitions.  */
+      defs = get_defs (insn, reg, NULL);
       if (!defs)
 	{
 	  if (dump_file)
@@ -1009,7 +1029,7 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
 	  return;
 	}
 
-      /* Second, make sure the reaching definitions don't feed another and
+      /* Third, make sure the reaching definitions don't feed another and
 	 different extension.  FIXME: this obviously can be improved.  */
       for (def = defs; def; def = def->next)
 	if ((idx = def_map[INSN_UID (DF_REF_INSN (def->ref))])
@@ -1099,18 +1119,33 @@ find_removable_extensions (void)
   rtx_insn *insn;
   rtx set;
   unsigned *def_map = XCNEWVEC (unsigned, max_insn_uid);
+  bitmap_head init, kill, gen, tmp;
+
+  bitmap_initialize (&init, NULL);
+  bitmap_initialize (&kill, NULL);
+  bitmap_initialize (&gen, NULL);
+  bitmap_initialize (&tmp, NULL);
 
   FOR_EACH_BB_FN (bb, cfun)
-    FOR_BB_INSNS (bb, insn)
-      {
-	if (!NONDEBUG_INSN_P (insn))
-	  continue;
+    {
+      bitmap_copy (&init, DF_MIR_IN (bb));
+      bitmap_clear (&kill);
+      bitmap_clear (&gen);
 
-	set = single_set (insn);
-	if (set == NULL_RTX)
-	  continue;
-	add_removable_extension (set, insn, &insn_list, def_map);
-      }
+      FOR_BB_INSNS (bb, insn)
+	{
+	  if (NONDEBUG_INSN_P (insn))
+	    {
+	      set = single_set (insn);
+	      if (set != NULL_RTX)
+		add_removable_extension (set, insn, &insn_list, def_map,
+					 &init);
+	      df_mir_simulate_one_insn (bb, insn, &kill, &gen);
+	      bitmap_ior_and_compl (&tmp, &gen, &init, &kill);
+	      bitmap_copy (&init, &tmp);
+	    }
+	}
+    }
 
   XDELETEVEC (def_map);
 
@@ -1135,6 +1170,7 @@ find_and_remove_re (void)
      extension instruction.  */
   df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
   df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
+  df_mir_add_problem ();
   df_analyze ();
   df_set_flags (DF_DEFER_INSN_RESCAN);
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9130c7d..5a32885 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2015-10-19  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+	* gnat.dg/opt50.adb: New test.
+	* gnat.dg/opt50_pkg.adb: New helper.
+	* gnat.dg/opt50_pkg.ads: New helper.
+
 2015-10-19  Steven G. Kargl  <kargl@gcc.gnu.org>
 
 	PR fortran/68019
diff --git a/gcc/testsuite/gnat.dg/opt50.adb b/gcc/testsuite/gnat.dg/opt50.adb
new file mode 100644
index 0000000..f930d09
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt50.adb
@@ -0,0 +1,23 @@
+-- { dg-do run }
+-- { dg-options "-O3 -gnatn" }
+
+with Opt50_Pkg; use Opt50_Pkg;
+
+procedure Opt50 is
+  B : Boolean;
+  E : Enum;
+begin
+  Get ("four", E, B);
+  if B = True then
+    raise Program_Error;
+  end if;
+  Get ("three", E, B);
+  if B = False then
+    raise Program_Error;
+  end if;
+  declare
+    A : Enum_Boolean_Array (One .. E) := (others => True);
+  begin
+    Set (A);
+  end;
+end Opt50;
diff --git a/gcc/testsuite/gnat.dg/opt50_pkg.adb b/gcc/testsuite/gnat.dg/opt50_pkg.adb
new file mode 100644
index 0000000..0f92f7d
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt50_pkg.adb
@@ -0,0 +1,48 @@
+with Ada.Characters.Handling;
+with Ada.Containers;
+with Ada.Containers.Indefinite_Hashed_Maps;
+with Ada.Strings.Hash;
+
+package body Opt50_Pkg is
+
+   type Enum_Name is array (Enum) of access constant String;
+
+   Enum_Name_Table : constant Enum_Name := (
+      One   => new String'("one"),
+      Two   => new String'("two"),
+      Three => new String'("three"));
+
+   package String_To_Enum_Map is new Ada.Containers.Indefinite_Hashed_Maps
+      (Key_Type => String, Element_Type => Enum,
+       Hash => Ada.Strings.Hash, Equivalent_Keys => "=");
+
+   function Fill_Hashed_Map return String_To_Enum_Map.Map is
+      Res : String_To_Enum_Map.Map;
+      use String_To_Enum_Map;
+   begin
+      for I in Enum_Name_Table'Range loop
+         declare
+            Kind : constant String := Enum_Name_Table (I).all;
+         begin
+            Res.Insert(Key => Kind, New_Item => I);
+         end;
+      end loop;
+      return Res;
+   end;
+
+   String_To_Enum : constant String_To_Enum_Map.Map := Fill_Hashed_Map;
+
+   procedure Get (Kind : String; Result : out Enum; Success : out Boolean) is
+      X : constant String := Ada.Characters.Handling.To_Lower (Kind);
+      use String_To_Enum_Map;
+      Curs : constant Cursor := String_To_Enum.Find (X);
+   begin
+      Success := Curs /= No_Element;
+      if Success then
+         Result := Element(Curs);
+      end if;
+   end;
+
+   procedure Set (A : Enum_Boolean_Array) is null;
+
+end Opt50_Pkg;
diff --git a/gcc/testsuite/gnat.dg/opt50_pkg.ads b/gcc/testsuite/gnat.dg/opt50_pkg.ads
new file mode 100644
index 0000000..9faea54
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt50_pkg.ads
@@ -0,0 +1,12 @@
+package Opt50_Pkg is
+
+   type Enum is (One, Two, Three);
+   for Enum'Size use 16;
+
+   type Enum_Boolean_Array is array (Enum range <>) of Boolean;
+
+   procedure Get (Kind : String; Result : out Enum; Success : out Boolean);
+
+   procedure Set (A : Enum_Boolean_Array);
+
+end Opt50_Pkg;
diff --git a/gcc/timevar.def b/gcc/timevar.def
index ac41075..2fbfb17 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -115,6 +115,7 @@ DEFTIMEVAR (TV_DF_MD		     , "df multiple defs")
 DEFTIMEVAR (TV_DF_RD		     , "df reaching defs")
 DEFTIMEVAR (TV_DF_LR		     , "df live regs")
 DEFTIMEVAR (TV_DF_LIVE		     , "df live&initialized regs")
+DEFTIMEVAR (TV_DF_MIR		     , "df must-initialized regs")
 DEFTIMEVAR (TV_DF_CHAIN		     , "df use-def / def-use chains")
 DEFTIMEVAR (TV_DF_WORD_LR	     , "df live reg subwords")
 DEFTIMEVAR (TV_DF_NOTE		     , "df reg dead/unused notes")
-- 
2.6.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-10-13 15:17       ` [PATCH v2] " Pierre-Marie de Rodat
  2015-10-14 13:41         ` Bernd Schmidt
@ 2015-10-23 11:31         ` Bernd Schmidt
  1 sibling, 0 replies; 11+ messages in thread
From: Bernd Schmidt @ 2015-10-23 11:31 UTC (permalink / raw)
  To: Pierre-Marie de Rodat, gcc-patches
  Cc: Richard Biener, Jeff Law, Bernd Schmidt

On 10/13/2015 05:17 PM, Pierre-Marie de Rodat wrote:
> diff --git a/gcc/df-problems.c b/gcc/df-problems.c
> index c08ae36..56e1cf5 100644
> --- a/gcc/df-problems.c
> +++ b/gcc/df-problems.c
> @@ -1464,9 +1464,12 @@ df_live_bb_local_compute (unsigned int bb_index)
>   	       seen are included in the gen set. */
>   	    bitmap_set_bit (&bb_info->gen, regno);
>   	  else if (DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
> -	    /* Only must clobbers for the entire reg destroy the
> -	       value.  */
> -	    bitmap_set_bit (&bb_info->kill, regno);
> +	    {
> +	      /* Only must clobbers for the entire reg destroy the
> +		 value.  */
> +	      bitmap_set_bit (&bb_info->kill, regno);
> +	      bitmap_clear_bit (&bb_info->gen, regno);
> +	    }
>   	  else if (! DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER))
>   	    bitmap_set_bit (&bb_info->gen, regno);
>   	}

I think I haven't approved that yet. It is ok, but I do wonder whether 
there really is a point distinguishing between MUST_CLOBBER and MAY_CLOBBER.


Bernd

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-10-20 18:14 ` Pierre-Marie de Rodat
@ 2015-10-20 20:38   ` Bernd Schmidt
  0 siblings, 0 replies; 11+ messages in thread
From: Bernd Schmidt @ 2015-10-20 20:38 UTC (permalink / raw)
  To: Pierre-Marie de Rodat, David Edelsohn, Kenneth Zadeck
  Cc: Richard Biener, Jeff Law, Bernd Schmidt, GCC Patches

> Do you refer to this comment?
> (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790#c20)
>> I do have to say that I am still uncomfortable with changing RRE to
>> use a MUST problem rather than a MAY problem.   I see this as dumbing
>> down the compiler to provide the semantics of uninitialized variables
>> and it is a path that we have generally avoided in GCC. I do not have
>> a better solution, but there is a feeling that something is being
>> missed here.
>
> I answered it with questions in comment #27 but there was no followup on
> this point afterwards and Bernd approved the change so I thought it was
> fine: what should I do?

I think the approach in this patch is necessary to prevent ree from 
making incorrect transformations. So I think nothing further is required.


Bernd

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] PR rtl-optimization/66790: uninitialized registers handling in REE
  2015-10-20 15:26 David Edelsohn
@ 2015-10-20 18:14 ` Pierre-Marie de Rodat
  2015-10-20 20:38   ` Bernd Schmidt
  0 siblings, 1 reply; 11+ messages in thread
From: Pierre-Marie de Rodat @ 2015-10-20 18:14 UTC (permalink / raw)
  To: David Edelsohn, Kenneth Zadeck
  Cc: Richard Biener, Jeff Law, Bernd Schmidt, GCC Patches

David,

On 10/20/2015 11:17 AM, David Edelsohn wrote:
> Did this revised patch address the comments about MIR from Kenny?

Do you refer to this comment? 
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66790#c20)
> I do have to say that I am still uncomfortable with changing RRE to
> use a MUST problem rather than a MAY problem.   I see this as dumbing
> down the compiler to provide the semantics of uninitialized variables
> and it is a path that we have generally avoided in GCC. I do not have
> a better solution, but there is a feeling that something is being
> missed here.

I answered it with questions in comment #27 but there was no followup on 
this point afterwards and Bernd approved the change so I thought it was 
fine: what should I do?

Thanks in advance,

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] PR rtl-optimization/66790: uninitialized registers handling in REE
@ 2015-10-20 15:26 David Edelsohn
  2015-10-20 18:14 ` Pierre-Marie de Rodat
  0 siblings, 1 reply; 11+ messages in thread
From: David Edelsohn @ 2015-10-20 15:26 UTC (permalink / raw)
  To: Pierre-Marie de Rodat, Kenneth Zadeck
  Cc: Richard Biener, Jeff Law, Bernd Schmidt, GCC Patches

Pierre,

Did this revised patch address the comments about MIR from Kenny?

- David

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-10-23 11:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-19  6:40 [PATCH] PR rtl-optimization/66790: uninitialized registers handling in REE Pierre-Marie de Rodat
2015-07-27  9:05 ` [PATCH, PING] " Pierre-Marie de Rodat
2015-08-08  8:58   ` [PATCH, PING*2] " Pierre-Marie de Rodat
2015-08-31  7:26     ` [PATCH, PING*3] " Pierre-Marie de Rodat
2015-10-13 15:17       ` [PATCH v2] " Pierre-Marie de Rodat
2015-10-14 13:41         ` Bernd Schmidt
2015-10-19 23:51           ` Pierre-Marie de Rodat
2015-10-23 11:31         ` Bernd Schmidt
2015-10-20 15:26 David Edelsohn
2015-10-20 18:14 ` Pierre-Marie de Rodat
2015-10-20 20:38   ` Bernd Schmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).