mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-27 14:04:42 +08:00
Workaround for Itanium A/B step errata
From-SVN: r37482
This commit is contained in:
parent
4e7b85edbe
commit
099dde21d2
@ -1,3 +1,20 @@
|
||||
2000-11-15 Bernd Schmidt <bernds@redhat.co.uk>
|
||||
|
||||
* ia64.c (struct group): New structure.
|
||||
(last_group): New static array.
|
||||
(group_idx): New static variable.
|
||||
(emit_group_barrier_after, errata_find_address_regs, errata_emit_nops):
|
||||
New static functions.
|
||||
(emit_insn_group_barriers): Initialize and keep track of group_idx
|
||||
and last_group.
|
||||
Call errata_emit_nops if TARGET_B_STEP or TARGET_A_STEP.
|
||||
Replace all calls to emit_insn_after that emit a group barrier to use
|
||||
emit_group_barrier_after.
|
||||
* ia64.h (MASK_B_STEP): New.
|
||||
(other MASK_XXX macros): Renumbered.
|
||||
(TARGET_B_STEP): New.
|
||||
(TARGET_SWITCHES): Add -mb-step.
|
||||
|
||||
2000-11-15 Fred Fish <fnf@be.com>
|
||||
|
||||
* fixinc/mkfixinc.sh (fixincludes): Add *-*-beos* to list of
|
||||
|
@ -4279,6 +4279,128 @@ rtx_needs_barrier (x, flags, pred)
|
||||
return need_barrier;
|
||||
}
|
||||
|
||||
/* This structure is used to track some details about the previous insns
|
||||
groups so we can determine if it may be necessary to insert NOPs to
|
||||
workaround hardware errata. */
|
||||
static struct group
|
||||
{
|
||||
HARD_REG_SET p_reg_set;
|
||||
HARD_REG_SET gr_reg_conditionally_set;
|
||||
} last_group[3];
|
||||
|
||||
/* Index into the last_group array. */
|
||||
static int group_idx;
|
||||
|
||||
static void emit_group_barrier_after PARAMS ((rtx));
|
||||
static int errata_find_address_regs PARAMS ((rtx *, void *));
|
||||
static void errata_emit_nops PARAMS ((rtx));
|
||||
|
||||
/* Create a new group barrier, emit it after AFTER, and advance group_idx. */
|
||||
static void
|
||||
emit_group_barrier_after (after)
|
||||
rtx after;
|
||||
{
|
||||
emit_insn_after (gen_insn_group_barrier (), after);
|
||||
group_idx = (group_idx + 1) % 3;
|
||||
memset (last_group + group_idx, 0, sizeof last_group[group_idx]);
|
||||
}
|
||||
|
||||
/* Called through for_each_rtx; determines if a hard register that was
|
||||
conditionally set in the previous group is used as an address register.
|
||||
It ensures that for_each_rtx returns 1 in that case. */
|
||||
static int
|
||||
errata_find_address_regs (xp, data)
|
||||
rtx *xp;
|
||||
void *data ATTRIBUTE_UNUSED;
|
||||
{
|
||||
rtx x = *xp;
|
||||
if (GET_CODE (x) != MEM)
|
||||
return 0;
|
||||
x = XEXP (x, 0);
|
||||
if (GET_CODE (x) == POST_MODIFY)
|
||||
x = XEXP (x, 0);
|
||||
if (GET_CODE (x) == REG)
|
||||
{
|
||||
struct group *prev_group = last_group + (group_idx + 2) % 3;
|
||||
if (TEST_HARD_REG_BIT (prev_group->gr_reg_conditionally_set,
|
||||
REGNO (x)))
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called for each insn; this function keeps track of the state in
|
||||
last_group and emits additional NOPs if necessary to work around
|
||||
an Itanium A/B step erratum. */
|
||||
static void
|
||||
errata_emit_nops (insn)
|
||||
rtx insn;
|
||||
{
|
||||
struct group *this_group = last_group + group_idx;
|
||||
struct group *prev_group = last_group + (group_idx + 2) % 3;
|
||||
rtx pat = PATTERN (insn);
|
||||
rtx cond = GET_CODE (pat) == COND_EXEC ? COND_EXEC_TEST (pat) : 0;
|
||||
rtx real_pat = cond ? COND_EXEC_CODE (pat) : pat;
|
||||
enum attr_type type;
|
||||
rtx set = real_pat;
|
||||
|
||||
if (GET_CODE (real_pat) == USE
|
||||
|| GET_CODE (real_pat) == CLOBBER
|
||||
|| GET_CODE (real_pat) == ASM_INPUT
|
||||
|| GET_CODE (real_pat) == ADDR_VEC
|
||||
|| GET_CODE (real_pat) == ADDR_DIFF_VEC
|
||||
|| asm_noperands (insn) >= 0)
|
||||
return;
|
||||
|
||||
/* single_set doesn't work for COND_EXEC insns, so we have to duplicate
|
||||
parts of it. */
|
||||
|
||||
if (GET_CODE (set) == PARALLEL)
|
||||
{
|
||||
int i;
|
||||
set = XVECEXP (real_pat, 0, 0);
|
||||
for (i = 1; i < XVECLEN (real_pat, 0); i++)
|
||||
if (GET_CODE (XVECEXP (real_pat, 0, i)) != USE
|
||||
&& GET_CODE (XVECEXP (real_pat, 0, i)) != CLOBBER)
|
||||
{
|
||||
set = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (set && GET_CODE (set) != SET)
|
||||
set = 0;
|
||||
|
||||
type = get_attr_type (insn);
|
||||
|
||||
if (type == TYPE_F
|
||||
&& set && REG_P (SET_DEST (set)) && PR_REGNO_P (REGNO (SET_DEST (set))))
|
||||
SET_HARD_REG_BIT (this_group->p_reg_set, REGNO (SET_DEST (set)));
|
||||
|
||||
if ((type == TYPE_M || type == TYPE_A) && cond && set
|
||||
&& REG_P (SET_DEST (set))
|
||||
&& GET_CODE (SET_SRC (set)) != PLUS
|
||||
&& GET_CODE (SET_SRC (set)) != MINUS
|
||||
&& (GET_CODE (SET_SRC (set)) != MEM
|
||||
|| GET_CODE (XEXP (SET_SRC (set), 0)) != POST_MODIFY)
|
||||
&& GENERAL_REGNO_P (REGNO (SET_DEST (set))))
|
||||
{
|
||||
if (GET_RTX_CLASS (GET_CODE (cond)) != '<'
|
||||
|| ! REG_P (XEXP (cond, 0)))
|
||||
abort ();
|
||||
|
||||
if (TEST_HARD_REG_BIT (prev_group->p_reg_set, REGNO (XEXP (cond, 0))))
|
||||
SET_HARD_REG_BIT (this_group->gr_reg_conditionally_set, REGNO (SET_DEST (set)));
|
||||
}
|
||||
if (for_each_rtx (&real_pat, errata_find_address_regs, NULL))
|
||||
{
|
||||
emit_insn_before (gen_insn_group_barrier (), insn);
|
||||
emit_insn_before (gen_nop (), insn);
|
||||
emit_insn_before (gen_insn_group_barrier (), insn);
|
||||
}
|
||||
}
|
||||
|
||||
/* INSNS is an chain of instructions. Scan the chain, and insert stop bits
|
||||
as necessary to eliminate dependendencies. */
|
||||
|
||||
@ -4290,12 +4412,18 @@ emit_insn_group_barriers (insns)
|
||||
|
||||
memset (rws_sum, 0, sizeof (rws_sum));
|
||||
|
||||
group_idx = 0;
|
||||
memset (last_group, 0, sizeof last_group);
|
||||
|
||||
prev_insn = 0;
|
||||
for (insn = insns; insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
int need_barrier = 0;
|
||||
struct reg_flags flags;
|
||||
|
||||
if ((TARGET_B_STEP || TARGET_A_STEP) && INSN_P (insn))
|
||||
errata_emit_nops (insn);
|
||||
|
||||
memset (&flags, 0, sizeof (flags));
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
@ -4310,7 +4438,7 @@ emit_insn_group_barriers (insns)
|
||||
need_barrier = rws_access_regno (AR_LC_REGNUM, flags, 0);
|
||||
if (need_barrier)
|
||||
{
|
||||
emit_insn_after (gen_insn_group_barrier (), insn);
|
||||
emit_group_barrier_after (insn);
|
||||
memset (rws_sum, 0, sizeof(rws_sum));
|
||||
prev_insn = NULL_RTX;
|
||||
}
|
||||
@ -4328,7 +4456,7 @@ emit_insn_group_barriers (insns)
|
||||
/* PREV_INSN null can happen if the very first insn is a
|
||||
volatile asm. */
|
||||
if (prev_insn)
|
||||
emit_insn_after (gen_insn_group_barrier (), prev_insn);
|
||||
emit_group_barrier_after (prev_insn);
|
||||
memcpy (rws_sum, rws_insn, sizeof (rws_sum));
|
||||
}
|
||||
|
||||
@ -4354,7 +4482,7 @@ emit_insn_group_barriers (insns)
|
||||
}
|
||||
if (need_barrier)
|
||||
{
|
||||
emit_insn_after (gen_insn_group_barrier (), insn);
|
||||
emit_group_barrier_after (insn);
|
||||
memset (rws_sum, 0, sizeof (rws_sum));
|
||||
prev_insn = NULL_RTX;
|
||||
}
|
||||
@ -4412,7 +4540,7 @@ emit_insn_group_barriers (insns)
|
||||
/* PREV_INSN null can happen if the very first insn is a
|
||||
volatile asm. */
|
||||
if (prev_insn)
|
||||
emit_insn_after (gen_insn_group_barrier (), prev_insn);
|
||||
emit_group_barrier_after (prev_insn);
|
||||
memcpy (rws_sum, rws_insn, sizeof (rws_sum));
|
||||
}
|
||||
prev_insn = insn;
|
||||
|
@ -55,13 +55,15 @@ extern int target_flags;
|
||||
|
||||
#define MASK_A_STEP 0x00000020 /* Emit code for Itanium A step. */
|
||||
|
||||
#define MASK_REG_NAMES 0x00000040 /* Use in/loc/out register names. */
|
||||
#define MASK_B_STEP 0x00000040 /* Emit code for Itanium B step. */
|
||||
|
||||
#define MASK_NO_SDATA 0x00000080 /* Disable sdata/scommon/sbss. */
|
||||
#define MASK_REG_NAMES 0x00000080 /* Use in/loc/out register names. */
|
||||
|
||||
#define MASK_CONST_GP 0x00000100 /* treat gp as program-wide constant */
|
||||
#define MASK_NO_SDATA 0x00000100 /* Disable sdata/scommon/sbss. */
|
||||
|
||||
#define MASK_AUTO_PIC 0x00000200 /* generate automatically PIC */
|
||||
#define MASK_CONST_GP 0x00000200 /* treat gp as program-wide constant */
|
||||
|
||||
#define MASK_AUTO_PIC 0x00000400 /* generate automatically PIC */
|
||||
|
||||
#define MASK_INLINE_DIV_LAT 0x00000400 /* inline div, min latency. */
|
||||
|
||||
@ -81,6 +83,8 @@ extern int target_flags;
|
||||
|
||||
#define TARGET_A_STEP (target_flags & MASK_A_STEP)
|
||||
|
||||
#define TARGET_B_STEP (target_flags & MASK_B_STEP)
|
||||
|
||||
#define TARGET_REG_NAMES (target_flags & MASK_REG_NAMES)
|
||||
|
||||
#define TARGET_NO_SDATA (target_flags & MASK_NO_SDATA)
|
||||
@ -124,6 +128,8 @@ extern int target_flags;
|
||||
N_("Don't emit stop bits before and after volatile extended asms") }, \
|
||||
{ "a-step", MASK_A_STEP, \
|
||||
N_("Emit code for Itanium (TM) processor A step")}, \
|
||||
{ "b-step", MASK_B_STEP, \
|
||||
N_("Emit code for Itanium (TM) processor B step")}, \
|
||||
{ "register-names", MASK_REG_NAMES, \
|
||||
N_("Use in/loc/out register names")}, \
|
||||
{ "no-sdata", MASK_NO_SDATA, \
|
||||
|
Loading…
Reference in New Issue
Block a user