[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-06-12 Thread sjames at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

Sam James  changed:

   What|Removed |Added

   See Also||https://gcc.gnu.org/bugzill
   ||a/show_bug.cgi?id=120638

--- Comment #15 from Sam James  ---
(In reply to chenglulu from comment #14)
> Hi:
> 
> With the patch, the following testcase generates an incorrect assembly on
> LoongArch.
> [...]

(For the record, filed as PR120638).

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-06-10 Thread chenglulu at loongson dot cn via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

chenglulu  changed:

   What|Removed |Added

 CC||chenglulu at loongson dot cn

--- Comment #14 from chenglulu  ---
Hi:

With the patch, the following testcase generates an incorrect assembly on
LoongArch.

test.c
```
unsigned int step;
double sqrt (double x);
void test1 (double);
void
test ()
{
  test1 (0.5 / sqrt (1. + step));
}
```
# cc1 test.c -o test.s -Ofast -fdump-tree-dom3

```
test:
.LFB0 = .
.cfi_startproc
pcalau12i   $r12,%pc_hi20(.LC0)
fld.d   $f0,$r12,%pc_lo12(.LC0)
b   %plt(test1)
```
I found that in the dom3 optimization, the range calculation of _5 is
incorrect.

```
Exporting new  global ranges:

Global Exported: _5 = [frange] double [5.0e-1 (0x0.8p+0), 5.0e-1 (0x0.8p+0)]
= Done =
void test ()
{
  unsigned int step.0_1;
  double _2;
  double _3;
  double _4;
  double _5;

   [local count: 1073741824]:
  step.0_1 = step;
  _2 = (double) step.0_1;
  _3 = _2 + 1.0e+0; 
  _4 = .RSQRT (_3); 
  _5 = _4 * 5.0e-1; 
  test1 (5.0e-1);
  return;

} 
```

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-06-05 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

Jakub Jelinek  changed:

   What|Removed |Added

 Status|NEW |RESOLVED
   Assignee|unassigned at gcc dot gnu.org  |jakub at gcc dot gnu.org
 Resolution|--- |FIXED

--- Comment #13 from Jakub Jelinek  ---
Should be implemented now.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-06-05 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #12 from GCC Commits  ---
The master branch has been updated by Jakub Jelinek :

https://gcc.gnu.org/g:b6b238ddcb119bb51555ead9be0fa7b06b8a6be7

commit r16-1191-gb6b238ddcb119bb51555ead9be0fa7b06b8a6be7
Author: Jakub Jelinek 
Date:   Thu Jun 5 18:10:22 2025 +0200

ranger: Add support for float <-> int casts [PR120231]

The following patch adds support for float <-> integer conversions in
ranger.
The patch reverts part of the r16-571 changes, those changes were right
for fold_range, but not for op1_range, where RO_IFI and RO_FIF are actually
called rather than RO_IFF and RO_FII that the patch expected.
Also, the float -> int operation actually uses FIX_TRUNC_EXPR tree code
rather than NOP_EXPR or CONVERT_EXPR and int -> float uses FLOAT_EXPR,
but I think we can just handle all of them using operator_cast, at least
as long as we don't try to use VIEW_CONVERT_EXPR using that too; not really
sure handling VCE at least for floating to integral or vice versa would
be actually useful though.

The patch "regressed" two tests, gfortran.dg/inline_matmul_16.f90 and
g++.dg/tree-ssa/loop-split-1.C.  In the first case, there is a loop doing
matmul on various sizes of matrices, up to 10x10 matrices, and Fortran
FE given the options emits two implementations of the matmul, one inline
for the case where the matmul has less than 1000 elements and one for
larger matmuls.  The check for whatever reason uses floating point
calculations and before this patch we weren't able to prove that all the
matrices will be smaller than the cutoff and the test was checking for
presence of the fallback call; with the patch we are able to figure it
out and only keep the inline copy.  I've duplicated the test, once
unmodified source which doesn't expect _gfortran_matmul string in optimized
dump anymore, and another copy which uses volatile ten instead of 10 in
loop upper bounds so that it has to keep the fallback and scans for it.
The other test is g++.dg/tree-ssa/loop-split-1.C, which does
constexpr unsigned s = 1;
...
for(unsigned i = 0; i < s; ++i)
{
if(i == 0)
a[i] = b[i] * c[i];
else
a[i] = (b[i] + c[i]) * c[i-1] * std::log(i);
}
and for some reason the successful loop splitting for which the test
searches in a dump file is dependent on the errno fallback of std::log,
where we do t = std::log((double)i); if ((double)i) u> 0); else log
((double)i);
But i goes only from 1 to 1, so (double)i has the range
[1.0, 1.0] with the patch and so we see it will never need errno
nor raise exception.  I've tested adding + d for it where d is 0.0 but
modifiable in some other TU, and tested it also with r14-2851 and r14-2852,
where the former FAILed the test both unmodified and modified, while
the latter PASSed both versions.

2025-06-05  Jakub Jelinek  

PR tree-optimization/120231
* range-op.cc (range_op_table::range_op_table): Register op_cast
also for FLOAT_EXPR and FIX_TRUNC_EXPR.
(RO_III): Adjust comment.
(range_op_handler::op1_range): Handle RO_IFI rather than RO_IFF.
Don't handle RO_FII.
(range_operator::op1_range): Remove overload with
irange &, tree, const frange &, const frange &, relation_trio
and frange &, tree, const irange &, const irange &, relation_trio
arguments.  Add overload with
irange &, tree, const frange &, const irange &, relation_trio
arguments.
* range-op-mixed.h (operator_cast::op1_range): Remove overload with
irange &, tree, const frange &, const frange &, relation_trio
and frange &, tree, const irange &, const irange &, relation_trio
arguments.  Add overload with
irange &, tree, const frange &, const irange &, relation_trio and
frange &, tree, const irange &, const frange &, relation_trio
arguments.
* range-op.h (range_operator::op1_cast): Remove overload with
irange &, tree, const frange &, const frange &, relation_trio
and frange &, tree, const irange &, const irange &, relation_trio
arguments.  Add overload with
irange &, tree, const frange &, const irange &, relation_trio
arguments.
* range-op-float.cc (operator_cast::fold_range): Implement
float to int and int to float casts.
(operator_cast::op1_range): Remove overload with
irange &, tree, const frange &, const frange &, relation_trio
and frange &, tree, const irange &, const irange &, relation_trio
arguments.  Add overload with
irange &, tree, const frange &, const irange &, r

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-06-04 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #11 from Jakub Jelinek  ---
Created attachment 61583
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61583&action=edit
gcc16-pr120231.patch

Untested patch for the float -> int and int -> float casts and their reverse
ops.

Unfortunately it regresses
FAIL: g++.dg/tree-ssa/loop-split-1.C   scan-tree-dump-times lsplit "loop split"
1
FAIL: gfortran.dg/inline_matmul_16.f90   -O   scan-tree-dump-times optimized
"_gfortran_matmul" 1
tests, so I'll need to study those up tomorrow.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-06-04 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #10 from GCC Commits  ---
The master branch has been updated by Jakub Jelinek :

https://gcc.gnu.org/g:b7960a3f966a0f87888de0fc588999d026918449

commit r16-1108-gb7960a3f966a0f87888de0fc588999d026918449
Author: Jakub Jelinek 
Date:   Wed Jun 4 17:21:51 2025 +0200

ranger: Add support for float <-> float casts [PR120231]

I've noticed we don't even support say float -> double and other
scalar floating point to scalar floating point conversions in the
ranger, we just end up with VARYING for those.

The following patch attempts to fix that.
The reverse cast case uses float_binary_op_range_finish e.g. because
if the result isn't infinite, then the source couldn't be infinite
either even if the reverse fold_range would suggest that.
And special cases the case of guaranteed widening cast (where
we have assurance that all the source type values are exactly
representable in the destination type; using ieee_bits for that).

2025-06-04  Jakub Jelinek  

PR tree-optimization/120231
* range-op-mixed.h (operator_cast::fold_range): Add overload
with 3 {,const} frange & operands.  Change parameter names and
add final override keywords for float <-> integer cast overloads.
(operator_cast::op1_range): Likewise.
* range-op-float.cc (operator_cast::fold_range): New overload
with 3 {,const} frange & operands.
(operator_cast::op1_range): Likewise.

* gcc.dg/tree-ssa/pr120231-1.c: New test.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-06-02 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #9 from Jakub Jelinek  ---
Apparently we are missing range implementation of casts between different
floating point types as well.

Trying now:
--- gcc/range-op-mixed.h.jj 2025-05-20 08:14:06.520404648 +0200
+++ gcc/range-op-mixed.h2025-06-02 14:30:37.304673412 +0200
@@ -473,14 +473,15 @@ public:
   bool fold_range (prange &r, tree type,
   const irange &op1, const prange &op2,
   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (frange &r, tree type,
+  const frange &op1, const frange &op2,
+  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
-  const frange &lh,
-  const irange &rh,
-  relation_trio = TRIO_VARYING) const;
+  const frange &op1, const irange &op2,
+  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (frange &r, tree type,
-  const irange &lh,
-  const frange &rh,
-  relation_trio = TRIO_VARYING) const;
+  const irange &op1, const frange &op2,
+  relation_trio = TRIO_VARYING) const final override;

   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
@@ -495,13 +496,14 @@ public:
  const irange &lhs, const prange &op2,
  relation_trio rel = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
- const irange &lhs,
- const irange &op2,
- relation_trio = TRIO_VARYING) const;
+ const frange &lhs, const frange &op2,
+ relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (frange &r, tree type,
+ const irange &lhs, const irange &op2,
+ relation_trio = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
- const frange &lhs,
- const frange &op2,
- relation_trio = TRIO_VARYING) const;
+ const frange &lhs, const frange &op2,
+ relation_trio = TRIO_VARYING) const final override;

   relation_kind lhs_op1_relation (const irange &lhs,
  const irange &op1, const irange &op2,
--- gcc/range-op-float.cc.jj2025-05-20 08:14:06.519404661 +0200
+++ gcc/range-op-float.cc   2025-06-02 15:23:14.171003089 +0200
@@ -2899,6 +2899,107 @@ private:
   }
 } fop_div;

