Re: [2/2] RISC-V: Constant FP Optimization with 'Zfa'

2023-08-25 Thread Jeff Law via Gcc-patches




On 8/14/23 06:51, Jin Ma wrote:



This code is great and completely different from the way I implemented it.
I'm not sure which one is better, but my idea is that the fli instruction
corresponds to three tables (HF, SF and DF), all of which represent
specific values. the library in gcc's real.h can very well convert
the corresponding values into the values in the table, so it is only
necessary to perform a simple binary search to look up the tables.
Yea, I was kindof amazed at how Tsukasa implemented that code.  But I 
think the tables are easier to understand, so I'd tend to prefer them.


I'm still evaluating, but in general it looks like your implementation 
is (functionally) a superset of what Tsukasa has done.  I've still got 
some testing to do with Tsukasa's tests to verify, but my inclination is 
to go with your v10 patch right now.


Jeff


Re: [2/2] RISC-V: Constant FP Optimization with 'Zfa'

2023-08-15 Thread Jin Ma via Gcc-patches
On 2023/08/15 12:38, Tsukasa OI wrote:
> > On 2023/08/14 21:51, Jin Ma wrote:
> >> Hi Tsukasa,
> >>   What a coincidence, I also implemented zfa extension, which also 
> >> includes fli related instructions :)
> > 
> > Hi, I'm glad to know that someone is working on this extension more
> > comprehensively (especially when "someone" is an experienced GCC
> > contributor).  I prefer your patch set in general and glad to learn from
> > your patch set and your response that my approach was not *that* bad as
> > I expected.
> > 
> > When a new extension gets available, I will be more confident making a
> > patch set for GCC (as I already do in GNU Binutils).
> > 
> >>
> >> links: https://gcc.gnu.org/pipermail/gcc-patches/2023-August/627294.html
> >>
> >>> +  if (!TARGET_HARD_FLOAT || !TARGET_ZFA)
> >>> +return result;
> >>> +  switch (GET_MODE (x))
> >>> +{
> >>> +case HFmode:
> >>> +  /* Not only 'Zfhmin', either 'Zfh' or 'Zvfh' is required.  */
> >>> +  if (!TARGET_ZFH && !TARGET_ZVFH)
> >>
> >> When Zvfh means that zfh is also on, so there may be no need to judge
> >> the TARGET_ZVFH here. By the way,the format here seems wrong, maybe 'tab'
> >> is needed for alignment?
> > 
> > For indentation, I believe this is okay considering 3 indent (soft tab)
> > from the top (meaning 6 spaces).
> > 
> > For specification requirements, I think I'm correct.
> > 
> > The spec says that 'Zvfh' depends on 'Zve32f' and 'Zfhmin'.  'Zfhmin' is
> > a conversion-only 'Zfh' subset ('Zve32f' doesn't require any
> > FP16-related extensions).
> > 
> > Note that "fli.h" requires 'Zfa' and ('Zfh' and/or 'Zvfh').
> > 
> > So, 'Zfh' alone will not be sufficient to check requirements to the
> > "fli.h" instruction.  So, checking TARGET_ZFH || TARGET_ZVFH (for
> > existence of the "fli.h") should be correct and I think your patch needs
> > to be changed "in the long term".
> > 
> > "In the long term" means that, current GNU Binutils has a bug which
> > "fli.h" requires 'Zfa' and 'Zfh' ('Zfa' and 'Zvfh' does not work).
> > My initial 'Zfa' proposal (improved by Christoph Müllner and upstreamed
> > into master) intentionally ignored this case because I assumed that
> > approval/ratification of 'Zvfh' will take some time and we have a time
> > to fix before a release of Binutils following approval of both 'Zfa' and
> > 'Zvfh' (it turned out to be wrong).
> > 
> > cf. 
> > 
> > So, "fixing" this part (on your patch) alone will not make the program
> > work (on the simulator) because current buggy GNU Binutils won't accept
> > it.  I'm working on it on the GNU Binutils side.
> 
> Okay, the bug is fixed on GNU Binutils (master) and waiting approval
> from the release maintainer (for binutils-2_41-branch).
> 
> Thanks,
> Tsukasa
> 

Yes, you are right. I did not notice that zfh and zvfh are relatively 
independent.

Re: [2/2] RISC-V: Constant FP Optimization with 'Zfa'

2023-08-15 Thread Tsukasa OI via Gcc-patches
On 2023/08/15 12:38, Tsukasa OI wrote:
> On 2023/08/14 21:51, Jin Ma wrote:
>> Hi Tsukasa,
>>   What a coincidence, I also implemented zfa extension, which also includes 
>> fli related instructions :)
> 
> Hi, I'm glad to know that someone is working on this extension more
> comprehensively (especially when "someone" is an experienced GCC
> contributor).  I prefer your patch set in general and glad to learn from
> your patch set and your response that my approach was not *that* bad as
> I expected.
> 
> When a new extension gets available, I will be more confident making a
> patch set for GCC (as I already do in GNU Binutils).
> 
>>
>> links: https://gcc.gnu.org/pipermail/gcc-patches/2023-August/627294.html
>>
>>> +  if (!TARGET_HARD_FLOAT || !TARGET_ZFA)
>>> +return result;
>>> +  switch (GET_MODE (x))
>>> +{
>>> +case HFmode:
>>> +  /* Not only 'Zfhmin', either 'Zfh' or 'Zvfh' is required.  */
>>> +  if (!TARGET_ZFH && !TARGET_ZVFH)
>>
>> When Zvfh means that zfh is also on, so there may be no need to judge
>> the TARGET_ZVFH here. By the way,the format here seems wrong, maybe 'tab'
>> is needed for alignment?
> 
> For indentation, I believe this is okay considering 3 indent (soft tab)
> from the top (meaning 6 spaces).
> 
> For specification requirements, I think I'm correct.
> 
> The spec says that 'Zvfh' depends on 'Zve32f' and 'Zfhmin'.  'Zfhmin' is
> a conversion-only 'Zfh' subset ('Zve32f' doesn't require any
> FP16-related extensions).
> 
> Note that "fli.h" requires 'Zfa' and ('Zfh' and/or 'Zvfh').
> 
> So, 'Zfh' alone will not be sufficient to check requirements to the
> "fli.h" instruction.  So, checking TARGET_ZFH || TARGET_ZVFH (for
> existence of the "fli.h") should be correct and I think your patch needs
> to be changed "in the long term".
> 
> "In the long term" means that, current GNU Binutils has a bug which
> "fli.h" requires 'Zfa' and 'Zfh' ('Zfa' and 'Zvfh' does not work).
> My initial 'Zfa' proposal (improved by Christoph Müllner and upstreamed
> into master) intentionally ignored this case because I assumed that
> approval/ratification of 'Zvfh' will take some time and we have a time
> to fix before a release of Binutils following approval of both 'Zfa' and
> 'Zvfh' (it turned out to be wrong).
> 
> cf. 
> 
> So, "fixing" this part (on your patch) alone will not make the program
> work (on the simulator) because current buggy GNU Binutils won't accept
> it.  I'm working on it on the GNU Binutils side.

Okay, the bug is fixed on GNU Binutils (master) and waiting approval
from the release maintainer (for binutils-2_41-branch).

Thanks,
Tsukasa

> 
>>
>>> +   return result;
>>> +  break;
>>> +case SFmode: break;
>>> +case DFmode: break;
>>
>> Maybe we still have to judge TARGET_DOUBLE_FLOAT?
> 
> Indeed.  I just missed that.
> 
>>
>>> +default: return result;
>>> +}
>>> +
>>> +  if (!CONST_DOUBLE_P (x))
>>> +return result;
>>
>> I think it might be better to judge whether x satisfies the CONST_DOUBLE_P
>> before switch (GET_MODE (x)) above.
> 
> That's correct.  I think that's a part of leftover when I'm experimenting.
> 
>>
>>> +
>>> +  r = *CONST_DOUBLE_REAL_VALUE (x);
>>> +
>>> +  if (REAL_VALUE_ISNAN (r))
>>> +{
>>> +  long reprs[2] = { 0 };
>>> +  /* Compare with canonical NaN.  */
>>> +  switch (GET_MODE (x))
>>> +   {
>>> +   case HFmode:
>>> + reprs[0] = real_to_target (NULL, ,
>>> +float_mode_for_size (16).require ());
>>> + /* 0x7e00: Canonical NaN for binary16.  */
>>> + if (reprs[0] != 0x7e00)
>>> +   return result;
>>> + break;
>>> +   case SFmode:
>>> + reprs[0] = real_to_target (NULL, ,
>>> +float_mode_for_size (32).require ());
>>> + /* 0x7fc0: Canonical NaN for binary32.  */
>>> + if (reprs[0] != 0x7fc0)
>>> +   return result;
>>> + break;
>>> +   case DFmode:
>>> + real_to_target (reprs, , float_mode_for_size (64).require ());
>>> + if (FLOAT_WORDS_BIG_ENDIAN)
>>> +   std::swap (reprs[0], reprs[1]);
>>> + /* 0x7ff8_: Canonical NaN for binary64.  */
>>> + if (reprs[0] != 0 || reprs[1] != 0x7ff8)
>>> +   return result;
>>> + break;
>>> +   default:
>>> + gcc_unreachable ();
>>> +   }
>>> +  result.type = RISCV_FLOAT_CONST_NAN;
>>> +  result.valid = true;
>>> +  return result;
>>> +}
>>> +  else if (REAL_VALUE_ISINF (r))
>>> +{
>>> +  if (REAL_VALUE_NEGATIVE (r))
>>> +   return result;
>>> +  result.type = RISCV_FLOAT_CONST_INF;
>>> +  result.valid = true;
>>> +  return result;
>>> +}
>>> +
>>> +  bool sign = REAL_VALUE_NEGATIVE (r);
>>> +  result.sign = sign;
>>> +
>>> +  r = real_value_abs ();
>>> +  /* GCC internally does not use IEEE754-like encoding (where normalized
>>> + significands are in the range [1, 2).  GCC uses [0.5, 1) (see 
>>> 

Re: [2/2] RISC-V: Constant FP Optimization with 'Zfa'

2023-08-14 Thread Tsukasa OI via Gcc-patches
On 2023/08/14 21:51, Jin Ma wrote:
> Hi Tsukasa,
>   What a coincidence, I also implemented zfa extension, which also includes 
> fli related instructions :)

Hi, I'm glad to know that someone is working on this extension more
comprehensively (especially when "someone" is an experienced GCC
contributor).  I prefer your patch set in general and glad to learn from
your patch set and your response that my approach was not *that* bad as
I expected.

When a new extension gets available, I will be more confident making a
patch set for GCC (as I already do in GNU Binutils).

> 
> links: https://gcc.gnu.org/pipermail/gcc-patches/2023-August/627294.html
> 
>> +  if (!TARGET_HARD_FLOAT || !TARGET_ZFA)
>> +return result;
>> +  switch (GET_MODE (x))
>> +{
>> +case HFmode:
>> +  /* Not only 'Zfhmin', either 'Zfh' or 'Zvfh' is required.  */
>> +  if (!TARGET_ZFH && !TARGET_ZVFH)
> 
> When Zvfh means that zfh is also on, so there may be no need to judge
> the TARGET_ZVFH here. By the way,the format here seems wrong, maybe 'tab'
> is needed for alignment?

