From: Eric Botcazou Date: Thu, 20 Mar 2014 11:39:39 +0000 (+0000) Subject: sparc.c (sparc_do_work_around_errata): Implement work around for store forwarding... X-Git-Tag: releases/gcc-4.9.0~375 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7075c7929077a12412742ba1179b75d1a55348ac;p=thirdparty%2Fgcc.git sparc.c (sparc_do_work_around_errata): Implement work around for store forwarding issue in the FPU on the UT699. * config/sparc/sparc.c (sparc_do_work_around_errata): Implement work around for store forwarding issue in the FPU on the UT699. * config/sparc/sparc.md (in_branch_delay): Return false for single FP loads and operations if -mfix-ut699 is specified. (divtf3_hq): Tweak attribute. (sqrttf2_hq): Likewise. From-SVN: r208695 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f0640642d88d..c35b8245c828 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2014-03-20 Eric Botcazou + + * config/sparc/sparc.c (sparc_do_work_around_errata): Implement work + around for store forwarding issue in the FPU on the UT699. + * config/sparc/sparc.md (in_branch_delay): Return false for single FP + loads and operations if -mfix-ut699 is specified. + (divtf3_hq): Tweak attribute. + (sqrttf2_hq): Likewise. + 2014-03-20 Eric Botcazou * calls.c (store_one_arg): Remove incorrect const qualification on the diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 12b35f36b8ce..f52b9761a1ae 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -1012,6 +1012,106 @@ sparc_do_work_around_errata (void) } } + /* Look for a single-word load/operation into an FP register. */ + else if (sparc_fix_ut699 + && NONJUMP_INSN_P (insn) + && (set = single_set (insn)) != NULL_RTX + && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 + && REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) > 31) + { + /* Number of instructions in the problematic window. */ + const int n_insns = 4; + /* The problematic combination is with the sibling FP register. */ + const unsigned int x = REGNO (SET_DEST (set)); + const unsigned int y = x ^ 1; + rtx after; + int i; + + next = next_active_insn (insn); + if (!next) + break; + /* If the insn is a branch, then it cannot be problematic. */ + if (!NONJUMP_INSN_P (next) || GET_CODE (PATTERN (next)) == SEQUENCE) + continue; + + /* Look for a second load/operation into the sibling FP register. */ + if (!((set = single_set (next)) != NULL_RTX + && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 + && REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) == y)) + continue; + + /* Look for a (possible) store from the FP register in the next N + instructions, but bail out if it is again modified or if there + is a store from the sibling FP register before this store. */ + for (after = next, i = 0; i < n_insns; i++) + { + bool branch_p; + + after = next_active_insn (after); + if (!after) + break; + + /* This is a branch with an empty delay slot. */ + if (!NONJUMP_INSN_P (after)) + { + if (++i == n_insns) + break; + branch_p = true; + after = NULL_RTX; + } + /* This is a branch with a filled delay slot. */ + else if (GET_CODE (PATTERN (after)) == SEQUENCE) + { + if (++i == n_insns) + break; + branch_p = true; + after = XVECEXP (PATTERN (after), 0, 1); + } + /* This is a regular instruction. */ + else + branch_p = false; + + if (after && (set = single_set (after)) != NULL_RTX) + { + const rtx src = SET_SRC (set); + const rtx dest = SET_DEST (set); + const unsigned int size = GET_MODE_SIZE (GET_MODE (dest)); + + /* If the FP register is again modified before the store, + then the store isn't affected. */ + if (REG_P (dest) + && (REGNO (dest) == x + || (REGNO (dest) == y && size == 8))) + break; + + if (MEM_P (dest) && REG_P (src)) + { + /* If there is a store from the sibling FP register + before the store, then the store is not affected. */ + if (REGNO (src) == y || (REGNO (src) == x && size == 8)) + break; + + /* Otherwise, the store is affected. */ + if (REGNO (src) == x && size == 4) + { + insert_nop = true; + break; + } + } + } + + /* If we have a branch in the first M instructions, then we + cannot see the (M+2)th instruction so we play safe. */ + if (branch_p && i <= (n_insns - 2)) + { + insert_nop = true; + break; + } + } + } + else next = NEXT_INSN (insn); diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 7f4bd81b7f8b..8b6c647fc008 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -462,6 +462,10 @@ (const_string "false") (and (eq_attr "fix_ut699" "true") (eq_attr "type" "load,sload")) (const_string "false") + (and (eq_attr "fix_ut699" "true") + (and (eq_attr "type" "fpload,fp,fpmove,fpmul,fpdivs,fpsqrts") + (eq_attr "fptype" "single"))) + (const_string "false") (eq_attr "length" "1") (const_string "true") ] (const_string "false"))) @@ -5513,7 +5517,7 @@ (match_operand:TF 2 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" "fdivq\t%1, %2, %0" - [(set_attr "type" "fpdivd")]) + [(set_attr "type" "fpdivs")]) (define_expand "divdf3" [(set (match_operand:DF 0 "register_operand" "=e") @@ -5744,7 +5748,7 @@ (sqrt:TF (match_operand:TF 1 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" "fsqrtq\t%1, %0" - [(set_attr "type" "fpsqrtd")]) + [(set_attr "type" "fpsqrts")]) (define_expand "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=e")