re PR target/54680 ([SH] Unnecessary int-float-int conversion of fsca fixed point...
authorOleg Endo <olegendo@gcc.gnu.org>
Fri, 12 Oct 2012 23:19:27 +0000 (23:19 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Fri, 12 Oct 2012 23:19:27 +0000 (23:19 +0000)
PR target/54680
* config/sh/sh.c (sh_fsca_sf2int, sh_fsca_int2sf): Fix swapped
comments.
* config/sh/predicates.md (fpul_operand): Add comment.
(fpul_fsca_operand, fsca_scale_factor): New predicates.
* config/sh/sh.md (fsca): Move below sincossf3 expander.  Convert to
insn_and_split.  Use fpul_fsca_operand and fsca_scale_factor predicates.
Simplify fpul operand in splitter.

PR target/54680
* gcc.target/sh/pr54680.c: New.

From-SVN: r192416

gcc/ChangeLog
gcc/config/sh/predicates.md
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr54680.c [new file with mode: 0644]

index 8ece083..a501dec 100644 (file)
@@ -1,3 +1,14 @@
+2012-10-12  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54680
+       * config/sh/sh.c (sh_fsca_sf2int, sh_fsca_int2sf): Fix swapped
+       comments.
+       * config/sh/predicates.md (fpul_operand): Add comment.
+       (fpul_fsca_operand, fsca_scale_factor): New predicates.
+       * config/sh/sh.md (fsca): Move below sincossf3 expander.  Convert to
+       insn_and_split.  Use fpul_fsca_operand and fsca_scale_factor predicates.
+       Simplify fpul operand in splitter.
+
 2012-10-12  Jan Hubicka <jh@suse.cz>
 
        * tree-ssa-threadupdate.c (def_split_header_continue_p): Do not
index 8ada743..cd98055 100644 (file)
          && GET_MODE (op) == PSImode);
 })
 
-;; TODO: Add a comment here.
-
+;; Returns true if OP is an operand that is either the fpul hard reg or
+;; a pseudo.  This prevents combine from propagating function arguments
+;; in hard regs into insns that need the operand in fpul.  If it's a pseudo
+;; reload can fix it up.
 (define_predicate "fpul_operand"
   (match_code "reg")
 {
          && GET_MODE (op) == mode);
 })
 
+;; Returns true if OP is a valid fpul input operand for the fsca insn.
+;; The value in fpul is a fixed-point value and its scaling is described
+;; in the fsca insn by a mult:SF.  To allow pre-scaled fixed-point inputs
+;; in fpul we have to permit things like
+;;   (reg:SI)
+;;   (fix:SF (float:SF (reg:SI)))
+(define_predicate "fpul_fsca_operand"
+  (match_code "fix,reg")
+{
+  if (fpul_operand (op, SImode))
+    return true;
+  if (GET_CODE (op) == FIX && GET_MODE (op) == SImode
+      && GET_CODE (XEXP (op, 0)) == FLOAT && GET_MODE (XEXP (op, 0)) == SFmode)
+    return fpul_fsca_operand (XEXP (XEXP (op, 0), 0),
+                             GET_MODE (XEXP (XEXP (op, 0), 0)));
+  return false;
+})
+
+;; Returns true if OP is a valid constant scale factor for the fsca insn.
+(define_predicate "fsca_scale_factor"
+  (and (match_code "const_double")
+       (match_test "op == sh_fsca_int2sf ()")))
+
 ;; TODO: Add a comment here.
 
 (define_predicate "general_extend_operand"
index 3e6fbdc..b617351 100644 (file)
@@ -12659,11 +12659,9 @@ check_use_sfunc_addr (rtx insn, rtx reg)
   gcc_unreachable ();
 }
 
-/* This function returns a constant rtx that represents pi / 2**15 in
-   SFmode.  it's used to scale SFmode angles, in radians, to a
-   fixed-point signed 16.16-bit fraction of a full circle, i.e., 2*pi
-   maps to 0x10000).  */
-
+/* This function returns a constant rtx that represents 2**15 / pi in
+   SFmode.  It's used to scale a fixed-point signed 16.16-bit fraction
+   of a full circle back to an SFmode value, i.e. 0x10000 maps to 2*pi.  */
 static GTY(()) rtx sh_fsca_sf2int_rtx;
 
 rtx
@@ -12680,11 +12678,10 @@ sh_fsca_sf2int (void)
   return sh_fsca_sf2int_rtx;
 }
 
-/* This function returns a constant rtx that represents 2**15 / pi in
-   SFmode.  it's used to scale a fixed-point signed 16.16-bit fraction
-   of a full circle back to a SFmode value, i.e., 0x10000 maps to
-   2*pi).  */
-
+/* This function returns a constant rtx that represents pi / 2**15 in
+   SFmode.  It's used to scale SFmode angles, in radians, to a
+   fixed-point signed 16.16-bit fraction of a full circle, i.e. 2*pi
+   maps to 0x10000.  */
 static GTY(()) rtx sh_fsca_int2sf_rtx;
 
 rtx
index 0ff6aae..6e168ea 100644 (file)
@@ -12208,22 +12208,6 @@ label:
   [(set_attr "type" "fsrra")
    (set_attr "fp_mode" "single")])
 
