NEON FP flags

Hal, James,

My plan to disable vectorization on NEON FP had two steps:

1. Create the infrastructure to detect unsafe FP maths and force NEON
FP via fast-math.
2. Use -mfpmath=neon/sse to fine-tune the flags even further, but this
needs a lot of work in IR.

The expected behaviour is to have most performance with least options,
but with correctness in mind. So, we can't vectorize FP loops without
either -ffast-math or -mfpmath=neon, but we want to tell the users
that they could get more performance out of their compiler if either
option was chosen.

If I force the need for -ffast-math, many other deviations from
IEEE-754 will be allowed, not just denormals, so you're left with
either slow or potentially bad results. Using -mfpmath hits the right
spot, but is less known and is not plugged in yet.

Vectorizing FP loops is a correctness problem in NEON (and I assume
SSE), so it would be good to be safe. But I take it it's not a serious
correctness problem, so we can go about it the right way from the
beginning, which I'm ok with.

So...

If I got it right, we need to tell FP instructions that they allow
denormals. So far, I could only find flags about NaNs, Infs, signed
zeroes and reciprocals, as well as the "fast" flag that turns them all
on.

In the target transform info, we need to add a denormal flag to be set
if fpmath=neon/sse/etc on all FP instructions, and in the vectorizer,
we just test for that flag (which should also be set by fast-math).

The Darwin vs. Linux problem is, then, moved to the target transform
info, only setting the flag on ARM if...

isDarwin OR ARMISA >= v8 OR fastMath OR fpMath == NEON

Makes sense?

cheers,
--renato

Hi,

Right, I meant the information to set/not set would be in TTI, not the
actual setting.

I don't want Clang to have that kind of information independent of LLVM.

cheers,
--renato

Hi Renato,

