Skip to content

Commit

Permalink
IRA: Use minimal cost for hard register movement
Browse files Browse the repository at this point in the history
This is the 2nd attempt to fix PR90706.  IRA calculates wrong AVR
costs for moving general hard regs of SFmode.  This was the reason for
spilling a pseudo in the PR.  In this patch we use smaller move cost
of hard reg in its natural and operand modes.

        PR rtl-optimization/90706

gcc/ChangeLog:

	* ira-costs.cc: Include print-rtl.h.
	(record_reg_classes, scan_one_insn): Add code to print debug info.
	(record_operand_costs): Find and use smaller cost for hard reg
	move.

gcc/testsuite/ChangeLog:

	* gcc.target/avr/pr90706.c: New.
  • Loading branch information
vnmakarov committed Mar 2, 2023
1 parent ce9cd72 commit 2639f9d
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 25 deletions.
156 changes: 131 additions & 25 deletions gcc/ira-costs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "ira-int.h"
#include "addresses.h"
#include "reload.h"
#include "print-rtl.h"

/* The flags is set up every time when we calculate pseudo register
classes through function ira_set_pseudo_classes. */
Expand Down Expand Up @@ -503,6 +504,18 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
int insn_allows_mem[MAX_RECOG_OPERANDS];
move_table *move_in_cost, *move_out_cost;
short (*mem_cost)[2];
const char *p;

if (ira_dump_file != NULL && internal_flag_ira_verbose > 5)
{
fprintf (ira_dump_file, " Processing insn %u", INSN_UID (insn));
if (INSN_CODE (insn) >= 0
&& (p = get_insn_name (INSN_CODE (insn))) != NULL)
fprintf (ira_dump_file, " {%s}", p);
fprintf (ira_dump_file, " (freq=%d)\n",
REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn)));
dump_insn_slim (ira_dump_file, insn);
}

for (i = 0; i < n_ops; i++)
insn_allows_mem[i] = 0;
Expand All @@ -526,6 +539,21 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
continue;
}

if (ira_dump_file != NULL && internal_flag_ira_verbose > 5)
{
fprintf (ira_dump_file, " Alt %d:", alt);
for (i = 0; i < n_ops; i++)
{
p = constraints[i];
if (*p == '\0')
continue;
fprintf (ira_dump_file, " (%d) ", i);
for (; *p != '\0' && *p != ',' && *p != '#'; p++)
fputc (*p, ira_dump_file);
}
fprintf (ira_dump_file, "\n");
}