For indentation, I believe this is okay considering 3 indent (soft tab)
from the top (meaning 6 spaces).

For specification requirements, I think I'm correct.

The spec says that 'Zvfh' depends on 'Zve32f' and 'Zfhmin'.  'Zfhmin' is
a conversion-only 'Zfh' subset ('Zve32f' doesn't require any
FP16-related extensions).

Note that "fli.h" requires 'Zfa' and ('Zfh' and/or 'Zvfh').

So, 'Zfh' alone will not be sufficient to check requirements to the
"fli.h" instruction.  So, checking TARGET_ZFH || TARGET_ZVFH (for
existence of the "fli.h") should be correct and I think your patch needs
to be changed "in the long term".

"In the long term" means that, current GNU Binutils has a bug which
"fli.h" requires 'Zfa' and 'Zfh' ('Zfa' and 'Zvfh' does not work).
My initial 'Zfa' proposal (improved by Christoph Müllner and upstreamed
into master) intentionally ignored this case because I assumed that
approval/ratification of 'Zvfh' will take some time and we have a time
to fix before a release of Binutils following approval of both 'Zfa' and
'Zvfh' (it turned out to be wrong).

cf. 

So, "fixing" this part (on your patch) alone will not make the program
work (on the simulator) because current buggy GNU Binutils won't accept
it.  I'm working on it on the GNU Binutils side.

