/* Matrix layout transformations.
- Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Razya Ladelsky <razya@il.ibm.com>
Originally written by Revital Eres and Mustafa Hagog.
-
+
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
<http://www.gnu.org/licenses/>. */
/*
- Matrix flattening optimization tries to replace a N-dimensional
+ Matrix flattening optimization tries to replace a N-dimensional
matrix with its equivalent M-dimensional matrix, where M < N.
This first implementation focuses on global matrices defined dynamically.
and transformation.
The driver of the optimization is matrix_reorg ().
-
-
+
+
Analysis phase:
===============
- We'll number the dimensions outside-in, meaning the most external
- is 0, then 1, and so on.
- The analysis part of the optimization determines K, the escape
- level of a N-dimensional matrix (K <= N), that allows flattening of
+ We'll number the dimensions outside-in, meaning the most external
+ is 0, then 1, and so on.
+ The analysis part of the optimization determines K, the escape
+ level of a N-dimensional matrix (K <= N), that allows flattening of
the external dimensions 0,1,..., K-1. Escape level 0 means that the
whole matrix escapes and no flattening is possible.
-
- The analysis part is implemented in analyze_matrix_allocation_site()
+
+ The analysis part is implemented in analyze_matrix_allocation_site()
and analyze_matrix_accesses().
Transformation phase:
=====================
- In this phase we define the new flattened matrices that replace the
- original matrices in the code.
- Implemented in transform_allocation_sites(),
- transform_access_sites().
+ In this phase we define the new flattened matrices that replace the
+ original matrices in the code.
+ Implemented in transform_allocation_sites(),
+ transform_access_sites().
Matrix Transposing
==================
- The idea of Matrix Transposing is organizing the matrix in a different
+ The idea of Matrix Transposing is organizing the matrix in a different
layout such that the dimensions are reordered.
This could produce better cache behavior in some cases.
for (j=0; j<M; j++)
access to a[i][j]
- This loop can produce good cache behavior because the elements of
+ This loop can produce good cache behavior because the elements of
the inner dimension are accessed sequentially.
However, if the accesses of the matrix were of the following form:
for (j=0; j<M; j++)
access to a[j][i]
- In this loop we iterate the columns and not the rows.
- Therefore, replacing the rows and columns
+ In this loop we iterate the columns and not the rows.
+ Therefore, replacing the rows and columns
would have had an organization with better (cache) locality.
Replacing the dimensions of the matrix is called matrix transposing.
- This example, of course, could be enhanced to multiple dimensions matrices
+ This example, of course, could be enhanced to multiple dimensions matrices
as well.
- Since a program could include all kind of accesses, there is a decision
- mechanism, implemented in analyze_transpose(), which implements a
+ Since a program could include all kind of accesses, there is a decision
+ mechanism, implemented in analyze_transpose(), which implements a
heuristic that tries to determine whether to transpose the matrix or not,
according to the form of the more dominant accesses.
- This decision is transferred to the flattening mechanism, and whether
+ This decision is transferred to the flattening mechanism, and whether
the matrix was transposed or not, the matrix is flattened (if possible).
-
+
This decision making is based on profiling information and loop information.
- If profiling information is available, decision making mechanism will be
+ If profiling information is available, decision making mechanism will be
operated, otherwise the matrix will only be flattened (if possible).
- Both optimizations are described in the paper "Matrix flattening and
- transposing in GCC" which was presented in GCC summit 2006.
+ Both optimizations are described in the paper "Matrix flattening and
+ transposing in GCC" which was presented in GCC summit 2006.
http://www.gccsummit.org/2006/2006-GCC-Summit-Proceedings.pdf. */
#include "config.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
-#include "c-tree.h"
#include "tree-inline.h"
#include "tree-flow.h"
#include "tree-flow-inline.h"
#include "langhooks.h"
#include "hashtab.h"
-#include "toplev.h"
#include "flags.h"
#include "ggc.h"
#include "debug.h"
#include "target.h"
#include "cgraph.h"
-#include "diagnostic.h"
+#include "diagnostic-core.h"
#include "timevar.h"
#include "params.h"
#include "fibheap.h"
-#include "c-common.h"
#include "intl.h"
#include "function.h"
#include "basic-block.h"
#include "tree-data-ref.h"
#include "tree-chrec.h"
#include "tree-scalar-evolution.h"
+#include "tree-ssa-sccvn.h"
/* We need to collect a lot of data from the original malloc,
particularly as the gimplifier has converted:
initial address and index of each dimension. */
struct access_site_info
{
- /* The statement (INDIRECT_REF or POINTER_PLUS_EXPR). */
+ /* The statement (MEM_REF or POINTER_PLUS_EXPR). */
gimple stmt;
/* In case of POINTER_PLUS_EXPR, what is the offset. */
DEF_VEC_P (access_site_info_p);
DEF_VEC_ALLOC_P (access_site_info_p, heap);
+/* Calls to free when flattening a matrix. */
+
+struct free_info
+{
+ gimple stmt;
+ tree func;
+};
+
/* Information about matrix to flatten. */
struct matrix_info
{
tree allocation_function_decl;
/* The calls to free for each level of indirection. */
- struct free_info
- {
- gimple stmt;
- tree func;
- } *free_stmts;
+ struct free_info *free_stmts;
/* An array which holds for each dimension its size. where
dimension 0 is the outer most (one that contains all the others).
*/
tree *dimension_size;
- /* An array which holds for each dimension it's original size
+ /* An array which holds for each dimension it's original size
(before transposing and flattening take place). */
tree *dimension_size_orig;
elements are of type "struct access_site_info *". */
VEC (access_site_info_p, heap) * access_l;
- /* A map of how the dimensions will be organized at the end of
+ /* A map of how the dimensions will be organized at the end of
the analyses. */
int *dim_map;
};
/* The variable whose accesses in the tree we are looking for. */
tree ssa_var;
/* The tree and code inside it the ssa_var is accessed, currently
- it could be an INDIRECT_REF or CALL_EXPR. */
+ it could be an MEM_REF or CALL_EXPR. */
enum tree_code t_code;
tree t_tree;
/* The place in the containing tree. */
return false;
}
-/* Return false if STMT may contain a vector expression.
+/* Return false if STMT may contain a vector expression.
In this situation, all matrices should not be flattened. */
static bool
may_flatten_matrices_1 (gimple stmt)
{
- tree t;
-
switch (gimple_code (stmt))
{
case GIMPLE_ASSIGN:
- if (!gimple_assign_cast_p (stmt))
+ case GIMPLE_CALL:
+ if (!gimple_has_lhs (stmt))
return true;
-
- t = gimple_assign_rhs1 (stmt);
- while (CONVERT_EXPR_P (t))
+ if (TREE_CODE (TREE_TYPE (gimple_get_lhs (stmt))) == VECTOR_TYPE)
{
- if (TREE_TYPE (t) && POINTER_TYPE_P (TREE_TYPE (t)))
- {
- tree pointee;
-
- pointee = TREE_TYPE (t);
- while (POINTER_TYPE_P (pointee))
- pointee = TREE_TYPE (pointee);
- if (TREE_CODE (pointee) == VECTOR_TYPE)
- {
- if (dump_file)
- fprintf (dump_file,
- "Found vector type, don't flatten matrix\n");
- return false;
- }
- }
- t = TREE_OPERAND (t, 0);
+ if (dump_file)
+ fprintf (dump_file,
+ "Found vector type, don't flatten matrix\n");
+ return false;
}
break;
case GIMPLE_ASM:
return true;
}
-/* Return false if there are hand-written vectors in the program.
+/* Return false if there are hand-written vectors in the program.
We disable the flattening in such a case. */
static bool
may_flatten_matrices (struct cgraph_node *node)
basic_block bb;
gimple_stmt_iterator gsi;
- decl = node->decl;
+ decl = node->symbol.decl;
if (node->analyzed)
{
func = DECL_STRUCT_FUNCTION (decl);
if (!mat)
return;
- if (mat->free_stmts)
- free (mat->free_stmts);
- if (mat->dim_hot_level)
- free (mat->dim_hot_level);
- if (mat->malloc_for_level)
- free (mat->malloc_for_level);
+ free (mat->free_stmts);
+ free (mat->dim_hot_level);
+ free (mat->malloc_for_level);
}
/* Find all potential matrices.
/* For every global variable in the program:
Check to see if it's of a candidate type and record it. */
- for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
+ FOR_EACH_DEFINED_VARIABLE (vnode)
{
- tree var_decl = vnode->decl;
+ tree var_decl = vnode->symbol.decl;
if (!var_decl || TREE_CODE (var_decl) != VAR_DECL)
continue;
/* Find if the SSA variable is accessed inside the
tree and record the tree containing it.
The only relevant uses are the case of SSA_NAME, or SSA inside
- INDIRECT_REF, PLUS_EXPR, POINTER_PLUS_EXPR, MULT_EXPR. */
+ MEM_REF, PLUS_EXPR, POINTER_PLUS_EXPR, MULT_EXPR. */
static void
ssa_accessed_in_tree (tree t, struct ssa_acc_in_tree *a)
{
if (t == a->ssa_var)
a->var_found = true;
break;
- case INDIRECT_REF:
+ case MEM_REF:
if (SSA_VAR_P (TREE_OPERAND (t, 0))
&& TREE_OPERAND (t, 0) == a->ssa_var)
a->var_found = true;
tree op1, op2;
case SSA_NAME:
- case INDIRECT_REF:
+ case MEM_REF:
CASE_CONVERT:
case VIEW_CONVERT_EXPR:
ssa_accessed_in_tree (gimple_assign_rhs1 (stmt), a);
}
}
-/* Record the access/allocation site information for matrix MI so we can
+/* Record the access/allocation site information for matrix MI so we can
handle it later in transformation. */
static void
record_access_alloc_site_info (struct matrix_info *mi, gimple stmt, tree offset,
must be set accordingly. */
for (min_malloc_level = 0;
min_malloc_level < mi->max_malloced_level
- && mi->malloc_for_level[min_malloc_level]; min_malloc_level++);
+ && mi->malloc_for_level[min_malloc_level]; min_malloc_level++)
+ ;
if (level < min_malloc_level)
{
mi->allocation_function_decl = current_function_decl;
else
{
mark_min_matrix_escape_level (mi, level, stmt);
- /* cannot be that (level == min_malloc_level)
+ /* cannot be that (level == min_malloc_level)
we would have returned earlier. */
return;
}
will hold the size for each dimension; each malloc that allocates a
dimension has the size parameter; we use that parameter to
initialize the dimension size variable so we can use it later in
- the address calculations. LEVEL is the dimension we're inspecting.
+ the address calculations. LEVEL is the dimension we're inspecting.
Return if STMT is related to an allocation site. */
static void
else
{
tree malloc_fn_decl;
- const char *malloc_fname;
malloc_fn_decl = gimple_call_fndecl (stmt);
if (malloc_fn_decl == NULL_TREE)
mark_min_matrix_escape_level (mi, level, stmt);
return;
}
- malloc_fname = IDENTIFIER_POINTER (DECL_NAME (malloc_fn_decl));
if (DECL_FUNCTION_CODE (malloc_fn_decl) != BUILT_IN_MALLOC)
{
if (dump_file)
return;
}
}
- /* This is a call to malloc of level 'level'.
- mi->max_malloced_level-1 == level means that we've
- seen a malloc statement of level 'level' before.
- If the statement is not the same one that we've
- seen before, then there's another malloc statement
- for the same level, which means that we need to mark
+ /* This is a call to malloc of level 'level'.
+ mi->max_malloced_level-1 == level means that we've
+ seen a malloc statement of level 'level' before.
+ If the statement is not the same one that we've
+ seen before, then there's another malloc statement
+ for the same level, which means that we need to mark
it escaping. */
if (mi->malloc_for_level
&& mi->max_malloced_level-1 == level
}
/* The transposing decision making.
- In order to to calculate the profitability of transposing, we collect two
+ In order to calculate the profitability of transposing, we collect two
types of information regarding the accesses:
1. profiling information used to express the hotness of an access, that
- is how often the matrix is accessed by this access site (count of the
- access site).
+ is how often the matrix is accessed by this access site (count of the
+ access site).
2. which dimension in the access site is iterated by the inner
most loop containing this access.
- The matrix will have a calculated value of weighted hotness for each
+ The matrix will have a calculated value of weighted hotness for each
dimension.
- Intuitively the hotness level of a dimension is a function of how
- many times it was the most frequently accessed dimension in the
+ Intuitively the hotness level of a dimension is a function of how
+ many times it was the most frequently accessed dimension in the
highly executed access sites of this matrix.
As computed by following equation:
- m n
- __ __
- \ \ dim_hot_level[i] +=
+ m n
+ __ __
+ \ \ dim_hot_level[i] +=
/_ /_
- j i
+ j i
acc[j]->dim[i]->iter_by_inner_loop * count(j)
Where n is the number of dims and m is the number of the matrix
{
if (mi->access_l)
{
- for (i = 0;
- VEC_iterate (access_site_info_p, mi->access_l, i, acc_info);
- i++)
+ FOR_EACH_VEC_ELT (access_site_info_p, mi->access_l, i, acc_info)
free (acc_info);
VEC_free (access_site_info_p, heap, mi->access_l);
return 1;
}
-/* Find the index which defines the OFFSET from base.
+/* Find the index which defines the OFFSET from base.
We walk from use to def until we find how the offset was defined. */
static tree
get_index_from_offset (tree offset, gimple def_stmt)
/* update MI->dimension_type_size[CURRENT_INDIRECT_LEVEL] with the size
of the type related to the SSA_VAR, or the type related to the
- lhs of STMT, in the case that it is an INDIRECT_REF. */
+ lhs of STMT, in the case that it is an MEM_REF. */
static void
update_type_size (struct matrix_info *mi, gimple stmt, tree ssa_var,
int current_indirect_level)
tree lhs;
HOST_WIDE_INT type_size;
- /* Update type according to the type of the INDIRECT_REF expr. */
+ /* Update type according to the type of the MEM_REF expr. */
if (is_gimple_assign (stmt)
- && TREE_CODE (gimple_assign_lhs (stmt)) == INDIRECT_REF)
+ && TREE_CODE (gimple_assign_lhs (stmt)) == MEM_REF)
{
lhs = gimple_assign_lhs (stmt);
gcc_assert (POINTER_TYPE_P
}
}
-/* USE_STMT represents a GIMPLE_CALL, where one of the arguments is the
- ssa var that we want to check because it came from some use of matrix
- MI. CURRENT_INDIRECT_LEVEL is the indirection level we reached so
+/* USE_STMT represents a GIMPLE_CALL, where one of the arguments is the
+ ssa var that we want to check because it came from some use of matrix
+ MI. CURRENT_INDIRECT_LEVEL is the indirection level we reached so
far. */
static int
at this level because in this case we cannot calculate the
address correctly. */
if ((lhs_acc.var_found && rhs_acc.var_found
- && lhs_acc.t_code == INDIRECT_REF)
+ && lhs_acc.t_code == MEM_REF)
|| (!rhs_acc.var_found && !lhs_acc.var_found))
{
mark_min_matrix_escape_level (mi, current_indirect_level, use_stmt);
{
int l = current_indirect_level + 1;
- gcc_assert (lhs_acc.t_code == INDIRECT_REF);
+ gcc_assert (lhs_acc.t_code == MEM_REF);
mark_min_matrix_escape_level (mi, l, use_stmt);
return current_indirect_level;
}
return current_indirect_level;
}
-/* USE_STMT represents a phi node of the ssa var that we want to
- check because it came from some use of matrix
+/* USE_STMT represents a phi node of the ssa var that we want to
+ check because it came from some use of matrix
MI.
We check all the escaping levels that get to the PHI node
and make sure they are all the same escaping;
if not (which is rare) we let the escaping level be the
minimum level that gets into that PHI because starting from
- that level we cannot expect the behavior of the indirections.
+ that level we cannot expect the behavior of the indirections.
CURRENT_INDIRECT_LEVEL is the indirection level we reached so far. */
static void
}
}
-/* USE_STMT represents an assign statement (the rhs or lhs include
- the ssa var that we want to check because it came from some use of matrix
+/* USE_STMT represents an assign statement (the rhs or lhs include
+ the ssa var that we want to check because it came from some use of matrix
MI. CURRENT_INDIRECT_LEVEL is the indirection level we reached so far. */
static int
at this level because in this case we cannot calculate the
address correctly. */
if ((lhs_acc.var_found && rhs_acc.var_found
- && lhs_acc.t_code == INDIRECT_REF)
+ && lhs_acc.t_code == MEM_REF)
|| (!rhs_acc.var_found && !lhs_acc.var_found))
{
mark_min_matrix_escape_level (mi, current_indirect_level, use_stmt);
{
int l = current_indirect_level + 1;
- gcc_assert (lhs_acc.t_code == INDIRECT_REF);
+ gcc_assert (lhs_acc.t_code == MEM_REF);
if (!(gimple_assign_copy_p (use_stmt)
|| gimple_assign_cast_p (use_stmt))
}
return current_indirect_level;
}
- /* Now, check the right-hand-side, to see how the SSA variable
+ /* Now, check the right-hand-side, to see how the SSA variable
is used. */
if (rhs_acc.var_found)
{
- if (rhs_acc.t_code != INDIRECT_REF
+ if (rhs_acc.t_code != MEM_REF
&& rhs_acc.t_code != POINTER_PLUS_EXPR && rhs_acc.t_code != SSA_NAME)
{
mark_min_matrix_escape_level (mi, current_indirect_level, use_stmt);
}
/* If the access in the RHS has an indirection increase the
indirection level. */
- if (rhs_acc.t_code == INDIRECT_REF)
+ if (rhs_acc.t_code == MEM_REF)
{
if (record_accesses)
record_access_alloc_site_info (mi, use_stmt, NULL_TREE,
}
/* If we are storing this level of indirection mark it as
escaping. */
- if (lhs_acc.t_code == INDIRECT_REF || TREE_CODE (lhs) != SSA_NAME)
+ if (lhs_acc.t_code == MEM_REF || TREE_CODE (lhs) != SSA_NAME)
{
int l = current_indirect_level;
/* One exception is when we are storing to the matrix
variable itself; this is the case of malloc, we must make
- sure that it's the one and only one call to malloc so
- we call analyze_matrix_allocation_site to check
+ sure that it's the one and only one call to malloc so
+ we call analyze_matrix_allocation_site to check
this out. */
if (TREE_CODE (lhs) != VAR_DECL || lhs != mi->decl)
mark_min_matrix_escape_level (mi, current_indirect_level,
return current_indirect_level;
}
-/* Given a SSA_VAR (coming from a use statement of the matrix MI),
+/* Given a SSA_VAR (coming from a use statement of the matrix MI),
follow its uses and level of indirection and find out the minimum
indirection level it escapes in (the highest dimension) and the maximum
level it is accessed in (this will be the actual dimension of the
return;
/* Now go over the uses of the SSA_NAME and check how it is used in
- each one of them. We are mainly looking for the pattern INDIRECT_REF,
- then a POINTER_PLUS_EXPR, then INDIRECT_REF etc. while in between there could
+ each one of them. We are mainly looking for the pattern MEM_REF,
+ then a POINTER_PLUS_EXPR, then MEM_REF etc. while in between there could
be any number of copies and casts. */
gcc_assert (TREE_CODE (ssa_var) == SSA_NAME);
}
}
-typedef struct
+typedef struct
{
tree fn;
gimple stmt;
case GIMPLE_ASSIGN:
code = gimple_assign_rhs_code (stmt);
op1 = gimple_assign_rhs1 (stmt);
-
+
switch (code)
{
case POINTER_PLUS_EXPR:
check_allocation_function (void **slot, void *data ATTRIBUTE_UNUSED)
{
int level;
- gimple_stmt_iterator gsi;
- basic_block bb_level_0;
struct matrix_info *mi = (struct matrix_info *) *slot;
sbitmap visited;
mark_min_matrix_escape_level (mi, level, NULL);
- gsi = gsi_for_stmt (mi->malloc_for_level[0]);
- bb_level_0 = gsi.bb;
-
/* Check if the expression of the size passed to malloc could be
pre-calculated before the malloc of level 0. */
for (level = 1; level < mi->min_indirect_level_escape; level++)
according to the following equation:
a[I1][I2]...[Ik] , where D1..Dk is the length of each dimension and the
- escaping level is m <= k, and a' is the new allocated matrix,
+ escaping level is m <= k, and a' is the new allocated matrix,
will be translated to :
-
+
b[I(m+1)]...[Ik]
-
- where
+
+ where
b = a' + I1*D2...*Dm + I2*D3...Dm + ... + Im
*/
gimple new_stmt;
gcc_assert (gimple_assign_rhs_code (acc_info->stmt)
- == INDIRECT_REF);
+ == MEM_REF);
/* Emit convert statement to convert to type of use. */
tmp = create_tmp_var (TREE_TYPE (lhs), "new");
add_referenced_var (tmp);
rhs = gimple_assign_rhs1 (acc_info->stmt);
- new_stmt = gimple_build_assign (tmp,
- TREE_OPERAND (rhs, 0));
+ rhs = fold_convert (TREE_TYPE (tmp),
+ TREE_OPERAND (rhs, 0));
+ new_stmt = gimple_build_assign (tmp, rhs);
tmp = make_ssa_name (tmp, new_stmt);
gimple_assign_set_lhs (new_stmt, tmp);
gsi = gsi_for_stmt (acc_info->stmt);
continue;
}
code = gimple_assign_rhs_code (acc_info->stmt);
- if (code == INDIRECT_REF
+ if (code == MEM_REF
&& acc_info->level < min_escape_l - 1)
{
- /* Replace the INDIRECT_REF with NOP (cast) usually we are casting
+ /* Replace the MEM_REF with NOP (cast) usually we are casting
from "pointer to type" to "type". */
tree t =
build1 (NOP_EXPR, TREE_TYPE (gimple_assign_rhs1 (acc_info->stmt)),
else
{
tree new_offset;
- tree d_type_size, d_type_size_k;
-
- d_type_size = size_int (mi->dimension_type_size[min_escape_l]);
- d_type_size_k = size_int (mi->dimension_type_size[k + 1]);
new_offset =
compute_offset (mi->dimension_type_size[min_escape_l],
num_elements =
fold_build2 (MULT_EXPR, sizetype, fold_convert (sizetype, acc_info->index),
fold_convert (sizetype, d_size));
- add_referenced_var (d_size);
gsi = gsi_for_stmt (acc_info->stmt);
tmp1 = force_gimple_operand_gsi (&gsi, num_elements, true,
NULL, true, GSI_SAME_STMT);
Make sure that we hold the size in the malloc site inside a
new global variable; this way we ensure that the size doesn't
change and it is accessible from all the other functions that
- uses the matrix. Also, the original calls to free are deleted,
+ uses the matrix. Also, the original calls to free are deleted,
and replaced by a new call to free the flattened matrix. */
static int
true, GSI_SAME_STMT);
/* GLOBAL_HOLDING_THE_SIZE = DIM_SIZE. */
stmt = gimple_build_assign (dim_var, dim_size);
- mark_symbols_for_renaming (stmt);
gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
prev_dim_size = mi->dimension_size[i] = dim_var;
update_ssa (TODO_update_ssa);
/* Replace the malloc size argument in the malloc of level 0 to be
the size of all the dimensions. */
- c_node = cgraph_node (mi->allocation_function_decl);
+ c_node = cgraph_get_node (mi->allocation_function_decl);
+ gcc_checking_assert (c_node);
old_size_0 = gimple_call_arg (call_stmt_0, 0);
tmp = force_gimple_operand_gsi (&gsi, mi->dimension_size[0], true,
NULL, true, GSI_SAME_STMT);
for (i = 1; i < mi->min_indirect_level_escape; i++)
{
gimple_stmt_iterator gsi;
- gimple use_stmt1 = NULL;
gimple call_stmt = mi->malloc_for_level[i];
gcc_assert (is_gimple_call (call_stmt));
gsi = gsi_for_stmt (call_stmt);
/* Remove the call stmt. */
gsi_remove (&gsi, true);
- /* remove the type cast stmt. */
- FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter,
- gimple_call_lhs (call_stmt))
- {
- use_stmt1 = use_stmt;
- gsi = gsi_for_stmt (use_stmt);
- gsi_remove (&gsi, true);
- }
/* Remove the assignment of the allocated area. */
FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter,
- gimple_get_lhs (use_stmt1))
+ gimple_call_lhs (call_stmt))
{
gsi = gsi_for_stmt (use_stmt);
gsi_remove (&gsi, true);
if (!mi->free_stmts[i].stmt)
continue;
- c_node = cgraph_node (mi->free_stmts[i].func);
+ c_node = cgraph_get_node (mi->free_stmts[i].func);
+ gcc_checking_assert (c_node);
gcc_assert (is_gimple_call (mi->free_stmts[i].stmt));
e = cgraph_edge (c_node, mi->free_stmts[i].stmt);
gcc_assert (e);
else
check_transpose_p = false;
/* If there are hand written vectors, we skip this optimization. */
- for (node = cgraph_nodes; node; node = node->next)
+ FOR_EACH_FUNCTION (node)
if (!may_flatten_matrices (node))
return 0;
matrices_to_reorg = htab_create (37, mtt_info_hash, mtt_info_eq, mat_free);
/* Find and record all potential matrices in the program. */
find_matrices_decl ();
/* Analyze the accesses of the matrices (escaping analysis). */
- for (node = cgraph_nodes; node; node = node->next)
- if (node->analyzed)
- {
- tree temp_fn;
+ FOR_EACH_DEFINED_FUNCTION (node)
+ {
+ tree temp_fn;
- temp_fn = current_function_decl;
- current_function_decl = node->decl;
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
- bitmap_obstack_initialize (NULL);
- gimple_register_cfg_hooks ();
+ temp_fn = current_function_decl;
+ current_function_decl = node->symbol.decl;
+ push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+ bitmap_obstack_initialize (NULL);
+ gimple_register_cfg_hooks ();
- if (!gimple_in_ssa_p (cfun))
- {
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- pop_cfun ();
- current_function_decl = temp_fn;
- bitmap_obstack_release (NULL);
+ if (!gimple_in_ssa_p (cfun))
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ pop_cfun ();
+ current_function_decl = temp_fn;
+ bitmap_obstack_release (NULL);
- return 0;
- }
+ return 0;
+ }
#ifdef ENABLE_CHECKING
- verify_flow_info ();
+ verify_flow_info ();
#endif
- if (!matrices_to_reorg)
- {
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- pop_cfun ();
- current_function_decl = temp_fn;
- bitmap_obstack_release (NULL);
+ if (!matrices_to_reorg)
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ pop_cfun ();
+ current_function_decl = temp_fn;
+ bitmap_obstack_release (NULL);
- return 0;
- }
+ return 0;
+ }
- /* Create htap for phi nodes. */
- htab_mat_acc_phi_nodes = htab_create (37, mat_acc_phi_hash,
- mat_acc_phi_eq, free);
- if (!check_transpose_p)
- find_sites_in_func (false);
- else
- {
- find_sites_in_func (true);
- loop_optimizer_init (LOOPS_NORMAL);
- if (current_loops)
- scev_initialize ();
- htab_traverse (matrices_to_reorg, analyze_transpose, NULL);
- if (current_loops)
- {
- scev_finalize ();
- loop_optimizer_finalize ();
- current_loops = NULL;
- }
- }
- /* If the current function is the allocation function for any of
- the matrices we check its allocation and the escaping level. */
- htab_traverse (matrices_to_reorg, check_allocation_function, NULL);
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- pop_cfun ();
- current_function_decl = temp_fn;
- bitmap_obstack_release (NULL);
- }
+ /* Create htap for phi nodes. */
+ htab_mat_acc_phi_nodes = htab_create (37, mat_acc_phi_hash,
+ mat_acc_phi_eq, free);
+ if (!check_transpose_p)
+ find_sites_in_func (false);
+ else
+ {
+ find_sites_in_func (true);
+ loop_optimizer_init (LOOPS_NORMAL);
+ if (current_loops)
+ scev_initialize ();
+ htab_traverse (matrices_to_reorg, analyze_transpose, NULL);
+ if (current_loops)
+ {
+ scev_finalize ();
+ loop_optimizer_finalize ();
+ current_loops = NULL;
+ }
+ }
+ /* If the current function is the allocation function for any of
+ the matrices we check its allocation and the escaping level. */
+ htab_traverse (matrices_to_reorg, check_allocation_function, NULL);
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ pop_cfun ();
+ current_function_decl = temp_fn;
+ bitmap_obstack_release (NULL);
+ }
htab_traverse (matrices_to_reorg, transform_allocation_sites, NULL);
/* Now transform the accesses. */
- for (node = cgraph_nodes; node; node = node->next)
- if (node->analyzed)
- {
- /* Remember that allocation sites have been handled. */
- tree temp_fn;
-
- temp_fn = current_function_decl;
- current_function_decl = node->decl;
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
- bitmap_obstack_initialize (NULL);
- gimple_register_cfg_hooks ();
- record_all_accesses_in_func ();
- htab_traverse (matrices_to_reorg, transform_access_sites, NULL);
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- pop_cfun ();
- current_function_decl = temp_fn;
- bitmap_obstack_release (NULL);
- }
+ FOR_EACH_DEFINED_FUNCTION (node)
+ {
+ /* Remember that allocation sites have been handled. */
+ tree temp_fn;
+
+ temp_fn = current_function_decl;
+ current_function_decl = node->symbol.decl;
+ push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+ bitmap_obstack_initialize (NULL);
+ gimple_register_cfg_hooks ();
+ record_all_accesses_in_func ();
+ htab_traverse (matrices_to_reorg, transform_access_sites, NULL);
+ cgraph_rebuild_references ();
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ pop_cfun ();
+ current_function_decl = temp_fn;
+ bitmap_obstack_release (NULL);
+ }
htab_traverse (matrices_to_reorg, dump_matrix_reorg_analysis, NULL);
current_function_decl = NULL;
return flag_ipa_matrix_reorg && flag_whole_program;
}
-struct simple_ipa_opt_pass pass_ipa_matrix_reorg =
+struct simple_ipa_opt_pass pass_ipa_matrix_reorg =
{
{
SIMPLE_IPA_PASS,
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
- PROP_trees, /* properties_provided */
+ 0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_cgraph | TODO_dump_func /* todo_flags_finish */
+ TODO_dump_symtab /* todo_flags_finish */
}
};
-