As I understand it, the fundamental property being addresses here is: Are the semantics of scalar FP math the same as vector FP math? TTI seems like a good place to expose that information. If the semantics are indeed different, then the vectorizer would require fast-math flags in order to vectorize FP operations (similarly, gcc's man page says it requires -funsafe-math-optimizations for vectorization unless -mfpu=neon or similar is specified). In this context, this different-semantics query would return true if:

  !(isDarwin OR ARMISA >= v8 OR fpMath == NEON)

and then we need to teach people to use -mfpu=neon :wink:

I think this more-or-less matches what you've proposed. Is that right?

-Hal

P.S. Looking at gcc's man page, gcc seems to use -mfpu for ARM and -mfpmath for x86. Do we use -mfpmath for both?

As I understand it, the fundamental property being addresses here is: Are the semantics of scalar FP math the same as vector FP math? TTI seems like a good place to expose that information. If the semantics are indeed different, then the vectorizer would require fast-math flags in order to vectorize FP operations (similarly, gcc's man page says it requires -funsafe-math-optimizations for vectorization unless -mfpu=neon or similar is specified). In this context, this different-semantics query would return true if:

The semantics is indeed different, VFP is IEEE-754 compliant while
NEON is not. We don't want to stop the compiler from using VFP for FP
math, but we want to be cautious when using NEON in the same way..

  !(isDarwin OR ARMISA >= v8 OR fpMath == NEON)

and then we need to teach people to use -mfpu=neon :wink:

So, there's the catch. In GCC, -mfpu=neon means to use NEON, which is
not enabled by default, so the compiler assumes that the user is aware
that NEON FP is not IEEE compliant. I don't think that's a safe
assumption, but I also don't want to have a slightly different
behaviour than GCC gratuitously.

Clang defaults to -mfpu=neon when we choose -mcpu=cortex-a* or
-march=armv7a, so our current behaviour is on par with GCC. But I
think that's a dangerous assumption.

Furthermore, the only alternatives we have at the moment is to either
use NEON for everything or nothing. It would be good to have an option
to use NEON for integer arithmetic and VFP for FP if the user requires
IEEE compliance..

P.S. Looking at gcc's man page, gcc seems to use -mfpu for ARM and -mfpmath for x86. Do we use -mfpmath for both?

We already support -mfpmath=vfp/neon in Clang, but it's bogus. My
proposal is to make it count.

The best way I can think of is to let -mfpmath=vfp *disable* only FP
NEON and -mfpmath=neon *enable* only FP NEON, both orthogonal from
integer math.

Examples:

Works today:
-mfpu=soft -> Int (ALU), FP (LIB), no VFP/NEON instructions
-mfpu=softfp -> Int (ALU), FP (LIB), VFP/NEON instructions allowed
-mfpu=vfp -> Int (ALU), FP (VFP)
-mfpu=neon -> Int (NEON), FP (NEON)

Change proposed:
-mfpmath=neon -mfpu=vfp -> Int (ALU), FP (NEON)
-mfpmath=vfp -mfpu=neon -> Int (NEON), FP (VFP)

This would be similar enough to GCC, and would allow the small number
of users that care about IEEE-754 compliance to disable FP NEON on
demand.

cheers,
--renato

From: "Renato Golin" <renato.golin@linaro.org>
To: "Hal Finkel" <hfinkel@anl.gov>
Cc: "LLVM Dev" <llvm-dev@lists.llvm.org>, "James Molloy" <James.Molloy@arm.com>
Sent: Friday, March 25, 2016 8:23:03 AM
Subject: Re: NEON FP flags

> As I understand it, the fundamental property being addresses here
> is: Are the semantics of scalar FP math the same as vector FP
> math? TTI seems like a good place to expose that information. If
> the semantics are indeed different, then the vectorizer would
> require fast-math flags in order to vectorize FP operations
> (similarly, gcc's man page says it requires
> -funsafe-math-optimizations for vectorization unless -mfpu=neon or
> similar is specified). In this context, this different-semantics
> query would return true if:

The semantics is indeed different, VFP is IEEE-754 compliant while
NEON is not. We don't want to stop the compiler from using VFP for FP
math, but we want to be cautious when using NEON in the same way..

> !(isDarwin OR ARMISA >= v8 OR fpMath == NEON)
>
> and then we need to teach people to use -mfpu=neon :wink:

So, there's the catch. In GCC, -mfpu=neon means to use NEON, which is
not enabled by default, so the compiler assumes that the user is
aware
that NEON FP is not IEEE compliant. I don't think that's a safe
assumption, but I also don't want to have a slightly different
behaviour than GCC gratuitously.

Clang defaults to -mfpu=neon when we choose -mcpu=cortex-a* or
-march=armv7a, so our current behaviour is on par with GCC. But I
think that's a dangerous assumption.

Furthermore, the only alternatives we have at the moment is to either
use NEON for everything or nothing. It would be good to have an
option
to use NEON for integer arithmetic and VFP for FP if the user
requires
IEEE compliance..

> P.S. Looking at gcc's man page, gcc seems to use -mfpu for ARM and
> -mfpmath for x86. Do we use -mfpmath for both?

We already support -mfpmath=vfp/neon in Clang, but it's bogus. My
proposal is to make it count.

The best way I can think of is to let -mfpmath=vfp *disable* only FP
NEON and -mfpmath=neon *enable* only FP NEON, both orthogonal from
integer math.

Examples:

Works today:
-mfpu=soft -> Int (ALU), FP (LIB), no VFP/NEON instructions
-mfpu=softfp -> Int (ALU), FP (LIB), VFP/NEON instructions allowed
-mfpu=vfp -> Int (ALU), FP (VFP)
-mfpu=neon -> Int (NEON), FP (NEON)

Change proposed:
-mfpmath=neon -mfpu=vfp -> Int (ALU), FP (NEON)
-mfpmath=vfp -mfpu=neon -> Int (NEON), FP (VFP)

This would be similar enough to GCC, and would allow the small number
of users that care about IEEE-754 compliance to disable FP NEON on
demand.

I think this seems reasonable, although it is somewhat unfortunate, in terms of naming, that "-mfpu" affects non-FP operations too. However, I think we're stuck because of what GCC decided to do.

Thanks again,
Hal

> As I understand it, the fundamental property being addresses here is: Are
> the semantics of scalar FP math the same as vector FP math? TTI seems like
> a good place to expose that information. If the semantics are indeed
> different, then the vectorizer would require fast-math flags in order to
> vectorize FP operations (similarly, gcc's man page says it requires
> -funsafe-math-optimizations for vectorization unless -mfpu=neon or similar
> is specified). In this context, this different-semantics query would return
> true if:

The semantics is indeed different, VFP is IEEE-754 compliant while
NEON is not. We don't want to stop the compiler from using VFP for FP
math, but we want to be cautious when using NEON in the same way..

> !(isDarwin OR ARMISA >= v8 OR fpMath == NEON)
>
> and then we need to teach people to use -mfpu=neon :wink:

So, there's the catch. In GCC, -mfpu=neon means to use NEON, which is
not enabled by default, so the compiler assumes that the user is aware
that NEON FP is not IEEE compliant. I don't think that's a safe
assumption, but I also don't want to have a slightly different
behaviour than GCC gratuitously.

Note that my discussion below relates to the AArch32 behaviour (the ARM
port of GCC, not the AArch64 port of GCC).

I can see why the text in the man page might be misleading, but let me quote
the part I think Hal was referring to here (with added emphasis):

    If the selected floating-point hardware includes the NEON extension
    (e.g. -mfpu=neon), note that floating-point operations are **not**
    generated by GCC's auto-vectorization pass **unless**
    -funsafe-math-optimizations is also specified. This is because
    NEON hardware does not fully implement the IEEE 754 standard for
    floating-point arithmetic (in particular denormal values are treated
    as zero), so the use of NEON instructions may lead to a loss of
    precision.

That is to say, GCC will only auto-vectorize floationg-point arithmetic
if both -mfpu=neon AND -funsafe-math-optimizations are given. -mfpu=neon
by itself does not imply that it is OK for GCC to generate non-IEEE
compliant code. The default is safe until explicitly told otherwise.

Clang defaults to -mfpu=neon when we choose -mcpu=cortex-a* or
-march=armv7a, so our current behaviour is on par with GCC. But I
think that's a dangerous assumption.

If your current behaviour is to generate unsafe math when -mfpu=neon
is passed, then I agree this is dangerous. Again, this is *NOT* GCC's
behaviour.

Furthermore, the only alternatives we have at the moment is to either
use NEON for everything or nothing. It would be good to have an option
to use NEON for integer arithmetic and VFP for FP if the user requires
IEEE compliance.

In GCC, this is -mfpu=neon.

> P.S. Looking at gcc's man page, gcc seems to use -mfpu for ARM and -mfpmath
> for x86. Do we use -mfpmath for both?

We already support -mfpmath=vfp/neon in Clang, but it's bogus. My
proposal is to make it count.

The best way I can think of is to let -mfpmath=vfp *disable* only FP
NEON and -mfpmath=neon *enable* only FP NEON, both orthogonal from
integer math.

Examples:

Works today:
-mfpu=soft -> Int (ALU), FP (LIB), no VFP/NEON instructions
-mfpu=softfp -> Int (ALU), FP (LIB), VFP/NEON instructions allowed
-mfpu=vfp -> Int (ALU), FP (VFP)
-mfpu=neon -> Int (NEON), FP (NEON)

Change proposed:
-mfpmath=neon -mfpu=vfp -> Int (ALU), FP (NEON)
-mfpmath=vfp -mfpu=neon -> Int (NEON), FP (VFP)

This would be similar enough to GCC, and would allow the small number
of users that care about IEEE-754 compliance to disable FP NEON on
demand.

In GCC today:

  -mfpu=vfp is the minimum floating-point instruction set supported, the
    choice of which ABI you use (-mfloat-abi) is independent from the choice
    of floating-point hardware that exists. -mfpu=soft and -mfpu=softfp are
    rejected by GCC.

Starting with that:

  -mfloat-abi=soft -> Generate library calls for all floating-point
    operations, do not permit Neon operations.
  -mfloat-abi=softfp -> Pass floating point arguments using the softfloat
    abi (i.e. in core registers). Emit floating point instructions as
    appropriate.
  -mfloat-abi=hard -> Pass floating point arguments in VFP registers.
    Emit floating point instructions as appropriate.

Independent of this, we have -mfpu:

  -mfpu=neon -> Permit generation of Neon instructions (both integer and
    floating point) where allowed by the language specification. Note that
    this does not by itself allow the generation of non-IEEE compliant code.

And on top of that, -funsafe-math-optimizations to enable generating Neon
instructions for floating point operations.

For your set of use cases:

  Int (ALU), FP (LIB), no VFP/NEON instructions

    -mfloat-abi=soft

  Int (ALU), FP (LIB), VFP/NEON instructions allowed

    Impossible

  Int (ALU), FP (VFP)

    -mfloat-abi=hard or -mfloat-abi=softfp
   + -mfpu=vfp (or other non-neon FPU)

  Int (NEON), FP (VFP)
    -float-abi=hard or -mfloat-abi=softfp
   + -mfpu=neon (or greater)

  Int (NEON), FP (NEON)

    -float-abi=hard or -mfloat-abi=softfp
   + -mfpu=neon (or greater)
   + -funsafe-math-optimizations (or equivalent)

  Int (ALU), FP (NEON)

    Impossible (as far as I know).

Hope this helps,
James

That is to say, GCC will only auto-vectorize floationg-point arithmetic
if both -mfpu=neon AND -funsafe-math-optimizations are given. -mfpu=neon
by itself does not imply that it is OK for GCC to generate non-IEEE
compliant code. The default is safe until explicitly told otherwise.

Right, that was what I originally though from Hal's bug report, but
recent emails on the thread confused me.

I think this is the right behaviour, and I'm glad GCC does it, so we
can follow the correct approach from start.

Furthermore, the only alternatives we have at the moment is to either
use NEON for everything or nothing. It would be good to have an option
to use NEON for integer arithmetic and VFP for FP if the user requires
IEEE compliance.

In GCC, this is -mfpu=neon.

This makes my life *so* much easier! :slight_smile:

In GCC today:

  -mfpu=vfp is the minimum floating-point instruction set supported, the
    choice of which ABI you use (-mfloat-abi) is independent from the choice
    of floating-point hardware that exists. -mfpu=soft and -mfpu=softfp are
    rejected by GCC.

Yes, I mixed mfpu with mfloat-abi, my bad.

For your set of use cases:

  Int (ALU), FP (LIB), no VFP/NEON instructions
    -mfloat-abi=soft

  Int (ALU), FP (LIB), VFP/NEON instructions allowed
    Impossible

I mentioned this as -mfloat-abi=floatfp. Now I see my representation
of int/fp mixed concepts. Ignore this.

  Int (ALU), FP (VFP)
    -mfloat-abi=hard or -mfloat-abi=softfp
   + -mfpu=vfp (or other non-neon FPU)

  Int (NEON), FP (VFP)
    -float-abi=hard or -mfloat-abi=softfp
   + -mfpu=neon (or greater)

Excellent! This means I can only make -fsubnormal flags count, and all
will be the same.

This was my first approach, but Hal convinced me that we may want a
specific flag that is included by fast/unsafe maths flags. See below.

  Int (NEON), FP (NEON)
    -float-abi=hard or -mfloat-abi=softfp
   + -mfpu=neon (or greater)
   + -funsafe-math-optimizations (or equivalent)

Do you have one specifically for subnormals? -funsafe-math is a bit of
a big hammer and will enable other (potentially unwanted) behaviour
from the vectorizer.

However, -ffast-math / unsafe-math should include subnormal support.

  Int (ALU), FP (NEON)
    Impossible (as far as I know).

Irrelevant, as far as I care. :slight_smile:

cheers,
--renato

> That is to say, GCC will only auto-vectorize floationg-point arithmetic
> if both -mfpu=neon AND -funsafe-math-optimizations are given. -mfpu=neon
> by itself does not imply that it is OK for GCC to generate non-IEEE
> compliant code. The default is safe until explicitly told otherwise.

Right, that was what I originally though from Hal's bug report, but
recent emails on the thread confused me.

I think this is the right behaviour, and I'm glad GCC does it, so we
can follow the correct approach from start.

Perfect. I think this is sensible.

> Int (NEON), FP (VFP)
> -float-abi=hard or -mfloat-abi=softfp
> + -mfpu=neon (or greater)

Excellent! This means I can only make -fsubnormal flags count, and all
will be the same.

This was my first approach, but Hal convinced me that we may want a
specific flag that is included by fast/unsafe maths flags. See below.

> Int (NEON), FP (NEON)
> -float-abi=hard or -mfloat-abi=softfp
> + -mfpu=neon (or greater)
> + -funsafe-math-optimizations (or equivalent)

Do you have one specifically for subnormals? -funsafe-math is a bit of
a big hammer and will enable other (potentially unwanted) behaviour
from the vectorizer.

However, -ffast-math / unsafe-math should include subnormal support.

No, we only have the big hammer throughout the ARM back-end to
enable/disable support for the RTL IR that the vectorizer looks for
when pattern matching. That means you also get your reduction loops and
friends potentially changing your IEEE-754 expectations. Something more
fine-grained would be feasible, but there'd be a fair bit of work needed to
upgrade the implementation. In GCC we either take the performance hit or
you use the big hammer.

> Int (ALU), FP (NEON)
> Impossible (as far as I know).

Irrelevant, as far as I care. :slight_smile:

Having read the bug reports (16275/16274?) I realise I should have
mentioned Neon intrinsics in my original mail. These *are* available
with the appropriate -mfpu/-mfloat-abi/-march flags, no matter whether
your have -funsafe-math-optimizations, and always map to their instruction
(the implementation for this is not neat, essentially we have two backend RTL
patterns, one which is always available for intrinsics, one which is
conditionally available for auto-vectorization).

Thanks,
James

However, -ffast-math / unsafe-math should include subnormal support.

No, we only have the big hammer throughout the ARM back-end to
enable/disable support for the RTL IR that the vectorizer looks for
when pattern matching. That means you also get your reduction loops and
friends potentially changing your IEEE-754 expectations. Something more
fine-grained would be feasible, but there'd be a fair bit of work needed to
upgrade the implementation. In GCC we either take the performance hit or
you use the big hammer.

Ok, so I think it's sensible to take the same approach and discuss the
extra subnormal flag with GCC/Clang folks.

I'll rebase my original patch so that at least our behaviour is
consistent for now.

Having read the bug reports (16275/16274?) I realise I should have
mentioned Neon intrinsics in my original mail. These *are* available
with the appropriate -mfpu/-mfloat-abi/-march flags, no matter whether
your have -funsafe-math-optimizations, and always map to their instruction
(the implementation for this is not neat, essentially we have two backend RTL
patterns, one which is always available for intrinsics, one which is
conditionally available for auto-vectorization).

That's what I was trying to say with the Int vs FP vs allow VFP
instructions, but failed miserably. But this is not relevant to this
discussion now (and we have similar issues lowering them :).

My change above will make the behaviour identical, so we can discuss
about the subnormal flag later.

Thanks!!

--renato