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:
Eric Botcazou 2014-03-20 11:39:39 +00:00 committed by Eric Botcazou
parent 9ee5337dd5
commit 7075c79290
3 changed files with 115 additions and 2 deletions

View File

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

View File

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

View File

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