/**************************************************************************** * * * GNAT COMPILER COMPONENTS * * * * C U I N T P * * * * C Implementation File * * * * Copyright (C) 1992-2024, Free Software Foundation, Inc. * * * * GNAT is free software; you can redistribute it and/or modify it under * * terms of the GNU General Public License as published by the Free Soft- * * ware Foundation; either version 3, or (at your option) any later ver- * * sion. GNAT is distributed in the hope that it will be useful, but WITH- * * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. You should have received a copy of the GNU General * * Public License along with GCC; see the file COPYING3. If not see * * . * * * * GNAT was originally developed by the GNAT team at New York University. * * Extensive contributions were provided by Ada Core Technologies Inc. * * * ****************************************************************************/ /* This file corresponds to the Ada package body Uintp. It was created manually from the files uintp.ads and uintp.adb. */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" #include "vec.h" #include "alias.h" #include "tree.h" #include "inchash.h" #include "fold-const.h" #include "stor-layout.h" #include "ada.h" #include "types.h" #include "uintp.h" #include "sinfo.h" #include "ada-tree.h" #include "gigi.h" /* Universal integers are represented by the Uint type which is an index into the Uints_Ptr table containing Uint_Entry values. A Uint_Entry contains an index and length for getting the "digits" of the universal integer from the Udigits_Ptr table. For efficiency, this method is used only for integer values larger than the constant Uint_Bias. If a Uint is less than this constant, then it contains the integer value itself. First define a utility function that is build_int_cst for integral types and does a conversion for floating-point types. */ static tree build_cst_from_int (tree type, HOST_WIDE_INT low) { if (SCALAR_FLOAT_TYPE_P (type)) return convert (type, build_int_cst (gnat_type_for_size (32, 0), low)); else return build_int_cst (type, low); } /* Similar to UI_To_Int, but return a GCC INTEGER_CST or REAL_CST node, depending on whether TYPE is an integral or real type. Overflow is tested by the constant-folding used to build the node. TYPE is the GCC type of the resulting node. If TYPE is NULL, an unsigned integer type wide enough to hold the entire constant is selected, and if no such type exists, return NULL_TREE. */ tree UI_To_gnu (Uint Input, tree type) { /* We might have a TYPE with biased representation and be passed an unbiased value that doesn't fit. We always use an unbiased type to be able to hold any such possible value for intermediate computations and then rely on a conversion back to TYPE to perform the bias adjustment when need be. */ tree comp_type = (!type ? gnat_type_for_size (32, 1) : (TREE_CODE (type) == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (type)) ? get_base_type (type) : type); tree gnu_ret; if (Input <= Uint_Direct_Last) gnu_ret = build_cst_from_int (comp_type, Input - Uint_Direct_Bias); else { Int Idx = (*Uints_Ptr)[Input - Uint_Table_Start].Loc; Pos Length = (*Uints_Ptr)[Input - Uint_Table_Start].Length; Int First = (*Udigits_Ptr)[Idx]; tree_code code = First < 0 ? MINUS_EXPR : PLUS_EXPR; tree gnu_base; gcc_assert (Length > 0); /* The extension of unsigned types we use to try to fit the constant only works if we're dealing with nonnegative constants, but that's what we expect when !TYPE. */ gcc_assert (type || First >= 0); /* The computations we perform below always require a type at least as large as an integer not to overflow. FP types are always fine, but INTEGER or ENUMERAL types we are handed may be too short. We use a base integer type node for the computations in this case and will convert the final result back to the incoming type later on. */ if (!SCALAR_FLOAT_TYPE_P (comp_type) && TYPE_PRECISION (comp_type) < 32) comp_type = gnat_type_for_size (32, 0); gnu_base = build_cst_from_int (comp_type, Base); gnu_ret = build_cst_from_int (comp_type, First); for (Idx++, Length--; Length; Idx++, Length--) for (;;) { tree elt, scaled, next_ret; elt = build_cst_from_int (comp_type, (*Udigits_Ptr)[Idx]); /* We want to detect overflows with an unsigned type when TYPE is not given, but int_const_binop doesn't work for e.g. floating-point TYPEs. */ if (!type) { scaled = int_const_binop (MULT_EXPR, gnu_ret, gnu_base, -1); next_ret = int_const_binop (code, scaled, elt, -1); } else { scaled = fold_build2 (MULT_EXPR, comp_type, gnu_ret, gnu_base); next_ret = fold_build2 (code, comp_type, scaled, elt); } if (!TREE_OVERFLOW (next_ret) || type) { gnu_ret = next_ret; break; } opt_scalar_int_mode wider_mode = GET_MODE_WIDER_MODE (SCALAR_INT_TYPE_MODE (comp_type)).require (); if (!wider_mode.exists ()) /* Signal that we couldn't represent the value. */ return NULL_TREE; comp_type = make_unsigned_type (GET_MODE_BITSIZE (wider_mode.require ())); gnu_base = convert (comp_type, gnu_base); gnu_ret = convert (comp_type, gnu_ret); } } if (!type) type = comp_type; gnu_ret = convert (type, gnu_ret); /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on GNU_RET. */ while ((TREE_CODE (gnu_ret) == NOP_EXPR || TREE_CODE (gnu_ret) == NON_LVALUE_EXPR) && TREE_TYPE (TREE_OPERAND (gnu_ret, 0)) == TREE_TYPE (gnu_ret)) gnu_ret = TREE_OPERAND (gnu_ret, 0); return gnu_ret; } /* Similar to UI_From_Int, but take a GCC INTEGER_CST. We use UI_From_Int when possible, i.e. for a 32-bit signed value, to take advantage of its built-in caching mechanism. For values of larger magnitude, we compute digits into a vector and call Vector_To_Uint. */ Uint UI_From_gnu (tree Input) { tree gnu_type = TREE_TYPE (Input), gnu_base, gnu_temp; /* UI_Base is defined so that 5 Uint digits is sufficient to hold the largest possible signed 64-bit value. */ const int Max_For_Dint = 5; int v[Max_For_Dint]; Vector_Template temp; Int_Vector vec; #if HOST_BITS_PER_WIDE_INT < 64 #error unsupported HOST_BITS_PER_WIDE_INT setting #endif /* On 64-bit hosts, tree_fits_shwi_p tells whether the input fits in a signed 64-bit integer. Then a truncation tells whether it fits in a signed 32-bit integer. */ if (tree_fits_shwi_p (Input)) { HOST_WIDE_INT hw_input = tree_to_shwi (Input); if (hw_input == (int) hw_input) return UI_From_Int (hw_input); } else return No_Uint; gnu_base = build_int_cst (gnu_type, UI_Base); gnu_temp = Input; for (int i = Max_For_Dint - 1; i >= 0; i--) { v[i] = tree_to_shwi (fold_build1 (ABS_EXPR, gnu_type, fold_build2 (TRUNC_MOD_EXPR, gnu_type, gnu_temp, gnu_base))); gnu_temp = fold_build2 (TRUNC_DIV_EXPR, gnu_type, gnu_temp, gnu_base); } temp.Low_Bound = 1; temp.High_Bound = Max_For_Dint; vec.Bounds = &temp; vec.Array = v; return Vector_To_Uint (vec, tree_int_cst_sgn (Input) < 0); }