/* IRA processing allocno lives to build allocno live ranges.
- Copyright (C) 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2006-2013 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
continue;
curr_reg_pressure[cl] += n;
if (high_pressure_start_point[cl] < 0
- && (curr_reg_pressure[cl] > ira_available_class_regs[cl]))
+ && (curr_reg_pressure[cl] > ira_class_hard_regs_num[cl]))
high_pressure_start_point[cl] = curr_point;
if (curr_bb_node->reg_pressure[cl] < curr_reg_pressure[cl])
curr_bb_node->reg_pressure[cl] = curr_reg_pressure[cl];
curr_reg_pressure[cl] -= nregs;
ira_assert (curr_reg_pressure[cl] >= 0);
if (high_pressure_start_point[cl] >= 0
- && curr_reg_pressure[cl] <= ira_available_class_regs[cl])
+ && curr_reg_pressure[cl] <= ira_class_hard_regs_num[cl])
set_p = true;
}
if (set_p)
if (! ira_reg_pressure_class_p[cl])
continue;
if (high_pressure_start_point[cl] >= 0
- && curr_reg_pressure[cl] <= ira_available_class_regs[cl])
+ && curr_reg_pressure[cl] <= ira_class_hard_regs_num[cl])
high_pressure_start_point[cl] = -1;
}
}
}
+/* Determine from the objects_live bitmap whether REGNO is currently live,
+ and occupies only one object. Return false if we have no information. */
+static bool
+pseudo_regno_single_word_and_live_p (int regno)
+{
+ ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+ ira_object_t obj;
+
+ if (a == NULL)
+ return false;
+ if (ALLOCNO_NUM_OBJECTS (a) > 1)
+ return false;
+
+ obj = ALLOCNO_OBJECT (a, 0);
+
+ return sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj));
+}
+
/* Mark the pseudo register REGNO as live. Update all information about
live ranges and register pressure. */
static void
/* If REG is a pseudo or a subreg of it, and the class of its allocno
intersects CL, make a conflict with pseudo DREG. ORIG_DREG is the
- rtx actually accessed, it may be indentical to DREG or a subreg of it.
+ rtx actually accessed, it may be identical to DREG or a subreg of it.
Advance the current program point before making the conflict if
ADVANCE_P. Return TRUE if we will need to advance the current
program point. */
/* Check and make if necessary conflicts for pseudo DREG of class
DEF_CL of the current insn with input operand USE of class USE_CL.
- ORIG_DREG is the rtx actually accessed, it may be indentical to
+ ORIG_DREG is the rtx actually accessed, it may be identical to
DREG or a subreg of it. Advance the current program point before
making the conflict if ADVANCE_P. Return TRUE if we will need to
advance the current program point. */
break;
case 'n':
- if (CONST_INT_P (op)
- || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
- || (equiv_const != NULL_RTX
- && (CONST_INT_P (equiv_const)
- || (GET_CODE (equiv_const) == CONST_DOUBLE
- && GET_MODE (equiv_const) == VOIDmode))))
+ if (CONST_SCALAR_INT_P (op)
+ || (equiv_const != NULL_RTX && CONST_SCALAR_INT_P (equiv_const)))
return NO_REGS;
break;
case 's':
- if ((CONSTANT_P (op) && !CONST_INT_P (op)
- && (GET_CODE (op) != CONST_DOUBLE || GET_MODE (op) != VOIDmode))
+ if ((CONSTANT_P (op) && !CONST_SCALAR_INT_P (op))
|| (equiv_const != NULL_RTX
&& CONSTANT_P (equiv_const)
- && !CONST_INT_P (equiv_const)
- && (GET_CODE (equiv_const) != CONST_DOUBLE
- || GET_MODE (equiv_const) != VOIDmode)))
+ && !CONST_SCALAR_INT_P (equiv_const)))
return NO_REGS;
break;
case 'E':
case 'F':
- if (GET_CODE (op) == CONST_DOUBLE
+ if (CONST_DOUBLE_AS_FLOAT_P (op)
|| (GET_CODE (op) == CONST_VECTOR
&& GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT)
|| (equiv_const != NULL_RTX
- && (GET_CODE (equiv_const) == CONST_DOUBLE
+ && (CONST_DOUBLE_AS_FLOAT_P (equiv_const)
|| (GET_CODE (equiv_const) == CONST_VECTOR
&& (GET_MODE_CLASS (GET_MODE (equiv_const))
== MODE_VECTOR_FLOAT)))))
case 'G':
case 'H':
- if ((GET_CODE (op) == CONST_DOUBLE
+ if ((CONST_DOUBLE_AS_FLOAT_P (op)
&& CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, constraints))
|| (equiv_const != NULL_RTX
- && GET_CODE (equiv_const) == CONST_DOUBLE
+ && CONST_DOUBLE_AS_FLOAT_P (equiv_const)
&& CONST_DOUBLE_OK_FOR_CONSTRAINT_P (equiv_const,
c, constraints)))
return NO_REGS;
next_cl = (c == 'r'
? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT (c, constraints));
- if ((cl != NO_REGS && next_cl != cl)
- || (ira_available_class_regs[next_cl]
- > ira_reg_class_max_nregs[next_cl][GET_MODE (op)]))
+ if (cl == NO_REGS
+ ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
+ : (ira_class_singleton[cl][GET_MODE (op)]
+ != ira_class_singleton[next_cl][GET_MODE (op)]))
return NO_REGS;
cl = next_cl;
break;
next_cl
= single_reg_class (recog_data.constraints[c - '0'],
recog_data.operand[c - '0'], NULL_RTX);
- if ((cl != NO_REGS && next_cl != cl)
- || next_cl == NO_REGS
- || (ira_available_class_regs[next_cl]
- > ira_reg_class_max_nregs[next_cl][GET_MODE (op)]))
+ if (cl == NO_REGS
+ ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
+ : (ira_class_singleton[cl][GET_MODE (op)]
+ != ira_class_singleton[next_cl][GET_MODE (op)]))
return NO_REGS;
cl = next_cl;
break;
cl = (c == 'r'
? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT (c, p));
- if (cl != NO_REGS
+ if (cl != NO_REGS)
+ {
/* There is no register pressure problem if all of the
regs in this class are fixed. */
- && ira_available_class_regs[cl] != 0
- && (ira_available_class_regs[cl]
- <= ira_reg_class_max_nregs[cl][mode]))
- IOR_HARD_REG_SET (*set, reg_class_contents[cl]);
+ int regno = ira_class_singleton[cl][mode];
+ if (regno >= 0)
+ add_to_hard_reg_set (set, mode, regno);
+ }
break;
}
}
operand_a = ira_curr_regno_allocno_map[regno];
aclass = ALLOCNO_CLASS (operand_a);
- if (ira_class_subset_p[cl][aclass]
- && ira_class_hard_regs_num[cl] != 0)
+ if (ira_class_subset_p[cl][aclass])
{
/* View the desired allocation of OPERAND as:
HOST_WIDE_INT offset;
xmode = recog_data.operand_mode[i];
- xregno = ira_class_hard_regs[cl][0];
+ xregno = ira_class_singleton[cl][xmode];
+ gcc_assert (xregno >= 0);
ymode = ALLOCNO_MODE (operand_a);
offset = subreg_lowpart_offset (ymode, xmode);
yregno = simplify_subreg_regno (xregno, xmode, offset, ymode);
return false;
}
+/* Look through the CALL_INSN_FUNCTION_USAGE of a call insn INSN, and see if
+ we find a SET rtx that we can use to deduce that a register can be cheaply
+ caller-saved. Return such a register, or NULL_RTX if none is found. */
+static rtx
+find_call_crossed_cheap_reg (rtx insn)
+{
+ rtx cheap_reg = NULL_RTX;
+ rtx exp = CALL_INSN_FUNCTION_USAGE (insn);
+
+ while (exp != NULL)
+ {
+ rtx x = XEXP (exp, 0);
+ if (GET_CODE (x) == SET)
+ {
+ exp = x;
+ break;
+ }
+ exp = XEXP (exp, 1);
+ }
+ if (exp != NULL)
+ {
+ basic_block bb = BLOCK_FOR_INSN (insn);
+ rtx reg = SET_SRC (exp);
+ rtx prev = PREV_INSN (insn);
+ while (prev && !(INSN_P (prev)
+ && BLOCK_FOR_INSN (prev) != bb))
+ {
+ if (NONDEBUG_INSN_P (prev))
+ {
+ rtx set = single_set (prev);
+
+ if (set && rtx_equal_p (SET_DEST (set), reg))
+ {
+ rtx src = SET_SRC (set);
+ if (!REG_P (src) || HARD_REGISTER_P (src)
+ || !pseudo_regno_single_word_and_live_p (REGNO (src)))
+ break;
+ if (!modified_between_p (src, prev, insn))
+ cheap_reg = src;
+ break;
+ }
+ if (set && rtx_equal_p (SET_SRC (set), reg))
+ {
+ rtx dest = SET_DEST (set);
+ if (!REG_P (dest) || HARD_REGISTER_P (dest)
+ || !pseudo_regno_single_word_and_live_p (REGNO (dest)))
+ break;
+ if (!modified_between_p (dest, prev, insn))
+ cheap_reg = dest;
+ break;
+ }
+
+ if (reg_overlap_mentioned_p (reg, PATTERN (prev)))
+ break;
+ }
+ prev = PREV_INSN (prev);
+ }
+ }
+ return cheap_reg;
+}
+
/* Process insns of the basic block given by its LOOP_TREE_NODE to
update allocno live ranges, allocno hard register conflicts,
intersected calls, and register pressure info for allocnos for the
high_pressure_start_point[ira_pressure_classes[i]] = -1;
}
curr_bb_node = loop_tree_node;
- reg_live_out = DF_LR_OUT (bb);
+ reg_live_out = df_get_live_out (bb);
sparseset_clear (objects_live);
REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out);
AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
if (curr_bb_node->reg_pressure[cl] < curr_reg_pressure[cl])
curr_bb_node->reg_pressure[cl] = curr_reg_pressure[cl];
ira_assert (curr_reg_pressure[cl]
- <= ira_available_class_regs[cl]);
+ <= ira_class_hard_regs_num[cl]);
}
}
EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
if (call_p)
{
+ /* Try to find a SET in the CALL_INSN_FUNCTION_USAGE, and from
+ there, try to find a pseudo that is live across the call but
+ can be cheaply reconstructed from the return value. */
+ rtx cheap_reg = find_call_crossed_cheap_reg (insn);
+ if (cheap_reg != NULL_RTX)
+ add_reg_note (insn, REG_RETURNED, cheap_reg);
+
last_call_num++;
sparseset_clear (allocnos_processed);
/* The current set of live allocnos are live across the call. */
/* Mark it as saved at the next call. */
allocno_saved_at_call[num] = last_call_num + 1;
ALLOCNO_CALLS_CROSSED_NUM (a)++;
+ if (cheap_reg != NULL_RTX
+ && ALLOCNO_REGNO (a) == (int) REGNO (cheap_reg))
+ ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a)++;
}
}
int *map;
ira_object_t obj;
ira_object_iterator oi;
- live_range_t r;
+ live_range_t r, prev_r, next_r;
sbitmap born_or_dead, born, dead;
sbitmap_iterator sbi;
bool born_p, dead_p, prev_born_p, prev_dead_p;
born = sbitmap_alloc (ira_max_point);
dead = sbitmap_alloc (ira_max_point);
- sbitmap_zero (born);
- sbitmap_zero (dead);
+ bitmap_clear (born);
+ bitmap_clear (dead);
FOR_EACH_OBJECT (obj, oi)
for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
{
ira_assert (r->start <= r->finish);
- SET_BIT (born, r->start);
- SET_BIT (dead, r->finish);
+ bitmap_set_bit (born, r->start);
+ bitmap_set_bit (dead, r->finish);
}
born_or_dead = sbitmap_alloc (ira_max_point);
- sbitmap_a_or_b (born_or_dead, born, dead);
+ bitmap_ior (born_or_dead, born, dead);
map = (int *) ira_allocate (sizeof (int) * ira_max_point);
n = -1;
prev_born_p = prev_dead_p = false;
- EXECUTE_IF_SET_IN_SBITMAP (born_or_dead, 0, i, sbi)
+ EXECUTE_IF_SET_IN_BITMAP (born_or_dead, 0, i, sbi)
{
- born_p = TEST_BIT (born, i);
- dead_p = TEST_BIT (dead, i);
+ born_p = bitmap_bit_p (born, i);
+ dead_p = bitmap_bit_p (dead, i);
if ((prev_born_p && ! prev_dead_p && born_p && ! dead_p)
|| (prev_dead_p && ! prev_born_p && dead_p && ! born_p))
map[i] = n;
ira_max_point = n;
FOR_EACH_OBJECT (obj, oi)
- for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+ for (r = OBJECT_LIVE_RANGES (obj), prev_r = NULL; r != NULL; r = next_r)
{
+ next_r = r->next;
r->start = map[r->start];
r->finish = map[r->finish];
+ if (prev_r == NULL || prev_r->start > r->finish + 1)
+ {
+ prev_r = r;
+ continue;
+ }
+ prev_r->start = r->start;
+ prev_r->next = next_r;
+ ira_finish_live_range (r);
}
ira_free (map);