common.opt (flra-remat): New.

2014-11-12  Vladimir Makarov  <vmakarov@redhat.com>

	* common.opt (flra-remat): New.
	* opts.c (default_options_table): Add entry for flra_remat.
	* timevar_def (TV_LRA_REMAT): New.
	* doc/invoke.texi (-flra-remat): Add description of the new
	option.
	* doc/passes.texi (-flra-remat): Remove lra-equivs.c and
	lra-saves.c.  Add lra-remat.c.
	* Makefile.in (OBJS): Add lra-remat.o.
	* lra-remat.c: New file.
	* lra.c: Add info about the rematerialization pass in the top
	comment.
	(collect_non_operand_hard_regs, add_regs_to_insn_regno_info):
	Process unallocatable regs too.
	(lra_constraint_new_insn_uid_start): Remove.
	(lra): Add code for calling rematerialization sub-pass.
	* lra-int.h (lra_constraint_new_insn_uid_start): Remove.
	(lra_constrain_insn, lra_remat): New prototypes.
	(lra_eliminate_regs_1): Add parameter.
	* lra-lives.c (make_hard_regno_born, make_hard_regno_dead):
	Process unallocatable hard regs too.
	(process_bb_lives): Ditto.
	* lra-spills.c (remove_pseudos): Add argument to
	lra_eliminate_regs_1 call.
	* lra-eliminations.c (lra_eliminate_regs_1): Add parameter.  Use it
	for sp offset calculation.
	(lra_eliminate_regs): Add argument for lra_eliminate_regs_1 call.
	(eliminate_regs_in_insn): Add parameter.  Use it for sp offset
	calculation.
	(process_insn_for_elimination): Add argument for
	eliminate_regs_in_insn call.
	* lra-constraints.c (get_equiv_with_elimination):  Add argument
	for lra_eliminate_regs_1 call.
	(process_addr_reg): Add parameter.  Use it.
	(process_address_1): Ditto.  Add argument for process_addr_reg
	call.
	(process_address): Ditto.
	(curr_insn_transform): Add parameter.  Use it.  Add argument for
	process_address calls.
	(lra_constrain_insn): New function.
	(lra_constraints): Add argument for curr_insn_transform call.

From-SVN: r217458
This commit is contained in:
Vladimir Makarov 2014-11-13 03:02:49 +00:00 committed by Vladimir Makarov
parent 778e02fdc4
commit d9cf932c33
14 changed files with 1532 additions and 162 deletions

View File

@ -1,3 +1,46 @@
2014-11-12 Vladimir Makarov <vmakarov@redhat.com>
* common.opt (flra-remat): New.
* opts.c (default_options_table): Add entry for flra_remat.
* timevar_def (TV_LRA_REMAT): New.
* doc/invoke.texi (-flra-remat): Add description of the new
option.
* doc/passes.texi (-flra-remat): Remove lra-equivs.c and
lra-saves.c. Add lra-remat.c.
* Makefile.in (OBJS): Add lra-remat.o.
* lra-remat.c: New file.
* lra.c: Add info about the rematerialization pass in the top
comment.
(collect_non_operand_hard_regs, add_regs_to_insn_regno_info):
Process unallocatable regs too.
(lra_constraint_new_insn_uid_start): Remove.
(lra): Add code for calling rematerialization sub-pass.
* lra-int.h (lra_constraint_new_insn_uid_start): Remove.
(lra_constrain_insn, lra_remat): New prototypes.
(lra_eliminate_regs_1): Add parameter.
* lra-lives.c (make_hard_regno_born, make_hard_regno_dead):
Process unallocatable hard regs too.
(process_bb_lives): Ditto.
* lra-spills.c (remove_pseudos): Add argument to
lra_eliminate_regs_1 call.
* lra-eliminations.c (lra_eliminate_regs_1): Add parameter. Use it
for sp offset calculation.
(lra_eliminate_regs): Add argument for lra_eliminate_regs_1 call.
(eliminate_regs_in_insn): Add parameter. Use it for sp offset
calculation.
(process_insn_for_elimination): Add argument for
eliminate_regs_in_insn call.
* lra-constraints.c (get_equiv_with_elimination): Add argument
for lra_eliminate_regs_1 call.
(process_addr_reg): Add parameter. Use it.
(process_address_1): Ditto. Add argument for process_addr_reg
call.
(process_address): Ditto.
(curr_insn_transform): Add parameter. Use it. Add argument for
process_address calls.
(lra_constrain_insn): New function.
(lra_constraints): Add argument for curr_insn_transform call.
2014-11-13 Manuel López-Ibáñez <manu@gcc.gnu.org> 2014-11-13 Manuel López-Ibáñez <manu@gcc.gnu.org>
* opts-global.c (postpone_unknown_option_warning): Fix spelling. * opts-global.c (postpone_unknown_option_warning): Fix spelling.

View File

@ -1304,6 +1304,7 @@ OBJS = \
lra-constraints.o \ lra-constraints.o \
lra-eliminations.o \ lra-eliminations.o \
lra-lives.o \ lra-lives.o \
lra-remat.o \
lra-spills.o \ lra-spills.o \
lto-cgraph.o \ lto-cgraph.o \
lto-streamer.o \ lto-streamer.o \

View File

@ -1551,6 +1551,10 @@ floop-optimize
Common Ignore Common Ignore
Does nothing. Preserved for backward compatibility. Does nothing. Preserved for backward compatibility.
flra-remat
Common Report Var(flag_lra_remat) Optimization
Do CFG-sensitive rematerialization in LRA
flto flto
Common Common
Enable link-time optimization. Enable link-time optimization.

View File

