Message ID | 20190820091845.80750-2-iii@linux.ibm.com |
---|---|
State | New |
Headers | show |
Series | Use signaling FP comparison instructions | expand |
On Tue, Aug 20, 2019 at 11:18:38AM +0200, Ilya Leoshkevich wrote: > Currently it's not clear whether or not min, max and ltgt should raise > floating point exceptions when dealing with qNaNs. > > Right now a lot of code assumes that LTGT is signaling: in particular, > it's generated for ((x < y) || (x > y)), which is signaling. The > behavior of MIN/MAX is (intentionally?) left unspecified, according to > commit 64dd117734d0 ("Unconditionally use MAX_EXPR/MIN_EXPR for MAX/MIN > intrinsics"). The < and > operators separately already can cause exceptions, unless you use -fno-trapping-math, in which case you cannot have LTGT at all. Segher
> Am 20.08.2019 um 17:04 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > > On Tue, Aug 20, 2019 at 11:18:38AM +0200, Ilya Leoshkevich wrote: >> Currently it's not clear whether or not min, max and ltgt should raise >> floating point exceptions when dealing with qNaNs. >> >> Right now a lot of code assumes that LTGT is signaling: in particular, >> it's generated for ((x < y) || (x > y)), which is signaling. The >> behavior of MIN/MAX is (intentionally?) left unspecified, according to >> commit 64dd117734d0 ("Unconditionally use MAX_EXPR/MIN_EXPR for MAX/MIN >> intrinsics"). > > The < and > operators separately already can cause exceptions, unless > you use -fno-trapping-math, in which case you cannot have LTGT at all. Hmm, I've just tried compiling: int foo(float a, float b) { return ((a < b) || (a > b)); } with -ftrapping-math and -fno-trapping-math with gcc 8.0.1, and got LTGT on tree and rtl levels in both cases: 232t.optimized: _1 = a_2(D) <> b_3(D); 312r.final: (if_then_else:SI (ltgt (reg:CCS 33 %cc)
On Tue, Aug 20, 2019 at 05:19:46PM +0200, Ilya Leoshkevich wrote: > > Am 20.08.2019 um 17:04 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > > The < and > operators separately already can cause exceptions, unless > > you use -fno-trapping-math, in which case you cannot have LTGT at all. > > Hmm, I've just tried compiling: > > int foo(float a, float b) { return ((a < b) || (a > b)); } > > with -ftrapping-math and -fno-trapping-math with gcc 8.0.1, and got LTGT > on tree and rtl levels in both cases: > > 232t.optimized: _1 = a_2(D) <> b_3(D); > 312r.final: (if_then_else:SI (ltgt (reg:CCS 33 %cc) Hrm, it seems to need -ffinite-math-only, even? Or just -ffast-math of course. (That'll teach me to post without testing for another year or two, sorry!) Segher
On Tue, Aug 20, 2019 at 11:18:38AM +0200, Ilya Leoshkevich wrote: > Currently it's not clear whether or not min, max and ltgt should raise > floating point exceptions when dealing with qNaNs. > > Right now a lot of code assumes that LTGT is signaling: in particular, > it's generated for ((x < y) || (x > y)), which is signaling. The > behavior of MIN/MAX is (intentionally?) left unspecified, according to > commit 64dd117734d0 ("Unconditionally use MAX_EXPR/MIN_EXPR for MAX/MIN > intrinsics"). Btw, this is not the difference between LTGT and NE, which is exactly the same difference as that between LT and UNLT: if NaNs are allowed, the first is false for unordered, while the second is true. If NaNs are not allowed, only one of the two is generated. (0 UNORD) LT UNLT EQ UNEQ LE UNLE GT UNGT LTGT NE GE UNGE (ORD 1) There is currently no way to say (in trees or gimple or rtl) whether comparisons are signaling ("ordered", generate a trap on an unordered result). I am working on this, but :-) Segher
> Am 20.08.2019 um 17:32 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > > On Tue, Aug 20, 2019 at 05:19:46PM +0200, Ilya Leoshkevich wrote: >>> Am 20.08.2019 um 17:04 schrieb Segher Boessenkool <segher@kernel.crashing.org>: >>> The < and > operators separately already can cause exceptions, unless >>> you use -fno-trapping-math, in which case you cannot have LTGT at all. >> >> Hmm, I've just tried compiling: >> >> int foo(float a, float b) { return ((a < b) || (a > b)); } >> >> with -ftrapping-math and -fno-trapping-math with gcc 8.0.1, and got LTGT >> on tree and rtl levels in both cases: >> >> 232t.optimized: _1 = a_2(D) <> b_3(D); >> 312r.final: (if_then_else:SI (ltgt (reg:CCS 33 %cc) > > Hrm, it seems to need -ffinite-math-only, even? Or just -ffast-math > of course. (That'll teach me to post without testing for another year > or two, sorry!) Ah, that's correct, and I have even added s390 tests for this: with -ffinite-math-only the generated code is more "straightforward". I should update the commit message, but this isn't affecting the manual update itself, right?
> Am 20.08.2019 um 17:50 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > > On Tue, Aug 20, 2019 at 11:18:38AM +0200, Ilya Leoshkevich wrote: >> Currently it's not clear whether or not min, max and ltgt should raise >> floating point exceptions when dealing with qNaNs. >> >> Right now a lot of code assumes that LTGT is signaling: in particular, >> it's generated for ((x < y) || (x > y)), which is signaling. The >> behavior of MIN/MAX is (intentionally?) left unspecified, according to >> commit 64dd117734d0 ("Unconditionally use MAX_EXPR/MIN_EXPR for MAX/MIN >> intrinsics"). > > Btw, this is not the difference between LTGT and NE, which is exactly > the same difference as that between LT and UNLT: if NaNs are allowed, > the first is false for unordered, while the second is true. If NaNs > are not allowed, only one of the two is generated. > > (0 UNORD) > LT UNLT > EQ UNEQ > LE UNLE > GT UNGT > LTGT NE > GE UNGE > (ORD 1) This matches my understanding (modulo signaling). cThis also doesn't contradict the proposed manual update, right? > There is currently no way to say (in trees or gimple or rtl) whether > comparisons are signaling ("ordered", generate a trap on an unordered > result). I am working on this, but :-) Isn't there? This whole series is based on the following assumption: LT, LE, GT, GE are definitely signaling; LTGT is most likely signaling as well; the rest are not signaling. This is based on gccint 11.6.3: Unary and Binary Expressions.
On Tue, Aug 20, 2019 at 06:13:00PM +0200, Ilya Leoshkevich wrote: > > Am 20.08.2019 um 17:50 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > > There is currently no way to say (in trees or gimple or rtl) whether > > comparisons are signaling ("ordered", generate a trap on an unordered > > result). I am working on this, but :-) > > Isn't there? This whole series is based on the following assumption: > LT, LE, GT, GE are definitely signaling; LTGT is most likely signaling > as well; the rest are not signaling. This is based on gccint 11.6.3: > Unary and Binary Expressions. There is currently no way to implement, say, iseqsig. And whether an operation is signaling should be determined by the language frontend, not separately by each backend! (There should be a signaling and a non-signaling version of every float comparison that can be unordered). Segher
> Am 20.08.2019 um 19:13 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > > On Tue, Aug 20, 2019 at 06:13:00PM +0200, Ilya Leoshkevich wrote: >>> Am 20.08.2019 um 17:50 schrieb Segher Boessenkool <segher@kernel.crashing.org>: >>> There is currently no way to say (in trees or gimple or rtl) whether >>> comparisons are signaling ("ordered", generate a trap on an unordered >>> result). I am working on this, but :-) >> >> Isn't there? This whole series is based on the following assumption: >> LT, LE, GT, GE are definitely signaling; LTGT is most likely signaling >> as well; the rest are not signaling. This is based on gccint 11.6.3: >> Unary and Binary Expressions. > > There is currently no way to implement, say, iseqsig. And whether an > operation is signaling should be determined by the language frontend, > not separately by each backend! Wouldn't expressing it as ((x <= y) && (x >= y)) work? In any case, I'll need to check whether my patch series handles iseqsig in at least remotely sane way.. > > (There should be a signaling and a non-signaling version of every float > comparison that can be unordered). I wholeheartedly agree. I had to write quite a few ugly patterns to work around the lack of e.g. non-signaling GT.
On Wed, Aug 21, 2019 at 02:00:10PM +0200, Ilya Leoshkevich wrote: > > Am 20.08.2019 um 19:13 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > > On Tue, Aug 20, 2019 at 06:13:00PM +0200, Ilya Leoshkevich wrote: > >>> Am 20.08.2019 um 17:50 schrieb Segher Boessenkool <segher@kernel.crashing.org>: > >>> There is currently no way to say (in trees or gimple or rtl) whether > >>> comparisons are signaling ("ordered", generate a trap on an unordered > >>> result). I am working on this, but :-) > >> > >> Isn't there? This whole series is based on the following assumption: > >> LT, LE, GT, GE are definitely signaling; LTGT is most likely signaling > >> as well; the rest are not signaling. This is based on gccint 11.6.3: > >> Unary and Binary Expressions. > > > > There is currently no way to implement, say, iseqsig. And whether an > > operation is signaling should be determined by the language frontend, > > not separately by each backend! > > Wouldn't expressing it as ((x <= y) && (x >= y)) work? That is optimised only partially (on gimple) (first a compare for <=, then a branch if false, then return "=="). I meant it cannot be implemented directly as one RTL (or gimple) insn, although it can be done as one machine insn on many architectures. > > (There should be a signaling and a non-signaling version of every float > > comparison that can be unordered). > > I wholeheartedly agree. I had to write quite a few ugly patterns to > work around the lack of e.g. non-signaling GT. Ooh, buy in, I like it. Thanks for the encouragement :-) Segher
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi index 8901d5f357e..d5ae20bd461 100644 --- a/gcc/doc/generic.texi +++ b/gcc/doc/generic.texi @@ -1331,6 +1331,8 @@ the byte offset of the field, but should not be used directly; call @tindex UNGE_EXPR @tindex UNEQ_EXPR @tindex LTGT_EXPR +@tindex MIN_EXPR +@tindex MAX_EXPR @tindex MODIFY_EXPR @tindex INIT_EXPR @tindex COMPOUND_EXPR @@ -1602,13 +1604,21 @@ These operations take two floating point operands and determine whether the operands are unordered or are less than, less than or equal to, greater than, greater than or equal to, or equal respectively. For example, @code{UNLT_EXPR} returns true if either operand is an IEEE -NaN or the first operand is less than the second. With the possible -exception of @code{LTGT_EXPR}, all of these operations are guaranteed -not to generate a floating point exception. The result +NaN or the first operand is less than the second. Only @code{LTGT_EXPR} +is expected to raise an invalid floating-point-operation trap when the +outcome is unordered. All other operations are guaranteed not to raise +a floating point exception. The result type of these expressions will always be of integral or boolean type. These operations return the result type's zero value for false, and the result type's one value for true. +@item MIN_EXPR +@itemx MAX_EXPR +These nodes represent minimum and maximum operations. When used with +floating point, if both operands are zeros, or if either operand is +@code{NaN}, then it is unspecified which of the two operands is returned +as the result and whether or not a floating point exception is raised. + @item MODIFY_EXPR These nodes represent assignment. The left-hand side is the first operand; the right-hand side is the second operand. The left-hand side diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 7751984bf5f..74f8ec84974 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5353,7 +5353,8 @@ in the rtl as @item @samp{smin@var{m}3}, @samp{smax@var{m}3} Signed minimum and maximum operations. When used with floating point, if both operands are zeros, or if either operand is @code{NaN}, then -it is unspecified which of the two operands is returned as the result. +it is unspecified which of the two operands is returned as the result +and whether or not a floating point exception is raised. @cindex @code{fmin@var{m}3} instruction pattern @cindex @code{fmax@var{m}3} instruction pattern diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 0814b66a486..e0628da893d 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -2596,7 +2596,8 @@ Represents the smaller (for @code{smin}) or larger (for @code{smax}) of @var{x} and @var{y}, interpreted as signed values in mode @var{m}. When used with floating point, if both operands are zeros, or if either operand is @code{NaN}, then it is unspecified which of the two operands -is returned as the result. +is returned as the result and whether or not a floating point exception +is raised. @findex umin @findex umax