@@ -119,6 +119,7 @@ extern void s390_expand_atomic (machine_mode, enum rtx_code,
extern void s390_expand_tbegin (rtx, rtx, rtx, bool);
extern void s390_expand_vec_compare (rtx, enum rtx_code, rtx, rtx);
extern void s390_expand_vec_compare_cc (rtx, enum rtx_code, rtx, rtx, bool);
+extern enum rtx_code s390_reverse_condition (machine_mode, enum rtx_code);
extern void s390_expand_vcond (rtx, rtx, rtx, enum rtx_code, rtx, rtx);
extern void s390_expand_vec_init (rtx, rtx);
extern rtx s390_return_addr_rtx (int, rtx);
@@ -1722,6 +1722,31 @@ s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
}
tmp = *op0; *op0 = *op1; *op1 = tmp;
}
+
+ /* A comparison result is compared against zero. Replace it with
+ the (perhaps inverted) original comparison.
+ This probably should be done by simplify_relational_operation. */
+ if ((*code == EQ || *code == NE)
+ && *op1 == const0_rtx
+ && COMPARISON_P (*op0)
+ && CC_REG_P (XEXP (*op0, 0)))
+ {
+ enum rtx_code new_code;
+
+ if (*code == EQ)
+ new_code = reversed_comparison_code_parts (GET_CODE (*op0),
+ XEXP (*op0, 0),
+ XEXP (*op1, 0), NULL);
+ else
+ new_code = GET_CODE (*op0);
+
+ if (new_code != UNKNOWN)
+ {
+ *code = new_code;
+ *op1 = XEXP (*op0, 1);
+ *op0 = XEXP (*op0, 0);
+ }
+ }
}
/* Helper function for s390_emit_compare. If possible emit a 64 bit
@@ -6343,6 +6368,23 @@ s390_expand_vec_compare_cc (rtx target, enum rtx_code code,
tmp_reg, target));
}
+/* Invert the comparison CODE applied to a CC mode. This is only safe
+ if we know whether there result was created by a floating point
+ compare or not. For the CCV modes this is encoded as part of the
+ mode. */
+enum rtx_code
+s390_reverse_condition (machine_mode mode, enum rtx_code code)
+{
+ /* Reversal of FP compares takes care -- an ordered compare
+ becomes an unordered compare and vice versa. */
+ if (mode == CCVFALLmode || mode == CCVFANYmode)
+ return reverse_condition_maybe_unordered (code);
+ else if (mode == CCVIALLmode || mode == CCVIANYmode)
+ return reverse_condition (code);
+ else
+ gcc_unreachable ();
+}
+
/* Generate a vector comparison expression loading either elements of
THEN or ELS into TARGET depending on the comparison COND of CMP_OP1
and CMP_OP2. */
@@ -513,6 +513,18 @@ extern const char *s390_host_detect_local_cpu (int argc, const char **argv);
#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
s390_cannot_change_mode_class ((FROM), (TO), (CLASS))
+/* We can reverse a CC mode safely if we know whether it comes from a
+ floating point compare or not. With the vector modes it is encoded
+ as part of the mode.
+ FIXME: It might make sense to do this for other cc modes as well. */
+#define REVERSIBLE_CC_MODE(MODE) \
+ ((MODE) == CCVIALLmode || (MODE) == CCVIANYmode \
+ || (MODE) == CCVFALLmode || (MODE) == CCVFANYmode)
+
+/* Given a condition code and a mode, return the inverse condition. */
+#define REVERSE_CONDITION(CODE, MODE) s390_reverse_condition (MODE, CODE)
+
+
/* Register classes. */
/* We use the following register classes:
new file mode 100644
@@ -0,0 +1,203 @@
+/* Similiar to vec-cmp-1.c but requires that
+ s390_canonicalize_comparison is able to merge the the two nested
+ compares. */
+
+/* { dg-do compile { target { s390*-*-* } } } */
+/* { dg-options "-O3 -mzarch -march=z13 -mzvector -fno-asynchronous-unwind-tables" } */
+
+#include <vecintrin.h>
+
+extern void foo (void);
+
+int __attribute__((noinline,noclone))
+all_eq_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_all_eq (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_eq_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+all_ne_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_all_ne (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_ne_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tjle 1 } } */
+
+int __attribute__((noinline,noclone))
+all_gt_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_all_gt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_gt_double:\n\tvfchdbs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+all_lt_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_all_lt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_lt_double:\n\tvfchdbs\t%v\[0-9\]*,%v26,%v24\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+all_ge_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_all_ge (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_ge_double:\n\tvfchedbs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+all_le_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_all_le (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_le_double:\n\tvfchedbs\t%v\[0-9\]*,%v26,%v24\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+any_eq_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_any_eq (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_eq_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_ne_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_any_ne (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_ne_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tje 1 } } */
+
+int __attribute__((noinline,noclone))
+any_gt_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_any_gt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_gt_double:\n\tvfchdbs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_lt_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_any_lt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_lt_double:\n\tvfchdbs\t%v\[0-9\]*,%v26,%v24\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_ge_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_any_ge (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_ge_double:\n\tvfchedbs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_le_double (vector double a, vector double b)
+{
+ if (__builtin_expect (vec_any_le (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_le_double:\n\tvfchedbs\t%v\[0-9\]*,%v26,%v24\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+all_eq_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_all_eq (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_eq_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+all_ne_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_all_ne (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_ne_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tjle 1 } } */
+
+int __attribute__((noinline,noclone))
+all_gt_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_all_gt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_gt_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+all_lt_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_all_lt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_lt_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tjne 1 } } */
+
+int __attribute__((noinline,noclone))
+all_ge_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_all_ge (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_ge_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tjle 1 } } */
+
+int __attribute__((noinline,noclone))
+all_le_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_all_le (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times all_le_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tjle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_eq_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_any_eq (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_eq_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_ne_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_any_ne (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_ne_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tje 1 } } */
+
+int __attribute__((noinline,noclone))
+any_gt_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_any_gt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_gt_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_lt_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_any_lt (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_lt_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tjnle 1 } } */
+
+int __attribute__((noinline,noclone))
+any_ge_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_any_ge (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_ge_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tje 1 } } */
+
+int __attribute__((noinline,noclone))
+any_le_int (vector int a, vector int b)
+{
+ if (__builtin_expect (vec_any_le (a, b), 1))
+ foo ();
+}
+/* { dg-final { scan-assembler-times any_le_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tje 1 } } */
+