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  <rearn...@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.
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")]
 )
 

Reply via email to