> 
>> +return result;
>> +  break;
>> +case SFmode: break;
>> +case DFmode: break;
> 
> Maybe we still have to judge TARGET_DOUBLE_FLOAT?

Indeed.  I just missed that.

> 
>> +default: return result;
>> +}
>> +
>> +  if (!CONST_DOUBLE_P (x))
>> +return result;
> 
> I think it might be better to judge whether x satisfies the CONST_DOUBLE_P
> before switch (GET_MODE (x)) above.

That's correct.  I think that's a part of leftover when I'm experimenting.

> 
>> +
>> +  r = *CONST_DOUBLE_REAL_VALUE (x);
>> +
>> +  if (REAL_VALUE_ISNAN (r))
>> +{
>> +  long reprs[2] = { 0 };
>> +  /* Compare with canonical NaN.  */
>> +  switch (GET_MODE (x))
>> +{
>> +case HFmode:
>> +  reprs[0] = real_to_target (NULL, ,
>> + float_mode_for_size (16).require ());
>> +  /* 0x7e00: Canonical NaN for binary16.  */
>> +  if (reprs[0] != 0x7e00)
>> +return result;
>> +  break;
>> +case SFmode:
>> +  reprs[0] = real_to_target (NULL, ,
>> + float_mode_for_size (32).require ());
>> +  /* 0x7fc0: Canonical NaN for binary32.  */
>> +  if (reprs[0] != 0x7fc0)
>> +return result;
>> +  break;
>> +case DFmode:
>> +  real_to_target (reprs, , float_mode_for_size (64).require ());
>> +  if (FLOAT_WORDS_BIG_ENDIAN)
>> +std::swap (reprs[0], reprs[1]);
>> +  /* 0x7ff8_: Canonical NaN for binary64.  */
>> +  if (reprs[0] != 0 || reprs[1] != 0x7ff8)
>> +return result;
>> +  break;
>> +default:
>> +  gcc_unreachable ();
>> +}
>> +  result.type = RISCV_FLOAT_CONST_NAN;
>> +  result.valid = true;
>> +  return result;
>> +}
>> +  else if (REAL_VALUE_ISINF (r))
>> +{
>> +  if (REAL_VALUE_NEGATIVE (r))
>> +return result;
>> +  result.type = RISCV_FLOAT_CONST_INF;
>> +  result.valid = true;
>> +  return result;
>> +}
>> +
>> +  bool sign = REAL_VALUE_NEGATIVE (r);
>> +  result.sign = sign;
>> +
>> +  r = real_value_abs ();
>> +  /* GCC internally does not use IEEE754-like encoding (where normalized
>> + significands are in the range [1, 2).  GCC uses [0.5, 1) (see real.cc).
>> + So, this exponent_p1 variable equals IEEE754 unbiased exponent + 1.  */
>> +  int exponent_p1 = REAL_EXP ();
>> +
>> +  /* For the mantissa, we expand into two HOST_WIDE_INTS, apart from the
>> + highest (sign) bit, with a fixed binary point at bit point_pos.
>> + m1 holds the low part of the mantissa, m2 

RE: [2/2] RISC-V: Constant FP Optimization with 'Zfa'

2023-08-14 Thread Jin Ma via Gcc-patches
Hi Tsukasa,
  What a coincidence, I also implemented zfa extension, which also includes fli 
related instructions :)

links: https://gcc.gnu.org/pipermail/gcc-patches/2023-August/627294.html

> +  if (!TARGET_HARD_FLOAT || !TARGET_ZFA)
> +return result;
> +  switch (GET_MODE (x))
> +{
> +case HFmode:
> +  /* Not only 'Zfhmin', either 'Zfh' or 'Zvfh' is required.  */
> +  if (!TARGET_ZFH && !TARGET_ZVFH)

