@@ -44,6 +44,9 @@
(define_register_constraint "h" "(TARGET_V9 && TARGET_V8PLUS ? I64_REGS : NO_REGS)"
"64-bit global or out register in V8+ mode")
+(define_register_constraint "U" "(TARGET_ARCH32 ? EVEN_REGS : NO_REGS)"
+ "Even-numbered integer register")
+
;; Floating-point constant constraints
(define_constraint "G"
@@ -135,51 +138,6 @@
(match_code "mem")
(match_test "memory_ok_for_ldd (op)")))
-;; This awkward register constraint is necessary because it is not
-;; possible to express the "must be even numbered register" condition
-;; using register classes. The problem is that membership in a
-;; register class requires that all registers of a multi-regno
-;; register be included in the set. It is add_to_hard_reg_set
-;; and in_hard_reg_set_p which populate and test regsets with these
-;; semantics.
-;;
-;; So this means that we would have to put both the even and odd
-;; register into the register class, which would not restrict things
-;; at all.
-;;
-;; Using a combination of GENERAL_REGS and HARD_REGNO_MODE_OK is not a
-;; full solution either. In fact, even though IRA uses the macro
-;; HARD_REGNO_MODE_OK to calculate which registers are prohibited from
-;; use in certain modes, it still can allocate an odd hard register
-;; for DImode values. This is due to how IRA populates the table
-;; ira_useful_class_mode_regs[][]. It suffers from the same problem
-;; as using a register class to describe this restriction. Namely, it
-;; sets both the odd and even part of an even register pair in the
-;; regset. Therefore IRA can and will allocate odd registers for
-;; DImode values on 32-bit.
-;;
-;; There are legitimate cases where DImode values can end up in odd
-;; hard registers, the most notable example is argument passing.
-;;
-;; What saves us is reload and the DImode splitters. Both are
-;; necessary. The odd register splitters cannot match if, for
-;; example, we have a non-offsetable MEM. Reload will notice this
-;; case and reload the address into a single hard register.
-;;
-;; The real downfall of this awkward register constraint is that it does
-;; not evaluate to a true register class like a bonafide use of
-;; define_register_constraint would. This currently means that we cannot
-;; use LRA on Sparc, since the constraint processing of LRA really depends
-;; upon whether an extra constraint is for registers or not. It uses
-;; REG_CLASS_FROM_CONSTRAINT, and checks it against NO_REGS.
-(define_constraint "U"
- "Pseudo-register or hard even-numbered integer register"
- (and (match_test "TARGET_ARCH32")
- (match_code "reg")
- (ior (match_test "REGNO (op) < FIRST_PSEUDO_REGISTER")
- (not (match_test "reload_in_progress && reg_renumber [REGNO (op)] < 0")))
- (match_test "register_ok_for_ldd (op)")))
-
;; Equivalent to 'T' but available in 64-bit mode
(define_memory_constraint "W"
"Memory reference for 'e' constraint floating-point register"
@@ -4492,6 +4492,8 @@ sparc_init_modes (void)
{
if (i < 16 && TARGET_V8PLUS)
sparc_regno_reg_class[i] = I64_REGS;
+ else if (i < 32 && (i & 1) == 0)
+ sparc_regno_reg_class[i] = EVEN_REGS;
else if (i < 32 || i == FRAME_POINTER_REGNUM)
sparc_regno_reg_class[i] = GENERAL_REGS;
else if (i < 64)
@@ -10592,12 +10594,13 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
}
}
-/* Return true if CLASS is either GENERAL_REGS or I64_REGS. */
+/* Return true if CLASS is either GENERAL_REGS or I64_REGS or
+ EVEN_REGS. */
static inline bool
-general_or_i64_p (reg_class_t rclass)
+integer_regclass_p (reg_class_t rclass)
{
- return (rclass == GENERAL_REGS || rclass == I64_REGS);
+ return (rclass == GENERAL_REGS || rclass == I64_REGS || rclass == EVEN_REGS);
}
/* Implement TARGET_REGISTER_MOVE_COST. */
@@ -10610,8 +10613,8 @@ sparc_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
if (from == FPCC_REGS || to == FPCC_REGS)
need_memory = true;
- else if ((FP_REG_CLASS_P (from) && general_or_i64_p (to))
- || (general_or_i64_p (from) && FP_REG_CLASS_P (to)))
+ else if ((FP_REG_CLASS_P (from) && integer_regclass_p (to))
+ || (integer_regclass_p (from) && FP_REG_CLASS_P (to)))
{
if (TARGET_VIS3)
{
@@ -11926,7 +11929,7 @@ sparc_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
move between EXTRA_FP_REGS and GENERAL_REGS, we will need
an FP_REGS intermediate move. */
if ((rclass == EXTRA_FP_REGS && SPARC_INT_REG_P (regno))
- || ((general_or_i64_p (rclass)
+ || ((integer_regclass_p (rclass)
|| rclass == GENERAL_OR_FP_REGS)
&& SPARC_FP_REG_P (regno)))
{
@@ -858,7 +858,7 @@ extern int sparc_mode_class[];
??? Should %fcc[0123] be handled similarly?
*/
-enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, FP_REGS,
+enum reg_class { NO_REGS, FPCC_REGS, EVEN_REGS, I64_REGS, GENERAL_REGS, FP_REGS,
EXTRA_FP_REGS, GENERAL_OR_FP_REGS, GENERAL_OR_EXTRA_FP_REGS,
ALL_REGS, LIM_REG_CLASSES };
@@ -867,9 +867,9 @@ enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, FP_REGS,
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
- { "NO_REGS", "FPCC_REGS", "I64_REGS", "GENERAL_REGS", "FP_REGS", \
- "EXTRA_FP_REGS", "GENERAL_OR_FP_REGS", "GENERAL_OR_EXTRA_FP_REGS", \
- "ALL_REGS" }
+ { "NO_REGS", "FPCC_REGS", "EVEN_REGS", "I64_REGS", "GENERAL_REGS", \
+ "FP_REGS", "EXTRA_FP_REGS", "GENERAL_OR_FP_REGS", \
+ "GENERAL_OR_EXTRA_FP_REGS", "ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
@@ -878,6 +878,7 @@ enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, FP_REGS,
#define REG_CLASS_CONTENTS \
{{0, 0, 0, 0}, /* NO_REGS */ \
{0, 0, 0, 0xf}, /* FPCC_REGS */ \
+ {0x55555555, 0, 0, 0},/* EVEN_REGS */ \
{0xffff, 0, 0, 0}, /* I64_REGS */ \
{-1, 0, 0, 0x20}, /* GENERAL_REGS */ \
{0, -1, 0, 0}, /* FP_REGS */ \
@@ -351,10 +351,6 @@ in_hard_reg_set_p (const HARD_REG_SET regs, enum machine_mode mode,
if (!HARD_REGISTER_NUM_P (end_regno - 1))
return false;
- while (++regno < end_regno)
- if (!TEST_HARD_REG_BIT (regs, regno))
- return false;
-
return true;
}
@@ -680,8 +680,7 @@ find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED,
if (HARD_REGNO_MODE_OK (regno, inner))
{
good = 1;
- if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], regno + n)
- || ! HARD_REGNO_MODE_OK (regno + n, outer))
+ if (! HARD_REGNO_MODE_OK (regno + n, outer))
bad = 1;
}
}
@@ -1648,19 +1647,20 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
unsigned int nregs = MAX (hard_regno_nregs[regno][inmode],
hard_regno_nregs[regno][outmode]);
- for (offs = 0; offs < nregs; offs++)
- if (fixed_regs[regno + offs]
- || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
- regno + offs))
- break;
-
- if (offs == nregs
- && (! (refers_to_regno_for_reload_p
- (regno, end_hard_regno (inmode, regno), in, (rtx *) 0))
- || can_reload_into (in, regno, inmode)))
+ if (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], regno))
{
- rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
- break;
+ for (offs = 0; offs < nregs; offs++)
+ if (fixed_regs[regno + offs])
+ break;
+
+ if (offs == nregs
+ && (! (refers_to_regno_for_reload_p
+ (regno, end_hard_regno (inmode, regno), in, (rtx *) 0))
+ || can_reload_into (in, regno, inmode)))
+ {
+ rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
+ break;
+ }
}
}
}
@@ -2052,18 +2052,19 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
{
unsigned int i;
- for (i = 0; i < nwords; i++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
- regno + i)
- || fixed_regs[regno + i])
- break;
-
- if (i == nwords)
+ if (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], regno))
{
- if (REG_P (real_out))
- value = real_out;
- else
- value = gen_rtx_REG (outmode, regno);
+ for (i = 0; i < nwords; i++)
+ if (fixed_regs[regno + i])
+ break;
+
+ if (i == nwords)
+ {
+ if (REG_P (real_out))
+ value = real_out;
+ else
+ value = gen_rtx_REG (outmode, regno);
+ }
}
}
@@ -2121,12 +2122,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
{
unsigned int i;
- for (i = 0; i < nwords; i++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
- regno + i))
- break;
-
- if (i == nwords)
+ if (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], regno))
{
/* If we were going to use OUT as the reload reg
and changed our mind, it means OUT is a dummy that
@@ -4635,15 +4631,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
&& TEST_HARD_REG_BIT (reg_class_contents[rld[i].rclass], regno)
&& HARD_REGNO_MODE_OK (regno, rld[i].mode))
{
- int nr = hard_regno_nregs[regno][rld[i].mode];
- int ok = 1, nri;
-
- for (nri = 1; nri < nr; nri ++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].rclass], regno + nri))
- ok = 0;
-
- if (ok)
- rld[i].reg_rtx = dest;
+ rld[i].reg_rtx = dest;
}
}
@@ -1868,7 +1868,6 @@ find_reg (struct insn_chain *chain, int order)
COPY_HARD_REG_SET (not_usable, bad_spill_regs);
IOR_HARD_REG_SET (not_usable, bad_spill_regs_global);
- IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->rclass]);
CLEAR_HARD_REG_SET (used_by_other_reload);
for (k = 0; k < order; k++)
@@ -1888,7 +1887,8 @@ find_reg (struct insn_chain *chain, int order)
unsigned int regno = i;
#endif
- if (! TEST_HARD_REG_BIT (not_usable, regno)
+ if (TEST_HARD_REG_BIT (reg_class_contents[rl->rclass], regno)
+ && ! TEST_HARD_REG_BIT (not_usable, regno)
&& ! TEST_HARD_REG_BIT (used_by_other_reload, regno)
&& HARD_REGNO_MODE_OK (regno, rl->mode))
{
@@ -6265,8 +6265,7 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r,
while (nr > 1)
{
int regno = regnum + nr - 1;
- if (!(TEST_HARD_REG_BIT (reg_class_contents[rclass], regno)
- && spill_reg_order[regno] >= 0
+ if (!(spill_reg_order[regno] >= 0
&& reload_reg_free_p (regno, rld[r].opnum,
rld[r].when_needed)))
break;
@@ -6604,10 +6603,9 @@ choose_reload_regs (struct insn_chain *chain)
last_reg = (GET_MODE (last_reg) == mode
? last_reg : gen_rtx_REG (mode, i));
- bad_for_class = 0;
- for (k = 0; k < nr; k++)
- bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass],
- i+k);
+ bad_for_class =
+ (! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass],
+ i));
/* We found a register that contains the
value we need. If this register is the
@@ -6731,12 +6729,13 @@ choose_reload_regs (struct insn_chain *chain)
int bad_for_class = 0;
int max_regno = regno + rld[r].nregs;
+ bad_for_class =
+ (! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass],
+ regno));
for (i = regno; i < max_regno; i++)
{
regs_used |= TEST_HARD_REG_BIT (reload_reg_used_at_all,
i);
- bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass],
- i);
}
if ((regs_used