Hi all,
This patch uses the new ARMv8 AArch32 vsel instruction to implement
conditional moves of floating point numbers.
For example, an instruction of the form:
        vsel<cond>.f32  s0, s1, s2
means
        s0 := cond ? s1 : s2

This can be useful, among other places, in Thumb2 because it doesn't require
an enclosing IT block.
A small catch: The condition code used in vsel can only be one of {GE, GT,
EQ, VS}. If we want to use their negations {LT, LE, NE, VC} we just flip the
source operands.
A new predicate is introduced that checks that the comparison yields an ARM
condition code in the set {GE, GT, EQ, VS, LT, LE, NE, VC}.

New compilation tests are added. They pass on a model and no new regressions
on arm-none-eabi with qemu.

Ok for trunk?

Thanks,
Kyrill

gcc/ChangeLog

2013-01-30  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

        * config/arm/arm.md (f_sels, f_seld): New types.
        (*cmov<mode>): New pattern.
        * config/arm/predicates.md (arm_vsel_comparison_operator): New
predicate.      


gcc/testsuite/ChangeLog

2013-01-30  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

        * gcc.target/arm/vseleqdf.c: New test.
        * gcc.target/arm/vseleqsf.c: Likewise.
        * gcc.target/arm/vselgedf.c: Likewise.
        * gcc.target/arm/vselgesf.c: Likewise.
        * gcc.target/arm/vselgtdf.c: Likewise.
        * gcc.target/arm/vselgtsf.c: Likewise.
        * gcc.target/arm/vselledf.c: Likewise.
        * gcc.target/arm/vsellesf.c: Likewise.
        * gcc.target/arm/vselltdf.c: Likewise.
        * gcc.target/arm/vselltsf.c: Likewise.
        * gcc.target/arm/vselnedf.c: Likewise.
        * gcc.target/arm/vselnesf.c: Likewise.
        * gcc.target/arm/vselvcdf.c: Likewise.
        * gcc.target/arm/vselvcsf.c: Likewise.
        * gcc.target/arm/vselvsdf.c: Likewise.
        * gcc.target/arm/vselvssf.c: Likewise.
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index ac507ef..a6bd8bc 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -388,6 +388,8 @@
   f_2_r,\
   r_2_f,\
   f_cvt,\
+  f_sels,\
+  f_seld,\
   branch,\
   call,\
   load_byte,\
@@ -8140,6 +8142,39 @@
   }"
 )
 