@ -392,7 +392,7 @@ Objective-C and Objective-C++ Dialects}.
-fisolate-erroneous-paths-dereference -fisolate-erroneous-paths-attribute @gol -fisolate-erroneous-paths-dereference -fisolate-erroneous-paths-attribute @gol
-fivopts -fkeep-inline-functions -fkeep-static-consts -flive-range-shrinkage @gol -fivopts -fkeep-inline-functions -fkeep-static-consts -flive-range-shrinkage @gol
-floop-block -floop-interchange -floop-strip-mine -floop-nest-optimize @gol -floop-block -floop-interchange -floop-strip-mine -floop-nest-optimize @gol
-floop-parallelize-all -flto -flto-compression-level @gol -floop-parallelize-all -flra-remat -flto -flto-compression-level @gol
-flto-partition=@var{alg} -flto-report -flto-report-wpa -fmerge-all-constants @gol -flto-partition=@var{alg} -flto-report -flto-report-wpa -fmerge-all-constants @gol
-fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves @gol -fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves @gol
-fmove-loop-invariants -fno-branch-count-reg @gol -fmove-loop-invariants -fno-branch-count-reg @gol
@ -7183,6 +7183,7 @@ also turns on the following optimization flags:
-fipa-sra @gol -fipa-sra @gol
-fipa-icf @gol -fipa-icf @gol
-fisolate-erroneous-paths-dereference @gol -fisolate-erroneous-paths-dereference @gol
-flra-remat @gol
-foptimize-sibling-calls @gol -foptimize-sibling-calls @gol
-foptimize-strlen @gol -foptimize-strlen @gol
-fpartial-inlining @gol -fpartial-inlining @gol
@ -7811,6 +7812,14 @@ Control the verbosity of the dump file for the integrated register allocator.
The default value is 5. If the value @var{n} is greater or equal to 10, The default value is 5. If the value @var{n} is greater or equal to 10,
the dump output is sent to stderr using the same format as @var{n} minus 10. the dump output is sent to stderr using the same format as @var{n} minus 10.
@item -flra-remat
@opindex fcaller-saves
Enable CFG-sensitive rematerialization in LRA. Instead of loading
values of spilled pseudos, LRA tries to rematerialize (recalculate)
values if it is profitable.
Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
@item -fdelayed-branch @item -fdelayed-branch
@opindex fdelayed-branch @opindex fdelayed-branch
If supported for the target machine, attempt to reorder instructions If supported for the target machine, attempt to reorder instructions

View File

@ -911,10 +911,10 @@ Source files are @file{reload.c} and @file{reload1.c}, plus the header
This pass is a modern replacement of the reload pass. Source files This pass is a modern replacement of the reload pass. Source files
are @file{lra.c}, @file{lra-assign.c}, @file{lra-coalesce.c}, are @file{lra.c}, @file{lra-assign.c}, @file{lra-coalesce.c},
@file{lra-constraints.c}, @file{lra-eliminations.c}, @file{lra-constraints.c}, @file{lra-eliminations.c},
@file{lra-equivs.c}, @file{lra-lives.c}, @file{lra-saves.c}, @file{lra-lives.c}, @file{lra-remat.c}, @file{lra-spills.c}, the
@file{lra-spills.c}, the header @file{lra-int.h} used for header @file{lra-int.h} used for communication between them, and the
communication between them, and the header @file{lra.h} used for header @file{lra.h} used for communication between LRA and the rest of
communication between LRA and the rest of compiler. compiler.
Unlike the reload pass, intermediate LRA decisions are reflected in Unlike the reload pass, intermediate LRA decisions are reflected in
RTL as much as possible. This reduces the number of target-dependent RTL as much as possible. This reduces the number of target-dependent

View File

