Commit 04be694e by Martin Jambor Committed by Martin Jambor

ipa-prop.h (ipa_alignment): New type.

2014-12-04  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.h (ipa_alignment): New type.
	(ipa_jump_func): New field alignment.
	(ipcp_transformation_summary) New type.
	(ipcp_grow_transformations_if_necessary): Declare.
	(ipa_node_agg_replacements): Removed.
	(ipcp_transformations): Declare.
	(ipcp_get_transformation_summary): New function.
	(ipa_get_agg_replacements_for_node): Use it.
	* ipa-cp.c (ipcp_param_lattices): New field alignment.
	(print_all_lattices): Also print alignment.
	(alignment_bottom_p): New function.
	(set_alignment_to_bottom): Likewise.
	(set_all_contains_variable): Also set alignment to bottom.
	(initialize_node_lattices): Likewise.
	(propagate_alignment_accross_jump_function): New function.
	(propagate_constants_accross_call): Call it.
	(ipcp_store_alignment_results): New function.
	(ipcp_driver): Call it.
	* ipa-prop.c (ipa_node_agg_replacements): Removed.
	(ipcp_transformations): New.
	(ipa_print_node_jump_functions_for_edge): Also print alignment.
	(ipa_set_jf_unknown): New function.
	(detect_type_change_from_memory_writes): Use ipa_set_jf_unknown.
	(ipa_compute_jump_functions_for_edge): Also calculate alignment.
	(update_jump_functions_after_inlining): Use ipa_set_jf_unknown.
	(ipcp_grow_transformations_if_necessary): New function.
	(ipa_set_node_agg_value_chain): Use ipcp_transformations.
	(ipa_node_removal_hook): Likewise.
	(ipa_node_duplication_hook): Also duplicate alignment results.
	(ipa_write_jump_function): Also stream alignments.
	(ipa_read_jump_function): Use ipa_set_jf_unknown, also stream
	alignments.
	(write_agg_replacement_chain): Renamed to
	write_ipcp_transformation_info, also stream alignments.
	(read_agg_replacement_chain): Renamed to
	read_ipcp_transformation_info, also stream alignments.
	(ipa_prop_write_all_agg_replacement): Renamed to
	ipcp_write_transformation_summaries. Stream always.
	(ipa_prop_read_all_agg_replacement): Renamed to
	ipcp_read_transformation_summaries.
	(ipcp_update_alignments): New function.
	(ipcp_transform_function): Call it, free also alignments.

testsuite/
	* gcc.dg/ipa/propalign-1.c: New test.
	* gcc.dg/ipa/propalign-2.c: Likewise.

