|
|
|
@ -1,597 +0,0 @@
|
|
|
|
|
/* Promotion of static variables to ssa registers
|
|
|
|
|
Copyright (C) 2004-2005 Free Software Foundation, Inc.
|
|
|
|
|
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
|
|
|
|
|
|
|
|
|
|
This file is part of GCC.
|
|
|
|
|
|
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
|
|
GCC is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with GCC; see the file COPYING. If not, write to
|
|
|
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
|
|
Boston, MA 02111-1307, USA. */
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "system.h"
|
|
|
|
|
#include "coretypes.h"
|
|
|
|
|
#include "tm.h"
|
|
|
|
|
#include "tree.h"
|
|
|
|
|
#include "basic-block.h"
|
|
|
|
|
#include "tree-flow.h"
|
|
|
|
|
#include "ipa-utils.h"
|
|
|
|
|
#include "ipa-reference.h"
|
|
|
|
|
#include "bitmap.h"
|
|
|
|
|
#include "tree-pass.h"
|
|
|
|
|
#include "flags.h"
|
|
|
|
|
#include "timevar.h"
|
|
|
|
|
#include "langhooks.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
The main idea is to promote some static variables from memory to SSA
|
|
|
|
|
registers. This transformation is only applied to those static
|
|
|
|
|
variables for which the effects of subroutine calls can be understood.
|
|
|
|
|
Such infomation is provided by functions in cgraphunit.c.
|
|
|
|
|
|
|
|
|
|
The following table shows the actions that are taken to promote
|
|
|
|
|
variables. The analysis in cgraphunit constructs information about
|
|
|
|
|
both local usage and the effect of any particular call. Variables are
|
|
|
|
|
broken into 4 categories: only-read, only-write, read-write, and no
|
|
|
|
|
information. (No information variables are never promoted.)
|
|
|
|
|
|
|
|
|
|
All information is of the "may" variety: if a function is marked read,
|
|
|
|
|
it means the call may read the variable, but it also may not read the
|
|
|
|
|
variable.
|
|
|
|
|
|
|
|
|
|
There are two possible ways to perform the promotion: assume that the
|
|
|
|
|
static is live everywhere or compute the minimal live range for the
|
|
|
|
|
static variable.
|
|
|
|
|
|
|
|
|
|
The minimal live range path has a lot of problems:
|
|
|
|
|
|
|
|
|
|
1) live variables and upwards exposed uses must be first comuputed.
|
|
|
|
|
2) new machiney must be invented to prevent code motion algorithms
|
|
|
|
|
from floating a use of the surrogate register across a register
|
|
|
|
|
function call that clobbers the variable, but was not in any minimal
|
|
|
|
|
live range at the time of this analysis.
|
|
|
|
|
|
|
|
|
|
While the first problem is simply a lot of code, the second problem
|
|
|
|
|
requires a new mechanism for pinning code and teaching all passes that
|
|
|
|
|
can move code to obey this new fenceposts.
|
|
|
|
|
|
|
|
|
|
The maximum live range path has the problem that this technique can
|
|
|
|
|
create many false live ranges where the register is loaded after on
|
|
|
|
|
call only to be stored back right before the next call. This will eat
|
|
|
|
|
a certain amount of space and requires special smarts to get rid of them.
|
|
|
|
|
|
|
|
|
|
There are really 7 situations to cover in the following table.
|
|
|
|
|
|
|
|
|
|
action read write read-write
|
|
|
|
|
|
|
|
|
|
-+---------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
entry | load load load
|
|
|
|
|
|
|
|
|
|
|
load | getfromreg xxxxx getfromreg
|
|
|
|
|
|
|
|
|
|
|
store | xxxx puttoreg puttoreg
|
|
|
|
|
|
|
|
|
|
|
call-read | noaction store before store before
|
|
|
|
|
|
|
|
|
|
|
call-write | load after store before store before
|
|
|
|
|
| load after load after
|
|
|
|
|
call-readwrite| load after store before store before
|
|
|
|
|
| load after load after
|
|
|
|
|
|
|
|
|
|
|
return | no action store store
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
l-r l-w c-r c-w store-b load-a
|
|
|
|
|
|
|
|
|
|
0 0 0 0 | 0 0
|
|
|
|
|
0 0 0 1 | 0 0
|
|
|
|
|
0 0 1 0 | 0 0
|
|
|
|
|
0 0 1 1 | 0 0
|
|
|
|
|
0 1 0 0 | 0 0
|
|
|
|
|
0 1 0 1 | 1 1
|
|
|
|
|
0 1 1 0 | 1 0
|
|
|
|
|
0 1 1 1 | 1 1
|
|
|
|
|
1 0 0 0 | 0 0
|
|
|
|
|
1 0 0 1 | 0 1
|
|
|
|
|
1 0 1 0 | 0 0
|
|
|
|
|
1 0 1 1 | 0 1
|
|
|
|
|
1 1 0 0 | 0 0
|
|
|
|
|
1 1 0 1 | 1 1
|
|
|
|
|
1 1 1 0 | 1 0
|
|
|
|
|
1 1 1 1 | 1 1
|
|
|
|
|
|
|
|
|
|
store_before = local_written & (callee_read | callee_written)
|
|
|
|
|
load_after = (local_read | local_written) & callee_written
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static bitmap_obstack promote_obstack;
|
|
|
|
|
|
|
|
|
|
/* All of the static variables under consideration by this pass that
|
|
|
|
|
do reads or writes withing this function. */
|
|
|
|
|
static bitmap local_read;
|
|
|
|
|
static bitmap local_written;
|
|
|
|
|
static bitmap local_all;
|
|
|
|
|
|
|
|
|
|
/* Return true if the asm STMT clobbers memory. */
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
asm_clobbers_mem (tree stmt)
|
|
|
|
|
{
|
|
|
|
|
tree link;
|
|
|
|
|
for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link))
|
|
|
|
|
if (simple_cst_equal(TREE_VALUE (link), memory_identifier_string) == 1)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return a INPUT_BITMAP for the asm inputs and OUTPUT_BITMAP for the
|
|
|
|
|
asm outputs of variables written by the asm STMT. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_asm_read_and_write (bitmap input_bitmap, bitmap output_bitmap, tree stmt)
|
|
|
|
|
{
|
|
|
|
|
int noutputs = list_length (ASM_OUTPUTS (stmt));
|
|
|
|
|
const char **oconstraints
|
|
|
|
|
= (const char **) alloca ((noutputs) * sizeof (const char *));
|
|
|
|
|
int i;
|
|
|
|
|
tree link;
|
|
|
|
|
const char *constraint;
|
|
|
|
|
bool allows_mem, allows_reg, is_inout;
|
|
|
|
|
|
|
|
|
|
for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
|
|
|
|
|
{
|
|
|
|
|
oconstraints[i] = constraint
|
|
|
|
|
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
|
|
|
|
|
parse_output_constraint (&constraint, i, 0, 0,
|
|
|
|
|
&allows_mem, &allows_reg, &is_inout);
|
|
|
|
|
|
|
|
|
|
/* The variable is only added to the bitmap if there is an aux
|
|
|
|
|
field, ie.this is a variable we care about. */
|
|
|
|
|
if (!allows_reg && allows_mem)
|
|
|
|
|
{
|
|
|
|
|
tree var = TREE_VALUE (link);
|
|
|
|
|
var = get_base_address (var);
|
|
|
|
|
if (TREE_CODE (var) == VAR_DECL)
|
|
|
|
|
{
|
|
|
|
|
var_ann_t va = var_ann (var);
|
|
|
|
|
if (va && va->common.aux)
|
|
|
|
|
bitmap_set_bit(output_bitmap, DECL_UID (var));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
|
|
|
|
|
{
|
|
|
|
|
constraint
|
|
|
|
|
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
|
|
|
|
|
parse_input_constraint (&constraint, 0, 0, noutputs, 0,
|
|
|
|
|
oconstraints, &allows_mem, &allows_reg);
|
|
|
|
|
|
|
|
|
|
/* The variable is only added to the bitmap if there is an aux
|
|
|
|
|
field, ie.this is a variable we care about. */
|
|
|
|
|
if (!allows_reg && allows_mem)
|
|
|
|
|
{
|
|
|
|
|
tree var = TREE_VALUE (link);
|
|
|
|
|
var = get_base_address (var);
|
|
|
|
|
if (TREE_CODE (var) == VAR_DECL)
|
|
|
|
|
{
|
|
|
|
|
var_ann_t va = var_ann (var);
|
|
|
|
|
if (va && va->common.aux)
|
|
|
|
|
bitmap_set_bit(input_bitmap, DECL_UID (var));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate a series of loads from the static variables pointed to by
|
|
|
|
|
B1 && B2 or just B1 (if B2 is NULL) and insert them after
|
|
|
|
|
BSI). */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gen_loads (bitmap b1, bitmap b2, block_stmt_iterator *bsi)
|
|
|
|
|
{
|
|
|
|
|
bitmap result;
|
|
|
|
|
bitmap_iterator bi;
|
|
|
|
|
unsigned int index;
|
|
|
|
|
tree list = NULL;
|
|
|
|
|
|
|
|
|
|
if (b2)
|
|
|
|
|
{
|
|
|
|
|
result = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap_and (result, b1, b2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
result = b1;
|
|
|
|
|
|
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP(result, 0, index, bi)
|
|
|
|
|
{
|
|
|
|
|
tree src = referenced_var (index);
|
|
|
|
|
tree dest = (tree) (var_ann (src)->common.aux);
|
|
|
|
|
tree stmt = build (MODIFY_EXPR, TREE_TYPE (src), dest, src);
|
|
|
|
|
append_to_statement_list (stmt, &list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
|
sra_insert_after (bsi, list);
|
|
|
|
|
|
|
|
|
|
if (b2)
|
|
|
|
|
BITMAP_FREE (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate a series of stores to the static variables pointed to by
|
|
|
|
|
B1 && B2 or just B1 (if B2 is NULL) and insert them before
|
|
|
|
|
BSI). */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gen_stores (bitmap b1, bitmap b2, block_stmt_iterator *bsi)
|
|
|
|
|
{
|
|
|
|
|
bitmap result;
|
|
|
|
|
bitmap_iterator bi;
|
|
|
|
|
unsigned int index;
|
|
|
|
|
tree list = NULL;
|
|
|
|
|
|
|
|
|
|
if (b2)
|
|
|
|
|
{
|
|
|
|
|
result = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap_and (result, b1, b2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
result = b1;
|
|
|
|
|
|
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP(result, 0, index, bi)
|
|
|
|
|
{
|
|
|
|
|
tree dest = referenced_var (index);
|
|
|
|
|
tree src = (tree) (var_ann (dest)->common.aux);
|
|
|
|
|
tree stmt = build (MODIFY_EXPR, TREE_TYPE (src), dest, src);
|
|
|
|
|
append_to_statement_list (stmt, &list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
|
sra_insert_before (bsi, list);
|
|
|
|
|
|
|
|
|
|
if (b2)
|
|
|
|
|
BITMAP_FREE (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Replace the static references if it exists in the TPTR. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
try_replace_operand(tree * tptr)
|
|
|
|
|
{
|
|
|
|
|
tree t = *tptr;
|
|
|
|
|
if (TREE_CODE (t) == VAR_DECL)
|
|
|
|
|
{
|
|
|
|
|
var_ann_t va = var_ann (t);
|
|
|
|
|
tree replacement = (tree) (va->common.aux);
|
|
|
|
|
if (replacement)
|
|
|
|
|
*tptr = replacement;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Walk an expression TPTR replacing all of the static references. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
try_replace (tree *tptr)
|
|
|
|
|
{
|
|
|
|
|
tree t = *tptr;
|
|
|
|
|
if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* The INTEGER_CST is because some people use cute things like &0->a
|
|
|
|
|
for offsetof. */
|
|
|
|
|
while (t && !SSA_VAR_P (t)
|
|
|
|
|
&& (!CONSTANT_CLASS_P (t))
|
|
|
|
|
&& TREE_CODE (t) != LABEL_DECL
|
|
|
|
|
&& TREE_CODE (t) != CONST_DECL
|
|
|
|
|
&& TREE_CODE (t) != FUNCTION_DECL
|
|
|
|
|
&& TREE_CODE (t) != EXC_PTR_EXPR)
|
|
|
|
|
{
|
|
|
|
|
if (TREE_CODE (t) == ARRAY_REF)
|
|
|
|
|
try_replace_operand (&TREE_OPERAND (t, 1));
|
|
|
|
|
|
|
|
|
|
tptr = &TREE_OPERAND (t, 0);
|
|
|
|
|
t = *tptr;
|
|
|
|
|
}
|
|
|
|
|
if (t)
|
|
|
|
|
try_replace_operand (tptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Repalce the static references that exist in a constructor. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
try_replace_constructor (tree ctor)
|
|
|
|
|
{
|
|
|
|
|
tree t;
|
|
|
|
|
for (t = TREE_OPERAND (ctor, 0); t; t = TREE_CHAIN (t))
|
|
|
|
|
{
|
|
|
|
|
try_replace (&TREE_VALUE (t));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Replace all the static references in the operand list of
|
|
|
|
|
CALL_EXPR. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
try_replace_call_operands (tree call_expr)
|
|
|
|
|
{
|
|
|
|
|
tree operandList = TREE_OPERAND (call_expr, 1);
|
|
|
|
|
tree operand;
|
|
|
|
|
|
|
|
|
|
for (operand = operandList;
|
|
|
|
|
operand != NULL_TREE;
|
|
|
|
|
operand = TREE_CHAIN (operand))
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE(TREE_VALUE (operand)) != FUNCTION_DECL)
|
|
|
|
|
try_replace (&TREE_VALUE (operand));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate loads and stores and replace all the static references in
|
|
|
|
|
function FN using statement iterator SI. This form is used when
|
|
|
|
|
there is not info available about the caller. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gen_dumb_call (tree fn, block_stmt_iterator si)
|
|
|
|
|
{
|
|
|
|
|
gen_stores (local_written, NULL, &si);
|
|
|
|
|
try_replace (&TREE_OPERAND (fn, 0));
|
|
|
|
|
try_replace_call_operands (fn);
|
|
|
|
|
gen_loads (local_all, NULL, &si);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Generate loads and stores and replace all the static references in
|
|
|
|
|
function FN using statement iterator SI. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
try_replace_call (tree fn, block_stmt_iterator si)
|
|
|
|
|
{
|
|
|
|
|
/* Store intersection of call_read and local_written
|
|
|
|
|
registers back to memory before calling. */
|
|
|
|
|
/* int call_flags = call_expr_flags (fn); */
|
|
|
|
|
tree callee = get_callee_fndecl (fn);
|
|
|
|
|
if (callee)
|
|
|
|
|
{
|
|
|
|
|
bitmap callee_all = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap callee_written = ipa_reference_get_written_global (callee);
|
|
|
|
|
if (callee_written)
|
|
|
|
|
{
|
|
|
|
|
bitmap_ior (callee_all,
|
|
|
|
|
ipa_reference_get_read_global (callee),
|
|
|
|
|
callee_written);
|
|
|
|
|
|
|
|
|
|
gen_stores (local_written, callee_all, &si);
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (callee) != FUNCTION_DECL)
|
|
|
|
|
try_replace (&TREE_OPERAND (fn, 0));
|
|
|
|
|
try_replace_call_operands (fn);
|
|
|
|
|
|
|
|
|
|
/* This is a hack required because the call_flags are set on a
|
|
|
|
|
function by function basis during compilation. Thus these
|
|
|
|
|
flags are only set if the callee has already been compiled. */
|
|
|
|
|
/* if (!(call_flags & (ECF_PURE | ECF_CONST | ECF_NORETURN))) */
|
|
|
|
|
gen_loads (local_all, callee_written, &si);
|
|
|
|
|
BITMAP_FREE (callee_all);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
gen_dumb_call (fn, si);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
gen_dumb_call (fn, si);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Walk the entire function looking uses or stores to global variables
|
|
|
|
|
and changing them to use ssa shadow registers. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
walk_function (void)
|
|
|
|
|
{
|
|
|
|
|
basic_block bb;
|
|
|
|
|
block_stmt_iterator si, ni;
|
|
|
|
|
|
|
|
|
|
FOR_EACH_BB (bb)
|
|
|
|
|
for (si = bsi_start (bb); !bsi_end_p (si); si = ni)
|
|
|
|
|
{
|
|
|
|
|
tree stmt = bsi_stmt (si);
|
|
|
|
|
|
|
|
|
|
ni = si;
|
|
|
|
|
bsi_next (&ni);
|
|
|
|
|
|
|
|
|
|
switch (TREE_CODE (stmt))
|
|
|
|
|
{
|
|
|
|
|
case RETURN_EXPR:
|
|
|
|
|
/* Store all of the local_written registers back to memory
|
|
|
|
|
before returning. */
|
|
|
|
|
gen_stores (local_written, NULL, &si);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODIFY_EXPR:
|
|
|
|
|
/* Change load of static to use of reg. Change store of
|
|
|
|
|
static to store of reg. */
|
|
|
|
|
{
|
|
|
|
|
tree rhs = TREE_OPERAND (stmt, 1);
|
|
|
|
|
tree *rhsp = &TREE_OPERAND (stmt, 1);
|
|
|
|
|
tree *lhsp = &TREE_OPERAND (stmt, 0);
|
|
|
|
|
|
|
|
|
|
/* If we have a call on the rhs, try to replace the arguments.
|
|
|
|
|
Otherwise, try to replace the operand on the LHS and the operand on
|
|
|
|
|
the RHS. */
|
|
|
|
|
if (TREE_CODE (rhs) == CALL_EXPR)
|
|
|
|
|
try_replace_call (rhs, si);
|
|
|
|
|
else if (TREE_CODE (rhs) == CONSTRUCTOR)
|
|
|
|
|
try_replace_constructor (rhs);
|
|
|
|
|
else
|
|
|
|
|
try_replace (rhsp);
|
|
|
|
|
try_replace (lhsp);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CALL_EXPR:
|
|
|
|
|
try_replace_call (stmt, si);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case ASM_EXPR:
|
|
|
|
|
/* If the asm clobbers memory, just store everything and
|
|
|
|
|
load it back. */
|
|
|
|
|
if (asm_clobbers_mem (stmt))
|
|
|
|
|
{
|
|
|
|
|
gen_stores (local_written, NULL, &si);
|
|
|
|
|
gen_loads (local_all, NULL, &si);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bitmap store_bitmap = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap load_bitmap = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap all_bitmap = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
/* The asm read generates a stores before, and the asm
|
|
|
|
|
write generates loads after. */
|
|
|
|
|
get_asm_read_and_write (store_bitmap, load_bitmap, stmt);
|
|
|
|
|
bitmap_ior (all_bitmap, store_bitmap, load_bitmap);
|
|
|
|
|
|
|
|
|
|
gen_stores (local_written, all_bitmap , &si);
|
|
|
|
|
gen_loads (local_all, load_bitmap, &si);
|
|
|
|
|
|
|
|
|
|
BITMAP_FREE (store_bitmap);
|
|
|
|
|
BITMAP_FREE (load_bitmap);
|
|
|
|
|
BITMAP_FREE (all_bitmap);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Main entry point for the promotion of statics to ssa regsisters. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
execute_promote_statics (void)
|
|
|
|
|
{
|
|
|
|
|
unsigned int index;
|
|
|
|
|
bitmap_iterator bi;
|
|
|
|
|
bitmap tb = ipa_reference_get_read_local (current_function_decl);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* There are some options that cause this pass to run even if file
|
|
|
|
|
at a time is not set. */
|
|
|
|
|
if (!tb)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bitmap_obstack_initialize (&promote_obstack);
|
|
|
|
|
sra_init_cache ();
|
|
|
|
|
|
|
|
|
|
local_read = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap_copy (local_read, tb);
|
|
|
|
|
tb = ipa_reference_get_written_local (current_function_decl);
|
|
|
|
|
local_written = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap_copy (local_written, tb);
|
|
|
|
|
|
|
|
|
|
local_all = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
tb = BITMAP_ALLOC (&promote_obstack);
|
|
|
|
|
bitmap_ior (local_all, local_read, local_written);
|
|
|
|
|
|
|
|
|
|
if (dump_file)
|
|
|
|
|
fprintf (dump_file, "promoting in %s\n",
|
|
|
|
|
lang_hooks.decl_printable_name (current_function_decl, 2));
|
|
|
|
|
|
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP (local_all, 0, index, bi)
|
|
|
|
|
{
|
|
|
|
|
tree svar = referenced_var_lookup_if_exists (index);
|
|
|
|
|
if (svar)
|
|
|
|
|
{
|
|
|
|
|
tree type = TREE_TYPE (svar);
|
|
|
|
|
/* We only promote variables that are either scalars or if
|
|
|
|
|
they are aggregrates, they must be a type that sra is
|
|
|
|
|
willing to scalarize. Otherwise there is no reason to
|
|
|
|
|
promote it a register.
|
|
|
|
|
|
|
|
|
|
We also do not promote anything that is marked READONLY
|
|
|
|
|
since there is little gain. The optimizations should
|
|
|
|
|
generally be able to look thru the operations and find the
|
|
|
|
|
constants. */
|
|
|
|
|
if ((!TREE_READONLY(svar))
|
|
|
|
|
&& (TREE_CODE (type) != ARRAY_TYPE)
|
|
|
|
|
&& ((!AGGREGATE_TYPE_P (type))
|
|
|
|
|
|| (sra_type_can_be_decomposed_p (type))))
|
|
|
|
|
{
|
|
|
|
|
tree tmp = create_tmp_var (type, get_name (svar));
|
|
|
|
|
add_referenced_tmp_var (tmp);
|
|
|
|
|
var_ann (svar)->common.aux = tmp;
|
|
|
|
|
|
|
|
|
|
/* Insert loads from all read statics in the entry
|
|
|
|
|
block. */
|
|
|
|
|
insert_edge_copies (build (MODIFY_EXPR, TREE_TYPE (svar),
|
|
|
|
|
tmp, svar),
|
|
|
|
|
ENTRY_BLOCK_PTR);
|
|
|
|
|
if (dump_file)
|
|
|
|
|
fprintf (dump_file, " var=%s, read=%d,write=%d\n",
|
|
|
|
|
get_name (svar),
|
|
|
|
|
bitmap_bit_p (local_read, index),
|
|
|
|
|
bitmap_bit_p (local_written, index));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* There is nothing to be done with this variable. */
|
|
|
|
|
bitmap_set_bit (tb, index);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* There is nothing to be done with this variable because the
|
|
|
|
|
reference was optimized out before we got here. */
|
|
|
|
|
bitmap_set_bit (tb, index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear the to be ignored variables from the local maps. */
|
|
|
|
|
bitmap_and_compl_into (local_read, tb);
|
|
|
|
|
bitmap_and_compl_into (local_written, tb);
|
|
|
|
|
bitmap_and_compl_into (local_all, tb);
|
|
|
|
|
|
|
|
|
|
walk_function ();
|
|
|
|
|
bsi_commit_edge_inserts ();
|
|
|
|
|
|
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP (local_all, 0, index, bi)
|
|
|
|
|
{
|
|
|
|
|
tree svar = referenced_var (index);
|
|
|
|
|
var_ann (svar)->common.aux = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bitmap_obstack_release (&promote_obstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
gate_promote_statics (void)
|
|
|
|
|
{
|
|
|
|
|
return flag_unit_at_a_time != 0
|
|
|
|
|
&& flag_ipa_reference
|
|
|
|
|
&& flag_tree_promote_statics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct tree_opt_pass pass_promote_statics =
|
|
|
|
|
{
|
|
|
|
|
"promote-statics", /* name */
|
|
|
|
|
gate_promote_statics, /* gate */
|
|
|
|
|
execute_promote_statics, /* execute */
|
|
|
|
|
NULL, /* sub */
|
|
|
|
|
NULL, /* next */
|
|
|
|
|
0, /* static_pass_number */
|
|
|
|
|
TV_TREE_PROMOTE_STATICS, /* tv_id */
|
|
|
|
|
PROP_cfg, /* properties_required */
|
|
|
|
|
0, /* properties_provided */
|
|
|
|
|
0, /* properties_destroyed */
|
|
|
|
|
0, /* todo_flags_start */
|
|
|
|
|
TODO_dump_func, /* todo_flags_finish */
|
|
|
|
|
0 /* letter */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|