[v2,2/4] LoongArch: Add ftint{,rm,rp}.{w,l}.{s,d} instructions

Message ID 20221109135329.952128-3-xry111@xry111.site
State Accepted
Headers
Series LoongArch: Add some floating-point operations |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Xi Ruoyao Nov. 9, 2022, 1:53 p.m. UTC
  This allows to optimize the following builtins if -fno-math-errno:

- __builtin_lrint{,f}
- __builtin_lfloor{,f}
- __builtin_lceil{,f}

Inspired by
https://gcc.gnu.org/pipermail/gcc-patches/2022-November/605287.html.

ANYFI is added so the compiler won't try ftint.l.s if -mfpu=32.  If we
simply used GPR here an ICE would be triggered with __builtin_lrintf
and -mfpu=32.

ftint{rm,rp} instructions may raise inexact exception, so they can't be
used if -fno-trapping-math -fno-fp-int-builtin-inexact.

Note that the .w.{s,d} variants are not tested because we don't support
ILP32 for now.

gcc/ChangeLog:

	* config/loongarch/loongarch.md (UNSPEC_FTINT): New unspec.
	(UNSPEC_FTINTRM): Likewise.
	(UNSPEC_FTINTRP): Likewise.
	(LRINT): New define_int_iterator.
	(lrint_pattern): New define_int_attr.
	(lrint_submenmonic): Likewise.
	(lrint_allow_inexact): Likewise.
	(ANYFI): New define_mode_iterator.
	(lrint<ANYF><ANYFI>): New instruction template.

gcc/testsuite/ChangeLog:

	* gcc.target/loongarch/ftint.c: New test.
	* gcc.target/loongarch/ftint-no-inexact.c: New test.
---
 gcc/config/loongarch/loongarch.md             | 34 ++++++++++++++
 .../gcc.target/loongarch/ftint-no-inexact.c   | 44 +++++++++++++++++++
 gcc/testsuite/gcc.target/loongarch/ftint.c    | 44 +++++++++++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/ftint-no-inexact.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/ftint.c
  

Comments