From-SVN: r218369
parent de665bbd
2014-12-04 Martin Jambor <mjambor@suse.cz>
* ipa-prop.h (ipa_alignment): New type.
(ipa_jump_func): New field alignment.
(ipcp_transformation_summary) New type.
(ipcp_grow_transformations_if_necessary): Declare.
(ipa_node_agg_replacements): Removed.
(ipcp_transformations): Declare.
(ipcp_get_transformation_summary): New function.
(ipa_get_agg_replacements_for_node): Use it.
* ipa-cp.c (ipcp_param_lattices): New field alignment.
(print_all_lattices): Also print alignment.
(alignment_bottom_p): New function.
(set_alignment_to_bottom): Likewise.
(set_all_contains_variable): Also set alignment to bottom.
(initialize_node_lattices): Likewise.
(propagate_alignment_accross_jump_function): New function.
(propagate_constants_accross_call): Call it.
(ipcp_store_alignment_results): New function.
(ipcp_driver): Call it.
* ipa-prop.c (ipa_node_agg_replacements): Removed.
(ipcp_transformations): New.
(ipa_print_node_jump_functions_for_edge): Also print alignment.
(ipa_set_jf_unknown): New function.
(detect_type_change_from_memory_writes): Use ipa_set_jf_unknown.
(ipa_compute_jump_functions_for_edge): Also calculate alignment.
(update_jump_functions_after_inlining): Use ipa_set_jf_unknown.
(ipcp_grow_transformations_if_necessary): New function.
(ipa_set_node_agg_value_chain): Use ipcp_transformations.
(ipa_node_removal_hook): Likewise.
(ipa_node_duplication_hook): Also duplicate alignment results.
(ipa_write_jump_function): Also stream alignments.
(ipa_read_jump_function): Use ipa_set_jf_unknown, also stream
alignments.
(write_agg_replacement_chain): Renamed to
write_ipcp_transformation_info, also stream alignments.
(read_agg_replacement_chain): Renamed to
read_ipcp_transformation_info, also stream alignments.
(ipa_prop_write_all_agg_replacement): Renamed to
ipcp_write_transformation_summaries. Stream always.
(ipa_prop_read_all_agg_replacement): Renamed to
ipcp_read_transformation_summaries.
(ipcp_update_alignments): New function.
(ipcp_transform_function): Call it, free also alignments.
2014-12-04 Richard Biener <rguenther@suse.de>
* gimple-fold.c (replace_stmt_with_simplification): Properly
......@@ -262,6 +262,9 @@ public:
ipcp_lattice<ipa_polymorphic_call_context> ctxlat;
/* Lattices describing aggregate parts. */
ipcp_agg_lattice *aggs;
/* Alignment information. Very basic one value lattice where !known means
TOP and zero alignment bottom. */
ipa_alignment alignment;
/* Number of aggregate lattices */
int aggs_count;
/* True if aggregate data were passed by reference (as opposed to by
......@@ -444,6 +447,13 @@ print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
plats->itself.print (f, dump_sources, dump_benefits);
fprintf (f, " ctxs: ");
plats->ctxlat.print (f, dump_sources, dump_benefits);
if (plats->alignment.known && plats->alignment.align > 0)
fprintf (f, " Alignment %u, misalignment %u\n",
plats->alignment.align, plats->alignment.misalign);
else if (plats->alignment.known)
fprintf (f, " Alignment unusable\n");
else
fprintf (f, " Alignment unknown\n");
if (plats->virt_call)
fprintf (f, " virt_call flag set\n");
......@@ -761,6 +771,27 @@ set_agg_lats_contain_variable (struct ipcp_param_lattices *plats)
return ret;
}
/* Return true if alignment information in PLATS is known to be unusable. */
static inline bool
alignment_bottom_p (ipcp_param_lattices *plats)
{
return plats->alignment.known && (plats->alignment.align == 0);
}
/* Set alignment information in PLATS to unusable. Return true if it
previously was usable or unknown. */
static inline bool
set_alignment_to_bottom (ipcp_param_lattices *plats)
{
if (alignment_bottom_p (plats))
return false;
plats->alignment.known = true;
plats->alignment.align = 0;
return true;
}
/* Mark bot aggregate and scalar lattices as containing an unknown variable,
return true is any of them has not been marked as such so far. */
......@@ -771,6 +802,7 @@ set_all_contains_variable (struct ipcp_param_lattices *plats)
ret = plats->itself.set_contains_variable ();
ret |= plats->ctxlat.set_contains_variable ();
ret |= set_agg_lats_contain_variable (plats);
ret |= set_alignment_to_bottom (plats);
return ret;
}
......@@ -807,6 +839,7 @@ initialize_node_lattices (struct cgraph_node *node)
plats->itself.set_to_bottom ();
plats->ctxlat.set_to_bottom ();
set_agg_lats_to_bottom (plats);
set_alignment_to_bottom (plats);
}
else
set_all_contains_variable (plats);
......@@ -1369,6 +1402,77 @@ propagate_context_accross_jump_function (cgraph_edge *cs,
return ret;
}
/* Propagate alignments across jump function JFUNC that is associated with
edge CS and update DEST_LAT accordingly. */
static bool
propagate_alignment_accross_jump_function (struct cgraph_edge *cs,
struct ipa_jump_func *jfunc,
struct ipcp_param_lattices *dest_lat)
{
if (alignment_bottom_p (dest_lat))
return false;
ipa_alignment cur;
cur.known = false;
if (jfunc->alignment.known)
cur = jfunc->alignment;
else if (jfunc->type == IPA_JF_PASS_THROUGH
|| jfunc->type == IPA_JF_ANCESTOR)
{
struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
struct ipcp_param_lattices *src_lats;
HOST_WIDE_INT offset = 0;
int src_idx;
if (jfunc->type == IPA_JF_PASS_THROUGH)
{
enum tree_code op = ipa_get_jf_pass_through_operation (jfunc);
if (op != NOP_EXPR)
{
if (op != POINTER_PLUS_EXPR
&& op != PLUS_EXPR
&& op != MINUS_EXPR)
goto prop_fail;
tree operand = ipa_get_jf_pass_through_operand (jfunc);
if (!tree_fits_shwi_p (operand))
goto prop_fail;
offset = tree_to_shwi (operand);
}
src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
}
else
{
src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
offset = ipa_get_jf_ancestor_offset (jfunc);
}
src_lats = ipa_get_parm_lattices (caller_info, src_idx);
if (!src_lats->alignment.known
|| alignment_bottom_p (src_lats))
goto prop_fail;
cur = src_lats->alignment;
cur.misalign = (cur.misalign + offset) % cur.align;
}
if (cur.known)
{
if (!dest_lat->alignment.known)
{
dest_lat->alignment = cur;
return true;
}
else if (dest_lat->alignment.align == cur.align
&& dest_lat->alignment.misalign == cur.misalign)
return false;
}
prop_fail:
set_alignment_to_bottom (dest_lat);
return true;
}
/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
NEW_AGGS_BY_REF and if not, mark all aggs as bottoms and return true (in all
other cases, return false). If there are no aggregate items, set
......@@ -1705,6 +1809,8 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
&dest_plats->itself);
ret |= propagate_context_accross_jump_function (cs, jump_func, i,
&dest_plats->ctxlat);
ret |= propagate_alignment_accross_jump_function (cs, jump_func,
dest_plats);
ret |= propagate_aggs_accross_jump_function (cs, jump_func,
dest_plats);
}
......@@ -4190,6 +4296,63 @@ ipcp_decision_stage (struct ipa_topo_info *topo)
}
}
/* Look up all alignment information that we have discovered and copy it over
to the transformation summary. */
static void
ipcp_store_alignment_results (void)
{
cgraph_node *node;
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
{
ipa_node_params *info = IPA_NODE_REF (node);
bool dumped_sth = false;
bool found_useful_result = false;
if (info->ipcp_orig_node)
info = IPA_NODE_REF (info->ipcp_orig_node);
unsigned count = ipa_get_param_count (info);
for (unsigned i = 0; i < count ; i++)
{
ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
if (plats->alignment.known
&& plats->alignment.align > 0)
{
found_useful_result = true;
break;
}
}
if (!found_useful_result)
continue;
ipcp_grow_transformations_if_necessary ();
ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
vec_safe_reserve_exact (ts->alignments, count);
for (unsigned i = 0; i < count ; i++)
{
ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
if (plats->alignment.align == 0)
plats->alignment.known = false;
ts->alignments->quick_push (plats->alignment);
if (!dump_file || !plats->alignment.known)
continue;
if (!dumped_sth)
{
fprintf (dump_file, "Propagated alignment info for function %s/%i:\n",
node->name (), node->order);
dumped_sth = true;
}
fprintf (dump_file, " param %i: align: %u, misalign: %u\n",
i, plats->alignment.align, plats->alignment.misalign);
}
}
}
/* The IPCP driver. */
static unsigned int
......@@ -4231,6 +4394,8 @@ ipcp_driver (void)
ipcp_propagate_stage (&topo);
/* Decide what constant propagation and cloning should be performed. */
ipcp_decision_stage (&topo);
/* Store results of alignment propagation. */
ipcp_store_alignment_results ();
/* Free all IPCP structures. */
free_toporder_info (&topo);
......@@ -4303,9 +4468,9 @@ public:
ipcp_generate_summary, /* generate_summary */
ipcp_write_summary, /* write_summary */
ipcp_read_summary, /* read_summary */
ipa_prop_write_all_agg_replacement, /*
ipcp_write_transformation_summaries, /*
write_optimization_summary */
ipa_prop_read_all_agg_replacement, /*
ipcp_read_transformation_summaries, /*
read_optimization_summary */
NULL, /* stmt_fixup */
0, /* function_transform_todo_flags_start */
......
......@@ -144,6 +144,17 @@ struct GTY(()) ipa_agg_jump_function
typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p;
/* Info about pointer alignments. */
struct GTY(()) ipa_alignment
{
/* The data fields below are valid only if known is true. */
bool known;
/* See ptr_info_def and get_pointer_alignment_1 for description of these
two. */
unsigned align;
unsigned misalign;
};
/* A jump function for a callsite represents the values passed as actual
arguments of the callsite. See enum jump_func_type for the various
types of jump functions supported. */
......@@ -153,6 +164,9 @@ struct GTY (()) ipa_jump_func
description. */
struct ipa_agg_jump_function agg;
/* Information about alignment of pointers. */
struct ipa_alignment alignment;
enum jump_func_type type;
/* Represents a value of a jump function. pass_through is used only in jump
function context. constant represents the actual constant in constant jump
......@@ -402,10 +416,19 @@ struct GTY(()) ipa_agg_replacement_value
bool by_ref;
};
typedef struct ipa_agg_replacement_value *ipa_agg_replacement_value_p;
/* Structure holding information for the transformation phase of IPA-CP. */
struct GTY(()) ipcp_transformation_summary
{
/* Linked list of known aggregate values. */
ipa_agg_replacement_value *agg_values;
/* Alignment information for pointers. */
vec<ipa_alignment, va_gc> *alignments;
};
void ipa_set_node_agg_value_chain (struct cgraph_node *node,
struct ipa_agg_replacement_value *aggvals);
void ipcp_grow_transformations_if_necessary (void);
/* ipa_edge_args stores information related to a callsite and particularly its
arguments. It can be accessed by the IPA_EDGE_REF macro. */
......@@ -451,8 +474,8 @@ ipa_get_ith_polymorhic_call_context (struct ipa_edge_args *args, int i)
/* Vector where the parameter infos are actually stored. */
extern vec<ipa_node_params> ipa_node_params_vector;
/* Vector of known aggregate values in cloned nodes. */
extern GTY(()) vec<ipa_agg_replacement_value_p, va_gc> *ipa_node_agg_replacements;
/* Vector of IPA-CP transformation data for each clone. */
extern GTY(()) vec<ipcp_transformation_summary, va_gc> *ipcp_transformations;
/* Vector where the parameter infos are actually stored. */
extern GTY(()) vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
......@@ -510,14 +533,21 @@ ipa_edge_args_info_available_for_edge_p (struct cgraph_edge *edge)
return ((unsigned) edge->uid < vec_safe_length (ipa_edge_args_vector));
}
static inline ipcp_transformation_summary *
ipcp_get_transformation_summary (cgraph_node *node)
{
if ((unsigned) node->uid >= vec_safe_length (ipcp_transformations))
return NULL;
return &(*ipcp_transformations)[node->uid];
}
/* Return the aggregate replacements for NODE, if there are any. */
static inline struct ipa_agg_replacement_value *
ipa_get_agg_replacements_for_node (struct cgraph_node *node)
ipa_get_agg_replacements_for_node (cgraph_node *node)
{
if ((unsigned) node->uid >= vec_safe_length (ipa_node_agg_replacements))
return NULL;
return (*ipa_node_agg_replacements)[node->uid];
ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
return ts ? ts->agg_values : NULL;
}
/* Function formal parameters related computations. */
......@@ -646,8 +676,8 @@ void ipa_dump_agg_replacement_values (FILE *f,
struct ipa_agg_replacement_value *av);
void ipa_prop_write_jump_functions (void);
void ipa_prop_read_jump_functions (void);
void ipa_prop_write_all_agg_replacement (void);
void ipa_prop_read_all_agg_replacement (void);
void ipcp_write_transformation_summaries (void);
void ipcp_read_transformation_summaries (void);
void ipa_update_after_lto_read (void);
int ipa_get_param_decl_index (struct ipa_node_params *, tree);
tree ipa_value_from_jfunc (struct ipa_node_params *info,
......
2014-12-04 Martin Jambor <mjambor@suse.cz>
* gcc.dg/ipa/propalign-1.c: New test.
* gcc.dg/ipa/propalign-2.c: Likewise.
2014-12-04 Jakub Jelinek <jakub@redhat.com>
PR c++/56493
......
/* { dg-do compile } */
/* { dg-options "-O2 -fno-early-inlining -fdump-ipa-cp -fdump-tree-optimized" } */
#include <stdint.h>
extern int fail_the_test(void *);
extern int pass_the_test(void *);
extern int diversion (void *);
static int __attribute__((noinline))
foo (void *p)
{
uintptr_t a = (uintptr_t) p;
if (a % 4)
return fail_the_test (p);
else
return pass_the_test (p);
}
int
bar (void)
{
double buf[8] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
return foo (&buf);
}
/* { dg-final { scan-ipa-dump "Adjusting alignment of param" "cp" } } */
/* { dg-final { scan-tree-dump-not "fail_the_test" "optimized" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-early-inlining -fdump-ipa-cp -fdump-tree-optimized" } */
#include <stdint.h>
extern int fail_the_test(void *);
extern int pass_the_test(void *);
extern int diversion (void *);
struct somestruct
{
void *whee;
void *oops;
};
struct container
{
struct somestruct first;
struct somestruct buf[32];
};
static int __attribute__((noinline))
foo (void *p)
{
uintptr_t a = (uintptr_t) p;
if (a % 4)
return fail_the_test (p);
else
return pass_the_test (p);
}
int
bar (void)
{
struct container c;
return foo (c.buf);
}
static int
through (struct somestruct *p)
{
diversion (p);
return foo (&p[16]);
}
int
bar2 (void)
{
struct container c;
through (c.buf);
}
/* { dg-final { scan-ipa-dump "Adjusting alignment of param" "cp" } } */
/* { dg-final { scan-tree-dump-not "fail_the_test" "optimized" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment