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. From-SVN: r229008
This commit is contained in:
parent
32308c8db4
commit
524d9b4b90
|
@ -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
|
||||
|
|
|
@ -1848,6 +1848,409 @@ df_live_verify_transfer_functions (void)
|
|||
bitmap_clear (&all_blocks);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
CREATE DEF_USE (DU) and / or USE_DEF (UD) CHAINS
|
||||
|
||||
|
|
34
gcc/df.h
34
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
|
||||
|
|
62
gcc/ree.c
62
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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue