TYPE_{MIN/MAX}_VALUE for floats?
Checks
Commit Message
It has always irritated me that we don't have TYPE_MIN_VALUE and
TYPE_MAX_VALUE for floats (and for pointers for that matter). This
means, we have to recalculate it ad-nauseum in vrp_val_min and
vrp_val_max.
I know we have dconstinf and dconstninf for floats, which we can just
wrap around a TREE_REAL_CST, but it still seems like we should be more
consistent here. If we know the endpoint for a type, we should cache
it in it.
Furthermore, just the way we're chopping off NANs in the frange::set()
routine, we should be able to chop off things outside the min/max
representable range, at least for -ffinite-math-only. For example,
the endpoints to VR_VARYING for a float in -ffinite-math-only should
be real_{min/max}_representable(), which REAL_VALUE_TYPE already
provides. I am testing a patch to do this, but am unhappy that we
have recalculate things.
Is there a reason we can't store these in the type?
I tried the naive attached approach, but I quickly ran into LTO woes:
FAIL: gcc.c-torture/execute/ieee/20001122-1.c compilation, -O2 -flto
-fno-use-linker-plugin -flto-partition=none
(internal compiler error: 'verify_type' failed)
$ ./xgcc -B./ a.c -O2 -flto -w
lto1: error: type variant differs by TYPE_MAX_VALUE
So I clearly don't know what I'm doing.
Would folks be ok with filling TYPE_MIN_VALUE and friends for floats,
and if so, could someone give me a hand here? What am I missing?
Thanks.
Aldy
p.s. Now that we're onto this subject, in the distant future, I'd
actually like to store a vrange in the tree type. I mean, they are
first class citizens in the SSA name now, and we have a typeless way
of storing ranges in GC space. Anywho, that's for the future, cause I
like the pain... just wanted to gauge the temperature on that one as
well.
Comments
On Thu, Sep 22, 2022 at 05:02:19PM +0200, Aldy Hernandez wrote:
> It has always irritated me that we don't have TYPE_MIN_VALUE and
> TYPE_MAX_VALUE for floats (and for pointers for that matter). This
> means, we have to recalculate it ad-nauseum in vrp_val_min and
> vrp_val_max.
>
> I know we have dconstinf and dconstninf for floats, which we can just
> wrap around a TREE_REAL_CST, but it still seems like we should be more
> consistent here. If we know the endpoint for a type, we should cache
> it in it.
This looks problematic.
While for !MODE_HAS_INFINITIES there are clear values, otherwise
the flag_finite_math_only flag has Optimization keyword, so it can change
between different functions, while a type is a global entity that can be
used by both __attribute__((optimize ("Ofast"))) and standard floating point
functions.
In some sense it is similar to TYPE_MODE which for vectors needs to be
actually a function call that decides based on the current function.
But then, having it in TYPE_*_VALUE doesn't have the benefits you want from
it...
Jakub
On Thu, Sep 22, 2022 at 5:22 PM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Thu, Sep 22, 2022 at 05:02:19PM +0200, Aldy Hernandez wrote:
> > It has always irritated me that we don't have TYPE_MIN_VALUE and
> > TYPE_MAX_VALUE for floats (and for pointers for that matter). This
> > means, we have to recalculate it ad-nauseum in vrp_val_min and
> > vrp_val_max.
> >
> > I know we have dconstinf and dconstninf for floats, which we can just
> > wrap around a TREE_REAL_CST, but it still seems like we should be more
> > consistent here. If we know the endpoint for a type, we should cache
> > it in it.
>
> This looks problematic.
> While for !MODE_HAS_INFINITIES there are clear values, otherwise
> the flag_finite_math_only flag has Optimization keyword, so it can change
> between different functions, while a type is a global entity that can be
> used by both __attribute__((optimize ("Ofast"))) and standard floating point
> functions.
Oh...it can have different values in different functions? Yeah,
that's not gonna work. Oh well, thanks.
Aldy
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
#include "debug.h"
#include "calls.h"
+#include "real.h"
/* Data type for the expressions representing sizes of data types.
It is the first integer type laid out. */
@@ -7620,6 +7620,31 @@ build_offset_type (tree basetype, tree type)
return t;
}
+/* Create a floating point type with PRECISION. */
+
+tree
+build_float_type (unsigned precision)
+{
+ tree type = make_node (REAL_TYPE);
+ TYPE_PRECISION (type) = precision;
+ layout_type (type);
+
+ if (flag_finite_math_only)
+ {
+ REAL_VALUE_TYPE min, max;
+ real_min_representable (&min, type);
+ real_max_representable (&max, type);
+ TYPE_MIN_VALUE (type) = build_real (type, min);
+ TYPE_MAX_VALUE (type) = build_real (type, max);
+ }
+ else
+ {
+ TYPE_MIN_VALUE (type) = build_real (type, dconstninf);
+ TYPE_MAX_VALUE (type) = build_real (type, dconstinf);
+ }
+ return type;
+}
+
/* Create a complex type whose components are COMPONENT_TYPE.
If NAMED is true, the type is given a TYPE_NAME. We do not always
@@ -9427,17 +9452,9 @@ build_common_tree_nodes (bool signed_char)
pointer_sized_int_node = build_nonstandard_integer_type (POINTER_SIZE, 1);
- float_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
- layout_type (float_type_node);
-
- double_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
- layout_type (double_type_node);
-
- long_double_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
- layout_type (long_double_type_node);
+ float_type_node = build_float_type (FLOAT_TYPE_SIZE);
+ double_type_node = build_float_type (DOUBLE_TYPE_SIZE);
+ long_double_type_node = build_float_type (LONG_DOUBLE_TYPE_SIZE);
for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
{
@@ -4729,6 +4729,7 @@ extern tree build_varargs_function_type_array (tree, int, tree *);
extern tree build_method_type_directly (tree, tree, tree);
extern tree build_method_type (tree, tree);
extern tree build_offset_type (tree, tree);
+extern tree build_float_type (unsigned);
extern tree build_complex_type (tree, bool named = false);
extern tree array_type_nelts (const_tree);