chenglulu Nov. 10, 2022, 6:41 a.m. UTC | #1
在 2022/11/9 下午9:53, Xi Ruoyao 写道:
> +;; Convert floating-point numbers to integers
> +(define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
> +  [(set (match_operand:ANYFI 0 "register_operand" "=f")
> +	(unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
> +		      LRINT))]
> +  "TARGET_HARD_FLOAT &&
> +   (<lrint_allow_inexact>
> +    || flag_fp_int_builtin_inexact
> +    || !flag_trapping_math)"
>
+    || !flag_trapping_math

I think this condition is backwards.
  
Xi Ruoyao Nov. 10, 2022, 8:49 a.m. UTC | #2
On Thu, 2022-11-10 at 14:41 +0800, Lulu Cheng wrote:
> 
> 在 2022/11/9 下午9:53, Xi Ruoyao 写道:
> > +;; Convert floating-point numbers to integers
> > +(define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
> > +  [(set (match_operand:ANYFI 0 "register_operand" "=f")
> > +       (unspec:ANYFI [(match_operand:ANYF 1 "register_operand"
> > "f")]
> > +                     LRINT))]
> > +  "TARGET_HARD_FLOAT &&
> > +   (<lrint_allow_inexact>
> > +    || flag_fp_int_builtin_inexact
> > +    || !flag_trapping_math)"
> > 
> +    || !flag_trapping_math
> 
> I think this condition is backwards.

I copied the logic from aarch64.md:6702.

Joseph: can you confirm that -ftrapping-math allows floor and ceil to
raise inexact exception?  The man page currently says:

The default is -ffp-int-builtin-inexact, allowing the exception to be
raised, unless C2X or a later C standard is selected.  This option does 
                                                       ^^^^^^^^^^^
nothing unless -ftrapping-math is in effect.

To me it's not very clear that "this option" stands for -fno-fp-int-
builtin-inexact or -ffp-int-builtin-inexact.
  
Joseph Myers Nov. 11, 2022, 12:07 a.m. UTC | #3
On Thu, 10 Nov 2022, Xi Ruoyao via Gcc-patches wrote:

> Joseph: can you confirm that -ftrapping-math allows floor and ceil to
> raise inexact exception?  The man page currently says:
> 
> The default is -ffp-int-builtin-inexact, allowing the exception to be
> raised, unless C2X or a later C standard is selected.  This option does 
>                                                        ^^^^^^^^^^^
> nothing unless -ftrapping-math is in effect.
> 
> To me it's not very clear that "this option" stands for -fno-fp-int-
> builtin-inexact or -ffp-int-builtin-inexact.

The -ftrapping-math option (which is on by default) means that we care 
about whether operations raise exceptions: they should raise exceptions if 
and only if the relevant standard permit them to do so.

The combination of -ftrapping-math with -fno-fp-int-builtin-inexact means 
the listed built-in functions must not raise "inexact".

If -fno-trapping-math is used, then we don't care about whether exceptions 
are raised or not (for any floating-point operations, not just those 
functions).  So given -fno-trapping-math, there is no difference between 
-fno-fp-int-builtin-inexact and -ffp-int-builtin-inexact.

If -ffp-int-builtin-inexact (default before C2X), we don't care about 
whether those functions raise "inexact" (but still care about other 
exceptions and exceptions for other operations, unless 
-fno-trapping-math).
  
Xi Ruoyao Nov. 11, 2022, 5:29 a.m. UTC | #4
Lulu:

So I think the code is correct:

+   (<lrint_allow_inexact>
+    || flag_fp_int_builtin_inexact
+    || !flag_trapping_math)"

<lrint_allow_inexact> is 1 for lrint, 0 for lceil and lfloor.  As N3054
says:

   The lrint and llrint functions provide floating-to-integer conversion as prescribed by IEC 60559.
   They round according to the current rounding direction. If the rounded value is outside the range of
   the return type, the numeric result is unspecified and the "invalid" floating-point exception is raised.
   When they raise no other floating-point exception and the result differs from the argument, they
   raise the "inexact" floating-point exception.
   
If flag_fp_int_builtin_inexact is set, we allow lceil and lfloor to
raise "inexact".

If flag_trapping_math is not set (it's set by default and can only be
unset explicitly with -fno-trapping-math: it's not even implied by -
ffast-math), we don't care about whether exceptions are raised or not.

So lceil and lfloor can be used if -ffp-int-builtin-inexact, or -fno-
trapping-math.

On Fri, 2022-11-11 at 00:07 +0000, Joseph Myers wrote:
> On Thu, 10 Nov 2022, Xi Ruoyao via Gcc-patches wrote:
> 
> > Joseph: can you confirm that -ftrapping-math allows floor and ceil to
> > raise inexact exception?  The man page currently says:
> > 
> > The default is -ffp-int-builtin-inexact, allowing the exception to be
> > raised, unless C2X or a later C standard is selected.  This option does 
> >                                                        ^^^^^^^^^^^
> > nothing unless -ftrapping-math is in effect.
> > 
> > To me it's not very clear that "this option" stands for -fno-fp-int-
> > builtin-inexact or -ffp-int-builtin-inexact.
> 
> The -ftrapping-math option (which is on by default) means that we care
> about whether operations raise exceptions: they should raise exceptions if 
> and only if the relevant standard permit them to do so.
> 
> The combination of -ftrapping-math with -fno-fp-int-builtin-inexact means 
> the listed built-in functions must not raise "inexact".
> 
> If -fno-trapping-math is used, then we don't care about whether exceptions 
> are raised or not (for any floating-point operations, not just those 
> functions).  So given -fno-trapping-math, there is no difference between 
> -fno-fp-int-builtin-inexact and -ffp-int-builtin-inexact.
> 
> If -ffp-int-builtin-inexact (default before C2X), we don't care about 
> whether those functions raise "inexact" (but still care about other 
> exceptions and exceptions for other operations, unless 
> -fno-trapping-math).
  
chenglulu Nov. 12, 2022, 1:58 a.m. UTC | #5
I have no more questions.

Thanks.

在 2022/11/11 下午1:29, Xi Ruoyao 写道:
> Lulu:
>
> So I think the code is correct:
>
> +   (<lrint_allow_inexact>
> +    || flag_fp_int_builtin_inexact
> +    || !flag_trapping_math)"
>
> <lrint_allow_inexact> is 1 for lrint, 0 for lceil and lfloor.  As N3054
> says:
>
>     The lrint and llrint functions provide floating-to-integer conversion as prescribed by IEC 60559.
>     They round according to the current rounding direction. If the rounded value is outside the range of
>     the return type, the numeric result is unspecified and the "invalid" floating-point exception is raised.
>     When they raise no other floating-point exception and the result differs from the argument, they
>     raise the "inexact" floating-point exception.
>     
> If flag_fp_int_builtin_inexact is set, we allow lceil and lfloor to
> raise "inexact".
>
> If flag_trapping_math is not set (it's set by default and can only be
> unset explicitly with -fno-trapping-math: it's not even implied by -
> ffast-math), we don't care about whether exceptions are raised or not.
>
> So lceil and lfloor can be used if -ffp-int-builtin-inexact, or -fno-
> trapping-math.
>
> On Fri, 2022-11-11 at 00:07 +0000, Joseph Myers wrote:
>> On Thu, 10 Nov 2022, Xi Ruoyao via Gcc-patches wrote:
>>
>>> Joseph: can you confirm that -ftrapping-math allows floor and ceil to
>>> raise inexact exception?  The man page currently says:
>>>
>>> The default is -ffp-int-builtin-inexact, allowing the exception to be
>>> raised, unless C2X or a later C standard is selected.  This option does
>>>                                                         ^^^^^^^^^^^
>>> nothing unless -ftrapping-math is in effect.
>>>
>>> To me it's not very clear that "this option" stands for -fno-fp-int-
>>> builtin-inexact or -ffp-int-builtin-inexact.
>> The -ftrapping-math option (which is on by default) means that we care
>> about whether operations raise exceptions: they should raise exceptions if
>> and only if the relevant standard permit them to do so.
>>
>> The combination of -ftrapping-math with -fno-fp-int-builtin-inexact means
>> the listed built-in functions must not raise "inexact".
>>
>> If -fno-trapping-math is used, then we don't care about whether exceptions
>> are raised or not (for any floating-point operations, not just those
>> functions).  So given -fno-trapping-math, there is no difference between
>> -fno-fp-int-builtin-inexact and -ffp-int-builtin-inexact.
>>
>> If -ffp-int-builtin-inexact (default before C2X), we don't care about
>> whether those functions raise "inexact" (but still care about other
>> exceptions and exceptions for other operations, unless
>> -fno-trapping-math).
  

Patch

diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
index a14ab14ac24..eb127c346a3 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -38,6 +38,9 @@  (define_c_enum "unspec" [
   UNSPEC_FMAX
   UNSPEC_FMIN
   UNSPEC_FCOPYSIGN
+  UNSPEC_FTINT
+  UNSPEC_FTINTRM
+  UNSPEC_FTINTRP
 
   ;; Override return address for exception handling.
   UNSPEC_EH_RETURN
@@ -374,6 +377,11 @@  (define_mode_iterator QHWD [QI HI SI (DI "TARGET_64BIT")])
 (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
 			    (DF "TARGET_DOUBLE_FLOAT")])
 
+;; Iterator for fixed-point modes which can be hold by a hardware
+;; floating-point register.
+(define_mode_iterator ANYFI [(SI "TARGET_HARD_FLOAT")
+			     (DI "TARGET_DOUBLE_FLOAT")])
+
 ;; A mode for which moves involving FPRs may need to be split.
 (define_mode_iterator SPLITF
   [(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
@@ -515,6 +523,19 @@  (define_code_attr fcond [(unordered "cun")
 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
 
+;; Iterator and attributes for floating-point to fixed-point conversion
+;; instructions.
+(define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
+(define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
+				(UNSPEC_FTINTRM "lfloor")
+				(UNSPEC_FTINTRP "lceil")])
+(define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
+				    (UNSPEC_FTINTRM "rm")
+				    (UNSPEC_FTINTRP "rp")])
+(define_int_attr lrint_allow_inexact [(UNSPEC_FTINT "1")
+				      (UNSPEC_FTINTRM "0")
+				      (UNSPEC_FTINTRP "0")])
+
 ;;
 ;;  ....................
 ;;
@@ -2022,6 +2043,19 @@  (define_insn "rint<mode>2"
   [(set_attr "type" "fcvt")
    (set_attr "mode" "<MODE>")])
 
+;; Convert floating-point numbers to integers
+(define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
+  [(set (match_operand:ANYFI 0 "register_operand" "=f")
+	(unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
+		      LRINT))]
+  "TARGET_HARD_FLOAT &&
+   (<lrint_allow_inexact>
+    || flag_fp_int_builtin_inexact
+    || !flag_trapping_math)"
+  "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %0,%1"
+  [(set_attr "type" "fcvt")
+   (set_attr "mode" "<ANYF:MODE>")])
+
 ;; Load the low word of operand 0 with operand 1.
 (define_insn "load_low<mode>"
   [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
diff --git a/gcc/testsuite/gcc.target/loongarch/ftint-no-inexact.c b/gcc/testsuite/gcc.target/loongarch/ftint-no-inexact.c
new file mode 100644
index 00000000000..88b83a9c056
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/ftint-no-inexact.c
@@ -0,0 +1,44 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -mdouble-float -fno-math-errno -fno-fp-int-builtin-inexact" } */
+/* { dg-final { scan-assembler "ftint\\.l\\.s" } } */
+/* { dg-final { scan-assembler "ftint\\.l\\.d" } } */
+/* { dg-final { scan-assembler-not "ftintrm\\.l\\.s" } } */
+/* { dg-final { scan-assembler-not "ftintrm\\.l\\.d" } } */
+/* { dg-final { scan-assembler-not "ftintrp\\.l\\.s" } } */
+/* { dg-final { scan-assembler-not "ftintrp\\.l\\.d" } } */
+
+long
+my_lrint (double a)
+{
+  return __builtin_lrint (a);
+}
+
+long
+my_lrintf (float a)
+{
+  return __builtin_lrintf (a);
+}
+
+long
+my_lfloor (double a)
+{
+  return __builtin_lfloor (a);
+}
+
+long
+my_lfloorf (float a)
+{
+  return __builtin_lfloorf (a);
+}
+
+long
+my_lceil (double a)
+{
+  return __builtin_lceil (a);
+}
+
+long
+my_lceilf (float a)
+{
+  return __builtin_lceilf (a);
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/ftint.c b/gcc/testsuite/gcc.target/loongarch/ftint.c
new file mode 100644
index 00000000000..7a326a454d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/ftint.c
@@ -0,0 +1,44 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -mdouble-float -fno-math-errno -ffp-int-builtin-inexact" } */
+/* { dg-final { scan-assembler "ftint\\.l\\.s" } } */
+/* { dg-final { scan-assembler "ftint\\.l\\.d" } } */
+/* { dg-final { scan-assembler "ftintrm\\.l\\.s" } } */
+/* { dg-final { scan-assembler "ftintrm\\.l\\.d" } } */
+/* { dg-final { scan-assembler "ftintrp\\.l\\.s" } } */
+/* { dg-final { scan-assembler "ftintrp\\.l\\.d" } } */
+
+long
+my_lrint (double a)
+{
+  return __builtin_lrint (a);
+}
+
+long
+my_lrintf (float a)
+{
+  return __builtin_lrintf (a);
+}
+
+long
+my_lfloor (double a)
+{
+  return __builtin_lfloor (a);
+}
+
+long
+my_lfloorf (float a)
+{
+  return __builtin_lfloorf (a);
+}
+
+long
+my_lceil (double a)
+{
+  return __builtin_lceil (a);
+}
+
+long
+my_lceilf (float a)
+{
+  return __builtin_lceilf (a);
+}