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
This commit is contained in:
parent
9ee5337dd5
commit
7075c79290
@ -1,3 +1,12 @@
|
||||
2014-03-20 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* 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 <ebotcazou@adacore.com>
|
||||
|
||||
* calls.c (store_one_arg): Remove incorrect const qualification on the
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user