+bool
+operator_cast::fold_range (frange &r, tree type, const frange &op1,
+  const frange &, relation_trio) const
+{
+  REAL_VALUE_TYPE lb, ub;
+  enum machine_mode mode = TYPE_MODE (type);
+  bool mode_composite = MODE_COMPOSITE_P (mode);
+
+  if (empty_range_varying (r, type, op1, op1))
+return true;
+  if (!MODE_HAS_NANS (mode) && op1.maybe_isnan ())
+{
+  r.set_varying (type);
+  return true;
+}
+  if (op1.known_isnan ())
+{
+  r.set_nan (type);
+  return true;
+}
+
+  const REAL_VALUE_TYPE &lh_lb = op1.lower_bound ();
+  const REAL_VALUE_TYPE &lh_ub = op1.upper_bound ();
+  real_convert (&lb, mode, &lh_lb);
+  real_convert (&ub, mode, &lh_ub);
+
+  if (flag_rounding_math)
+{
+  if (real_less (&lh_lb, &lb))
+   {
+ if (mode_composite
+ && (real_isdenormal (&lb, mode) || real_iszero (&lb)))
+   {
+ // IBM extended denormals only have DFmode precision.
+ REAL_VALUE_TYPE tmp, tmp2;
+ real_convert (&tmp2, DFmode, &lh_lb);
+ real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2,
+ &dconstninf);
+ real_convert (&lb, mode, &tmp);
+   }
+ else
+   frange_nextafter (mode, lb, dconstninf);
+   }
+  if (real_less (&ub, &lh_ub))
+   {
+ if (mode_composite
+ && (real_isdenormal (&ub, mode) || real_iszero (&ub)))
+   {
+ // IBM extended denormals only have DFmode precision.
+ REAL_VALUE_TYPE tmp, tmp2;
+ real_convert (&tmp2, DFmode, &lh_ub);
+ real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2,
+ &dconstinf);
+ real_convert (&ub, mode, &tmp);
+   }
+ else
+   frange_nextafter (mode, ub, dconstinf);
+   }
+}
+
+  r.set (type, lb, ub, op1.get_nan_state ());
+
+  if (flag_trapping_math
+  && MODE_HAS_INFINITIES (TYPE_MODE (type))
+  && r.known_isinf ()
+  && !op1.known_isinf ())
+{
+  REAL_VALUE_TYPE inf = r.lower_bound ();
+  if (real_isneg (&inf))
+   {
+ REAL_VALUE_TYPE min = real_min_representable (type);
+ r.set (type, inf, min);
+   }
+  else
+   {
+ REAL_VALUE_TYPE max = real_max_

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-22 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #8 from Jakub Jelinek  ---
In any case, #c5 and onwards is completely unrelated to this PR, which is about
value ranges for casts from integers to floating point and vice versa.  So,
please move that elsewhere.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-22 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #7 from Jakub Jelinek  ---
(In reply to Alex Coplan from comment #6)
> I suppose that example boils down to whether code like:
> 
> _Bool f(_Float16 a) {
> return a * a >= 0;
> }
> _Bool g(float a) {
> return a * a >= 0;
> }
> 
> can be optimised to return true.  We currently do it with -ffast-math but
> not without.

And it is correct like that.  If a is a NaN (qNaN or sNaN), then a * a >= 0 is
false.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-22 Thread acoplan at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #6 from Alex Coplan  ---
I suppose that example boils down to whether code like:

_Bool f(_Float16 a) {
return a * a >= 0;
}
_Bool g(float a) {
return a * a >= 0;
}

can be optimised to return true.  We currently do it with -ffast-math but not
without.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-22 Thread joe.ramsay at arm dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

Joe Ramsay  changed:

   What|Removed |Added

 CC||joe.ramsay at arm dot com

--- Comment #5 from Joe Ramsay  ---
Hello! I have discovered a similar issue, commenting in case another data point
is useful. The following:

#include 

_Float16 norm(_Float16 re, _Float16 im) {
return sqrtf(re * re + im * im);
}

compiled with -march=armv8-a+fp16 -O3 gives

norm:
fmulh1, h1, h1
fmadd   h1, h0, h0, h1
fcvts0, h1
fcmps0, #0.0
bpl .L4
stp x29, x30, [sp, -32]!
mov x29, sp
str s1, [sp, 28]
bl  sqrtf
ldr s1, [sp, 28]
ldp x29, x30, [sp], 32
fsqrt   h0, h1
ret
.L4:
fsqrt   h0, h1
ret

and with -ffast-math added gives:

norm:
fmulh1, h1, h1
fmadd   h0, h0, h0, h1
fsqrt   h0, h0
ret

I think GCC is being overly cautious here - the fast FSQRT case is fine without
fast-math (the optimal sequence is emitted without -ffast-math for single- and
double-precision floats).

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-12 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #4 from GCC Commits  ---
The master branch has been updated by Andrew Macleod :

https://gcc.gnu.org/g:6f375445ef09d5c97d5bcc0fcb6069612217963e

commit r16-571-g6f375445ef09d5c97d5bcc0fcb6069612217963e
Author: Andrew MacLeod 
Date:   Mon May 12 11:41:37 2025 -0400

Add dispatch for casts between integer and float.

GCC currently does not implement range operators for casting between
integers and float.  This patch adds the missing dispatch patterns and
routines to facilitate implmenting these casts.

PR tree-optimization/120231
* range-op-float.cc (operator_cast::fold_range): New variants.
(operator_cast::op1_range): Likewise.
* range-op-mixed.h (operator_cast::fold_range): Likewise.
(operator_cast::op1_range): Likewise
* range-op.cc (range_op_handler::fold_range): Add RO_FIF dispatch.
(range_op_handler::op1_range): Add RO_IFF and RO_FII patterns.
(range_operator::fold_range): Provide new variant default.
(range_operator::op1_range): Likewise.
* range-op.h (range_operator): Add new variant methods.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-12 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #3 from Jakub Jelinek  ---
Yeah, I'd definitely appreciate blank handlers for those, which I can gradually
try to implement.  Working now on big-endian _BitInt, so it won't be
immediately, but will try to get to it before summer.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-12 Thread amacleod at redhat dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

--- Comment #2 from Andrew Macleod  ---
We do not have cast operators between int and float.  We are also missing some
dispatch code for them as we haven't actually used some of those patterns yet.

I am going to checked in a patch to trunk shortly using this PR as a tag.  It
supplies the needed patterns and blank versions of the required operator
methods for each cast. These are located near the bottom of range-op-float.cc. 
 These functions currently return false, which is the default behaviour if the
functions did not exist.


// Cast Float to Integer
bool operator_cast::fold_range (irange &lhs, tree type, const frange &op1,
const irange &, relation_trio) const;
bool operator_cast::op1_range (frange &op1, tree type, const irange &lhs, const
irange &, relation_trio) const;

// Cast Integer to Float.
bool operator_cast::fold_range (frange &lhs, tree type, const irange &op1,
const frange &, relation_trio) const;
bool operator_cast::op1_range (irange &op1, tree type, const frange &lhs, const
frange &, relation_trio) const;


Feel free to populate them for this PR.  If I get a chance and no one else
does, I may do some simple population. but it wont be complex since I'm not
familiar with working on floats.

[Bug tree-optimization/120231] GCC fails to notice that (double)u64 is non-negative

2025-05-12 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231

Jakub Jelinek  changed:

   What|Removed |Added

 Ever confirmed|0   |1
 CC||amacleod at redhat dot com,
   ||jakub at gcc dot gnu.org
 Status|UNCONFIRMED |NEW
   Last reconfirmed||2025-05-12

--- Comment #1 from Jakub Jelinek  ---
I think we don't have value range handlers for casts from integers to floating
point, from floating point to integers and their reverse operations, and it
would certainly be desirable to add those.
Say if we know that some integer SSA_NAME has [42, 48] range, then the frange
when that is converted to say double will be [42.0, 48.0].  Of course, when the
boundary values can't be converted exactly, we need to take it into account
etc.