diff mbox

[ARM] Work around erratum in VFP9

Message ID 53B5737E.5080906@arm.com
State New
Headers show

Commit Message

Richard Earnshaw July 3, 2014, 3:15 p.m. UTC
The VFP9 floating-point unit (as occasionally used with ARM9 devices)
has an erratum (760019) whereby it is possible for floating-point
division and square-root instructions to be executed twice.  This is not
a problem if the destination register is not used as an input, but can
cause incorrect results if they do.

The safest work-around for this issue is to make the compiler treat
these instructions as early-clobber; this ensures that the conditions
for result corruption cannot occur.

This patch takes that approach, but relaxes back to the original
behaviour when either the architecture level is ARMv6 or higher or the
VFP sub-architecture level is VFPv3 or higher; if either of these are
true then the code cannot run on an affected part.

2014-07-03  Richard Earnshaw  <rearnsha@arm.com>

	* arm.md (arch): Add armv6_or_vfpv3.
	(arch_enabled): Add test for the above.
	* vfp.md (divsf_vfp, divdf_vfp): Add earlyclobber when code can run
	on VFP9.
	(sqrtsf_vfp, sqrtdf_vfp): Likewise.

Committed to trunk.

R.

Comments

Bin.Cheng July 3, 2014, 4:32 p.m. UTC | #1
On Thu, Jul 3, 2014 at 4:15 PM, Richard Earnshaw <rearnsha@arm.com> wrote:
> The VFP9 floating-point unit (as occasionally used with ARM9 devices)
> has an erratum (760019) whereby it is possible for floating-point
> division and square-root instructions to be executed twice.  This is not
> a problem if the destination register is not used as an input, but can
> cause incorrect results if they do.
>
> The safest work-around for this issue is to make the compiler treat
> these instructions as early-clobber; this ensures that the conditions
> for result corruption cannot occur.
>
> This patch takes that approach, but relaxes back to the original
> behaviour when either the architecture level is ARMv6 or higher or the
> VFP sub-architecture level is VFPv3 or higher; if either of these are
> true then the code cannot run on an affected part.
>
> 2014-07-03  Richard Earnshaw  <rearnsha@arm.com>
>
>         * arm.md (arch): Add armv6_or_vfpv3.
>         (arch_enabled): Add test for the above.
>         * vfp.md (divsf_vfp, divdf_vfp): Add earlyclobber when code can run
>         on VFP9.
>         (sqrtsf_vfp, sqrtdf_vfp): Likewise.
Richard, you would need full relative path for back-end files here.

Thanks,
bin
>
> Committed to trunk.
>
> R.
diff mbox

Patch

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 97753ce..674565c 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -127,7 +127,7 @@ 
 ; for ARM or Thumb-2 with arm_arch6, and nov6 for ARM without
 ; arm_arch6.  This attribute is used to compute attribute "enabled",
 ; use type "any" to enable an alternative in all cases.
-(define_attr "arch" "any,a,t,32,t1,t2,v6,nov6,neon_for_64bits,avoid_neon_for_64bits,iwmmxt,iwmmxt2"
+(define_attr "arch" "any,a,t,32,t1,t2,v6,nov6,neon_for_64bits,avoid_neon_for_64bits,iwmmxt,iwmmxt2,armv6_or_vfpv3"
   (const_string "any"))
 
 (define_attr "arch_enabled" "no,yes"
@@ -174,7 +174,12 @@ 
 
 	 (and (eq_attr "arch" "iwmmxt2")
 	      (match_test "TARGET_REALLY_IWMMXT2"))
-	 (const_string "yes")]
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "armv6_or_vfpv3")
+	      (match_test "arm_arch6 || TARGET_VFP3"))
+	 (const_string "yes")
+	]
 
 	(const_string "no")))
 
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index e1a48ee..1c9ff19 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -714,25 +714,30 @@ 
 
 ;; Division insns
 
+; VFP9 Erratum 760019: It's potentially unsafe to overwrite the input
+; operands, so mark the output as early clobber for VFPv2 on ARMv5 or
+; earlier.
 (define_insn "*divsf3_vfp"
-  [(set (match_operand:SF	  0 "s_register_operand" "=t")
-	(div:SF (match_operand:SF 1 "s_register_operand" "t")
-		(match_operand:SF 2 "s_register_operand" "t")))]
+  [(set (match_operand:SF	  0 "s_register_operand" "=&t,t")
+	(div:SF (match_operand:SF 1 "s_register_operand" "t,t")
+		(match_operand:SF 2 "s_register_operand" "t,t")))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
   "fdivs%?\\t%0, %1, %2"
   [(set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")
+   (set_attr "arch" "*,armv6_or_vfpv3")
    (set_attr "type" "fdivs")]
 )
 
 (define_insn "*divdf3_vfp"
-  [(set (match_operand:DF	  0 "s_register_operand" "=w")
-	(div:DF (match_operand:DF 1 "s_register_operand" "w")
-		(match_operand:DF 2 "s_register_operand" "w")))]
+  [(set (match_operand:DF	  0 "s_register_operand" "=&w,w")
+	(div:DF (match_operand:DF 1 "s_register_operand" "w,w")
+		(match_operand:DF 2 "s_register_operand" "w,w")))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fdivd%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")
+   (set_attr "arch" "*,armv6_or_vfpv3")
    (set_attr "type" "fdivd")]
 )
 
@@ -1070,23 +1075,28 @@ 
 
 ;; Sqrt insns.
 
+; VFP9 Erratum 760019: It's potentially unsafe to overwrite the input
+; operands, so mark the output as early clobber for VFPv2 on ARMv5 or
+; earlier.
 (define_insn "*sqrtsf2_vfp"
-  [(set (match_operand:SF	   0 "s_register_operand" "=t")
-	(sqrt:SF (match_operand:SF 1 "s_register_operand" "t")))]
+  [(set (match_operand:SF	   0 "s_register_operand" "=&t,t")
+	(sqrt:SF (match_operand:SF 1 "s_register_operand" "t,t")))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
   "fsqrts%?\\t%0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")
+   (set_attr "arch" "*,armv6_or_vfpv3")
    (set_attr "type" "fsqrts")]
 )
 
 (define_insn "*sqrtdf2_vfp"
-  [(set (match_operand:DF	   0 "s_register_operand" "=w")
-	(sqrt:DF (match_operand:DF 1 "s_register_operand" "w")))]
+  [(set (match_operand:DF	   0 "s_register_operand" "=&w,w")
+	(sqrt:DF (match_operand:DF 1 "s_register_operand" "w,w")))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fsqrtd%?\\t%P0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")
+   (set_attr "arch" "*,armv6_or_vfpv3")
    (set_attr "type" "fsqrtd")]
 )