1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2016, Free Software Foundation, Inc. *
11 * GNAT is free software; you can redistribute it and/or modify it under *
12 * terms of the GNU General Public License as published by the Free Soft- *
13 * ware Foundation; either version 3, or (at your option) any later ver- *
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
17 * for more details. You should have received a copy of the GNU General *
18 * Public License along with GCC; see the file COPYING3. If not see *
19 * <http://www.gnu.org/licenses/>. *
21 * GNAT was originally developed by the GNAT team at New York University. *
22 * Extensive contributions were provided by Ada Core Technologies Inc. *
24 ****************************************************************************/
26 /* This file corresponds to the Ada package body Uintp. It was created
27 manually from the files uintp.ads and uintp.adb. */
31 #include "coretypes.h"
37 #include "fold-const.h"
45 /* Universal integers are represented by the Uint type which is an index into
46 the Uints_Ptr table containing Uint_Entry values. A Uint_Entry contains an
47 index and length for getting the "digits" of the universal integer from the
50 For efficiency, this method is used only for integer values larger than the
51 constant Uint_Bias. If a Uint is less than this constant, then it contains
52 the integer value itself. The origin of the Uints_Ptr table is adjusted so
53 that a Uint value of Uint_Bias indexes the first element.
55 First define a utility function that is build_int_cst for integral types and
56 does a conversion for floating-point types. */
59 build_cst_from_int (tree type
, HOST_WIDE_INT low
)
61 if (SCALAR_FLOAT_TYPE_P (type
))
62 return convert (type
, build_int_cst (gnat_type_for_size (32, 0), low
));
64 return build_int_cst (type
, low
);
67 /* Similar to UI_To_Int, but return a GCC INTEGER_CST or REAL_CST node,
68 depending on whether TYPE is an integral or real type. Overflow is tested
69 by the constant-folding used to build the node. TYPE is the GCC type of
70 the resulting node. */
73 UI_To_gnu (Uint Input
, tree type
)
75 /* We might have a TYPE with biased representation and be passed an unbiased
76 value that doesn't fit. We always use an unbiased type to be able to hold
77 any such possible value for intermediate computations and then rely on a
78 conversion back to TYPE to perform the bias adjustment when need be. */
80 = TREE_CODE (type
) == INTEGER_TYPE
&& TYPE_BIASED_REPRESENTATION_P (type
)
81 ? get_base_type (type
) : type
;
84 if (Input
<= Uint_Direct_Last
)
85 gnu_ret
= build_cst_from_int (comp_type
, Input
- Uint_Direct_Bias
);
88 Int Idx
= Uints_Ptr
[Input
].Loc
;
89 Pos Length
= Uints_Ptr
[Input
].Length
;
90 Int First
= Udigits_Ptr
[Idx
];
93 gcc_assert (Length
> 0);
95 /* The computations we perform below always require a type at least as
96 large as an integer not to overflow. FP types are always fine, but
97 INTEGER or ENUMERAL types we are handed may be too short. We use a
98 base integer type node for the computations in this case and will
99 convert the final result back to the incoming type later on. */
100 if (!SCALAR_FLOAT_TYPE_P (comp_type
) && TYPE_PRECISION (comp_type
) < 32)
101 comp_type
= gnat_type_for_size (32, 0);
103 gnu_base
= build_cst_from_int (comp_type
, Base
);
105 gnu_ret
= build_cst_from_int (comp_type
, First
);
107 for (Idx
++, Length
--; Length
; Idx
++, Length
--)
108 gnu_ret
= fold_build2 (MINUS_EXPR
, comp_type
,
109 fold_build2 (MULT_EXPR
, comp_type
,
111 build_cst_from_int (comp_type
,
114 for (Idx
++, Length
--; Length
; Idx
++, Length
--)
115 gnu_ret
= fold_build2 (PLUS_EXPR
, comp_type
,
116 fold_build2 (MULT_EXPR
, comp_type
,
118 build_cst_from_int (comp_type
,
122 gnu_ret
= convert (type
, gnu_ret
);
124 /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on GNU_RET. */
125 while ((TREE_CODE (gnu_ret
) == NOP_EXPR
126 || TREE_CODE (gnu_ret
) == NON_LVALUE_EXPR
)
127 && TREE_TYPE (TREE_OPERAND (gnu_ret
, 0)) == TREE_TYPE (gnu_ret
))
128 gnu_ret
= TREE_OPERAND (gnu_ret
, 0);
133 /* Similar to UI_From_Int, but take a GCC INTEGER_CST. We use UI_From_Int
134 when possible, i.e. for a 32-bit signed value, to take advantage of its
135 built-in caching mechanism. For values of larger magnitude, we compute
136 digits into a vector and call Vector_To_Uint. */
139 UI_From_gnu (tree Input
)
141 tree gnu_type
= TREE_TYPE (Input
), gnu_base
, gnu_temp
;
142 /* UI_Base is defined so that 5 Uint digits is sufficient to hold the
143 largest possible signed 64-bit value. */
144 const int Max_For_Dint
= 5;
145 int v
[Max_For_Dint
], i
;
146 Vector_Template temp
;
149 #if HOST_BITS_PER_WIDE_INT == 64
150 /* On 64-bit hosts, tree_fits_shwi_p tells whether the input fits in a
151 signed 64-bit integer. Then a truncation tells whether it fits
152 in a signed 32-bit integer. */
153 if (tree_fits_shwi_p (Input
))
155 HOST_WIDE_INT hw_input
= tree_to_shwi (Input
);
156 if (hw_input
== (int) hw_input
)
157 return UI_From_Int (hw_input
);
162 /* On 32-bit hosts, tree_fits_shwi_p tells whether the input fits in a
163 signed 32-bit integer. Then a sign test tells whether it fits
164 in a signed 64-bit integer. */
165 if (tree_fits_shwi_p (Input
))
166 return UI_From_Int (tree_to_shwi (Input
));
168 gcc_assert (TYPE_PRECISION (gnu_type
) <= 64);
169 if (TYPE_UNSIGNED (gnu_type
)
170 && TYPE_PRECISION (gnu_type
) == 64
171 && wi::neg_p (Input
, SIGNED
))
175 gnu_base
= build_int_cst (gnu_type
, UI_Base
);
178 for (i
= Max_For_Dint
- 1; i
>= 0; i
--)
180 v
[i
] = tree_to_shwi (fold_build1 (ABS_EXPR
, gnu_type
,
181 fold_build2 (TRUNC_MOD_EXPR
, gnu_type
,
182 gnu_temp
, gnu_base
)));
183 gnu_temp
= fold_build2 (TRUNC_DIV_EXPR
, gnu_type
, gnu_temp
, gnu_base
);
187 temp
.High_Bound
= Max_For_Dint
;
190 return Vector_To_Uint (vec
, tree_int_cst_sgn (Input
) < 0);