MIPS32 (and going back to MIPS II and III) has some instructions that
roughly map to these patterns, with some caveats (i.e. NaN returns zero
and Inf. is mapped to INT_MAX). For this reason these patterns are only
emitted under some conditions (builtin-inexact/trapping-math).
gcc/ChangeLog:
* config/mips/mips.h (ISA_HAS_CEFLRO_W): Defined a new macro.
(ISA_HAS_CEFLRO_L): Defined a new macro.
* config/mips/mips.md (floor): Define UNSPEC iterator.
(l<fproundop><SCALARF:mode>si2): New pattern.
(l<fproundop><SCALARF:mode>di2): New pattern.
gcc/testsuite/ChangeLog:
* gcc.target/mips/ceil-floor-round-l.c: New test.
* gcc.target/mips/ceil-floor-round-w.c: New test.
* gcc.target/mips/no-ceil-floor-round-l.c: New test.
* gcc.target/mips/no-ceil-floor-round-w.c: New test.
Signed-off-by: David Guillen Fandos <[email protected]>
---
gcc/config/mips/mips.h | 8 ++++
gcc/config/mips/mips.md | 33 ++++++++++++++
.../gcc.target/mips/ceil-floor-round-l.c | 44 +++++++++++++++++++
.../gcc.target/mips/ceil-floor-round-w.c | 44 +++++++++++++++++++
.../gcc.target/mips/no-ceil-floor-round-l.c | 44 +++++++++++++++++++
.../gcc.target/mips/no-ceil-floor-round-w.c | 44 +++++++++++++++++++
6 files changed, 217 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/mips/ceil-floor-round-l.c
create mode 100644 gcc/testsuite/gcc.target/mips/ceil-floor-round-w.c
create mode 100644 gcc/testsuite/gcc.target/mips/no-ceil-floor-round-l.c
create mode 100644 gcc/testsuite/gcc.target/mips/no-ceil-floor-round-w.c
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index f52d0d2358c..acd028b4fb8 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1298,6 +1298,14 @@ struct mips_cpu_info {
also requires TARGET_DOUBLE_FLOAT. */
#define ISA_HAS_TRUNC_W (!ISA_MIPS1)
+/* Similar as above but for ceil/floor/round instructions. */
+#define ISA_HAS_CEFLRO_W (!ISA_MIPS1 \
+ && !TARGET_MIPS5900) \
+
+/* 64 bit integer variant of the above. */
+#define ISA_HAS_CEFLRO_L (mips_isa >= MIPS_ISA_MIPS3 \
+ && !TARGET_MIPS5900) \
+
/* ISA includes the MIPS32r2 seb and seh instructions. */
#define ISA_HAS_SEB_SEH ((mips_isa_rev >= 2 && !TARGET_MIPS16)
\
|| TARGET_ALLEGREX)
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 85e7d67901f..20ed0edd8d5 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -103,6 +103,9 @@
UNSPEC_FMAX
UNSPEC_FRINT
UNSPEC_FCLASS
+ UNSPEC_CEIL
+ UNSPEC_FLOOR
+ UNSPEC_ROUND
;; HI/LO moves.
UNSPEC_MFHI
@@ -1039,6 +1042,14 @@
(define_code_iterator any_return [return simple_return])
+;; Defines iterators for the floating point rounding operations.
+(define_int_iterator FPROUND_OP [UNSPEC_FLOOR UNSPEC_ROUND UNSPEC_CEIL])
+
+;; <fproundop> expands to the specified rounding operation.
+(define_int_attr fproundop [(UNSPEC_FLOOR "floor")
+ (UNSPEC_ROUND "round")
+ (UNSPEC_CEIL "ceil")])
+
;; <u> expands to an empty string when doing a signed operation and
;; "u" when doing an unsigned operation.
(define_code_attr u [(sign_extend "") (zero_extend "u")
@@ -8116,6 +8127,28 @@
[(set_attr "type" "frint")
(set_attr "mode" "<UNITMODE>")])
+;;Float point rounding (ceil/floor/round).
+(define_insn "l<fproundop><SCALARF:mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (unspec:SI [(match_operand:SCALARF 1 "register_operand" "f")]
+ FPROUND_OP))]
+ "TARGET_HARD_FLOAT && ISA_HAS_CEFLRO_W
+ && (!flag_trapping_math || flag_fp_int_builtin_inexact)"
+ "<fproundop>.w.<fmt>\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "<UNITMODE>")])
+
+;;Float point rounding (ceil/floor/round), 64 bit vartiant.
+(define_insn "l<fproundop><SCALARF:mode>di2"
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (unspec:DI [(match_operand:SCALARF 1 "register_operand" "f")]
+ FPROUND_OP))]
+ "TARGET_HARD_FLOAT && TARGET_FLOAT64 && ISA_HAS_CEFLRO_L
+ && (!flag_trapping_math || flag_fp_int_builtin_inexact)"
+ "<fproundop>.l.<fmt>\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "<UNITMODE>")])
+
;;Float point class mask
(define_insn "fclass_<mode>"
[(set (match_operand:SCALARF 0 "register_operand" "=f")
diff --git a/gcc/testsuite/gcc.target/mips/ceil-floor-round-l.c
b/gcc/testsuite/gcc.target/mips/ceil-floor-round-l.c
new file mode 100644
index 00000000000..2d155788735
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/ceil-floor-round-l.c
@@ -0,0 +1,44 @@
+/* { dg-options "isa>=3 -mabi=64 -mhard-float -ffast-math" } */
+
+NOMIPS16 long long
+ceilf_to_llong (float x)
+{
+ return __builtin_llceilf(x);
+}
+
+NOMIPS16 long long
+floorf_to_llong (float x)
+{
+ return __builtin_llfloorf(x);
+}
+
+NOMIPS16 long long
+roundf_to_llong (float x)
+{
+ return __builtin_llroundf(x);
+}
+
+NOMIPS16 long long
+ceild_to_llong (double x)
+{
+ return __builtin_llceil(x);
+}
+
+NOMIPS16 long long
+floord_to_llong (double x)
+{
+ return __builtin_llfloor(x);
+}
+
+NOMIPS16 long long
+roundd_to_llong (double x)
+{
+ return __builtin_llround(x);
+}
+
+/* { dg-final { scan-assembler "\tceil\\.l\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfloor\\.l\\.s\t" } } */
+/* { dg-final { scan-assembler "\tround\\.l\\.s\t" } } */
+/* { dg-final { scan-assembler "\tceil\\.l\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfloor\\.l\\.d\t" } } */
+/* { dg-final { scan-assembler "\tround\\.l\\.d\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/ceil-floor-round-w.c
b/gcc/testsuite/gcc.target/mips/ceil-floor-round-w.c
new file mode 100644
index 00000000000..0f2413c2653
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/ceil-floor-round-w.c
@@ -0,0 +1,44 @@
+/* { dg-options "isa>=2 -mhard-float -ffast-math" } */
+
+NOMIPS16 long
+ceilf_to_long (float x)
+{
+ return __builtin_lceilf(x);
+}
+
+NOMIPS16 long
+floorf_to_long (float x)
+{
+ return __builtin_lfloorf(x);
+}
+
+NOMIPS16 long
+roundf_to_long (float x)
+{
+ return __builtin_lroundf(x);
+}
+
+NOMIPS16 long
+ceild_to_long (double x)
+{
+ return __builtin_lceil(x);
+}
+
+NOMIPS16 long
+floord_to_long (double x)
+{
+ return __builtin_lfloor(x);
+}
+
+NOMIPS16 long
+roundd_to_long (double x)
+{
+ return __builtin_lround(x);
+}
+
+/* { dg-final { scan-assembler "\tceil\\.w\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfloor\\.w\\.s\t" } } */
+/* { dg-final { scan-assembler "\tround\\.w\\.s\t" } } */
+/* { dg-final { scan-assembler "\tceil\\.w\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfloor\\.w\\.d\t" } } */
+/* { dg-final { scan-assembler "\tround\\.w\\.d\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/no-ceil-floor-round-l.c
b/gcc/testsuite/gcc.target/mips/no-ceil-floor-round-l.c
new file mode 100644
index 00000000000..4006d98507c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/no-ceil-floor-round-l.c
@@ -0,0 +1,44 @@
+/* { dg-options "isa>=3 -mabi=64 -mhard-float -fno-fast-math" } */
+
+NOMIPS16 long long
+ceilf_to_llong (float x)
+{
+ return __builtin_llceilf(x);
+}
+
+NOMIPS16 long long
+floorf_to_llong (float x)
+{
+ return __builtin_llfloorf(x);
+}
+
+NOMIPS16 long long
+roundf_to_llong (float x)
+{
+ return __builtin_llroundf(x);
+}
+
+NOMIPS16 long long
+ceild_to_llong (double x)
+{
+ return __builtin_llceil(x);
+}
+
+NOMIPS16 long long
+floord_to_llong (double x)
+{
+ return __builtin_llfloor(x);
+}
+
+NOMIPS16 long long
+roundd_to_llong (double x)
+{
+ return __builtin_llround(x);
+}
+
+/* { dg-final { scan-assembler-not "\tceil\\.l\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tfloor\\.l\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tround\\.l\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tceil\\.l\\.d\t" } } */
+/* { dg-final { scan-assembler-not "\tfloor\\.l\\.d\t" } } */
+/* { dg-final { scan-assembler-not "\tround\\.l\\.d\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/no-ceil-floor-round-w.c
b/gcc/testsuite/gcc.target/mips/no-ceil-floor-round-w.c
new file mode 100644
index 00000000000..0ad2208bfab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/no-ceil-floor-round-w.c
@@ -0,0 +1,44 @@
+/* { dg-options "isa>=2 -mhard-float -fno-fast-math" } */
+
+NOMIPS16 long
+ceilf_to_long (float x)
+{
+ return __builtin_lceilf(x);
+}
+
+NOMIPS16 long
+floorf_to_long (float x)
+{
+ return __builtin_lfloorf(x);
+}
+
+NOMIPS16 long
+roundf_to_long (float x)
+{
+ return __builtin_lroundf(x);
+}
+
+NOMIPS16 long
+ceild_to_long (double x)
+{
+ return __builtin_lceil(x);
+}
+
+NOMIPS16 long
+floord_to_long (double x)
+{
+ return __builtin_lfloor(x);
+}
+
+NOMIPS16 long
+roundd_to_long (double x)
+{
+ return __builtin_lround(x);
+}
+
+/* { dg-final { scan-assembler-not "\tceil\\.w\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tfloor\\.w\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tround\\.w\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tceil\\.w\\.d\t" } } */
+/* { dg-final { scan-assembler-not "\tfloor\\.w\\.d\t" } } */
+/* { dg-final { scan-assembler-not "\tround\\.w\\.d\t" } } */
--
2.51.1