+(define_insn "*cmov<mode>"
+    [(set (match_operand:SDF 0 "s_register_operand" "=<F_constraint>")
+       (if_then_else:SDF (match_operator 1 "arm_vsel_comparison_operator"
+                         [(match_operand 2 "cc_register" "") (const_int 0)])
+                         (match_operand:SDF 3 "s_register_operand"
+                                             "<F_constraint>")
+                         (match_operand:SDF 4 "s_register_operand"
+                                             "<F_constraint>")))]
+  "TARGET_HARD_FLOAT && TARGET_FPU_ARMV8 <vfp_double_cond>"
+  "*
+  {
+    enum arm_cond_code code = maybe_get_arm_condition_code (operands[1]);
+    switch (code)
+      {
+      case ARM_GE:
+      case ARM_GT:
+      case ARM_EQ:
+      case ARM_VS:
+        return \"vsel%d1.<V_if_elem>\\t%<V_reg>0, %<V_reg>3, %<V_reg>4\";
+      case ARM_LT:
+      case ARM_LE:
+      case ARM_NE:
+      case ARM_VC:
+        return \"vsel%D1.<V_if_elem>\\t%<V_reg>0, %<V_reg>4, %<V_reg>3\";
+      default:
+        gcc_unreachable ();
+      }
+    return \"\";
+  }"
+  [(set_attr "conds" "use")
+   (set_attr "type" "f_sel<vfp_type>")]
+)
+
 (define_insn "*movsicc_insn"
   [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r")
        (if_then_else:SI
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index 8f49450..898f558 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -270,6 +270,18 @@
 (define_special_predicate "lt_ge_comparison_operator"
   (match_code "lt,ge"))
 
+;; The vsel instruction only accepts the ARM condition codes listed below.
+(define_special_predicate "arm_vsel_comparison_operator"
+  (and (match_operand 0 "expandable_comparison_operator")
+       (match_test "maybe_get_arm_condition_code (op) == ARM_GE
+                    || maybe_get_arm_condition_code (op) == ARM_GT
+                    || maybe_get_arm_condition_code (op) == ARM_EQ
+                    || maybe_get_arm_condition_code (op) == ARM_VS
+                    || maybe_get_arm_condition_code (op) == ARM_LT
+                    || maybe_get_arm_condition_code (op) == ARM_LE
+                    || maybe_get_arm_condition_code (op) == ARM_NE
+                    || maybe_get_arm_condition_code (op) == ARM_VC")))
+
 (define_special_predicate "noov_comparison_operator"
   (match_code "lt,ge,eq,ne"))
 
diff --git a/gcc/testsuite/gcc.target/arm/vseleqdf.c 
b/gcc/testsuite/gcc.target/arm/vseleqdf.c
new file mode 100644
index 0000000..86e147b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vseleqdf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  volatile int i = 0;
+  return i == 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vseleq.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vseleqsf.c 
b/gcc/testsuite/gcc.target/arm/vseleqsf.c
new file mode 100644
index 0000000..120f44b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vseleqsf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  volatile int i = 0;
+  return i == 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vseleq.f32\ts\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselgedf.c 
b/gcc/testsuite/gcc.target/arm/vselgedf.c
new file mode 100644
index 0000000..cea08d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselgedf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  volatile int i = 0;
+  return i >= 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselge.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselgesf.c 
b/gcc/testsuite/gcc.target/arm/vselgesf.c
new file mode 100644
index 0000000..86f2a04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselgesf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  volatile int i = 0;
+  return i >= 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselge.f32\ts\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselgtdf.c 
b/gcc/testsuite/gcc.target/arm/vselgtdf.c
new file mode 100644
index 0000000..2c4a6ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselgtdf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  volatile int i = 0;
+  return i > 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselgt.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselgtsf.c 
b/gcc/testsuite/gcc.target/arm/vselgtsf.c
new file mode 100644
index 0000000..388e74c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselgtsf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  volatile int i = 0;
+  return i > 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselgt.f32\ts\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselledf.c 
b/gcc/testsuite/gcc.target/arm/vselledf.c
new file mode 100644
index 0000000..088dc04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselledf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  volatile int i = 0;
+  return i <= 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselgt.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vsellesf.c 
b/gcc/testsuite/gcc.target/arm/vsellesf.c
new file mode 100644
index 0000000..d0afdbc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vsellesf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  volatile int i = 0;
+  return i <= 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselgt.f32\ts\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselltdf.c 
b/gcc/testsuite/gcc.target/arm/vselltdf.c
new file mode 100644
index 0000000..fbcb9ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselltdf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  volatile int i = 0;
+  return i < 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselge.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselltsf.c 
b/gcc/testsuite/gcc.target/arm/vselltsf.c
new file mode 100644
index 0000000..959dab7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselltsf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  volatile int i = 0;
+  return i < 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselge.f32\ts\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselnedf.c 
b/gcc/testsuite/gcc.target/arm/vselnedf.c
new file mode 100644
index 0000000..cf67f29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselnedf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  volatile int i = 0;
+  return i != 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vseleq.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselnesf.c 
b/gcc/testsuite/gcc.target/arm/vselnesf.c
new file mode 100644
index 0000000..2e16423
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselnesf.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  volatile int i = 0;
+  return i != 0 ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vseleq.f32\ts\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselvcdf.c 
b/gcc/testsuite/gcc.target/arm/vselvcdf.c
new file mode 100644
index 0000000..7f30270
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselvcdf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  return !__builtin_isunordered (x, y) ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselvs.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselvcsf.c 
b/gcc/testsuite/gcc.target/arm/vselvcsf.c
new file mode 100644
index 0000000..1bb7369
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselvcsf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  return !__builtin_isunordered (x, y) ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselvs.f32\ts\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselvsdf.c 
b/gcc/testsuite/gcc.target/arm/vselvsdf.c
new file mode 100644
index 0000000..83ad5bf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselvsdf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+double
+foo (double x, double y)
+{
+  return __builtin_isunordered (x, y) ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselvs.f64\td\[0-9\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/vselvssf.c 
b/gcc/testsuite/gcc.target/arm/vselvssf.c
new file mode 100644
index 0000000..7d76289
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/vselvssf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_vfp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_vfp } */
+
+float
+foo (float x, float y)
+{
+  return __builtin_isunordered (x, y) ? x : y;
+}
+
+/* { dg-final { scan-assembler-times "vselvs.f32\ts\[0-9\]+" 1 } } */

Reply via email to