When Zvfh means that zfh is also on, so there may be no need to judge
the TARGET_ZVFH here. By the way,the format here seems wrong, maybe 'tab'
is needed for alignment?

> + return result;
> +  break;
> +case SFmode: break;
> +case DFmode: break;

Maybe we still have to judge TARGET_DOUBLE_FLOAT?

> +default: return result;
> +}
> +
> +  if (!CONST_DOUBLE_P (x))
> +return result;

I think it might be better to judge whether x satisfies the CONST_DOUBLE_P
before switch (GET_MODE (x)) above.

> +
> +  r = *CONST_DOUBLE_REAL_VALUE (x);
> +
> +  if (REAL_VALUE_ISNAN (r))
> +{
> +  long reprs[2] = { 0 };
> +  /* Compare with canonical NaN.  */
> +  switch (GET_MODE (x))
> + {
> + case HFmode:
> +   reprs[0] = real_to_target (NULL, ,
> +  float_mode_for_size (16).require ());
> +   /* 0x7e00: Canonical NaN for binary16.  */
> +   if (reprs[0] != 0x7e00)
> + return result;
> +   break;
> + case SFmode:
> +   reprs[0] = real_to_target (NULL, ,
> +  float_mode_for_size (32).require ());
> +   /* 0x7fc0: Canonical NaN for binary32.  */
> +   if (reprs[0] != 0x7fc0)
> + return result;
> +   break;
> + case DFmode:
> +   real_to_target (reprs, , float_mode_for_size (64).require ());
> +   if (FLOAT_WORDS_BIG_ENDIAN)
> + std::swap (reprs[0], reprs[1]);
> +   /* 0x7ff8_: Canonical NaN for binary64.  */
> +   if (reprs[0] != 0 || reprs[1] != 0x7ff8)
> + return result;
> +   break;
> + default:
> +   gcc_unreachable ();
> + }
> +  result.type = RISCV_FLOAT_CONST_NAN;
> +  result.valid = true;
> +  return result;
> +}
> +  else if (REAL_VALUE_ISINF (r))
> +{
> +  if (REAL_VALUE_NEGATIVE (r))
> + return result;
> +  result.type = RISCV_FLOAT_CONST_INF;
> +  result.valid = true;
> +  return result;
> +}
> +
> +  bool sign = REAL_VALUE_NEGATIVE (r);
> +  result.sign = sign;
> +
> +  r = real_value_abs ();
> +  /* GCC internally does not use IEEE754-like encoding (where normalized
> + significands are in the range [1, 2).  GCC uses [0.5, 1) (see real.cc).
> + So, this exponent_p1 variable equals IEEE754 unbiased exponent + 1.  */
> +  int exponent_p1 = REAL_EXP ();
> +
> +  /* For the mantissa, we expand into two HOST_WIDE_INTS, apart from the
> + highest (sign) bit, with a fixed binary point at bit point_pos.
> + m1 holds the low part of the mantissa, m2 the high part.
> + WARNING: If we ever have a representation using more than 2 * H_W_I - 1
> + bits for the mantissa, this can fail (low bits will be lost).  */
> +  bool fail = false;
> +  real_ldexp (, , (2 * HOST_BITS_PER_WIDE_INT - 1) - exponent_p1);
> +  wide_int w = real_to_integer (, , HOST_BITS_PER_WIDE_INT * 2);
> +  if (fail)
> +return result;
> +
> +  /* If the low part of the mantissa has bits set we cannot represent
> + the value.  */
> +  if (w.ulow () != 0)
> +return result;
> +  /* We have rejected the lower HOST_WIDE_INT, so update our
> + understanding of how many bits lie in the mantissa and
> + look only at the high HOST_WIDE_INT.  */
> +  unsigned HOST_WIDE_INT mantissa = w.elt (1);
> +
> +  /* We cannot represent the value 0.0.  */
> +  if (mantissa == 0)
> +return result;
> +
> +  /* We can only represent values with a mantissa of the form 1.xx.  */
> +  unsigned HOST_WIDE_INT mask
> +  = ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 4)) - 1;
> +  if ((mantissa & mask) != 0)
> +return result;
> +  mantissa >>= HOST_BITS_PER_WIDE_INT - 4;
> +  /* Now the lowest 3-bits of mantissa should form (1.xx)b.  */
> +  gcc_assert (mantissa & (1u << 2));
> +  /* Mask out the highest bit.  */
> +  mantissa &= ~(1u << 2);
> +
> +  if (mantissa == 0)
> +{
> +  /* We cannot represent any values but -1.0.  */
> +  if (exponent_p1 != 1 && sign)
> + return result;
> +  switch (exponent_p1)
> + {
> + case -15: /* 1.0 * 2^(-16)  */
> + case -14: /* 1.0 * 2^(-15)  */
> + case -7:  /* 1.0 * 2^(- 8)  */
> + case -6:  /* 1.0 * 2^(- 7)  */
> + case 8:   /* 1.0 * 2^(+ 7)  */
> + case 9:   /* 1.0 * 2^(+ 8)  */
> + case 16:  /* 1.0 * 2^(+15)  */
> + case 17:  /* 1.0 * 2^(+16)  */
> +   break;
> + default:
> +   if (exponent_p1 >= -3 && exponent_p1 <= 5)
> + /* 1.0 * 2^[-4,4]  */
> + break;
> +   switch (GET_MODE (x))
> +   

[PATCH 2/2] RISC-V: Constant FP Optimization with 'Zfa'

2023-08-13 Thread Tsukasa OI via Gcc-patches
From: Tsukasa OI 

This commit implements an optimization for assignments from a FP constant
to a FP register using a FLI instruction from the 'Zfa' extension.

To this purpose, it adds the constraint "H" and adds hardfloat move
instructions a "H -> f" variant.  Because FLI instruction constraint is
a bit complex, it adds the riscv_get_float_fli_const function to parse
a floating point constant if appropriate and the validness is contained
in its return value.

It also modifies the cost model for floating point constants and implements
simple yet bit-accurate printer for valid finite FLI constants.

This optimization is partially based on AArch64
(vmov instruction handling).

gcc/ChangeLog:

* config/riscv/constraints.md (H): New.
* config/riscv/riscv-protos.h (enum riscv_float_fli_const_type):
New to identify the FLI constant type.
(struct riscv_float_fli_const): New to represent an optional
FLI constant.
* config/riscv/riscv.cc (riscv_get_float_fli_const): New function
to parse a CONST_DOUBLE and return optionally-valid FLI constant.
(riscv_const_insns): Modify CONST_DOUBLE cost model.
(riscv_output_move): Add FLI instruction outputs.
(riscv_print_operand): Print a finite FLI constant as a hexadecimal
FP representation or a string operand "min", "inf" or "nan".
* config/riscv/riscv.md (movhf_hardfloat, movsf_hardfloat,
movdf_hardfloat_rv32, movdf_hardfloat_rv64): Add "H" variant
for 'Zfa' extension-based FP constant moves.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/zfa-fli-1.c: New test.
* gcc.target/riscv/zfa-fli-2.c: Ditto.
* gcc.target/riscv/zfa-fli-3.c: Ditto.
* gcc.target/riscv/zfa-fli-4.c: Ditto.
* gcc.target/riscv/zfa-fli-5.c: Ditto.
* gcc.target/riscv/zfa-fli-6.c: Ditto.
* gcc.target/riscv/zfa-fli-7.c: Ditto.
* gcc.target/riscv/zfa-fli-8.c: Ditto.
---
 gcc/config/riscv/constraints.md|   7 +
 gcc/config/riscv/riscv-protos.h|  34 +++
 gcc/config/riscv/riscv.cc  | 250 -
 gcc/config/riscv/riscv.md  |  24 +-
 gcc/testsuite/gcc.target/riscv/zfa-fli-1.c |  24 ++
 gcc/testsuite/gcc.target/riscv/zfa-fli-2.c |  24 ++
 gcc/testsuite/gcc.target/riscv/zfa-fli-3.c |  14 ++
 gcc/testsuite/gcc.target/riscv/zfa-fli-4.c | 111 +
 gcc/testsuite/gcc.target/riscv/zfa-fli-5.c |  98 
 gcc/testsuite/gcc.target/riscv/zfa-fli-6.c |  61 +
 gcc/testsuite/gcc.target/riscv/zfa-fli-7.c |  30 +++
 gcc/testsuite/gcc.target/riscv/zfa-fli-8.c |  39 
 12 files changed, 692 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-8.c

diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 44525b2da491..d57c72ef14f0 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -98,6 +98,13 @@
   (and (match_code "const_double")
(match_test "op == CONST0_RTX (mode)")))
 
+;; Floating-point constant that can be generated by a FLI instruction
+;; in the 'Zfa' standard extension.
+(define_constraint "H"
+  "@internal"
+  (and (match_code "const_double")
+   (match_test "riscv_get_float_fli_const (op).valid")))
+
 (define_memory_constraint "A"
   "An address that is held in a general-purpose register."
   (and (match_code "mem")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 2fbed04ff84c..6effa2437251 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -80,6 +80,39 @@ struct riscv_address_info {
   enum riscv_symbol_type symbol_type;
 };
 
+/* Classifies a floating point constant possibly retrieved by
+   the FLI instructions.
+
+   RISCV_FLOAT_CONST_MIN
+   The minimum positive normal value for given mode.
+
+   RISCV_FLOAT_CONST_INF
+   Positive infinity.
+
+   RISCV_FLOAT_CONST_NAN
+   Canonical NaN (positive, quiet and zero payload NaN).
+
+   RISCV_FLOAT_CONST_FINITE
+   A finite number.  */
+enum riscv_float_fli_const_type {
+  RISCV_FLOAT_CONST_MIN,
+  RISCV_FLOAT_CONST_INF,
+  RISCV_FLOAT_CONST_NAN,
+  RISCV_FLOAT_CONST_FINITE,
+};
+
+/* Information about a floating point constant possibly retrieved by
+   the FLI instructions.  */
+struct riscv_float_fli_const {
+  bool valid: 1;
+  bool sign: 1;
+  enum riscv_float_fli_const_type type: 2;
+  /* Highest 2 bits of IEEE754 mantissa on RISCV_FLOAT_CONST_FINITE.  */
+  unsigned int