-(define_insn "fsca"
-  [(set (match_operand:V2SF 0 "fp_arith_reg_operand" "=f")
-       (vec_concat:V2SF
-        (unspec:SF [(mult:SF
-                     (float:SF (match_operand:SI 1 "fpul_operand" "y"))
-                     (match_operand:SF 2 "immediate_operand" "i"))
-                   ] UNSPEC_FSINA)
-        (unspec:SF [(mult:SF (float:SF (match_dup 1)) (match_dup 2))
-                   ] UNSPEC_FCOSA)))
-   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
-  "TARGET_FPU_ANY && TARGET_FSCA
-   && operands[2] == sh_fsca_int2sf ()"
-  "fsca        fpul,%d0"
-  [(set_attr "type" "fsca")
-   (set_attr "fp_mode" "single")])
-
 ;; When the sincos pattern is defined, the builtin functions sin and cos
 ;; will be expanded to the sincos pattern and one of the output values will
 ;; remain unused.
@@ -12250,6 +12234,38 @@ label:
   DONE;
 })
 
+(define_insn_and_split "fsca"
+  [(set (match_operand:V2SF 0 "fp_arith_reg_operand" "=f")
+       (vec_concat:V2SF
+        (unspec:SF [(mult:SF
+                     (float:SF (match_operand:SI 1 "fpul_fsca_operand" "y"))
+                     (match_operand:SF 2 "fsca_scale_factor" "i"))
+                   ] UNSPEC_FSINA)
+        (unspec:SF [(mult:SF (float:SF (match_dup 1)) (match_dup 2))
+                   ] UNSPEC_FCOSA)))
+   (use (match_operand:PSI 3 "fpscr_operand" "c"))]
+  "TARGET_FPU_ANY && TARGET_FSCA"
+  "fsca        fpul,%d0"
+  "&& !fpul_operand (operands[1], SImode)"
+  [(const_int 0)]
+{
+  /* If operands[1] is something like (fix:SF (float:SF (reg:SI))) reduce it
+     to a simple reg, otherwise reload will have trouble reloading the
+     pseudo into fpul.  */
+  rtx x = XEXP (operands[1], 0);
+  while (x != NULL_RTX && !fpul_operand (x, SImode))
+    {
+      gcc_assert (GET_CODE (x) == FIX || GET_CODE (x) == FLOAT);
+      x = XEXP (x, 0);
+    }
+
+  gcc_assert (x != NULL_RTX && fpul_operand (x, SImode));
+  emit_insn (gen_fsca (operands[0], x, operands[2], operands[3]));
+  DONE;
+}
+  [(set_attr "type" "fsca")
+   (set_attr "fp_mode" "single")])
+
 (define_expand "abssf2"
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "")
        (abs:SF (match_operand:SF 1 "fp_arith_reg_operand" "")))]
index 2f4633e..9662467 100644 (file)
@@ -1,3 +1,8 @@
+2012-10-12  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54680
+       * gcc.target/sh/pr54680.c: New.
+
 2012-10-12  Jan Hubicka <jh@suse.cz>
 
        * gcc.dg/webizer.c: New testcase.
diff --git a/gcc/testsuite/gcc.target/sh/pr54680.c b/gcc/testsuite/gcc.target/sh/pr54680.c
new file mode 100644 (file)
index 0000000..27c44d3
--- /dev/null
@@ -0,0 +1,66 @@
+/* Verify that the fsca input value is not converted to float and then back
+   to int.  Notice that we can't count just "lds" insns because mode switches
+   use "lds.l".  */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2 -mfsca -funsafe-math-optimizations" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m1" "-m2*" "-m3*" "-m4al" "*nofpu" "-m4-340*" "-m4-400*" "-m4-500*" "-m5*" } { "" } }  */
+/* { dg-final { scan-assembler-times "fsca" 7 } } */
+/* { dg-final { scan-assembler-times "shad" 1 } } */
+/* { dg-final { scan-assembler-times "lds\t" 6 } } */
+/* { dg-final { scan-assembler-times "fmul" 2 } } */
+/* { dg-final { scan-assembler-times "ftrc" 1 } } */
+
+#include <math.h>
+
+static const float pi = 3.14159265359f;
+
+float
+test00 (int x)
+{
+  /* 1x shad, 1x lds, 1x fsca  */
+  return sinf ( (x >> 8) * (2*pi) / (1 << 16));
+}
+
+float
+test01 (int x)
+{
+  /* 1x lds, 1x fsca  */
+  return sinf (x * (2*pi) / 65536);
+}
+
+float
+test02 (int x)
+{
+  /* 1x lds, 1x fsca  */
+  return sinf (x * (2*pi / 65536));
+}
+
+float
+test03 (int x)
+{
+  /* 1x lds, 1x fsca  */
+  float scale = 2*pi / 65536;
+  return sinf (x * scale);
+}
+
+float
+test04 (int x)
+{
+  /* 1x lds, 1x fsca  */
+  return cosf (x / 65536.0f * 2*pi);
+}
+
+float
+test05 (int x)
+{
+  /* 1x lds, 1x fsca, 1x fmul  */
+  float scale = 2*pi / 65536;
+  return sinf (x * scale) * cosf (x * scale);
+}
+
+float
+test_06 (float x)
+{
+  /* 1x fmul, 1x ftrc, 1x fsca  */
+  return sinf (x);
+}