From: Bernd Schmidt Date: Wed, 28 Mar 2001 14:25:37 +0000 (+0000) Subject: Fix missing barrier problem X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=112333d3e40032c6d3fbf393a247c2b7f8ab9d98;p=gcc.git Fix missing barrier problem From-SVN: r40932 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ed0b19df34d..8c76b2e0c85 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,15 @@ * cselib.c (hash_rtx): Don't do tail recursion elimination by hand. + * config/ia64/ia64.c (update_set_flags): New function, broken out of + rtx_needs_barrier. + (set_src_needs_barrier): Likewise. + (rtx_needs_barrier): For SET case, use these two functions. Rework + PARALLEL case to handle all inputs before all outputs. + (emit_insn_group_barriers): Call init_insn_group_barriers only if we + saw a label and no stop bit since then. + (maybe_rotate, process_epilogue): Add prototypes. + 2001-03-28 Richard Henderson * config/rs6000/rs6000.h (EPILOGUE_USES): Use TARGET_AIX, diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 443f9bc39dd..37943864eb3 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -118,6 +118,7 @@ static void ia64_free_machine_status PARAMS ((struct function *)); static void emit_insn_group_barriers PARAMS ((FILE *, rtx)); static void emit_all_insn_group_barriers PARAMS ((FILE *, rtx)); static void emit_predicate_relation_info PARAMS ((void)); +static void process_epilogue PARAMS ((void)); static int process_set PARAMS ((FILE *, rtx)); static rtx ia64_expand_fetch_and_op PARAMS ((optab, enum machine_mode, @@ -3826,6 +3827,8 @@ static void rws_update PARAMS ((struct reg_write_state *, int, struct reg_flags, int)); static int rws_access_regno PARAMS ((int, struct reg_flags, int)); static int rws_access_reg PARAMS ((rtx, struct reg_flags, int)); +static void update_set_flags PARAMS ((rtx, struct reg_flags *, int *, rtx *)); +static int set_src_needs_barrier PARAMS ((rtx, struct reg_flags, int, rtx)); static int rtx_needs_barrier PARAMS ((rtx, struct reg_flags, int)); static void init_insn_group_barriers PARAMS ((void)); static int group_barrier_needed_p PARAMS ((rtx)); @@ -3994,6 +3997,132 @@ rws_access_reg (reg, flags, pred) } } +/* Examine X, which is a SET rtx, and update the flags, the predicate, and + the condition, stored in *PFLAGS, *PPRED and *PCOND. */ + +static void +update_set_flags (x, pflags, ppred, pcond) + rtx x; + struct reg_flags *pflags; + int *ppred; + rtx *pcond; +{ + rtx src = SET_SRC (x); + + *pcond = 0; + + switch (GET_CODE (src)) + { + case CALL: + return; + + case IF_THEN_ELSE: + if (SET_DEST (x) == pc_rtx) + /* X is a conditional branch. */ + return; + else + { + int is_complemented = 0; + + /* X is a conditional move. */ + rtx cond = XEXP (src, 0); + if (GET_CODE (cond) == EQ) + is_complemented = 1; + cond = XEXP (cond, 0); + if (GET_CODE (cond) != REG + && REGNO_REG_CLASS (REGNO (cond)) != PR_REGS) + abort (); + *pcond = cond; + if (XEXP (src, 1) == SET_DEST (x) + || XEXP (src, 2) == SET_DEST (x)) + { + /* X is a conditional move that conditionally writes the + destination. */ + + /* We need another complement in this case. */ + if (XEXP (src, 1) == SET_DEST (x)) + is_complemented = ! is_complemented; + + *ppred = REGNO (cond); + if (is_complemented) + ++*ppred; + } + + /* ??? If this is a conditional write to the dest, then this + instruction does not actually read one source. This probably + doesn't matter, because that source is also the dest. */ + /* ??? Multiple writes to predicate registers are allowed + if they are all AND type compares, or if they are all OR + type compares. We do not generate such instructions + currently. */ + } + /* ... fall through ... */ + + default: + if (GET_RTX_CLASS (GET_CODE (src)) == '<' + && GET_MODE_CLASS (GET_MODE (XEXP (src, 0))) == MODE_FLOAT) + /* Set pflags->is_fp to 1 so that we know we're dealing + with a floating point comparison when processing the + destination of the SET. */ + pflags->is_fp = 1; + + /* Discover if this is a parallel comparison. We only handle + and.orcm and or.andcm at present, since we must retain a + strict inverse on the predicate pair. */ + else if (GET_CODE (src) == AND) + pflags->is_and = 1; + else if (GET_CODE (src) == IOR) + pflags->is_or = 1; + + break; + } +} + +/* Subroutine of rtx_needs_barrier; this function determines whether the + source of a given SET rtx found in X needs a barrier. FLAGS and PRED + are as in rtx_needs_barrier. COND is an rtx that holds the condition + for this insn. */ + +static int +set_src_needs_barrier (x, flags, pred, cond) + rtx x; + struct reg_flags flags; + int pred; + rtx cond; +{ + int need_barrier = 0; + rtx dst; + rtx src = SET_SRC (x); + + if (GET_CODE (src) == CALL) + /* We don't need to worry about the result registers that + get written by subroutine call. */ + return rtx_needs_barrier (src, flags, pred); + else if (SET_DEST (x) == pc_rtx) + { + /* X is a conditional branch. */ + /* ??? This seems redundant, as the caller sets this bit for + all JUMP_INSNs. */ + flags.is_branch = 1; + return rtx_needs_barrier (src, flags, pred); + } + + need_barrier = rtx_needs_barrier (src, flags, pred); + + /* This instruction unconditionally uses a predicate register. */ + if (cond) + need_barrier |= rws_access_reg (cond, flags, 0); + + dst = SET_DEST (x); + if (GET_CODE (dst) == ZERO_EXTRACT) + { + need_barrier |= rtx_needs_barrier (XEXP (dst, 1), flags, pred); + need_barrier |= rtx_needs_barrier (XEXP (dst, 2), flags, pred); + dst = XEXP (dst, 0); + } + return need_barrier; +} + /* Handle an access to rtx X of type FLAGS using predicate register PRED. Return 1 is this access creates a dependency with an earlier instruction in the same group. */ @@ -4009,7 +4138,6 @@ rtx_needs_barrier (x, flags, pred) int need_barrier = 0; const char *format_ptr; struct reg_flags new_flags; - rtx src, dst; rtx cond = 0; if (! x) @@ -4019,95 +4147,14 @@ rtx_needs_barrier (x, flags, pred) switch (GET_CODE (x)) { - case SET: - src = SET_SRC (x); - switch (GET_CODE (src)) - { - case CALL: - /* We don't need to worry about the result registers that - get written by subroutine call. */ - need_barrier = rtx_needs_barrier (src, flags, pred); - return need_barrier; - - case IF_THEN_ELSE: - if (SET_DEST (x) == pc_rtx) - { - /* X is a conditional branch. */ - /* ??? This seems redundant, as the caller sets this bit for - all JUMP_INSNs. */ - new_flags.is_branch = 1; - need_barrier = rtx_needs_barrier (src, new_flags, pred); - return need_barrier; - } - else - { - /* X is a conditional move. */ - cond = XEXP (src, 0); - if (GET_CODE (cond) == EQ) - is_complemented = 1; - cond = XEXP (cond, 0); - if (GET_CODE (cond) != REG - && REGNO_REG_CLASS (REGNO (cond)) != PR_REGS) - abort (); - - if (XEXP (src, 1) == SET_DEST (x) - || XEXP (src, 2) == SET_DEST (x)) - { - /* X is a conditional move that conditionally writes the - destination. */ - - /* We need another complement in this case. */ - if (XEXP (src, 1) == SET_DEST (x)) - is_complemented = ! is_complemented; - - pred = REGNO (cond); - if (is_complemented) - ++pred; - } - - /* ??? If this is a conditional write to the dest, then this - instruction does not actually read one source. This probably - doesn't matter, because that source is also the dest. */ - /* ??? Multiple writes to predicate registers are allowed - if they are all AND type compares, or if they are all OR - type compares. We do not generate such instructions - currently. */ - } - /* ... fall through ... */ - - default: - if (GET_RTX_CLASS (GET_CODE (src)) == '<' - && GET_MODE_CLASS (GET_MODE (XEXP (src, 0))) == MODE_FLOAT) - /* Set new_flags.is_fp to 1 so that we know we're dealing - with a floating point comparison when processing the - destination of the SET. */ - new_flags.is_fp = 1; - - /* Discover if this is a parallel comparison. We only handle - and.orcm and or.andcm at present, since we must retain a - strict inverse on the predicate pair. */ - else if (GET_CODE (src) == AND) - new_flags.is_and = flags.is_and = 1; - else if (GET_CODE (src) == IOR) - new_flags.is_or = flags.is_or = 1; - - break; - } - need_barrier = rtx_needs_barrier (src, flags, pred); - - /* This instruction unconditionally uses a predicate register. */ - if (cond) - need_barrier |= rws_access_reg (cond, flags, 0); - - dst = SET_DEST (x); - if (GET_CODE (dst) == ZERO_EXTRACT) + case SET: + update_set_flags (x, &new_flags, &pred, &cond); + need_barrier = set_src_needs_barrier (x, new_flags, pred, cond); + if (GET_CODE (SET_SRC (x)) != CALL) { - need_barrier |= rtx_needs_barrier (XEXP (dst, 1), flags, pred); - need_barrier |= rtx_needs_barrier (XEXP (dst, 2), flags, pred); - dst = XEXP (dst, 0); + new_flags.is_write = 1; + need_barrier |= rtx_needs_barrier (SET_DEST (x), new_flags, pred); } - new_flags.is_write = 1; - need_barrier |= rtx_needs_barrier (dst, new_flags, pred); break; case CALL: @@ -4180,8 +4227,33 @@ rtx_needs_barrier (x, flags, pred) case PARALLEL: for (i = XVECLEN (x, 0) - 1; i >= 0; --i) - if (rtx_needs_barrier (XVECEXP (x, 0, i), flags, pred)) - need_barrier = 1; + { + rtx pat = XVECEXP (x, 0, i); + if (GET_CODE (pat) == SET) + { + update_set_flags (pat, &new_flags, &pred, &cond); + need_barrier |= set_src_needs_barrier (pat, new_flags, pred, cond); + } + else if (GET_CODE (pat) == USE || GET_CODE (pat) == CALL) + need_barrier |= rtx_needs_barrier (pat, flags, pred); + else if (GET_CODE (pat) != CLOBBER && GET_CODE (pat) != RETURN) + abort (); + } + for (i = XVECLEN (x, 0) - 1; i >= 0; --i) + { + rtx pat = XVECEXP (x, 0, i); + if (GET_CODE (pat) == SET) + { + if (GET_CODE (SET_SRC (pat)) != CALL) + { + new_flags.is_write = 1; + need_barrier |= rtx_needs_barrier (SET_DEST (pat), new_flags, + pred); + } + } + else if (GET_CODE (pat) == CLOBBER) + need_barrier |= rtx_needs_barrier (pat, flags, pred); + } break; case SUBREG: @@ -4532,9 +4604,10 @@ emit_insn_group_barriers (dump, insns) INSN_UID (last_label)); emit_insn_before (gen_insn_group_barrier (GEN_INT (3)), last_label); insn = last_label; + + init_insn_group_barriers (); + last_label = 0; } - init_insn_group_barriers (); - last_label = 0; } } } @@ -4783,9 +4856,7 @@ static int itanium_split_issue PARAMS ((const struct ia64_packet *, int)); static rtx ia64_single_set PARAMS ((rtx)); static int insn_matches_slot PARAMS ((const struct ia64_packet *, enum attr_type, int, rtx)); static void ia64_emit_insn_before PARAMS ((rtx, rtx)); -#if 0 -static rtx gen_nop_type PARAMS ((enum attr_type)); -#endif +static void maybe_rotate PARAMS ((FILE *)); static void finish_last_head PARAMS ((FILE *, int)); static void rotate_one_bundle PARAMS ((FILE *)); static void rotate_two_bundles PARAMS ((FILE *));