diff options
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/config/ia64/ia64.c | 136 | ||||
-rw-r--r-- | gcc/config/ia64/ia64.h | 14 |
3 files changed, 159 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 247d0e8..c9d8ff6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 47b9902..87cc12d 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -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; diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index 7ddb802..1f9250f 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -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, \ |