@ -506,7 +506,8 @@ get_equiv_with_elimination (rtx x, rtx_insn *insn)
if (x == res || CONSTANT_P (res)) if (x == res || CONSTANT_P (res))
return res; return res;
return lra_eliminate_regs_1 (insn, res, GET_MODE (res), false, false, true); return lra_eliminate_regs_1 (insn, res, GET_MODE (res),
0, false, false, true);
} }
/* Set up curr_operand_mode. */ /* Set up curr_operand_mode. */
@ -1243,12 +1244,16 @@ static bool no_input_reloads_p, no_output_reloads_p;
insn. */ insn. */
static int curr_swapped; static int curr_swapped;
/* Arrange for address element *LOC to be a register of class CL. /* if CHECK_ONLY_P is false, arrange for address element *LOC to be a
Add any input reloads to list BEFORE. AFTER is nonnull if *LOC is an register of class CL. Add any input reloads to list BEFORE. AFTER
automodified value; handle that case by adding the required output is nonnull if *LOC is an automodified value; handle that case by
reloads to list AFTER. Return true if the RTL was changed. */ adding the required output reloads to list AFTER. Return true if
the RTL was changed.
if CHECK_ONLY_P is true, check that the *LOC is a correct address
register. Return false if the address register is correct. */
static bool static bool
process_addr_reg (rtx *loc, rtx_insn **before, rtx_insn **after, process_addr_reg (rtx *loc, bool check_only_p, rtx_insn **before, rtx_insn **after,
enum reg_class cl) enum reg_class cl)
{ {
int regno; int regno;
@ -1265,6 +1270,8 @@ process_addr_reg (rtx *loc, rtx_insn **before, rtx_insn **after,
mode = GET_MODE (reg); mode = GET_MODE (reg);
if (! REG_P (reg)) if (! REG_P (reg))
{ {
if (check_only_p)
return true;
/* Always reload memory in an address even if the target supports /* Always reload memory in an address even if the target supports
such addresses. */ such addresses. */
new_reg = lra_create_new_reg_with_unique_value (mode, reg, cl, "address"); new_reg = lra_create_new_reg_with_unique_value (mode, reg, cl, "address");
@ -1274,7 +1281,8 @@ process_addr_reg (rtx *loc, rtx_insn **before, rtx_insn **after,
{ {
regno = REGNO (reg); regno = REGNO (reg);
rclass = get_reg_class (regno); rclass = get_reg_class (regno);
if ((*loc = get_equiv_with_elimination (reg, curr_insn)) != reg) if (! check_only_p
&& (*loc = get_equiv_with_elimination (reg, curr_insn)) != reg)
{ {
if (lra_dump_file != NULL) if (lra_dump_file != NULL)
{ {
@ -1288,6 +1296,8 @@ process_addr_reg (rtx *loc, rtx_insn **before, rtx_insn **after,
} }
if (*loc != reg || ! in_class_p (reg, cl, &new_class)) if (*loc != reg || ! in_class_p (reg, cl, &new_class))
{ {
if (check_only_p)
return true;
reg = *loc; reg = *loc;
if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT, if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT,
mode, reg, cl, subreg_p, "address", &new_reg)) mode, reg, cl, subreg_p, "address", &new_reg))
@ -1295,6 +1305,8 @@ process_addr_reg (rtx *loc, rtx_insn **before, rtx_insn **after,
} }
else if (new_class != NO_REGS && rclass != new_class) else if (new_class != NO_REGS && rclass != new_class)
{ {
if (check_only_p)
return true;
lra_change_class (regno, new_class, " Change to", true); lra_change_class (regno, new_class, " Change to", true);
return false; return false;
} }
@ -2740,8 +2752,9 @@ equiv_address_substitution (struct address_info *ad)
return change_p; return change_p;
} }
/* Major function to make reloads for an address in operand NOP. /* Major function to make reloads for an address in operand NOP or
The supported cases are: check its correctness (If CHECK_ONLY_P is true). The supported
cases are:
1) an address that existed before LRA started, at which point it 1) an address that existed before LRA started, at which point it
must have been valid. These addresses are subject to elimination must have been valid. These addresses are subject to elimination
@ -2761,18 +2774,19 @@ equiv_address_substitution (struct address_info *ad)
address. Return true for any RTL change. address. Return true for any RTL change.
The function is a helper function which does not produce all The function is a helper function which does not produce all
transformations which can be necessary. It does just basic steps. transformations (when CHECK_ONLY_P is false) which can be
To do all necessary transformations use function necessary. It does just basic steps. To do all necessary
process_address. */ transformations use function process_address. */
static bool static bool
process_address_1 (int nop, rtx_insn **before, rtx_insn **after) process_address_1 (int nop, bool check_only_p,
rtx_insn **before, rtx_insn **after)
{ {
struct address_info ad; struct address_info ad;
rtx new_reg; rtx new_reg;
rtx op = *curr_id->operand_loc[nop]; rtx op = *curr_id->operand_loc[nop];
const char *constraint = curr_static_id->operand[nop].constraint; const char *constraint = curr_static_id->operand[nop].constraint;
enum constraint_num cn = lookup_constraint (constraint); enum constraint_num cn = lookup_constraint (constraint);
bool change_p; bool change_p = false;
if (insn_extra_address_constraint (cn)) if (insn_extra_address_constraint (cn))
decompose_lea_address (&ad, curr_id->operand_loc[nop]); decompose_lea_address (&ad, curr_id->operand_loc[nop]);
@ -2783,10 +2797,11 @@ process_address_1 (int nop, rtx_insn **before, rtx_insn **after)
decompose_mem_address (&ad, SUBREG_REG (op)); decompose_mem_address (&ad, SUBREG_REG (op));
else else
return false; return false;
change_p = equiv_address_substitution (&ad); if (! check_only_p)
change_p = equiv_address_substitution (&ad);
if (ad.base_term != NULL if (ad.base_term != NULL
&& (process_addr_reg && (process_addr_reg
(ad.base_term, before, (ad.base_term, check_only_p, before,
(ad.autoinc_p (ad.autoinc_p
&& !(REG_P (*ad.base_term) && !(REG_P (*ad.base_term)
&& find_regno_note (curr_insn, REG_DEAD, && find_regno_note (curr_insn, REG_DEAD,
@ -2800,7 +2815,8 @@ process_address_1 (int nop, rtx_insn **before, rtx_insn **after)
*ad.base_term2 = *ad.base_term; *ad.base_term2 = *ad.base_term;
} }
if (ad.index_term != NULL if (ad.index_term != NULL
&& process_addr_reg (ad.index_term, before, NULL, INDEX_REG_CLASS)) && process_addr_reg (ad.index_term, check_only_p,
before, NULL, INDEX_REG_CLASS))
change_p = true; change_p = true;
/* Target hooks sometimes don't treat extra-constraint addresses as /* Target hooks sometimes don't treat extra-constraint addresses as
@ -2809,6 +2825,9 @@ process_address_1 (int nop, rtx_insn **before, rtx_insn **after)
&& satisfies_address_constraint_p (&ad, cn)) && satisfies_address_constraint_p (&ad, cn))
return change_p; return change_p;
if (check_only_p)
return change_p;
/* There are three cases where the shape of *AD.INNER may now be invalid: /* There are three cases where the shape of *AD.INNER may now be invalid:
1) the original address was valid, but either elimination or 1) the original address was valid, but either elimination or
@ -2977,15 +2996,24 @@ process_address_1 (int nop, rtx_insn **before, rtx_insn **after)
return true; return true;
} }
/* Do address reloads until it is necessary. Use process_address_1 as /* If CHECK_ONLY_P is false, do address reloads until it is necessary.
a helper function. Return true for any RTL changes. */ Use process_address_1 as a helper function. Return true for any
RTL changes.
If CHECK_ONLY_P is true, just check address correctness. Return
false if the address correct. */
static bool static bool
process_address (int nop, rtx_insn **before, rtx_insn **after) process_address (int nop, bool check_only_p,
rtx_insn **before, rtx_insn **after)
{ {
bool res = false; bool res = false;
while (process_address_1 (nop, before, after)) while (process_address_1 (nop, check_only_p, before, after))
res = true; {
if (check_only_p)
return true;
res = true;
}
return res; return res;
} }
@ -3157,9 +3185,15 @@ swap_operands (int nop)
model can be changed in future. Make commutative operand exchange model can be changed in future. Make commutative operand exchange
if it is chosen. if it is chosen.
Return true if some RTL changes happened during function call. */ if CHECK_ONLY_P is false, do RTL changes to satisfy the
constraints. Return true if any change happened during function
call.
If CHECK_ONLY_P is true then don't do any transformation. Just
check that the insn satisfies all constraints. If the insn does
not satisfy any constraint, return true. */
static bool static bool
curr_insn_transform (void) curr_insn_transform (bool check_only_p)
{ {
int i, j, k; int i, j, k;
int n_operands; int n_operands;
@ -3226,50 +3260,53 @@ curr_insn_transform (void)
curr_swapped = false; curr_swapped = false;
goal_alt_swapped = false; goal_alt_swapped = false;
/* Make equivalence substitution and memory subreg elimination if (! check_only_p)
before address processing because an address legitimacy can /* Make equivalence substitution and memory subreg elimination
depend on memory mode. */ before address processing because an address legitimacy can
for (i = 0; i < n_operands; i++) depend on memory mode. */
{ for (i = 0; i < n_operands; i++)
rtx op = *curr_id->operand_loc[i]; {
rtx subst, old = op; rtx op = *curr_id->operand_loc[i];
bool op_change_p = false; rtx subst, old = op;
bool op_change_p = false;
if (GET_CODE (old) == SUBREG)
old = SUBREG_REG (old); if (GET_CODE (old) == SUBREG)
subst = get_equiv_with_elimination (old, curr_insn); old = SUBREG_REG (old);
if (subst != old) subst = get_equiv_with_elimination (old, curr_insn);
{ if (subst != old)
subst = copy_rtx (subst); {
lra_assert (REG_P (old)); subst = copy_rtx (subst);
if (GET_CODE (op) == SUBREG) lra_assert (REG_P (old));
SUBREG_REG (op) = subst; if (GET_CODE (op) == SUBREG)
else SUBREG_REG (op) = subst;
*curr_id->operand_loc[i] = subst; else
if (lra_dump_file != NULL) *curr_id->operand_loc[i] = subst;
{ if (lra_dump_file != NULL)
fprintf (lra_dump_file, {
"Changing pseudo %d in operand %i of insn %u on equiv ", fprintf (lra_dump_file,
REGNO (old), i, INSN_UID (curr_insn)); "Changing pseudo %d in operand %i of insn %u on equiv ",
dump_value_slim (lra_dump_file, subst, 1); REGNO (old), i, INSN_UID (curr_insn));
dump_value_slim (lra_dump_file, subst, 1);
fprintf (lra_dump_file, "\n"); fprintf (lra_dump_file, "\n");
} }
op_change_p = change_p = true; op_change_p = change_p = true;
} }
if (simplify_operand_subreg (i, GET_MODE (old)) || op_change_p) if (simplify_operand_subreg (i, GET_MODE (old)) || op_change_p)
{ {
change_p = true; change_p = true;
lra_update_dup (curr_id, i); lra_update_dup (curr_id, i);
} }
} }
/* Reload address registers and displacements. We do it before /* Reload address registers and displacements. We do it before
finding an alternative because of memory constraints. */ finding an alternative because of memory constraints. */
before = after = NULL; before = after = NULL;
for (i = 0; i < n_operands; i++) for (i = 0; i < n_operands; i++)
if (! curr_static_id->operand[i].is_operator if (! curr_static_id->operand[i].is_operator
&& process_address (i, &before, &after)) && process_address (i, check_only_p, &before, &after))
{ {
if (check_only_p)
return true;
change_p = true; change_p = true;
lra_update_dup (curr_id, i); lra_update_dup (curr_id, i);
} }
@ -3279,13 +3316,13 @@ curr_insn_transform (void)
we chose previously may no longer be valid. */ we chose previously may no longer be valid. */
lra_set_used_insn_alternative (curr_insn, -1); lra_set_used_insn_alternative (curr_insn, -1);
if (curr_insn_set != NULL_RTX if (! check_only_p && curr_insn_set != NULL_RTX
&& check_and_process_move (&change_p, &sec_mem_p)) && check_and_process_move (&change_p, &sec_mem_p))
return change_p; return change_p;
try_swapped: try_swapped:
reused_alternative_num = curr_id->used_insn_alternative; reused_alternative_num = check_only_p ? -1 : curr_id->used_insn_alternative;
if (lra_dump_file != NULL && reused_alternative_num >= 0) if (lra_dump_file != NULL && reused_alternative_num >= 0)
fprintf (lra_dump_file, "Reusing alternative %d for insn #%u\n", fprintf (lra_dump_file, "Reusing alternative %d for insn #%u\n",
reused_alternative_num, INSN_UID (curr_insn)); reused_alternative_num, INSN_UID (curr_insn));
@ -3293,6 +3330,9 @@ curr_insn_transform (void)
if (process_alt_operands (reused_alternative_num)) if (process_alt_operands (reused_alternative_num))
alt_p = true; alt_p = true;
if (check_only_p)
return ! alt_p || best_losers != 0;
/* If insn is commutative (it's safe to exchange a certain pair of /* If insn is commutative (it's safe to exchange a certain pair of
operands) then we need to try each alternative twice, the second operands) then we need to try each alternative twice, the second
time matching those two operands as if we had exchanged them. To time matching those two operands as if we had exchanged them. To
@ -3522,7 +3562,7 @@ curr_insn_transform (void)
*curr_id->operand_loc[i] = tem; *curr_id->operand_loc[i] = tem;
lra_update_dup (curr_id, i); lra_update_dup (curr_id, i);
process_address (i, &before, &after); process_address (i, false, &before, &after);
/* If the alternative accepts constant pool refs directly /* If the alternative accepts constant pool refs directly
there will be no reload needed at all. */ there will be no reload needed at all. */
@ -3746,6 +3786,26 @@ curr_insn_transform (void)
return change_p; return change_p;
} }
/* Return true if INSN satisfies all constraints. In other words, no
reload insns are needed. */
bool
lra_constrain_insn (rtx_insn *insn)
{
int saved_new_regno_start = new_regno_start;
int saved_new_insn_uid_start = new_insn_uid_start;
bool change_p;
curr_insn = insn;
curr_id = lra_get_insn_recog_data (curr_insn);
curr_static_id = curr_id->insn_static_data;
new_insn_uid_start = get_max_uid ();
new_regno_start = max_reg_num ();
change_p = curr_insn_transform (true);
new_regno_start = saved_new_regno_start;
new_insn_uid_start = saved_new_insn_uid_start;
return ! change_p;
}
/* Return true if X is in LIST. */ /* Return true if X is in LIST. */
static bool static bool
in_list_p (rtx x, rtx list) in_list_p (rtx x, rtx list)
@ -4238,7 +4298,7 @@ lra_constraints (bool first_p)
curr_static_id = curr_id->insn_static_data; curr_static_id = curr_id->insn_static_data;
init_curr_insn_input_reloads (); init_curr_insn_input_reloads ();
init_curr_operand_mode (); init_curr_operand_mode ();
if (curr_insn_transform ()) if (curr_insn_transform (false))
changed_p = true; changed_p = true;
/* Check non-transformed insns too for equiv change as USE /* Check non-transformed insns too for equiv change as USE
or CLOBBER don't need reloads but can contain pseudos or CLOBBER don't need reloads but can contain pseudos

View File

@ -298,7 +298,8 @@ get_elimination (rtx reg)
a change in the offset between the eliminable register and its a change in the offset between the eliminable register and its
substitution if UPDATE_P, or the full offset if FULL_P, or substitution if UPDATE_P, or the full offset if FULL_P, or
otherwise zero. If FULL_P, we also use the SP offsets for otherwise zero. If FULL_P, we also use the SP offsets for
elimination to SP. elimination to SP. If UPDATE_P, use UPDATE_SP_OFFSET for updating
offsets of register elimnable to SP.
MEM_MODE is the mode of an enclosing MEM. We need this to know how MEM_MODE is the mode of an enclosing MEM. We need this to know how
much to adjust a register for, e.g., PRE_DEC. Also, if we are much to adjust a register for, e.g., PRE_DEC. Also, if we are
@ -311,7 +312,8 @@ get_elimination (rtx reg)
sp offset. */ sp offset. */
rtx rtx
lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode, lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
bool subst_p, bool update_p, bool full_p) bool subst_p, bool update_p,
HOST_WIDE_INT update_sp_offset, bool full_p)
{ {
enum rtx_code code = GET_CODE (x); enum rtx_code code = GET_CODE (x);
struct lra_elim_table *ep; struct lra_elim_table *ep;
@ -346,7 +348,10 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
rtx to = subst_p ? ep->to_rtx : ep->from_rtx; rtx to = subst_p ? ep->to_rtx : ep->from_rtx;
if (update_p) if (update_p)
return plus_constant (Pmode, to, ep->offset - ep->previous_offset); return plus_constant (Pmode, to,
ep->offset - ep->previous_offset
+ (ep->to_rtx == stack_pointer_rtx
? update_sp_offset : 0));
else if (full_p) else if (full_p)
return plus_constant (Pmode, to, return plus_constant (Pmode, to,
ep->offset ep->offset
@ -373,7 +378,10 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
return gen_rtx_PLUS (Pmode, to, XEXP (x, 1)); return gen_rtx_PLUS (Pmode, to, XEXP (x, 1));
offset = (update_p offset = (update_p
? ep->offset - ep->previous_offset : ep->offset); ? ep->offset - ep->previous_offset
+ (ep->to_rtx == stack_pointer_rtx
? update_sp_offset : 0)
: ep->offset);
if (full_p && insn != NULL_RTX && ep->to_rtx == stack_pointer_rtx) if (full_p && insn != NULL_RTX && ep->to_rtx == stack_pointer_rtx)
offset -= lra_get_insn_recog_data (insn)->sp_offset; offset -= lra_get_insn_recog_data (insn)->sp_offset;
if (CONST_INT_P (XEXP (x, 1)) if (CONST_INT_P (XEXP (x, 1))
@ -402,9 +410,11 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
{ {
rtx new0 = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, rtx new0 = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
rtx new1 = lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, rtx new1 = lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
return form_sum (new0, new1); return form_sum (new0, new1);
@ -423,11 +433,12 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
rtx to = subst_p ? ep->to_rtx : ep->from_rtx; rtx to = subst_p ? ep->to_rtx : ep->from_rtx;
if (update_p) if (update_p)
return return plus_constant (Pmode,
plus_constant (Pmode, gen_rtx_MULT (Pmode, to, XEXP (x, 1)),
gen_rtx_MULT (Pmode, to, XEXP (x, 1)), (ep->offset - ep->previous_offset
(ep->offset - ep->previous_offset) + (ep->to_rtx == stack_pointer_rtx
* INTVAL (XEXP (x, 1))); ? update_sp_offset : 0))
* INTVAL (XEXP (x, 1)));
else if (full_p) else if (full_p)
{ {
HOST_WIDE_INT offset = ep->offset; HOST_WIDE_INT offset = ep->offset;
@ -459,10 +470,12 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
case LE: case LT: case LEU: case LTU: case LE: case LT: case LEU: case LTU:
{ {
rtx new0 = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, rtx new0 = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
rtx new1 = XEXP (x, 1) rtx new1 = XEXP (x, 1)
? lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, ? lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode,
subst_p, update_p, full_p) : 0; subst_p, update_p,
update_sp_offset, full_p) : 0;
if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1); return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1);
@ -475,7 +488,8 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
if (XEXP (x, 0)) if (XEXP (x, 0))
{ {
new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
if (new_rtx != XEXP (x, 0)) if (new_rtx != XEXP (x, 0))
{ {
/* If this is a REG_DEAD note, it is not valid anymore. /* If this is a REG_DEAD note, it is not valid anymore.
@ -484,7 +498,8 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
if (REG_NOTE_KIND (x) == REG_DEAD) if (REG_NOTE_KIND (x) == REG_DEAD)
return (XEXP (x, 1) return (XEXP (x, 1)
? lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, ? lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode,
subst_p, update_p, full_p) subst_p, update_p,
update_sp_offset, full_p)
: NULL_RTX); : NULL_RTX);
x = alloc_reg_note (REG_NOTE_KIND (x), new_rtx, XEXP (x, 1)); x = alloc_reg_note (REG_NOTE_KIND (x), new_rtx, XEXP (x, 1));
@ -501,7 +516,8 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
if (XEXP (x, 1)) if (XEXP (x, 1))
{ {
new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode, new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 1), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
if (new_rtx != XEXP (x, 1)) if (new_rtx != XEXP (x, 1))
return return
gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x),
@ -528,8 +544,8 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
&& XEXP (XEXP (x, 1), 0) == XEXP (x, 0)) && XEXP (XEXP (x, 1), 0) == XEXP (x, 0))
{ {
rtx new_rtx = lra_eliminate_regs_1 (insn, XEXP (XEXP (x, 1), 1), rtx new_rtx = lra_eliminate_regs_1 (insn, XEXP (XEXP (x, 1), 1),
mem_mode, mem_mode, subst_p, update_p,
subst_p, update_p, full_p); update_sp_offset, full_p);
if (new_rtx != XEXP (XEXP (x, 1), 1)) if (new_rtx != XEXP (XEXP (x, 1), 1))
return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0), return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0),
@ -553,14 +569,16 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
case PARITY: case PARITY:
case BSWAP: case BSWAP:
new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode, new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
if (new_rtx != XEXP (x, 0)) if (new_rtx != XEXP (x, 0))
return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx); return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx);
return x; return x;
case SUBREG: case SUBREG:
new_rtx = lra_eliminate_regs_1 (insn, SUBREG_REG (x), mem_mode, new_rtx = lra_eliminate_regs_1 (insn, SUBREG_REG (x), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
if (new_rtx != SUBREG_REG (x)) if (new_rtx != SUBREG_REG (x))
{ {
@ -598,12 +616,12 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
replace_equiv_address_nv replace_equiv_address_nv
(x, (x,
lra_eliminate_regs_1 (insn, XEXP (x, 0), GET_MODE (x), lra_eliminate_regs_1 (insn, XEXP (x, 0), GET_MODE (x),
subst_p, update_p, full_p)); subst_p, update_p, update_sp_offset, full_p));
case USE: case USE:
/* Handle insn_list USE that a call to a pure function may generate. */ /* Handle insn_list USE that a call to a pure function may generate. */
new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), VOIDmode, new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, 0), VOIDmode,
subst_p, update_p, full_p); subst_p, update_p, update_sp_offset, full_p);
if (new_rtx != XEXP (x, 0)) if (new_rtx != XEXP (x, 0))
return gen_rtx_USE (GET_MODE (x), new_rtx); return gen_rtx_USE (GET_MODE (x), new_rtx);
return x; return x;
@ -624,7 +642,8 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
if (*fmt == 'e') if (*fmt == 'e')
{ {
new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, i), mem_mode, new_rtx = lra_eliminate_regs_1 (insn, XEXP (x, i), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
if (new_rtx != XEXP (x, i) && ! copied) if (new_rtx != XEXP (x, i) && ! copied)
{ {
x = shallow_copy_rtx (x); x = shallow_copy_rtx (x);
@ -638,7 +657,8 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
for (j = 0; j < XVECLEN (x, i); j++) for (j = 0; j < XVECLEN (x, i); j++)
{ {
new_rtx = lra_eliminate_regs_1 (insn, XVECEXP (x, i, j), mem_mode, new_rtx = lra_eliminate_regs_1 (insn, XVECEXP (x, i, j), mem_mode,
subst_p, update_p, full_p); subst_p, update_p,
update_sp_offset, full_p);
if (new_rtx != XVECEXP (x, i, j) && ! copied_vec) if (new_rtx != XVECEXP (x, i, j) && ! copied_vec)
{ {
rtvec new_v = gen_rtvec_v (XVECLEN (x, i), rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
@ -665,7 +685,7 @@ rtx
lra_eliminate_regs (rtx x, machine_mode mem_mode, lra_eliminate_regs (rtx x, machine_mode mem_mode,
rtx insn ATTRIBUTE_UNUSED) rtx insn ATTRIBUTE_UNUSED)
{ {
return lra_eliminate_regs_1 (NULL, x, mem_mode, true, false, true); return lra_eliminate_regs_1 (NULL, x, mem_mode, true, false, 0, true);
} }
/* Stack pointer offset before the current insn relative to one at the /* Stack pointer offset before the current insn relative to one at the
@ -850,13 +870,15 @@ remove_reg_equal_offset_note (rtx insn, rtx what)
If REPLACE_P is false, just update the offsets while keeping the If REPLACE_P is false, just update the offsets while keeping the
base register the same. If FIRST_P, use the sp offset for base register the same. If FIRST_P, use the sp offset for
elimination to sp. Attach the note about used elimination for elimination to sp. Otherwise, use UPDATE_SP_OFFSET for this.
insns setting frame pointer to update elimination easy (without Attach the note about used elimination for insns setting frame
parsing already generated elimination insns to find offset pointer to update elimination easy (without parsing already
previously used) in future. */ generated elimination insns to find offset previously used) in
future. */
static void void
eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p) eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p,
HOST_WIDE_INT update_sp_offset)
{ {
int icode = recog_memoized (insn); int icode = recog_memoized (insn);
rtx old_set = single_set (insn); rtx old_set = single_set (insn);
@ -986,8 +1008,13 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p)
if (! replace_p) if (! replace_p)
{ {
offset += (ep->offset - ep->previous_offset); offset += (ep->offset - ep->previous_offset);
if (first_p && ep->to_rtx == stack_pointer_rtx) if (ep->to_rtx == stack_pointer_rtx)
offset -= lra_get_insn_recog_data (insn)->sp_offset; {
if (first_p)
offset -= lra_get_insn_recog_data (insn)->sp_offset;
else
offset += update_sp_offset;
}
offset = trunc_int_for_mode (offset, GET_MODE (plus_cst_src)); offset = trunc_int_for_mode (offset, GET_MODE (plus_cst_src));
} }
@ -1061,7 +1088,7 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p)
substed_operand[i] substed_operand[i]
= lra_eliminate_regs_1 (insn, *id->operand_loc[i], VOIDmode, = lra_eliminate_regs_1 (insn, *id->operand_loc[i], VOIDmode,
replace_p, ! replace_p && ! first_p, replace_p, ! replace_p && ! first_p,
first_p); update_sp_offset, first_p);
if (substed_operand[i] != orig_operand[i]) if (substed_operand[i] != orig_operand[i])
validate_p = true; validate_p = true;
} }
@ -1349,7 +1376,7 @@ lra_eliminate_reg_if_possible (rtx *loc)
static void static void
process_insn_for_elimination (rtx_insn *insn, bool final_p, bool first_p) process_insn_for_elimination (rtx_insn *insn, bool final_p, bool first_p)
{ {
eliminate_regs_in_insn (insn, final_p, first_p); eliminate_regs_in_insn (insn, final_p, first_p, 0);
if (! final_p) if (! final_p)
{ {
/* Check that insn changed its code. This is a case when a move /* Check that insn changed its code. This is a case when a move

View File

@ -328,7 +328,6 @@ extern bitmap_head lra_inheritance_pseudos;
extern bitmap_head lra_split_regs; extern bitmap_head lra_split_regs;
extern bitmap_head lra_subreg_reload_pseudos; extern bitmap_head lra_subreg_reload_pseudos;
extern bitmap_head lra_optional_reload_pseudos; extern bitmap_head lra_optional_reload_pseudos;
extern int lra_constraint_new_insn_uid_start;
/* lra-constraints.c: */ /* lra-constraints.c: */
@ -339,6 +338,7 @@ extern int lra_constraint_iter;
extern bool lra_risky_transformations_p; extern bool lra_risky_transformations_p;
extern int lra_inheritance_iter; extern int lra_inheritance_iter;
extern int lra_undo_inheritance_iter; extern int lra_undo_inheritance_iter;
extern bool lra_constrain_insn (rtx_insn *);
extern bool lra_constraints (bool); extern bool lra_constraints (bool);
extern void lra_constraints_init (void); extern void lra_constraints_init (void);
extern void lra_constraints_finish (void); extern void lra_constraints_finish (void);
@ -389,13 +389,17 @@ extern bool lra_need_for_spills_p (void);
extern void lra_spill (void); extern void lra_spill (void);
extern void lra_final_code_change (void); extern void lra_final_code_change (void);
/* lra-remat.c: */
extern bool lra_remat (void);
/* lra-elimination.c: */ /* lra-elimination.c: */
extern void lra_debug_elim_table (void); extern void lra_debug_elim_table (void);
extern int lra_get_elimination_hard_regno (int); extern int lra_get_elimination_hard_regno (int);
extern rtx lra_eliminate_regs_1 (rtx_insn *, rtx, machine_mode, bool, extern rtx lra_eliminate_regs_1 (rtx_insn *, rtx, machine_mode,
bool, bool); bool, bool, HOST_WIDE_INT, bool);
extern void eliminate_regs_in_insn (rtx_insn *insn, bool, bool, HOST_WIDE_INT);
extern void lra_eliminate (bool, bool); extern void lra_eliminate (bool, bool);
extern void lra_eliminate_reg_if_possible (rtx *); extern void lra_eliminate_reg_if_possible (rtx *);

View File

@ -252,8 +252,7 @@ make_hard_regno_born (int regno)
unsigned int i; unsigned int i;
lra_assert (regno < FIRST_PSEUDO_REGISTER); lra_assert (regno < FIRST_PSEUDO_REGISTER);
if (TEST_HARD_REG_BIT (lra_no_alloc_regs, regno) if (TEST_HARD_REG_BIT (hard_regs_live, regno))
|| TEST_HARD_REG_BIT (hard_regs_live, regno))
return; return;
SET_HARD_REG_BIT (hard_regs_live, regno); SET_HARD_REG_BIT (hard_regs_live, regno);
sparseset_set_bit (start_living, regno); sparseset_set_bit (start_living, regno);
@ -267,8 +266,7 @@ static void
make_hard_regno_dead (int regno) make_hard_regno_dead (int regno)
{ {
lra_assert (regno < FIRST_PSEUDO_REGISTER); lra_assert (regno < FIRST_PSEUDO_REGISTER);
if (TEST_HARD_REG_BIT (lra_no_alloc_regs, regno) if (! TEST_HARD_REG_BIT (hard_regs_live, regno))
|| ! TEST_HARD_REG_BIT (hard_regs_live, regno))
return; return;
sparseset_set_bit (start_dying, regno); sparseset_set_bit (start_dying, regno);
CLEAR_HARD_REG_BIT (hard_regs_live, regno); CLEAR_HARD_REG_BIT (hard_regs_live, regno);
@ -662,7 +660,6 @@ process_bb_lives (basic_block bb, int &curr_point)
sparseset_clear (pseudos_live_through_setjumps); sparseset_clear (pseudos_live_through_setjumps);
REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out); REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out);
AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset); AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
AND_COMPL_HARD_REG_SET (hard_regs_live, lra_no_alloc_regs);
EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi) EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
mark_pseudo_live (j, curr_point); mark_pseudo_live (j, curr_point);

1212
gcc/lra-remat.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -445,7 +445,7 @@ remove_pseudos (rtx *loc, rtx_insn *insn)
{ {
rtx x = lra_eliminate_regs_1 (insn, pseudo_slots[i].mem, rtx x = lra_eliminate_regs_1 (insn, pseudo_slots[i].mem,
GET_MODE (pseudo_slots[i].mem), GET_MODE (pseudo_slots[i].mem),
false, false, true); 0, false, false, true);
*loc = x != pseudo_slots[i].mem ? x : copy_rtx (x); *loc = x != pseudo_slots[i].mem ? x : copy_rtx (x);
} }
return; return;

109
gcc/lra.c
View File

@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
generated; generated;
o Some pseudos might be spilled to assign hard registers to o Some pseudos might be spilled to assign hard registers to
new reload pseudos; new reload pseudos;
o Recalculating spilled pseudo values (rematerialization);
o Changing spilled pseudos to stack memory or their equivalences; o Changing spilled pseudos to stack memory or their equivalences;
o Allocation stack memory changes the address displacement and o Allocation stack memory changes the address displacement and
new iteration is needed. new iteration is needed.
@ -57,19 +58,26 @@ along with GCC; see the file COPYING3. If not see
----------- | ---------------- | ----------- | ---------------- |
| | | | | |
| V New | | V New |
---------------- No ------------ pseudos ------------------- | ------------ pseudos -------------------
| Spilled pseudo | change |Constraints:| or insns | Inheritance/split | | |Constraints:| or insns | Inheritance/split |
| to memory |<-------| RTL |--------->| transformations | | | RTL |--------->| transformations |
| substitution | | transfor- | | in EBB scope | | | transfor- | | in EBB scope |
---------------- | mations | ------------------- | substi- | mations | -------------------
| ------------ | tutions ------------
V | | No change
------------------------- ---------------- V
| Hard regs substitution, | | Spilled pseudo | -------------------
| devirtalization, and |------> Finish | to memory |<----| Rematerialization |
| restoring scratches got | | substitution | -------------------
| memory | ----------------
------------------------- | No susbtitions
V
-------------------------
| Hard regs substitution, |
| devirtalization, and |------> Finish
| restoring scratches got |
| memory |
-------------------------
To speed up the process: To speed up the process:
o We process only insns affected by changes on previous o We process only insns affected by changes on previous
@ -849,38 +857,38 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
{ {
if ((regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER) if ((regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER)
return list; return list;
/* Process all regs even unallocatable ones as we need info
about all regs for rematerialization pass. */
for (last = regno + hard_regno_nregs[regno][mode]; for (last = regno + hard_regno_nregs[regno][mode];
regno < last; regno < last;
regno++) regno++)
if (! TEST_HARD_REG_BIT (lra_no_alloc_regs, regno) {
|| TEST_HARD_REG_BIT (eliminable_regset, regno)) for (curr = list; curr != NULL; curr = curr->next)
{ if (curr->regno == regno && curr->subreg_p == subreg_p
for (curr = list; curr != NULL; curr = curr->next) && curr->biggest_mode == mode)
if (curr->regno == regno && curr->subreg_p == subreg_p
&& curr->biggest_mode == mode)
{
if (curr->type != type)
curr->type = OP_INOUT;
if (curr->early_clobber != early_clobber)
curr->early_clobber = true;
break;
}
if (curr == NULL)
{ {
/* This is a new hard regno or the info can not be if (curr->type != type)
integrated into the found structure. */ curr->type = OP_INOUT;
#ifdef STACK_REGS if (curr->early_clobber != early_clobber)
early_clobber curr->early_clobber = true;
= (early_clobber break;
/* This clobber is to inform popping floating
point stack only. */
&& ! (FIRST_STACK_REG <= regno
&& regno <= LAST_STACK_REG));
#endif
list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
early_clobber, list);
} }
} if (curr == NULL)
{
/* This is a new hard regno or the info can not be
integrated into the found structure. */
#ifdef STACK_REGS
early_clobber
= (early_clobber
/* This clobber is to inform popping floating
point stack only. */
&& ! (FIRST_STACK_REG <= regno
&& regno <= LAST_STACK_REG));
#endif
list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
early_clobber, list);
}
}
return list; return list;
} }
switch (code) switch (code)
@ -1456,10 +1464,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
if (REG_P (x)) if (REG_P (x))
{ {
regno = REGNO (x); regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER /* Process all regs even unallocatable ones as we need info about
&& TEST_HARD_REG_BIT (lra_no_alloc_regs, regno) all regs for rematerialization pass. */
&& ! TEST_HARD_REG_BIT (eliminable_regset, regno))
return;
expand_reg_info (); expand_reg_info ();
if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, uid)) if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, uid))
{ {
@ -2152,9 +2158,6 @@ bitmap_head lra_optional_reload_pseudos;
pass. */ pass. */
bitmap_head lra_subreg_reload_pseudos; bitmap_head lra_subreg_reload_pseudos;
/* First UID of insns generated before a new spill pass. */
int lra_constraint_new_insn_uid_start;
/* File used for output of LRA debug information. */ /* File used for output of LRA debug information. */
FILE *lra_dump_file; FILE *lra_dump_file;
@ -2252,7 +2255,6 @@ lra (FILE *f)
lra_curr_reload_num = 0; lra_curr_reload_num = 0;
push_insns (get_last_insn (), NULL); push_insns (get_last_insn (), NULL);
/* It is needed for the 1st coalescing. */ /* It is needed for the 1st coalescing. */
lra_constraint_new_insn_uid_start = get_max_uid ();
bitmap_initialize (&lra_inheritance_pseudos, &reg_obstack); bitmap_initialize (&lra_inheritance_pseudos, &reg_obstack);
bitmap_initialize (&lra_split_regs, &reg_obstack); bitmap_initialize (&lra_split_regs, &reg_obstack);
bitmap_initialize (&lra_optional_reload_pseudos, &reg_obstack); bitmap_initialize (&lra_optional_reload_pseudos, &reg_obstack);
@ -2345,12 +2347,21 @@ lra (FILE *f)
lra_create_live_ranges (lra_reg_spill_p); lra_create_live_ranges (lra_reg_spill_p);
live_p = true; live_p = true;
} }
/* Now we know what pseudos should be spilled. Try to
rematerialize them first. */
if (lra_remat ())
{
/* We need full live info -- see the comment above. */
lra_create_live_ranges (lra_reg_spill_p);
live_p = true;
if (! lra_need_for_spills_p ())
break;
}
lra_spill (); lra_spill ();
/* Assignment of stack slots changes elimination offsets for /* Assignment of stack slots changes elimination offsets for
some eliminations. So update the offsets here. */ some eliminations. So update the offsets here. */
lra_eliminate (false, false); lra_eliminate (false, false);
lra_constraint_new_regno_start = max_reg_num (); lra_constraint_new_regno_start = max_reg_num ();
lra_constraint_new_insn_uid_start = get_max_uid ();
lra_assignment_iter_after_spill = 0; lra_assignment_iter_after_spill = 0;
} }
restore_scratches (); restore_scratches ();

View File

@ -500,6 +500,7 @@ static const struct default_options default_options_table[] =
{ OPT_LEVELS_2_PLUS, OPT_fipa_icf, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_fipa_icf, NULL, 1 },
{ OPT_LEVELS_2_PLUS, OPT_fisolate_erroneous_paths_dereference, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_fisolate_erroneous_paths_dereference, NULL, 1 },
{ OPT_LEVELS_2_PLUS, OPT_fuse_caller_save, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_fuse_caller_save, NULL, 1 },
{ OPT_LEVELS_2_PLUS, OPT_flra_remat, NULL, 1 },
/* -O3 optimizations. */ /* -O3 optimizations. */
{ OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 }, { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },

View File

@ -237,6 +237,7 @@ DEFTIMEVAR (TV_LRA_INHERITANCE , "LRA reload inheritance")
DEFTIMEVAR (TV_LRA_CREATE_LIVE_RANGES, "LRA create live ranges") DEFTIMEVAR (TV_LRA_CREATE_LIVE_RANGES, "LRA create live ranges")
DEFTIMEVAR (TV_LRA_ASSIGN , "LRA hard reg assignment") DEFTIMEVAR (TV_LRA_ASSIGN , "LRA hard reg assignment")
DEFTIMEVAR (TV_LRA_COALESCE , "LRA coalesce pseudo regs") DEFTIMEVAR (TV_LRA_COALESCE , "LRA coalesce pseudo regs")
DEFTIMEVAR (TV_LRA_REMAT , "LRA rematerialization")
DEFTIMEVAR (TV_RELOAD , "reload") DEFTIMEVAR (TV_RELOAD , "reload")
DEFTIMEVAR (TV_RELOAD_CSE_REGS , "reload CSE regs") DEFTIMEVAR (TV_RELOAD_CSE_REGS , "reload CSE regs")
DEFTIMEVAR (TV_GCSE_AFTER_RELOAD , "load CSE after reload") DEFTIMEVAR (TV_GCSE_AFTER_RELOAD , "load CSE after reload")