for (i = 0; i < n_ops; i++)
{
unsigned char c;
Expand Down Expand Up @@ -593,12 +621,16 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
register, this alternative can't be used. */

if (classes[j] == NO_REGS)
alt_fail = 1;
/* Otherwise, add to the cost of this alternative
the cost to copy the other operand to the hard
register used for this operand. */
{
alt_fail = 1;
}
else
alt_cost += copy_cost (ops[j], mode, classes[j], 1, NULL);
/* Otherwise, add to the cost of this alternative the cost
to copy the other operand to the hard register used for
this operand. */
{
alt_cost += copy_cost (ops[j], mode, classes[j], 1, NULL);
}
}
else
{
Expand Down Expand Up @@ -1021,18 +1053,45 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
for (i = 0; i < n_ops; i++)
if (REG_P (ops[i]) && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
{
int old_cost;
bool cost_change_p = false;
struct costs *pp = op_costs[i], *qq = this_op_costs[i];
int *pp_costs = pp->cost, *qq_costs = qq->cost;
int scale = 1 + (recog_data.operand_type[i] == OP_INOUT);
cost_classes_t cost_classes_ptr
= regno_cost_classes[REGNO (ops[i])];

pp->mem_cost = MIN (pp->mem_cost,
old_cost = pp->mem_cost;
pp->mem_cost = MIN (old_cost,
(qq->mem_cost + op_cost_add) * scale);

if (ira_dump_file != NULL && internal_flag_ira_verbose > 5
&& pp->mem_cost < old_cost)
{
cost_change_p = true;
fprintf (ira_dump_file, " op %d(r=%u) new costs MEM:%d",
i, REGNO(ops[i]), pp->mem_cost);
}
for (k = cost_classes_ptr->num - 1; k >= 0; k--)
pp_costs[k]
= MIN (pp_costs[k], (qq_costs[k] + op_cost_add) * scale);
{
old_cost = pp_costs[k];
pp_costs[k]
= MIN (old_cost, (qq_costs[k] + op_cost_add) * scale);
if (ira_dump_file != NULL && internal_flag_ira_verbose > 5
&& pp_costs[k] < old_cost)
{
if (!cost_change_p)
fprintf (ira_dump_file, " op %d(r=%u) new costs",
i, REGNO(ops[i]));
cost_change_p = true;
fprintf (ira_dump_file, " %s:%d",
reg_class_names[cost_classes_ptr->classes[k]],
pp_costs[k]);
}
}
if (ira_dump_file != NULL && internal_flag_ira_verbose > 5
&& cost_change_p)
fprintf (ira_dump_file, "\n");
}
}

Expand Down Expand Up @@ -1307,34 +1366,56 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
|| ((regno = REGNO (dest)) >= FIRST_PSEUDO_REGISTER
&& (other_regno = REGNO (src)) < FIRST_PSEUDO_REGISTER)))
{
machine_mode mode = GET_MODE (SET_SRC (set));
machine_mode mode = GET_MODE (SET_SRC (set)), cost_mode = mode;
machine_mode hard_reg_mode = GET_MODE(regno_reg_rtx[other_regno]);
poly_int64 pmode_size = GET_MODE_SIZE (mode);
poly_int64 phard_reg_mode_size = GET_MODE_SIZE (hard_reg_mode);
HOST_WIDE_INT mode_size, hard_reg_mode_size;
cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
enum reg_class *cost_classes = cost_classes_ptr->classes;
reg_class_t rclass, hard_reg_class, bigger_hard_reg_class;
int cost, k;
int cost_factor = 1, cost, k;
move_table *move_costs;
bool dead_p = find_regno_note (insn, REG_DEAD, REGNO (src));

ira_init_register_move_cost_if_necessary (mode);
move_costs = ira_register_move_cost[mode];
hard_reg_class = REGNO_REG_CLASS (other_regno);
bigger_hard_reg_class = ira_pressure_class_translate[hard_reg_class];
/* Target code may return any cost for mode which does not
fit the hard reg class (e.g. DImode for AREG on
i386). Check this and use a bigger class to get the
right cost. */
if (bigger_hard_reg_class != NO_REGS
&& ! ira_hard_reg_in_set_p (other_regno, mode,
reg_class_contents[hard_reg_class]))
hard_reg_class = bigger_hard_reg_class;
bigger_hard_reg_class = ira_pressure_class_translate[hard_reg_class];
/* Target code may return any cost for mode which does not fit the
hard reg class (e.g. DImode for AREG on i386). Check this and use
a bigger class to get the right cost. */
if (bigger_hard_reg_class != NO_REGS
&& ! ira_hard_reg_in_set_p (other_regno, mode,
reg_class_contents[hard_reg_class]))
hard_reg_class = bigger_hard_reg_class;
ira_init_register_move_cost_if_necessary (mode);
ira_init_register_move_cost_if_necessary (hard_reg_mode);
/* Use smaller movement cost for natural hard reg mode or its mode as
operand. */
if (pmode_size.is_constant (&mode_size)
&& phard_reg_mode_size.is_constant (&hard_reg_mode_size))
{
/* Assume we are moving in the natural modes: */
cost_factor = mode_size / hard_reg_mode_size;
if (mode_size % hard_reg_mode_size != 0)
cost_factor++;
if (cost_factor
* (ira_register_move_cost
[hard_reg_mode][hard_reg_class][hard_reg_class])
< (ira_register_move_cost
[mode][hard_reg_class][hard_reg_class]))
cost_mode = hard_reg_mode;
else
cost_factor = 1;
}
move_costs = ira_register_move_cost[cost_mode];
i = regno == (int) REGNO (src) ? 1 : 0;
for (k = cost_classes_ptr->num - 1; k >= 0; k--)
{
rclass = cost_classes[k];
cost = (i == 0
? move_costs[hard_reg_class][rclass]
: move_costs[rclass][hard_reg_class]);

cost *= cost_factor;
op_costs[i]->cost[k] = cost * frequency;
/* If this insn is a single set copying operand 1 to
operand 0 and one operand is an allocno with the
Expand Down Expand Up @@ -1506,12 +1587,24 @@ scan_one_insn (rtx_insn *insn)

record_operand_costs (insn, pref);

if (ira_dump_file != NULL && internal_flag_ira_verbose > 5)
{
const char *p;
fprintf (ira_dump_file, " Final costs after insn %u", INSN_UID (insn));
if (INSN_CODE (insn) >= 0
&& (p = get_insn_name (INSN_CODE (insn))) != NULL)
fprintf (ira_dump_file, " {%s}", p);
fprintf (ira_dump_file, " (freq=%d)\n",
REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn)));
dump_insn_slim (ira_dump_file, insn);
}

/* Now add the cost for each operand to the total costs for its
allocno. */
for (i = 0; i < recog_data.n_operands; i++)
{
rtx op = recog_data.operand[i];

if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
Expand All @@ -1521,8 +1614,8 @@ scan_one_insn (rtx_insn *insn)
struct costs *q = op_costs[i];
int *p_costs = p->cost, *q_costs = q->cost;
cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
int add_cost;
int add_cost = 0;

/* If the already accounted for the memory "cost" above, don't
do so again. */
if (!counted_mem)
Expand All @@ -1533,14 +1626,27 @@ scan_one_insn (rtx_insn *insn)
else
p->mem_cost += add_cost;
}
if (ira_dump_file != NULL && internal_flag_ira_verbose > 5)
{
fprintf (ira_dump_file, " op %d(r=%u) MEM:%d(+%d)",
i, REGNO(op), p->mem_cost, add_cost);
}
for (k = cost_classes_ptr->num - 1; k >= 0; k--)
{
add_cost = q_costs[k];
if (add_cost > 0 && INT_MAX - add_cost < p_costs[k])
p_costs[k] = INT_MAX;
else
p_costs[k] += add_cost;
if (ira_dump_file != NULL && internal_flag_ira_verbose > 5)
{
fprintf (ira_dump_file, " %s:%d(+%d)",
reg_class_names[cost_classes_ptr->classes[k]],
p_costs[k], add_cost);
}
}
if (ira_dump_file != NULL && internal_flag_ira_verbose > 5)
fprintf (ira_dump_file, "\n");
}
}
return insn;
Expand Down
9 changes: 9 additions & 0 deletions gcc/testsuite/gcc.target/avr/pr90706.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* { dg-do compile } */
/* { dg-options "-Os" } */

unsigned char check(float x)
{
return (0.0 < x);
}
/* { dg-final { scan-assembler-not "ldd" } } */
/* { dg-final { scan-assembler-not "std" } } */

0 comments on commit 2639f9d

Please sign in to comment.