Workaround for Itanium A/B step errata

From-SVN: r37482
This commit is contained in:
Bernd Schmidt 2000-11-15 17:29:00 +00:00 committed by Bernd Schmidt
parent 4e7b85edbe
commit 099dde21d2
3 changed files with 159 additions and 8 deletions

View File

@ -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

View File

@ -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;

View File

@ -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, \