mirror of git://gcc.gnu.org/git/gcc.git
common.opt (flag_ira_hoist_pressure): New.
gcc/ChangeLog * common.opt (flag_ira_hoist_pressure): New. * doc/invoke.texi (-fira-hoist-pressure): Describe. * ira-costs.c (ira_set_pseudo_classes): New parameter. * ira.h: Update copyright dates. (ira_set_pseudo_classes): Update prototype. * haifa-sched.c (sched_init): Update call. * ira.c (ira): Update call. * regmove.c: Update copyright dates. (regmove_optimize): Update call. * loop-invariant.c: Update copyright dates. (move_loop_invariants): Update call. * gcse.c: (struct bb_data): New structure. (BB_DATA): New macro. (curr_bb, curr_reg_pressure): New static variables. (should_hoist_expr_to_dom): Rename from hoist_expr_reaches_here_p. Change parameter expr_index to expr. New parameters pressure_class, nregs and hoisted_bbs. Use reg pressure to determine the distance expr can be hoisted. (hoist_code): Use reg pressure to direct the hoist process. (get_regno_pressure_class, get_pressure_class_and_nregs) (change_pressure, calculate_bb_reg_pressure): New. (one_code_hoisting_pass): Calculate register pressure. Allocate and free data. gcc/testsuite/ChangeLog * testsuite/gcc.dg/hoist-register-pressure.c: New test. From-SVN: r192604
This commit is contained in:
parent
8cba9a0536
commit
b11f0116d6
|
|
@ -1,3 +1,29 @@
|
||||||
|
2012-10-19 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
* common.opt (flag_ira_hoist_pressure): New.
|
||||||
|
* doc/invoke.texi (-fira-hoist-pressure): Describe.
|
||||||
|
* ira-costs.c (ira_set_pseudo_classes): New parameter.
|
||||||
|
* ira.h: Update copyright dates.
|
||||||
|
(ira_set_pseudo_classes): Update prototype.
|
||||||
|
* haifa-sched.c (sched_init): Update call.
|
||||||
|
* ira.c (ira): Update call.
|
||||||
|
* regmove.c: Update copyright dates.
|
||||||
|
(regmove_optimize): Update call.
|
||||||
|
* loop-invariant.c: Update copyright dates.
|
||||||
|
(move_loop_invariants): Update call.
|
||||||
|
* gcse.c: (struct bb_data): New structure.
|
||||||
|
(BB_DATA): New macro.
|
||||||
|
(curr_bb, curr_reg_pressure): New static variables.
|
||||||
|
(should_hoist_expr_to_dom): Rename from hoist_expr_reaches_here_p.
|
||||||
|
Change parameter expr_index to expr.
|
||||||
|
New parameters pressure_class, nregs and hoisted_bbs.
|
||||||
|
Use reg pressure to determine the distance expr can be hoisted.
|
||||||
|
(hoist_code): Use reg pressure to direct the hoist process.
|
||||||
|
(get_regno_pressure_class, get_pressure_class_and_nregs)
|
||||||
|
(change_pressure, calculate_bb_reg_pressure): New.
|
||||||
|
(one_code_hoisting_pass): Calculate register pressure. Allocate
|
||||||
|
and free data.
|
||||||
|
|
||||||
2012-10-19 Bin Cheng <bin.cheng@arm.com>
|
2012-10-19 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
* gcse.c: Update copyright dates.
|
* gcse.c: Update copyright dates.
|
||||||
|
|
|
||||||
|
|
@ -1392,6 +1392,11 @@ Enum(ira_region) String(all) Value(IRA_REGION_ALL)
|
||||||
EnumValue
|
EnumValue
|
||||||
Enum(ira_region) String(mixed) Value(IRA_REGION_MIXED)
|
Enum(ira_region) String(mixed) Value(IRA_REGION_MIXED)
|
||||||
|
|
||||||
|
fira-hoist-pressure
|
||||||
|
Common Report Var(flag_ira_hoist_pressure) Init(1) Optimization
|
||||||
|
Use IRA based register pressure calculation
|
||||||
|
in RTL hoist optimizations.
|
||||||
|
|
||||||
fira-loop-pressure
|
fira-loop-pressure
|
||||||
Common Report Var(flag_ira_loop_pressure)
|
Common Report Var(flag_ira_loop_pressure)
|
||||||
Use IRA based register pressure calculation
|
Use IRA based register pressure calculation
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,7 @@ Objective-C and Objective-C++ Dialects}.
|
||||||
-finline-small-functions -fipa-cp -fipa-cp-clone @gol
|
-finline-small-functions -fipa-cp -fipa-cp-clone @gol
|
||||||
-fipa-pta -fipa-profile -fipa-pure-const -fipa-reference @gol
|
-fipa-pta -fipa-profile -fipa-pure-const -fipa-reference @gol
|
||||||
-fira-algorithm=@var{algorithm} @gol
|
-fira-algorithm=@var{algorithm} @gol
|
||||||
-fira-region=@var{region} @gol
|
-fira-region=@var{region} -fira-hoist-pressure @gol
|
||||||
-fira-loop-pressure -fno-ira-share-save-slots @gol
|
-fira-loop-pressure -fno-ira-share-save-slots @gol
|
||||||
-fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
|
-fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
|
||||||
-fivopts -fkeep-inline-functions -fkeep-static-consts @gol
|
-fivopts -fkeep-inline-functions -fkeep-static-consts @gol
|
||||||
|
|
@ -6996,6 +6996,14 @@ This typically results in the smallest code size, and is enabled by default for
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@item -fira-hoist-pressure
|
||||||
|
@opindex fira-hoist-pressure
|
||||||
|
Use IRA to evaluate register pressure in the code hoisting pass for
|
||||||
|
decisions to hoist expressions. This option usually results in smaller
|
||||||
|
code, but it can slow the compiler down.
|
||||||
|
|
||||||
|
This option is enabled at level @option{-Os} for all targets.
|
||||||
|
|
||||||
@item -fira-loop-pressure
|
@item -fira-loop-pressure
|
||||||
@opindex fira-loop-pressure
|
@opindex fira-loop-pressure
|
||||||
Use IRA to evaluate register pressure in loops for decisions to move
|
Use IRA to evaluate register pressure in loops for decisions to move
|
||||||
|
|
|
||||||
370
gcc/gcse.c
370
gcc/gcse.c
|
|
@ -20,9 +20,11 @@ along with GCC; see the file COPYING3. If not see
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
- reordering of memory allocation and freeing to be more space efficient
|
- reordering of memory allocation and freeing to be more space efficient
|
||||||
- do rough calc of how many regs are needed in each block, and a rough
|
- simulate register pressure change of each basic block accurately during
|
||||||
calc of how many regs are available in each class and use that to
|
hoist process. But I doubt the benefit since most expressions hoisted
|
||||||
throttle back the code in cases where RTX_COST is minimal.
|
are constant or address, which usually won't reduce register pressure.
|
||||||
|
- calc rough register pressure information and use the info to drive all
|
||||||
|
kinds of code motion (including code hoisting) in a unified way.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* References searched while implementing this.
|
/* References searched while implementing this.
|
||||||
|
|
@ -141,11 +143,12 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "diagnostic-core.h"
|
#include "diagnostic-core.h"
|
||||||
#include "toplev.h"
|
#include "toplev.h"
|
||||||
|
|
||||||
|
#include "hard-reg-set.h"
|
||||||
#include "rtl.h"
|
#include "rtl.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "tm_p.h"
|
#include "tm_p.h"
|
||||||
#include "regs.h"
|
#include "regs.h"
|
||||||
#include "hard-reg-set.h"
|
#include "ira.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
#include "insn-config.h"
|
#include "insn-config.h"
|
||||||
#include "recog.h"
|
#include "recog.h"
|
||||||
|
|
@ -412,6 +415,22 @@ static bool doing_code_hoisting_p = false;
|
||||||
/* For available exprs */
|
/* For available exprs */
|
||||||
static sbitmap *ae_kill;
|
static sbitmap *ae_kill;
|
||||||
|
|
||||||
|
/* Data stored for each basic block. */
|
||||||
|
struct bb_data
|
||||||
|
{
|
||||||
|
/* Maximal register pressure inside basic block for given register class
|
||||||
|
(defined only for the pressure classes). */
|
||||||
|
int max_reg_pressure[N_REG_CLASSES];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BB_DATA(bb) ((struct bb_data *) (bb)->aux)
|
||||||
|
|
||||||
|
static basic_block curr_bb;
|
||||||
|
|
||||||
|
/* Current register pressure for each pressure class. */
|
||||||
|
static int curr_reg_pressure[N_REG_CLASSES];
|
||||||
|
|
||||||
|
|
||||||
static void compute_can_copy (void);
|
static void compute_can_copy (void);
|
||||||
static void *gmalloc (size_t) ATTRIBUTE_MALLOC;
|
static void *gmalloc (size_t) ATTRIBUTE_MALLOC;
|
||||||
static void *gcalloc (size_t, size_t) ATTRIBUTE_MALLOC;
|
static void *gcalloc (size_t, size_t) ATTRIBUTE_MALLOC;
|
||||||
|
|
@ -460,9 +479,11 @@ static void alloc_code_hoist_mem (int, int);
|
||||||
static void free_code_hoist_mem (void);
|
static void free_code_hoist_mem (void);
|
||||||
static void compute_code_hoist_vbeinout (void);
|
static void compute_code_hoist_vbeinout (void);
|
||||||
static void compute_code_hoist_data (void);
|
static void compute_code_hoist_data (void);
|
||||||
static int hoist_expr_reaches_here_p (basic_block, int, basic_block, sbitmap,
|
static int should_hoist_expr_to_dom (basic_block, struct expr *, basic_block,
|
||||||
int, int *);
|
sbitmap, int, int *, enum reg_class,
|
||||||
|
int *, bitmap);
|
||||||
static int hoist_code (void);
|
static int hoist_code (void);
|
||||||
|
static enum reg_class get_pressure_class_and_nregs (rtx insn, int *nregs);
|
||||||
static int one_code_hoisting_pass (void);
|
static int one_code_hoisting_pass (void);
|
||||||
static rtx process_insert_insn (struct expr *);
|
static rtx process_insert_insn (struct expr *);
|
||||||
static int pre_edge_insert (struct edge_list *, struct expr **);
|
static int pre_edge_insert (struct edge_list *, struct expr **);
|
||||||
|
|
@ -1858,7 +1879,7 @@ prune_expressions (bool pre_p)
|
||||||
a basic block we should account for any side-effects of a subsequent
|
a basic block we should account for any side-effects of a subsequent
|
||||||
jump instructions that could clobber the expression. It would
|
jump instructions that could clobber the expression. It would
|
||||||
be best to implement this check along the lines of
|
be best to implement this check along the lines of
|
||||||
hoist_expr_reaches_here_p where the target block is already known
|
should_hoist_expr_to_dom where the target block is already known
|
||||||
and, hence, there's no need to conservatively prune expressions on
|
and, hence, there's no need to conservatively prune expressions on
|
||||||
"intermediate" set-and-jump instructions. */
|
"intermediate" set-and-jump instructions. */
|
||||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||||
|
|
@ -2826,10 +2847,21 @@ compute_code_hoist_data (void)
|
||||||
fprintf (dump_file, "\n");
|
fprintf (dump_file, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine if the expression identified by EXPR_INDEX would
|
/* Determine if the expression EXPR should be hoisted to EXPR_BB up in
|
||||||
reach BB unimpared if it was placed at the end of EXPR_BB.
|
flow graph, if it can reach BB unimpared. Stop the search if the
|
||||||
Stop the search if the expression would need to be moved more
|
expression would need to be moved more than DISTANCE instructions.
|
||||||
than DISTANCE instructions.
|
|
||||||
|
DISTANCE is the number of instructions through which EXPR can be
|
||||||
|
hoisted up in flow graph.
|
||||||
|
|
||||||
|
BB_SIZE points to an array which contains the number of instructions
|
||||||
|
for each basic block.
|
||||||
|
|
||||||
|
PRESSURE_CLASS and NREGS are register class and number of hard registers
|
||||||
|
for storing EXPR.
|
||||||
|
|
||||||
|
HOISTED_BBS points to a bitmap indicating basic blocks through which
|
||||||
|
EXPR is hoisted.
|
||||||
|
|
||||||
It's unclear exactly what Muchnick meant by "unimpared". It seems
|
It's unclear exactly what Muchnick meant by "unimpared". It seems
|
||||||
to me that the expression must either be computed or transparent in
|
to me that the expression must either be computed or transparent in
|
||||||
|
|
@ -2842,18 +2874,32 @@ compute_code_hoist_data (void)
|
||||||
paths. */
|
paths. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb,
|
should_hoist_expr_to_dom (basic_block expr_bb, struct expr *expr,
|
||||||
sbitmap visited, int distance, int *bb_size)
|
basic_block bb, sbitmap visited, int distance,
|
||||||
|
int *bb_size, enum reg_class pressure_class,
|
||||||
|
int *nregs, bitmap hoisted_bbs)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
edge pred;
|
edge pred;
|
||||||
edge_iterator ei;
|
edge_iterator ei;
|
||||||
|
sbitmap_iterator sbi;
|
||||||
int visited_allocated_locally = 0;
|
int visited_allocated_locally = 0;
|
||||||
|
|
||||||
/* Terminate the search if distance, for which EXPR is allowed to move,
|
/* Terminate the search if distance, for which EXPR is allowed to move,
|
||||||
is exhausted. */
|
is exhausted. */
|
||||||
if (distance > 0)
|
if (distance > 0)
|
||||||
{
|
{
|
||||||
distance -= bb_size[bb->index];
|
/* Let EXPR be hoisted through basic block at no cost if the block
|
||||||
|
has low register pressure. An exception is constant expression,
|
||||||
|
because hoisting constant expr aggressively results in worse code.
|
||||||
|
The exception is made by the observation of CSiBE on ARM target,
|
||||||
|
while it has no obvious effect on other targets like x86, x86_64,
|
||||||
|
mips and powerpc. */
|
||||||
|
if (!flag_ira_hoist_pressure
|
||||||
|
|| (BB_DATA (bb)->max_reg_pressure[pressure_class]
|
||||||
|
>= ira_class_hard_regs_num[pressure_class]
|
||||||
|
|| CONST_INT_P (expr->expr)))
|
||||||
|
distance -= bb_size[bb->index];
|
||||||
|
|
||||||
if (distance <= 0)
|
if (distance <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2878,21 +2924,35 @@ hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb,
|
||||||
continue;
|
continue;
|
||||||
else if (TEST_BIT (visited, pred_bb->index))
|
else if (TEST_BIT (visited, pred_bb->index))
|
||||||
continue;
|
continue;
|
||||||
|
else if (! TEST_BIT (transp[pred_bb->index], expr->bitmap_index))
|
||||||
else if (! TEST_BIT (transp[pred_bb->index], expr_index))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Not killed. */
|
/* Not killed. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SET_BIT (visited, pred_bb->index);
|
SET_BIT (visited, pred_bb->index);
|
||||||
if (! hoist_expr_reaches_here_p (expr_bb, expr_index, pred_bb,
|
if (! should_hoist_expr_to_dom (expr_bb, expr, pred_bb,
|
||||||
visited, distance, bb_size))
|
visited, distance, bb_size,
|
||||||
|
pressure_class, nregs, hoisted_bbs))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (visited_allocated_locally)
|
if (visited_allocated_locally)
|
||||||
sbitmap_free (visited);
|
{
|
||||||
|
/* If EXPR can be hoisted to expr_bb, record basic blocks through
|
||||||
|
which EXPR is hoisted in hoisted_bbs. Also update register
|
||||||
|
pressure for basic blocks newly added in hoisted_bbs. */
|
||||||
|
if (flag_ira_hoist_pressure && !pred)
|
||||||
|
{
|
||||||
|
EXECUTE_IF_SET_IN_SBITMAP (visited, 0, i, sbi)
|
||||||
|
if (!bitmap_bit_p (hoisted_bbs, i))
|
||||||
|
{
|
||||||
|
bitmap_set_bit (hoisted_bbs, i);
|
||||||
|
BB_DATA (BASIC_BLOCK (i))->max_reg_pressure[pressure_class]
|
||||||
|
+= *nregs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sbitmap_free (visited);
|
||||||
|
}
|
||||||
|
|
||||||
return (pred == NULL);
|
return (pred == NULL);
|
||||||
}
|
}
|
||||||
|
|
@ -2909,7 +2969,44 @@ find_occr_in_bb (struct occr *occr, basic_block bb)
|
||||||
return occr;
|
return occr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actually perform code hoisting. */
|
/* Actually perform code hoisting.
|
||||||
|
|
||||||
|
The code hoisting pass can hoist multiple computations of the same
|
||||||
|
expression along dominated path to a dominating basic block, like
|
||||||
|
from b2/b3 to b1 as depicted below:
|
||||||
|
|
||||||
|
b1 ------
|
||||||
|
/\ |
|
||||||
|
/ \ |
|
||||||
|
bx by distance
|
||||||
|
/ \ |
|
||||||
|
/ \ |
|
||||||
|
b2 b3 ------
|
||||||
|
|
||||||
|
Unfortunately code hoisting generally extends the live range of an
|
||||||
|
output pseudo register, which increases register pressure and hurts
|
||||||
|
register allocation. To address this issue, an attribute MAX_DISTANCE
|
||||||
|
is computed and attached to each expression. The attribute is computed
|
||||||
|
from rtx cost of the corresponding expression and it's used to control
|
||||||
|
how long the expression can be hoisted up in flow graph. As the
|
||||||
|
expression is hoisted up in flow graph, GCC decreases its DISTANCE
|
||||||
|
and stops the hoist if DISTANCE reaches 0.
|
||||||
|
|
||||||
|
Option "-fira-hoist-pressure" implements register pressure directed
|
||||||
|
hoist based on upper method. The rationale is:
|
||||||
|
1. Calculate register pressure for each basic block by reusing IRA
|
||||||
|
facility.
|
||||||
|
2. When expression is hoisted through one basic block, GCC checks
|
||||||
|
register pressure of the basic block and decrease DISTANCE only
|
||||||
|
when the register pressure is high. In other words, expression
|
||||||
|
will be hoisted through basic block with low register pressure
|
||||||
|
at no cost.
|
||||||
|
3. Update register pressure information for basic blocks through
|
||||||
|
which expression is hoisted.
|
||||||
|
TODO: It is possible to have register pressure decreased because
|
||||||
|
of shrinked live ranges of input pseudo registers when hoisting
|
||||||
|
an expression. For now, this effect is not simulated and we just
|
||||||
|
increase register pressure for hoisted expressions. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hoist_code (void)
|
hoist_code (void)
|
||||||
|
|
@ -2918,12 +3015,18 @@ hoist_code (void)
|
||||||
VEC (basic_block, heap) *dom_tree_walk;
|
VEC (basic_block, heap) *dom_tree_walk;
|
||||||
unsigned int dom_tree_walk_index;
|
unsigned int dom_tree_walk_index;
|
||||||
VEC (basic_block, heap) *domby;
|
VEC (basic_block, heap) *domby;
|
||||||
unsigned int i,j;
|
unsigned int i, j, k;
|
||||||
struct expr **index_map;
|
struct expr **index_map;
|
||||||
struct expr *expr;
|
struct expr *expr;
|
||||||
int *to_bb_head;
|
int *to_bb_head;
|
||||||
int *bb_size;
|
int *bb_size;
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
struct bb_data *data;
|
||||||
|
/* Basic blocks that have occurrences reachable from BB. */
|
||||||
|
bitmap from_bbs;
|
||||||
|
/* Basic blocks through which expr is hoisted. */
|
||||||
|
bitmap hoisted_bbs = NULL;
|
||||||
|
bitmap_iterator bi;
|
||||||
|
|
||||||
/* Compute a mapping from expression number (`bitmap_index') to
|
/* Compute a mapping from expression number (`bitmap_index') to
|
||||||
hash table entry. */
|
hash table entry. */
|
||||||
|
|
@ -2961,6 +3064,10 @@ hoist_code (void)
|
||||||
&& (EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
|
&& (EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
|
||||||
== ENTRY_BLOCK_PTR->next_bb));
|
== ENTRY_BLOCK_PTR->next_bb));
|
||||||
|
|
||||||
|
from_bbs = BITMAP_ALLOC (NULL);
|
||||||
|
if (flag_ira_hoist_pressure)
|
||||||
|
hoisted_bbs = BITMAP_ALLOC (NULL);
|
||||||
|
|
||||||
dom_tree_walk = get_all_dominated_blocks (CDI_DOMINATORS,
|
dom_tree_walk = get_all_dominated_blocks (CDI_DOMINATORS,
|
||||||
ENTRY_BLOCK_PTR->next_bb);
|
ENTRY_BLOCK_PTR->next_bb);
|
||||||
|
|
||||||
|
|
@ -2979,12 +3086,12 @@ hoist_code (void)
|
||||||
{
|
{
|
||||||
if (TEST_BIT (hoist_vbeout[bb->index], i))
|
if (TEST_BIT (hoist_vbeout[bb->index], i))
|
||||||
{
|
{
|
||||||
|
int nregs = 0;
|
||||||
|
enum reg_class pressure_class = NO_REGS;
|
||||||
/* Current expression. */
|
/* Current expression. */
|
||||||
struct expr *expr = index_map[i];
|
struct expr *expr = index_map[i];
|
||||||
/* Number of occurrences of EXPR that can be hoisted to BB. */
|
/* Number of occurrences of EXPR that can be hoisted to BB. */
|
||||||
int hoistable = 0;
|
int hoistable = 0;
|
||||||
/* Basic blocks that have occurrences reachable from BB. */
|
|
||||||
bitmap_head _from_bbs, *from_bbs = &_from_bbs;
|
|
||||||
/* Occurrences reachable from BB. */
|
/* Occurrences reachable from BB. */
|
||||||
VEC (occr_t, heap) *occrs_to_hoist = NULL;
|
VEC (occr_t, heap) *occrs_to_hoist = NULL;
|
||||||
/* We want to insert the expression into BB only once, so
|
/* We want to insert the expression into BB only once, so
|
||||||
|
|
@ -2992,8 +3099,6 @@ hoist_code (void)
|
||||||
int insn_inserted_p;
|
int insn_inserted_p;
|
||||||
occr_t occr;
|
occr_t occr;
|
||||||
|
|
||||||
bitmap_initialize (from_bbs, 0);
|
|
||||||
|
|
||||||
/* If an expression is computed in BB and is available at end of
|
/* If an expression is computed in BB and is available at end of
|
||||||
BB, hoist all occurrences dominated by BB to BB. */
|
BB, hoist all occurrences dominated by BB to BB. */
|
||||||
if (TEST_BIT (comp[bb->index], i))
|
if (TEST_BIT (comp[bb->index], i))
|
||||||
|
|
@ -3047,13 +3152,18 @@ hoist_code (void)
|
||||||
max_distance += (bb_size[dominated->index]
|
max_distance += (bb_size[dominated->index]
|
||||||
- to_bb_head[INSN_UID (occr->insn)]);
|
- to_bb_head[INSN_UID (occr->insn)]);
|
||||||
|
|
||||||
/* Note if the expression would reach the dominated block
|
pressure_class = get_pressure_class_and_nregs (occr->insn,
|
||||||
unimpared if it was placed at the end of BB.
|
&nregs);
|
||||||
|
|
||||||
|
/* Note if the expression should be hoisted from the dominated
|
||||||
|
block to BB if it can reach DOMINATED unimpared.
|
||||||
|
|
||||||
Keep track of how many times this expression is hoistable
|
Keep track of how many times this expression is hoistable
|
||||||
from a dominated block into BB. */
|
from a dominated block into BB. */
|
||||||
if (hoist_expr_reaches_here_p (bb, i, dominated, NULL,
|
if (should_hoist_expr_to_dom (bb, expr, dominated, NULL,
|
||||||
max_distance, bb_size))
|
max_distance, bb_size,
|
||||||
|
pressure_class, &nregs,
|
||||||
|
hoisted_bbs))
|
||||||
{
|
{
|
||||||
hoistable++;
|
hoistable++;
|
||||||
VEC_safe_push (occr_t, heap,
|
VEC_safe_push (occr_t, heap,
|
||||||
|
|
@ -3094,6 +3204,28 @@ hoist_code (void)
|
||||||
/* Punt, no point hoisting a single occurence. */
|
/* Punt, no point hoisting a single occurence. */
|
||||||
VEC_free (occr_t, heap, occrs_to_hoist);
|
VEC_free (occr_t, heap, occrs_to_hoist);
|
||||||
|
|
||||||
|
if (flag_ira_hoist_pressure
|
||||||
|
&& !VEC_empty (occr_t, occrs_to_hoist))
|
||||||
|
{
|
||||||
|
/* Update register pressure for basic block to which expr
|
||||||
|
is hoisted. */
|
||||||
|
data = BB_DATA (bb);
|
||||||
|
data->max_reg_pressure[pressure_class] += nregs;
|
||||||
|
}
|
||||||
|
else if (flag_ira_hoist_pressure)
|
||||||
|
{
|
||||||
|
/* Restore register pressure of basic block recorded in
|
||||||
|
hoisted_bbs when expr will not be hoisted. */
|
||||||
|
EXECUTE_IF_SET_IN_BITMAP (hoisted_bbs, 0, k, bi)
|
||||||
|
{
|
||||||
|
data = BB_DATA (BASIC_BLOCK (k));
|
||||||
|
data->max_reg_pressure[pressure_class] -= nregs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag_ira_hoist_pressure)
|
||||||
|
bitmap_clear (hoisted_bbs);
|
||||||
|
|
||||||
insn_inserted_p = 0;
|
insn_inserted_p = 0;
|
||||||
|
|
||||||
/* Walk through occurrences of I'th expressions we want
|
/* Walk through occurrences of I'th expressions we want
|
||||||
|
|
@ -3142,6 +3274,10 @@ hoist_code (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
VEC_free (basic_block, heap, dom_tree_walk);
|
VEC_free (basic_block, heap, dom_tree_walk);
|
||||||
|
BITMAP_FREE (from_bbs);
|
||||||
|
if (flag_ira_hoist_pressure)
|
||||||
|
BITMAP_FREE (hoisted_bbs);
|
||||||
|
|
||||||
free (bb_size);
|
free (bb_size);
|
||||||
free (to_bb_head);
|
free (to_bb_head);
|
||||||
free (index_map);
|
free (index_map);
|
||||||
|
|
@ -3149,6 +3285,165 @@ hoist_code (void)
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return pressure class and number of needed hard registers (through
|
||||||
|
*NREGS) of register REGNO. */
|
||||||
|
static enum reg_class
|
||||||
|
get_regno_pressure_class (int regno, int *nregs)
|
||||||
|
{
|
||||||
|
if (regno >= FIRST_PSEUDO_REGISTER)
|
||||||
|
{
|
||||||
|
enum reg_class pressure_class;
|
||||||
|
|
||||||
|
pressure_class = reg_allocno_class (regno);
|
||||||
|
pressure_class = ira_pressure_class_translate[pressure_class];
|
||||||
|
*nregs
|
||||||
|
= ira_reg_class_max_nregs[pressure_class][PSEUDO_REGNO_MODE (regno)];
|
||||||
|
return pressure_class;
|
||||||
|
}
|
||||||
|
else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)
|
||||||
|
&& ! TEST_HARD_REG_BIT (eliminable_regset, regno))
|
||||||
|
{
|
||||||
|
*nregs = 1;
|
||||||
|
return ira_pressure_class_translate[REGNO_REG_CLASS (regno)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*nregs = 0;
|
||||||
|
return NO_REGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return pressure class and number of hard registers (through *NREGS)
|
||||||
|
for destination of INSN. */
|
||||||
|
static enum reg_class
|
||||||
|
get_pressure_class_and_nregs (rtx insn, int *nregs)
|
||||||
|
{
|
||||||
|
rtx reg;
|
||||||
|
enum reg_class pressure_class;
|
||||||
|
rtx set = single_set (insn);
|
||||||
|
|
||||||
|
/* Considered invariant insns have only one set. */
|
||||||
|
gcc_assert (set != NULL_RTX);
|
||||||
|
reg = SET_DEST (set);
|
||||||
|
if (GET_CODE (reg) == SUBREG)
|
||||||
|
reg = SUBREG_REG (reg);
|
||||||
|
if (MEM_P (reg))
|
||||||
|
{
|
||||||
|
*nregs = 0;
|
||||||
|
pressure_class = NO_REGS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gcc_assert (REG_P (reg));
|
||||||
|
pressure_class = reg_allocno_class (REGNO (reg));
|
||||||
|
pressure_class = ira_pressure_class_translate[pressure_class];
|
||||||
|
*nregs
|
||||||
|
= ira_reg_class_max_nregs[pressure_class][GET_MODE (SET_SRC (set))];
|
||||||
|
}
|
||||||
|
return pressure_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increase (if INCR_P) or decrease current register pressure for
|
||||||
|
register REGNO. */
|
||||||
|
static void
|
||||||
|
change_pressure (int regno, bool incr_p)
|
||||||
|
{
|
||||||
|
int nregs;
|
||||||
|
enum reg_class pressure_class;
|
||||||
|
|
||||||
|
pressure_class = get_regno_pressure_class (regno, &nregs);
|
||||||
|
if (! incr_p)
|
||||||
|
curr_reg_pressure[pressure_class] -= nregs;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr_reg_pressure[pressure_class] += nregs;
|
||||||
|
if (BB_DATA (curr_bb)->max_reg_pressure[pressure_class]
|
||||||
|
< curr_reg_pressure[pressure_class])
|
||||||
|
BB_DATA (curr_bb)->max_reg_pressure[pressure_class]
|
||||||
|
= curr_reg_pressure[pressure_class];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate register pressure for each basic block by walking insns
|
||||||
|
from last to first. */
|
||||||
|
static void
|
||||||
|
calculate_bb_reg_pressure (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int j;
|
||||||
|
rtx insn;
|
||||||
|
basic_block bb;
|
||||||
|
bitmap curr_regs_live;
|
||||||
|
bitmap_iterator bi;
|
||||||
|
|
||||||
|
|
||||||
|
ira_setup_eliminable_regset ();
|
||||||
|
curr_regs_live = BITMAP_ALLOC (®_obstack);
|
||||||
|
FOR_EACH_BB (bb)
|
||||||
|
{
|
||||||
|
curr_bb = bb;
|
||||||
|
bitmap_copy (curr_regs_live, DF_LR_OUT (bb));
|
||||||
|
for (i = 0; i < ira_pressure_classes_num; i++)
|
||||||
|
curr_reg_pressure[ira_pressure_classes[i]] = 0;
|
||||||
|
EXECUTE_IF_SET_IN_BITMAP (curr_regs_live, 0, j, bi)
|
||||||
|
change_pressure (j, true);
|
||||||
|
|
||||||
|
FOR_BB_INSNS_REVERSE (bb, insn)
|
||||||
|
{
|
||||||
|
rtx dreg;
|
||||||
|
int regno;
|
||||||
|
df_ref *def_rec, *use_rec;
|
||||||
|
|
||||||
|
if (! NONDEBUG_INSN_P (insn))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
|
||||||
|
{
|
||||||
|
dreg = DF_REF_REAL_REG (*def_rec);
|
||||||
|
gcc_assert (REG_P (dreg));
|
||||||
|
regno = REGNO (dreg);
|
||||||
|
if (!(DF_REF_FLAGS (*def_rec)
|
||||||
|
& (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
|
||||||
|
{
|
||||||
|
if (bitmap_clear_bit (curr_regs_live, regno))
|
||||||
|
change_pressure (regno, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
|
||||||
|
{
|
||||||
|
dreg = DF_REF_REAL_REG (*use_rec);
|
||||||
|
gcc_assert (REG_P (dreg));
|
||||||
|
regno = REGNO (dreg);
|
||||||
|
if (bitmap_set_bit (curr_regs_live, regno))
|
||||||
|
change_pressure (regno, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BITMAP_FREE (curr_regs_live);
|
||||||
|
|
||||||
|
if (dump_file == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fprintf (dump_file, "\nRegister Pressure: \n");
|
||||||
|
FOR_EACH_BB (bb)
|
||||||
|
{
|
||||||
|
fprintf (dump_file, " Basic block %d: \n", bb->index);
|
||||||
|
for (i = 0; (int) i < ira_pressure_classes_num; i++)
|
||||||
|
{
|
||||||
|
enum reg_class pressure_class;
|
||||||
|
|
||||||
|
pressure_class = ira_pressure_classes[i];
|
||||||
|
if (BB_DATA (bb)->max_reg_pressure[pressure_class] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fprintf (dump_file, " %s=%d\n", reg_class_names[pressure_class],
|
||||||
|
BB_DATA (bb)->max_reg_pressure[pressure_class]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf (dump_file, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* Top level routine to perform one code hoisting (aka unification) pass
|
/* Top level routine to perform one code hoisting (aka unification) pass
|
||||||
|
|
||||||
Return nonzero if a change was made. */
|
Return nonzero if a change was made. */
|
||||||
|
|
@ -3168,6 +3463,16 @@ one_code_hoisting_pass (void)
|
||||||
|
|
||||||
doing_code_hoisting_p = true;
|
doing_code_hoisting_p = true;
|
||||||
|
|
||||||
|
/* Calculate register pressure for each basic block. */
|
||||||
|
if (flag_ira_hoist_pressure)
|
||||||
|
{
|
||||||
|
regstat_init_n_sets_and_refs ();
|
||||||
|
ira_set_pseudo_classes (false, dump_file);
|
||||||
|
alloc_aux_for_blocks (sizeof (struct bb_data));
|
||||||
|
calculate_bb_reg_pressure ();
|
||||||
|
regstat_free_n_sets_and_refs ();
|
||||||
|
}
|
||||||
|
|
||||||
/* We need alias. */
|
/* We need alias. */
|
||||||
init_alias_analysis ();
|
init_alias_analysis ();
|
||||||
|
|
||||||
|
|
@ -3188,6 +3493,11 @@ one_code_hoisting_pass (void)
|
||||||
free_code_hoist_mem ();
|
free_code_hoist_mem ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flag_ira_hoist_pressure)
|
||||||
|
{
|
||||||
|
free_aux_for_blocks ();
|
||||||
|
free_reg_info ();
|
||||||
|
}
|
||||||
free_hash_table (&expr_hash_table);
|
free_hash_table (&expr_hash_table);
|
||||||
free_gcse_mem ();
|
free_gcse_mem ();
|
||||||
obstack_free (&gcse_obstack, NULL);
|
obstack_free (&gcse_obstack, NULL);
|
||||||
|
|
|
||||||
|
|
@ -6633,7 +6633,7 @@ sched_init (void)
|
||||||
/* We need info about pseudos for rtl dumps about pseudo
|
/* We need info about pseudos for rtl dumps about pseudo
|
||||||
classes and costs. */
|
classes and costs. */
|
||||||
regstat_init_n_sets_and_refs ();
|
regstat_init_n_sets_and_refs ();
|
||||||
ira_set_pseudo_classes (sched_verbose ? sched_dump : NULL);
|
ira_set_pseudo_classes (true, sched_verbose ? sched_dump : NULL);
|
||||||
sched_regno_pressure_class
|
sched_regno_pressure_class
|
||||||
= (enum reg_class *) xmalloc (max_regno * sizeof (enum reg_class));
|
= (enum reg_class *) xmalloc (max_regno * sizeof (enum reg_class));
|
||||||
for (i = 0; i < max_regno; i++)
|
for (i = 0; i < max_regno; i++)
|
||||||
|
|
|
||||||
|
|
@ -2048,9 +2048,10 @@ ira_costs (void)
|
||||||
ira_free (total_allocno_costs);
|
ira_free (total_allocno_costs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Entry function which defines classes for pseudos. */
|
/* Entry function which defines classes for pseudos.
|
||||||
|
Set pseudo_classes_defined_p only if DEFINE_PSEUDO_CLASSES is true. */
|
||||||
void
|
void
|
||||||
ira_set_pseudo_classes (FILE *dump_file)
|
ira_set_pseudo_classes (bool define_pseudo_classes, FILE *dump_file)
|
||||||
{
|
{
|
||||||
allocno_p = false;
|
allocno_p = false;
|
||||||
internal_flag_ira_verbose = flag_ira_verbose;
|
internal_flag_ira_verbose = flag_ira_verbose;
|
||||||
|
|
@ -2059,7 +2060,9 @@ ira_set_pseudo_classes (FILE *dump_file)
|
||||||
initiate_regno_cost_classes ();
|
initiate_regno_cost_classes ();
|
||||||
find_costs_and_classes (dump_file);
|
find_costs_and_classes (dump_file);
|
||||||
finish_regno_cost_classes ();
|
finish_regno_cost_classes ();
|
||||||
pseudo_classes_defined_p = true;
|
if (define_pseudo_classes)
|
||||||
|
pseudo_classes_defined_p = true;
|
||||||
|
|
||||||
finish_costs ();
|
finish_costs ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4186,7 +4186,7 @@ ira (FILE *f)
|
||||||
crtl->is_leaf = leaf_function_p ();
|
crtl->is_leaf = leaf_function_p ();
|
||||||
|
|
||||||
if (resize_reg_info () && flag_ira_loop_pressure)
|
if (resize_reg_info () && flag_ira_loop_pressure)
|
||||||
ira_set_pseudo_classes (ira_dump_file);
|
ira_set_pseudo_classes (true, ira_dump_file);
|
||||||
|
|
||||||
rebuild_p = update_equiv_regs ();
|
rebuild_p = update_equiv_regs ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* Communication between the Integrated Register Allocator (IRA) and
|
/* Communication between the Integrated Register Allocator (IRA) and
|
||||||
the rest of the compiler.
|
the rest of the compiler.
|
||||||
Copyright (C) 2006, 2007, 2008, 2009, 2010
|
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2012
|
||||||
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
|
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ extern void ira_init (void);
|
||||||
extern void ira_finish_once (void);
|
extern void ira_finish_once (void);
|
||||||
extern void ira_setup_eliminable_regset (void);
|
extern void ira_setup_eliminable_regset (void);
|
||||||
extern rtx ira_eliminate_regs (rtx, enum machine_mode);
|
extern rtx ira_eliminate_regs (rtx, enum machine_mode);
|
||||||
extern void ira_set_pseudo_classes (FILE *);
|
extern void ira_set_pseudo_classes (bool, FILE *);
|
||||||
extern void ira_implicitly_set_insn_hard_regs (HARD_REG_SET *);
|
extern void ira_implicitly_set_insn_hard_regs (HARD_REG_SET *);
|
||||||
|
|
||||||
extern void ira_sort_regnos_for_alter_reg (int *, int, unsigned int *);
|
extern void ira_sort_regnos_for_alter_reg (int *, int, unsigned int *);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* RTL-level loop invariant motion.
|
/* RTL-level loop invariant motion.
|
||||||
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012
|
||||||
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GCC.
|
This file is part of GCC.
|
||||||
|
|
@ -1939,7 +1939,7 @@ move_loop_invariants (void)
|
||||||
{
|
{
|
||||||
df_analyze ();
|
df_analyze ();
|
||||||
regstat_init_n_sets_and_refs ();
|
regstat_init_n_sets_and_refs ();
|
||||||
ira_set_pseudo_classes (dump_file);
|
ira_set_pseudo_classes (true, dump_file);
|
||||||
calculate_loop_reg_pressure ();
|
calculate_loop_reg_pressure ();
|
||||||
regstat_free_n_sets_and_refs ();
|
regstat_free_n_sets_and_refs ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/* Move registers around to reduce number of move instructions needed.
|
/* Move registers around to reduce number of move instructions needed.
|
||||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||||
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
|
2012
|
||||||
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GCC.
|
This file is part of GCC.
|
||||||
|
|
@ -1237,7 +1238,7 @@ regmove_optimize (void)
|
||||||
regstat_compute_ri ();
|
regstat_compute_ri ();
|
||||||
|
|
||||||
if (flag_ira_loop_pressure)
|
if (flag_ira_loop_pressure)
|
||||||
ira_set_pseudo_classes (dump_file);
|
ira_set_pseudo_classes (true, dump_file);
|
||||||
|
|
||||||
regno_src_regno = XNEWVEC (int, nregs);
|
regno_src_regno = XNEWVEC (int, nregs);
|
||||||
for (i = nregs; --i >= 0; )
|
for (i = nregs; --i >= 0; )
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
2012-10-19 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
* testsuite/gcc.dg/hoist-register-pressure.c: New test.
|
||||||
|
|
||||||
2012-10-18 Paolo Carlini <paolo.carlini@oracle.com>
|
2012-10-18 Paolo Carlini <paolo.carlini@oracle.com>
|
||||||
|
|
||||||
PR c++/54501
|
PR c++/54501
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* { dg-options "-Os -fdump-rtl-hoist" } */
|
||||||
|
/* { dg-final { scan-rtl-dump "PRE/HOIST: end of bb .* copying expression" "hoist" } } */
|
||||||
|
|
||||||
|
#define BUF 100
|
||||||
|
int a[BUF];
|
||||||
|
|
||||||
|
void com (int);
|
||||||
|
void bar (int);
|
||||||
|
|
||||||
|
int foo (int x, int y, int z)
|
||||||
|
{
|
||||||
|
/* "x+y" won't be hoisted if "-fira-hoist-pressure" is disabled,
|
||||||
|
because its rtx_cost is too small. */
|
||||||
|
if (z)
|
||||||
|
{
|
||||||
|
a[1] = a[0] + a[2];
|
||||||
|
a[2] = a[1] + a[3];
|
||||||
|
a[3] = a[2] + a[4];
|
||||||
|
a[4] = a[3] + a[5];
|
||||||
|
a[5] = a[4] + a[6];
|
||||||
|
a[6] = a[5] + a[7];
|
||||||
|
a[7] = a[6] + a[8];
|
||||||
|
com (x+y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bar (x+y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue