annotate gcc/ada/gcc-interface/utils2.c @ 118:fd00160c1b76

ifdef TARGET_64BIT
author mir3636
date Tue, 27 Feb 2018 15:01:35 +0900
parents 04ced10e8804
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /****************************************************************************
kono
parents:
diff changeset
2 * *
kono
parents:
diff changeset
3 * GNAT COMPILER COMPONENTS *
kono
parents:
diff changeset
4 * *
kono
parents:
diff changeset
5 * U T I L S 2 *
kono
parents:
diff changeset
6 * *
kono
parents:
diff changeset
7 * C Implementation File *
kono
parents:
diff changeset
8 * *
kono
parents:
diff changeset
9 * Copyright (C) 1992-2017, Free Software Foundation, Inc. *
kono
parents:
diff changeset
10 * *
kono
parents:
diff changeset
11 * GNAT is free software; you can redistribute it and/or modify it under *
kono
parents:
diff changeset
12 * terms of the GNU General Public License as published by the Free Soft- *
kono
parents:
diff changeset
13 * ware Foundation; either version 3, or (at your option) any later ver- *
kono
parents:
diff changeset
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
kono
parents:
diff changeset
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
kono
parents:
diff changeset
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
kono
parents:
diff changeset
17 * for more details. You should have received a copy of the GNU General *
kono
parents:
diff changeset
18 * Public License along with GCC; see the file COPYING3. If not see *
kono
parents:
diff changeset
19 * <http://www.gnu.org/licenses/>. *
kono
parents:
diff changeset
20 * *
kono
parents:
diff changeset
21 * GNAT was originally developed by the GNAT team at New York University. *
kono
parents:
diff changeset
22 * Extensive contributions were provided by Ada Core Technologies Inc. *
kono
parents:
diff changeset
23 * *
kono
parents:
diff changeset
24 ****************************************************************************/
kono
parents:
diff changeset
25
kono
parents:
diff changeset
26 #include "config.h"
kono
parents:
diff changeset
27 #include "system.h"
kono
parents:
diff changeset
28 #include "coretypes.h"
kono
parents:
diff changeset
29 #include "memmodel.h"
kono
parents:
diff changeset
30 #include "tm.h"
kono
parents:
diff changeset
31 #include "vec.h"
kono
parents:
diff changeset
32 #include "alias.h"
kono
parents:
diff changeset
33 #include "tree.h"
kono
parents:
diff changeset
34 #include "inchash.h"
kono
parents:
diff changeset
35 #include "fold-const.h"
kono
parents:
diff changeset
36 #include "stor-layout.h"
kono
parents:
diff changeset
37 #include "stringpool.h"
kono
parents:
diff changeset
38 #include "varasm.h"
kono
parents:
diff changeset
39 #include "flags.h"
kono
parents:
diff changeset
40 #include "toplev.h"
kono
parents:
diff changeset
41 #include "ggc.h"
kono
parents:
diff changeset
42 #include "tree-inline.h"
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 #include "ada.h"
kono
parents:
diff changeset
45 #include "types.h"
kono
parents:
diff changeset
46 #include "atree.h"
kono
parents:
diff changeset
47 #include "elists.h"
kono
parents:
diff changeset
48 #include "namet.h"
kono
parents:
diff changeset
49 #include "nlists.h"
kono
parents:
diff changeset
50 #include "snames.h"
kono
parents:
diff changeset
51 #include "stringt.h"
kono
parents:
diff changeset
52 #include "uintp.h"
kono
parents:
diff changeset
53 #include "fe.h"
kono
parents:
diff changeset
54 #include "sinfo.h"
kono
parents:
diff changeset
55 #include "einfo.h"
kono
parents:
diff changeset
56 #include "ada-tree.h"
kono
parents:
diff changeset
57 #include "gigi.h"
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 /* Return the base type of TYPE. */
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 tree
kono
parents:
diff changeset
62 get_base_type (tree type)
kono
parents:
diff changeset
63 {
kono
parents:
diff changeset
64 if (TREE_CODE (type) == RECORD_TYPE
kono
parents:
diff changeset
65 && TYPE_JUSTIFIED_MODULAR_P (type))
kono
parents:
diff changeset
66 type = TREE_TYPE (TYPE_FIELDS (type));
kono
parents:
diff changeset
67
kono
parents:
diff changeset
68 while (TREE_TYPE (type)
kono
parents:
diff changeset
69 && (TREE_CODE (type) == INTEGER_TYPE
kono
parents:
diff changeset
70 || TREE_CODE (type) == REAL_TYPE))
kono
parents:
diff changeset
71 type = TREE_TYPE (type);
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 return type;
kono
parents:
diff changeset
74 }
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 /* EXP is a GCC tree representing an address. See if we can find how strictly
kono
parents:
diff changeset
77 the object at this address is aligned and, if so, return the alignment of
kono
parents:
diff changeset
78 the object in bits. Otherwise return 0. */
kono
parents:
diff changeset
79
kono
parents:
diff changeset
80 unsigned int
kono
parents:
diff changeset
81 known_alignment (tree exp)
kono
parents:
diff changeset
82 {
kono
parents:
diff changeset
83 unsigned int this_alignment;
kono
parents:
diff changeset
84 unsigned int lhs, rhs;
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 switch (TREE_CODE (exp))
kono
parents:
diff changeset
87 {
kono
parents:
diff changeset
88 CASE_CONVERT:
kono
parents:
diff changeset
89 case VIEW_CONVERT_EXPR:
kono
parents:
diff changeset
90 case NON_LVALUE_EXPR:
kono
parents:
diff changeset
91 /* Conversions between pointers and integers don't change the alignment
kono
parents:
diff changeset
92 of the underlying object. */
kono
parents:
diff changeset
93 this_alignment = known_alignment (TREE_OPERAND (exp, 0));
kono
parents:
diff changeset
94 break;
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 case COMPOUND_EXPR:
kono
parents:
diff changeset
97 /* The value of a COMPOUND_EXPR is that of its second operand. */
kono
parents:
diff changeset
98 this_alignment = known_alignment (TREE_OPERAND (exp, 1));
kono
parents:
diff changeset
99 break;
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 case PLUS_EXPR:
kono
parents:
diff changeset
102 case MINUS_EXPR:
kono
parents:
diff changeset
103 /* If two addresses are added, the alignment of the result is the
kono
parents:
diff changeset
104 minimum of the two alignments. */
kono
parents:
diff changeset
105 lhs = known_alignment (TREE_OPERAND (exp, 0));
kono
parents:
diff changeset
106 rhs = known_alignment (TREE_OPERAND (exp, 1));
kono
parents:
diff changeset
107 this_alignment = MIN (lhs, rhs);
kono
parents:
diff changeset
108 break;
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 case POINTER_PLUS_EXPR:
kono
parents:
diff changeset
111 /* If this is the pattern built for aligning types, decode it. */
kono
parents:
diff changeset
112 if (TREE_CODE (TREE_OPERAND (exp, 1)) == BIT_AND_EXPR
kono
parents:
diff changeset
113 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)) == NEGATE_EXPR)
kono
parents:
diff changeset
114 {
kono
parents:
diff changeset
115 tree op = TREE_OPERAND (TREE_OPERAND (exp, 1), 1);
kono
parents:
diff changeset
116 return
kono
parents:
diff changeset
117 known_alignment (fold_build1 (BIT_NOT_EXPR, TREE_TYPE (op), op));
kono
parents:
diff changeset
118 }
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 /* If we don't know the alignment of the offset, we assume that
kono
parents:
diff changeset
121 of the base. */
kono
parents:
diff changeset
122 lhs = known_alignment (TREE_OPERAND (exp, 0));
kono
parents:
diff changeset
123 rhs = known_alignment (TREE_OPERAND (exp, 1));
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 if (rhs == 0)
kono
parents:
diff changeset
126 this_alignment = lhs;
kono
parents:
diff changeset
127 else
kono
parents:
diff changeset
128 this_alignment = MIN (lhs, rhs);
kono
parents:
diff changeset
129 break;
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 case COND_EXPR:
kono
parents:
diff changeset
132 /* If there is a choice between two values, use the smaller one. */
kono
parents:
diff changeset
133 lhs = known_alignment (TREE_OPERAND (exp, 1));
kono
parents:
diff changeset
134 rhs = known_alignment (TREE_OPERAND (exp, 2));
kono
parents:
diff changeset
135 this_alignment = MIN (lhs, rhs);
kono
parents:
diff changeset
136 break;
kono
parents:
diff changeset
137
kono
parents:
diff changeset
138 case INTEGER_CST:
kono
parents:
diff changeset
139 {
kono
parents:
diff changeset
140 unsigned HOST_WIDE_INT c = TREE_INT_CST_LOW (exp);
kono
parents:
diff changeset
141 /* The first part of this represents the lowest bit in the constant,
kono
parents:
diff changeset
142 but it is originally in bytes, not bits. */
kono
parents:
diff changeset
143 this_alignment = (c & -c) * BITS_PER_UNIT;
kono
parents:
diff changeset
144 }
kono
parents:
diff changeset
145 break;
kono
parents:
diff changeset
146
kono
parents:
diff changeset
147 case MULT_EXPR:
kono
parents:
diff changeset
148 /* If we know the alignment of just one side, use it. Otherwise,
kono
parents:
diff changeset
149 use the product of the alignments. */
kono
parents:
diff changeset
150 lhs = known_alignment (TREE_OPERAND (exp, 0));
kono
parents:
diff changeset
151 rhs = known_alignment (TREE_OPERAND (exp, 1));
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 if (lhs == 0)
kono
parents:
diff changeset
154 this_alignment = rhs;
kono
parents:
diff changeset
155 else if (rhs == 0)
kono
parents:
diff changeset
156 this_alignment = lhs;
kono
parents:
diff changeset
157 else
kono
parents:
diff changeset
158 this_alignment = MIN (lhs * rhs, BIGGEST_ALIGNMENT);
kono
parents:
diff changeset
159 break;
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 case BIT_AND_EXPR:
kono
parents:
diff changeset
162 /* A bit-and expression is as aligned as the maximum alignment of the
kono
parents:
diff changeset
163 operands. We typically get here for a complex lhs and a constant
kono
parents:
diff changeset
164 negative power of two on the rhs to force an explicit alignment, so
kono
parents:
diff changeset
165 don't bother looking at the lhs. */
kono
parents:
diff changeset
166 this_alignment = known_alignment (TREE_OPERAND (exp, 1));
kono
parents:
diff changeset
167 break;
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169 case ADDR_EXPR:
kono
parents:
diff changeset
170 this_alignment = expr_align (TREE_OPERAND (exp, 0));
kono
parents:
diff changeset
171 break;
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 case CALL_EXPR:
kono
parents:
diff changeset
174 {
kono
parents:
diff changeset
175 tree fndecl = get_callee_fndecl (exp);
kono
parents:
diff changeset
176 if (fndecl == malloc_decl || fndecl == realloc_decl)
kono
parents:
diff changeset
177 return get_target_system_allocator_alignment () * BITS_PER_UNIT;
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 tree t = maybe_inline_call_in_expr (exp);
kono
parents:
diff changeset
180 if (t)
kono
parents:
diff changeset
181 return known_alignment (t);
kono
parents:
diff changeset
182 }
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 /* ... fall through ... */
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 default:
kono
parents:
diff changeset
187 /* For other pointer expressions, we assume that the pointed-to object
kono
parents:
diff changeset
188 is at least as aligned as the pointed-to type. Beware that we can
kono
parents:
diff changeset
189 have a dummy type here (e.g. a Taft Amendment type), for which the
kono
parents:
diff changeset
190 alignment is meaningless and should be ignored. */
kono
parents:
diff changeset
191 if (POINTER_TYPE_P (TREE_TYPE (exp))
kono
parents:
diff changeset
192 && !TYPE_IS_DUMMY_P (TREE_TYPE (TREE_TYPE (exp)))
kono
parents:
diff changeset
193 && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (exp))))
kono
parents:
diff changeset
194 this_alignment = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
kono
parents:
diff changeset
195 else
kono
parents:
diff changeset
196 this_alignment = 0;
kono
parents:
diff changeset
197 break;
kono
parents:
diff changeset
198 }
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 return this_alignment;
kono
parents:
diff changeset
201 }
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 /* We have a comparison or assignment operation on two types, T1 and T2, which
kono
parents:
diff changeset
204 are either both array types or both record types. T1 is assumed to be for
kono
parents:
diff changeset
205 the left hand side operand, and T2 for the right hand side. Return the
kono
parents:
diff changeset
206 type that both operands should be converted to for the operation, if any.
kono
parents:
diff changeset
207 Otherwise return zero. */
kono
parents:
diff changeset
208
kono
parents:
diff changeset
209 static tree
kono
parents:
diff changeset
210 find_common_type (tree t1, tree t2)
kono
parents:
diff changeset
211 {
kono
parents:
diff changeset
212 /* ??? As of today, various constructs lead to here with types of different
kono
parents:
diff changeset
213 sizes even when both constants (e.g. tagged types, packable vs regular
kono
parents:
diff changeset
214 component types, padded vs unpadded types, ...). While some of these
kono
parents:
diff changeset
215 would better be handled upstream (types should be made consistent before
kono
parents:
diff changeset
216 calling into build_binary_op), some others are really expected and we
kono
parents:
diff changeset
217 have to be careful. */
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 const bool variable_record_on_lhs
kono
parents:
diff changeset
220 = (TREE_CODE (t1) == RECORD_TYPE
kono
parents:
diff changeset
221 && TREE_CODE (t2) == RECORD_TYPE
kono
parents:
diff changeset
222 && get_variant_part (t1)
kono
parents:
diff changeset
223 && !get_variant_part (t2));
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 const bool variable_array_on_lhs
kono
parents:
diff changeset
226 = (TREE_CODE (t1) == ARRAY_TYPE
kono
parents:
diff changeset
227 && TREE_CODE (t2) == ARRAY_TYPE
kono
parents:
diff changeset
228 && !TREE_CONSTANT (TYPE_MIN_VALUE (TYPE_DOMAIN (t1)))
kono
parents:
diff changeset
229 && TREE_CONSTANT (TYPE_MIN_VALUE (TYPE_DOMAIN (t2))));
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 /* We must avoid writing more than what the target can hold if this is for
kono
parents:
diff changeset
232 an assignment and the case of tagged types is handled in build_binary_op
kono
parents:
diff changeset
233 so we use the lhs type if it is known to be smaller or of constant size
kono
parents:
diff changeset
234 and the rhs type is not, whatever the modes. We also force t1 in case of
kono
parents:
diff changeset
235 constant size equality to minimize occurrences of view conversions on the
kono
parents:
diff changeset
236 lhs of an assignment, except for the case of types with a variable part
kono
parents:
diff changeset
237 on the lhs but not on the rhs to make the conversion simpler. */
kono
parents:
diff changeset
238 if (TREE_CONSTANT (TYPE_SIZE (t1))
kono
parents:
diff changeset
239 && (!TREE_CONSTANT (TYPE_SIZE (t2))
kono
parents:
diff changeset
240 || tree_int_cst_lt (TYPE_SIZE (t1), TYPE_SIZE (t2))
kono
parents:
diff changeset
241 || (TYPE_SIZE (t1) == TYPE_SIZE (t2)
kono
parents:
diff changeset
242 && !variable_record_on_lhs
kono
parents:
diff changeset
243 && !variable_array_on_lhs)))
kono
parents:
diff changeset
244 return t1;
kono
parents:
diff changeset
245
kono
parents:
diff changeset
246 /* Otherwise, if the lhs type is non-BLKmode, use it, except for the case of
kono
parents:
diff changeset
247 a non-BLKmode rhs and array types with a variable part on the lhs but not
kono
parents:
diff changeset
248 on the rhs to make sure the conversion is preserved during gimplification.
kono
parents:
diff changeset
249 Note that we know that we will not have any alignment problems since, if
kono
parents:
diff changeset
250 we did, the non-BLKmode type could not have been used. */
kono
parents:
diff changeset
251 if (TYPE_MODE (t1) != BLKmode
kono
parents:
diff changeset
252 && (TYPE_MODE (t2) == BLKmode || !variable_array_on_lhs))
kono
parents:
diff changeset
253 return t1;
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 /* If the rhs type is of constant size, use it whatever the modes. At
kono
parents:
diff changeset
256 this point it is known to be smaller, or of constant size and the
kono
parents:
diff changeset
257 lhs type is not. */
kono
parents:
diff changeset
258 if (TREE_CONSTANT (TYPE_SIZE (t2)))
kono
parents:
diff changeset
259 return t2;
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 /* Otherwise, if the rhs type is non-BLKmode, use it. */
kono
parents:
diff changeset
262 if (TYPE_MODE (t2) != BLKmode)
kono
parents:
diff changeset
263 return t2;
kono
parents:
diff changeset
264
kono
parents:
diff changeset
265 /* In this case, both types have variable size and BLKmode. It's
kono
parents:
diff changeset
266 probably best to leave the "type mismatch" because changing it
kono
parents:
diff changeset
267 could cause a bad self-referential reference. */
kono
parents:
diff changeset
268 return NULL_TREE;
kono
parents:
diff changeset
269 }
kono
parents:
diff changeset
270
kono
parents:
diff changeset
271 /* Return an expression tree representing an equality comparison of A1 and A2,
kono
parents:
diff changeset
272 two objects of type ARRAY_TYPE. The result should be of type RESULT_TYPE.
kono
parents:
diff changeset
273
kono
parents:
diff changeset
274 Two arrays are equal in one of two ways: (1) if both have zero length in
kono
parents:
diff changeset
275 some dimension (not necessarily the same dimension) or (2) if the lengths
kono
parents:
diff changeset
276 in each dimension are equal and the data is equal. We perform the length
kono
parents:
diff changeset
277 tests in as efficient a manner as possible. */
kono
parents:
diff changeset
278
kono
parents:
diff changeset
279 static tree
kono
parents:
diff changeset
280 compare_arrays (location_t loc, tree result_type, tree a1, tree a2)
kono
parents:
diff changeset
281 {
kono
parents:
diff changeset
282 tree result = convert (result_type, boolean_true_node);
kono
parents:
diff changeset
283 tree a1_is_null = convert (result_type, boolean_false_node);
kono
parents:
diff changeset
284 tree a2_is_null = convert (result_type, boolean_false_node);
kono
parents:
diff changeset
285 tree t1 = TREE_TYPE (a1);
kono
parents:
diff changeset
286 tree t2 = TREE_TYPE (a2);
kono
parents:
diff changeset
287 bool a1_side_effects_p = TREE_SIDE_EFFECTS (a1);
kono
parents:
diff changeset
288 bool a2_side_effects_p = TREE_SIDE_EFFECTS (a2);
kono
parents:
diff changeset
289 bool length_zero_p = false;
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 /* If the operands have side-effects, they need to be evaluated only once
kono
parents:
diff changeset
292 in spite of the multiple references in the comparison. */
kono
parents:
diff changeset
293 if (a1_side_effects_p)
kono
parents:
diff changeset
294 a1 = gnat_protect_expr (a1);
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 if (a2_side_effects_p)
kono
parents:
diff changeset
297 a2 = gnat_protect_expr (a2);
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 /* Process each dimension separately and compare the lengths. If any
kono
parents:
diff changeset
300 dimension has a length known to be zero, set LENGTH_ZERO_P to true
kono
parents:
diff changeset
301 in order to suppress the comparison of the data at the end. */
kono
parents:
diff changeset
302 while (TREE_CODE (t1) == ARRAY_TYPE && TREE_CODE (t2) == ARRAY_TYPE)
kono
parents:
diff changeset
303 {
kono
parents:
diff changeset
304 tree lb1 = TYPE_MIN_VALUE (TYPE_DOMAIN (t1));
kono
parents:
diff changeset
305 tree ub1 = TYPE_MAX_VALUE (TYPE_DOMAIN (t1));
kono
parents:
diff changeset
306 tree lb2 = TYPE_MIN_VALUE (TYPE_DOMAIN (t2));
kono
parents:
diff changeset
307 tree ub2 = TYPE_MAX_VALUE (TYPE_DOMAIN (t2));
kono
parents:
diff changeset
308 tree length1 = size_binop (PLUS_EXPR, size_binop (MINUS_EXPR, ub1, lb1),
kono
parents:
diff changeset
309 size_one_node);
kono
parents:
diff changeset
310 tree length2 = size_binop (PLUS_EXPR, size_binop (MINUS_EXPR, ub2, lb2),
kono
parents:
diff changeset
311 size_one_node);
kono
parents:
diff changeset
312 tree comparison, this_a1_is_null, this_a2_is_null;
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 /* If the length of the first array is a constant, swap our operands
kono
parents:
diff changeset
315 unless the length of the second array is the constant zero. */
kono
parents:
diff changeset
316 if (TREE_CODE (length1) == INTEGER_CST && !integer_zerop (length2))
kono
parents:
diff changeset
317 {
kono
parents:
diff changeset
318 tree tem;
kono
parents:
diff changeset
319 bool btem;
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 tem = a1, a1 = a2, a2 = tem;
kono
parents:
diff changeset
322 tem = t1, t1 = t2, t2 = tem;
kono
parents:
diff changeset
323 tem = lb1, lb1 = lb2, lb2 = tem;
kono
parents:
diff changeset
324 tem = ub1, ub1 = ub2, ub2 = tem;
kono
parents:
diff changeset
325 tem = length1, length1 = length2, length2 = tem;
kono
parents:
diff changeset
326 tem = a1_is_null, a1_is_null = a2_is_null, a2_is_null = tem;
kono
parents:
diff changeset
327 btem = a1_side_effects_p, a1_side_effects_p = a2_side_effects_p,
kono
parents:
diff changeset
328 a2_side_effects_p = btem;
kono
parents:
diff changeset
329 }
kono
parents:
diff changeset
330
kono
parents:
diff changeset
331 /* If the length of the second array is the constant zero, we can just
kono
parents:
diff changeset
332 use the original stored bounds for the first array and see whether
kono
parents:
diff changeset
333 last < first holds. */
kono
parents:
diff changeset
334 if (integer_zerop (length2))
kono
parents:
diff changeset
335 {
kono
parents:
diff changeset
336 tree b = get_base_type (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
kono
parents:
diff changeset
337
kono
parents:
diff changeset
338 length_zero_p = true;
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 ub1
kono
parents:
diff changeset
341 = convert (b, TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1))));
kono
parents:
diff changeset
342 lb1
kono
parents:
diff changeset
343 = convert (b, TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1))));
kono
parents:
diff changeset
344
kono
parents:
diff changeset
345 comparison = fold_build2_loc (loc, LT_EXPR, result_type, ub1, lb1);
kono
parents:
diff changeset
346 comparison = SUBSTITUTE_PLACEHOLDER_IN_EXPR (comparison, a1);
kono
parents:
diff changeset
347 if (EXPR_P (comparison))
kono
parents:
diff changeset
348 SET_EXPR_LOCATION (comparison, loc);
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 this_a1_is_null = comparison;
kono
parents:
diff changeset
351 this_a2_is_null = convert (result_type, boolean_true_node);
kono
parents:
diff changeset
352 }
kono
parents:
diff changeset
353
kono
parents:
diff changeset
354 /* Otherwise, if the length is some other constant value, we know that
kono
parents:
diff changeset
355 this dimension in the second array cannot be superflat, so we can
kono
parents:
diff changeset
356 just use its length computed from the actual stored bounds. */
kono
parents:
diff changeset
357 else if (TREE_CODE (length2) == INTEGER_CST)
kono
parents:
diff changeset
358 {
kono
parents:
diff changeset
359 tree b = get_base_type (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 ub1
kono
parents:
diff changeset
362 = convert (b, TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1))));
kono
parents:
diff changeset
363 lb1
kono
parents:
diff changeset
364 = convert (b, TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1))));
kono
parents:
diff changeset
365 /* Note that we know that UB2 and LB2 are constant and hence
kono
parents:
diff changeset
366 cannot contain a PLACEHOLDER_EXPR. */
kono
parents:
diff changeset
367 ub2
kono
parents:
diff changeset
368 = convert (b, TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t2))));
kono
parents:
diff changeset
369 lb2
kono
parents:
diff changeset
370 = convert (b, TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t2))));
kono
parents:
diff changeset
371
kono
parents:
diff changeset
372 comparison
kono
parents:
diff changeset
373 = fold_build2_loc (loc, EQ_EXPR, result_type,
kono
parents:
diff changeset
374 build_binary_op (MINUS_EXPR, b, ub1, lb1),
kono
parents:
diff changeset
375 build_binary_op (MINUS_EXPR, b, ub2, lb2));
kono
parents:
diff changeset
376 comparison = SUBSTITUTE_PLACEHOLDER_IN_EXPR (comparison, a1);
kono
parents:
diff changeset
377 if (EXPR_P (comparison))
kono
parents:
diff changeset
378 SET_EXPR_LOCATION (comparison, loc);
kono
parents:
diff changeset
379
kono
parents:
diff changeset
380 this_a1_is_null
kono
parents:
diff changeset
381 = fold_build2_loc (loc, LT_EXPR, result_type, ub1, lb1);
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 this_a2_is_null = convert (result_type, boolean_false_node);
kono
parents:
diff changeset
384 }
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 /* Otherwise, compare the computed lengths. */
kono
parents:
diff changeset
387 else
kono
parents:
diff changeset
388 {
kono
parents:
diff changeset
389 length1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (length1, a1);
kono
parents:
diff changeset
390 length2 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (length2, a2);
kono
parents:
diff changeset
391
kono
parents:
diff changeset
392 comparison
kono
parents:
diff changeset
393 = fold_build2_loc (loc, EQ_EXPR, result_type, length1, length2);
kono
parents:
diff changeset
394
kono
parents:
diff changeset
395 /* If the length expression is of the form (cond ? val : 0), assume
kono
parents:
diff changeset
396 that cond is equivalent to (length != 0). That's guaranteed by
kono
parents:
diff changeset
397 construction of the array types in gnat_to_gnu_entity. */
kono
parents:
diff changeset
398 if (TREE_CODE (length1) == COND_EXPR
kono
parents:
diff changeset
399 && integer_zerop (TREE_OPERAND (length1, 2)))
kono
parents:
diff changeset
400 this_a1_is_null
kono
parents:
diff changeset
401 = invert_truthvalue_loc (loc, TREE_OPERAND (length1, 0));
kono
parents:
diff changeset
402 else
kono
parents:
diff changeset
403 this_a1_is_null = fold_build2_loc (loc, EQ_EXPR, result_type,
kono
parents:
diff changeset
404 length1, size_zero_node);
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 /* Likewise for the second array. */
kono
parents:
diff changeset
407 if (TREE_CODE (length2) == COND_EXPR
kono
parents:
diff changeset
408 && integer_zerop (TREE_OPERAND (length2, 2)))
kono
parents:
diff changeset
409 this_a2_is_null
kono
parents:
diff changeset
410 = invert_truthvalue_loc (loc, TREE_OPERAND (length2, 0));
kono
parents:
diff changeset
411 else
kono
parents:
diff changeset
412 this_a2_is_null = fold_build2_loc (loc, EQ_EXPR, result_type,
kono
parents:
diff changeset
413 length2, size_zero_node);
kono
parents:
diff changeset
414 }
kono
parents:
diff changeset
415
kono
parents:
diff changeset
416 /* Append expressions for this dimension to the final expressions. */
kono
parents:
diff changeset
417 result = build_binary_op (TRUTH_ANDIF_EXPR, result_type,
kono
parents:
diff changeset
418 result, comparison);
kono
parents:
diff changeset
419
kono
parents:
diff changeset
420 a1_is_null = build_binary_op (TRUTH_ORIF_EXPR, result_type,
kono
parents:
diff changeset
421 this_a1_is_null, a1_is_null);
kono
parents:
diff changeset
422
kono
parents:
diff changeset
423 a2_is_null = build_binary_op (TRUTH_ORIF_EXPR, result_type,
kono
parents:
diff changeset
424 this_a2_is_null, a2_is_null);
kono
parents:
diff changeset
425
kono
parents:
diff changeset
426 t1 = TREE_TYPE (t1);
kono
parents:
diff changeset
427 t2 = TREE_TYPE (t2);
kono
parents:
diff changeset
428 }
kono
parents:
diff changeset
429
kono
parents:
diff changeset
430 /* Unless the length of some dimension is known to be zero, compare the
kono
parents:
diff changeset
431 data in the array. */
kono
parents:
diff changeset
432 if (!length_zero_p)
kono
parents:
diff changeset
433 {
kono
parents:
diff changeset
434 tree type = find_common_type (TREE_TYPE (a1), TREE_TYPE (a2));
kono
parents:
diff changeset
435 tree comparison;
kono
parents:
diff changeset
436
kono
parents:
diff changeset
437 if (type)
kono
parents:
diff changeset
438 {
kono
parents:
diff changeset
439 a1 = convert (type, a1),
kono
parents:
diff changeset
440 a2 = convert (type, a2);
kono
parents:
diff changeset
441 }
kono
parents:
diff changeset
442
kono
parents:
diff changeset
443 comparison = fold_build2_loc (loc, EQ_EXPR, result_type, a1, a2);
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 result
kono
parents:
diff changeset
446 = build_binary_op (TRUTH_ANDIF_EXPR, result_type, result, comparison);
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 /* The result is also true if both sizes are zero. */
kono
parents:
diff changeset
450 result = build_binary_op (TRUTH_ORIF_EXPR, result_type,
kono
parents:
diff changeset
451 build_binary_op (TRUTH_ANDIF_EXPR, result_type,
kono
parents:
diff changeset
452 a1_is_null, a2_is_null),
kono
parents:
diff changeset
453 result);
kono
parents:
diff changeset
454
kono
parents:
diff changeset
455 /* If the operands have side-effects, they need to be evaluated before
kono
parents:
diff changeset
456 doing the tests above since the place they otherwise would end up
kono
parents:
diff changeset
457 being evaluated at run time could be wrong. */
kono
parents:
diff changeset
458 if (a1_side_effects_p)
kono
parents:
diff changeset
459 result = build2 (COMPOUND_EXPR, result_type, a1, result);
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 if (a2_side_effects_p)
kono
parents:
diff changeset
462 result = build2 (COMPOUND_EXPR, result_type, a2, result);
kono
parents:
diff changeset
463
kono
parents:
diff changeset
464 return result;
kono
parents:
diff changeset
465 }
kono
parents:
diff changeset
466
kono
parents:
diff changeset
467 /* Return an expression tree representing an equality comparison of P1 and P2,
kono
parents:
diff changeset
468 two objects of fat pointer type. The result should be of type RESULT_TYPE.
kono
parents:
diff changeset
469
kono
parents:
diff changeset
470 Two fat pointers are equal in one of two ways: (1) if both have a null
kono
parents:
diff changeset
471 pointer to the array or (2) if they contain the same couple of pointers.
kono
parents:
diff changeset
472 We perform the comparison in as efficient a manner as possible. */
kono
parents:
diff changeset
473
kono
parents:
diff changeset
474 static tree
kono
parents:
diff changeset
475 compare_fat_pointers (location_t loc, tree result_type, tree p1, tree p2)
kono
parents:
diff changeset
476 {
kono
parents:
diff changeset
477 tree p1_array, p2_array, p1_bounds, p2_bounds, same_array, same_bounds;
kono
parents:
diff changeset
478 tree p1_array_is_null, p2_array_is_null;
kono
parents:
diff changeset
479
kono
parents:
diff changeset
480 /* If either operand has side-effects, they have to be evaluated only once
kono
parents:
diff changeset
481 in spite of the multiple references to the operand in the comparison. */
kono
parents:
diff changeset
482 p1 = gnat_protect_expr (p1);
kono
parents:
diff changeset
483 p2 = gnat_protect_expr (p2);
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 /* The constant folder doesn't fold fat pointer types so we do it here. */
kono
parents:
diff changeset
486 if (TREE_CODE (p1) == CONSTRUCTOR)
kono
parents:
diff changeset
487 p1_array = CONSTRUCTOR_ELT (p1, 0)->value;
kono
parents:
diff changeset
488 else
kono
parents:
diff changeset
489 p1_array = build_component_ref (p1, TYPE_FIELDS (TREE_TYPE (p1)), true);
kono
parents:
diff changeset
490
kono
parents:
diff changeset
491 p1_array_is_null
kono
parents:
diff changeset
492 = fold_build2_loc (loc, EQ_EXPR, result_type, p1_array,
kono
parents:
diff changeset
493 fold_convert_loc (loc, TREE_TYPE (p1_array),
kono
parents:
diff changeset
494 null_pointer_node));
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 if (TREE_CODE (p2) == CONSTRUCTOR)
kono
parents:
diff changeset
497 p2_array = CONSTRUCTOR_ELT (p2, 0)->value;
kono
parents:
diff changeset
498 else
kono
parents:
diff changeset
499 p2_array = build_component_ref (p2, TYPE_FIELDS (TREE_TYPE (p2)), true);
kono
parents:
diff changeset
500
kono
parents:
diff changeset
501 p2_array_is_null
kono
parents:
diff changeset
502 = fold_build2_loc (loc, EQ_EXPR, result_type, p2_array,
kono
parents:
diff changeset
503 fold_convert_loc (loc, TREE_TYPE (p2_array),
kono
parents:
diff changeset
504 null_pointer_node));
kono
parents:
diff changeset
505
kono
parents:
diff changeset
506 /* If one of the pointers to the array is null, just compare the other. */
kono
parents:
diff changeset
507 if (integer_zerop (p1_array))
kono
parents:
diff changeset
508 return p2_array_is_null;
kono
parents:
diff changeset
509 else if (integer_zerop (p2_array))
kono
parents:
diff changeset
510 return p1_array_is_null;
kono
parents:
diff changeset
511
kono
parents:
diff changeset
512 /* Otherwise, do the fully-fledged comparison. */
kono
parents:
diff changeset
513 same_array
kono
parents:
diff changeset
514 = fold_build2_loc (loc, EQ_EXPR, result_type, p1_array, p2_array);
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 if (TREE_CODE (p1) == CONSTRUCTOR)
kono
parents:
diff changeset
517 p1_bounds = CONSTRUCTOR_ELT (p1, 1)->value;
kono
parents:
diff changeset
518 else
kono
parents:
diff changeset
519 p1_bounds
kono
parents:
diff changeset
520 = build_component_ref (p1, DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p1))),
kono
parents:
diff changeset
521 true);
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523 if (TREE_CODE (p2) == CONSTRUCTOR)
kono
parents:
diff changeset
524 p2_bounds = CONSTRUCTOR_ELT (p2, 1)->value;
kono
parents:
diff changeset
525 else
kono
parents:
diff changeset
526 p2_bounds
kono
parents:
diff changeset
527 = build_component_ref (p2, DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p2))),
kono
parents:
diff changeset
528 true);
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 same_bounds
kono
parents:
diff changeset
531 = fold_build2_loc (loc, EQ_EXPR, result_type, p1_bounds, p2_bounds);
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 /* P1_ARRAY == P2_ARRAY && (P1_ARRAY == NULL || P1_BOUNDS == P2_BOUNDS). */
kono
parents:
diff changeset
534 return build_binary_op (TRUTH_ANDIF_EXPR, result_type, same_array,
kono
parents:
diff changeset
535 build_binary_op (TRUTH_ORIF_EXPR, result_type,
kono
parents:
diff changeset
536 p1_array_is_null, same_bounds));
kono
parents:
diff changeset
537 }
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 /* Compute the result of applying OP_CODE to LHS and RHS, where both are of
kono
parents:
diff changeset
540 type TYPE. We know that TYPE is a modular type with a nonbinary
kono
parents:
diff changeset
541 modulus. */
kono
parents:
diff changeset
542
kono
parents:
diff changeset
543 static tree
kono
parents:
diff changeset
544 nonbinary_modular_operation (enum tree_code op_code, tree type, tree lhs,
kono
parents:
diff changeset
545 tree rhs)
kono
parents:
diff changeset
546 {
kono
parents:
diff changeset
547 tree modulus = TYPE_MODULUS (type);
kono
parents:
diff changeset
548 unsigned int needed_precision = tree_floor_log2 (modulus) + 1;
kono
parents:
diff changeset
549 unsigned int precision;
kono
parents:
diff changeset
550 bool unsignedp = true;
kono
parents:
diff changeset
551 tree op_type = type;
kono
parents:
diff changeset
552 tree result;
kono
parents:
diff changeset
553
kono
parents:
diff changeset
554 /* If this is an addition of a constant, convert it to a subtraction
kono
parents:
diff changeset
555 of a constant since we can do that faster. */
kono
parents:
diff changeset
556 if (op_code == PLUS_EXPR && TREE_CODE (rhs) == INTEGER_CST)
kono
parents:
diff changeset
557 {
kono
parents:
diff changeset
558 rhs = fold_build2 (MINUS_EXPR, type, modulus, rhs);
kono
parents:
diff changeset
559 op_code = MINUS_EXPR;
kono
parents:
diff changeset
560 }
kono
parents:
diff changeset
561
kono
parents:
diff changeset
562 /* For the logical operations, we only need PRECISION bits. For
kono
parents:
diff changeset
563 addition and subtraction, we need one more and for multiplication we
kono
parents:
diff changeset
564 need twice as many. But we never want to make a size smaller than
kono
parents:
diff changeset
565 our size. */
kono
parents:
diff changeset
566 if (op_code == PLUS_EXPR || op_code == MINUS_EXPR)
kono
parents:
diff changeset
567 needed_precision += 1;
kono
parents:
diff changeset
568 else if (op_code == MULT_EXPR)
kono
parents:
diff changeset
569 needed_precision *= 2;
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 precision = MAX (needed_precision, TYPE_PRECISION (op_type));
kono
parents:
diff changeset
572
kono
parents:
diff changeset
573 /* Unsigned will do for everything but subtraction. */
kono
parents:
diff changeset
574 if (op_code == MINUS_EXPR)
kono
parents:
diff changeset
575 unsignedp = false;
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 /* If our type is the wrong signedness or isn't wide enough, make a new
kono
parents:
diff changeset
578 type and convert both our operands to it. */
kono
parents:
diff changeset
579 if (TYPE_PRECISION (op_type) < precision
kono
parents:
diff changeset
580 || TYPE_UNSIGNED (op_type) != unsignedp)
kono
parents:
diff changeset
581 {
kono
parents:
diff changeset
582 /* Copy the type so we ensure it can be modified to make it modular. */
kono
parents:
diff changeset
583 op_type = copy_type (gnat_type_for_size (precision, unsignedp));
kono
parents:
diff changeset
584 modulus = convert (op_type, modulus);
kono
parents:
diff changeset
585 SET_TYPE_MODULUS (op_type, modulus);
kono
parents:
diff changeset
586 TYPE_MODULAR_P (op_type) = 1;
kono
parents:
diff changeset
587 lhs = convert (op_type, lhs);
kono
parents:
diff changeset
588 rhs = convert (op_type, rhs);
kono
parents:
diff changeset
589 }
kono
parents:
diff changeset
590
kono
parents:
diff changeset
591 /* Do the operation, then we'll fix it up. */
kono
parents:
diff changeset
592 result = fold_build2 (op_code, op_type, lhs, rhs);
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 /* For multiplication, we have no choice but to do a full modulus
kono
parents:
diff changeset
595 operation. However, we want to do this in the narrowest
kono
parents:
diff changeset
596 possible size. */
kono
parents:
diff changeset
597 if (op_code == MULT_EXPR)
kono
parents:
diff changeset
598 {
kono
parents:
diff changeset
599 /* Copy the type so we ensure it can be modified to make it modular. */
kono
parents:
diff changeset
600 tree div_type = copy_type (gnat_type_for_size (needed_precision, 1));
kono
parents:
diff changeset
601 modulus = convert (div_type, modulus);
kono
parents:
diff changeset
602 SET_TYPE_MODULUS (div_type, modulus);
kono
parents:
diff changeset
603 TYPE_MODULAR_P (div_type) = 1;
kono
parents:
diff changeset
604 result = convert (op_type,
kono
parents:
diff changeset
605 fold_build2 (TRUNC_MOD_EXPR, div_type,
kono
parents:
diff changeset
606 convert (div_type, result), modulus));
kono
parents:
diff changeset
607 }
kono
parents:
diff changeset
608
kono
parents:
diff changeset
609 /* For subtraction, add the modulus back if we are negative. */
kono
parents:
diff changeset
610 else if (op_code == MINUS_EXPR)
kono
parents:
diff changeset
611 {
kono
parents:
diff changeset
612 result = gnat_protect_expr (result);
kono
parents:
diff changeset
613 result = fold_build3 (COND_EXPR, op_type,
kono
parents:
diff changeset
614 fold_build2 (LT_EXPR, boolean_type_node, result,
kono
parents:
diff changeset
615 build_int_cst (op_type, 0)),
kono
parents:
diff changeset
616 fold_build2 (PLUS_EXPR, op_type, result, modulus),
kono
parents:
diff changeset
617 result);
kono
parents:
diff changeset
618 }
kono
parents:
diff changeset
619
kono
parents:
diff changeset
620 /* For the other operations, subtract the modulus if we are >= it. */
kono
parents:
diff changeset
621 else
kono
parents:
diff changeset
622 {
kono
parents:
diff changeset
623 result = gnat_protect_expr (result);
kono
parents:
diff changeset
624 result = fold_build3 (COND_EXPR, op_type,
kono
parents:
diff changeset
625 fold_build2 (GE_EXPR, boolean_type_node,
kono
parents:
diff changeset
626 result, modulus),
kono
parents:
diff changeset
627 fold_build2 (MINUS_EXPR, op_type,
kono
parents:
diff changeset
628 result, modulus),
kono
parents:
diff changeset
629 result);
kono
parents:
diff changeset
630 }
kono
parents:
diff changeset
631
kono
parents:
diff changeset
632 return convert (type, result);
kono
parents:
diff changeset
633 }
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 /* This page contains routines that implement the Ada semantics with regard
kono
parents:
diff changeset
636 to atomic objects. They are fully piggybacked on the middle-end support
kono
parents:
diff changeset
637 for atomic loads and stores.
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 *** Memory barriers and volatile objects ***
kono
parents:
diff changeset
640
kono
parents:
diff changeset
641 We implement the weakened form of the C.6(16) clause that was introduced
kono
parents:
diff changeset
642 in Ada 2012 (AI05-117). Earlier forms of this clause wouldn't have been
kono
parents:
diff changeset
643 implementable without significant performance hits on modern platforms.
kono
parents:
diff changeset
644
kono
parents:
diff changeset
645 We also take advantage of the requirements imposed on shared variables by
kono
parents:
diff changeset
646 9.10 (conditions for sequential actions) to have non-erroneous execution
kono
parents:
diff changeset
647 and consider that C.6(16) and C.6(17) only prescribe an uniform order of
kono
parents:
diff changeset
648 volatile updates with regard to sequential actions, i.e. with regard to
kono
parents:
diff changeset
649 reads or updates of atomic objects.
kono
parents:
diff changeset
650
kono
parents:
diff changeset
651 As such, an update of an atomic object by a task requires that all earlier
kono
parents:
diff changeset
652 accesses to volatile objects have completed. Similarly, later accesses to
kono
parents:
diff changeset
653 volatile objects cannot be reordered before the update of the atomic object.
kono
parents:
diff changeset
654 So, memory barriers both before and after the atomic update are needed.
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 For a read of an atomic object, to avoid seeing writes of volatile objects
kono
parents:
diff changeset
657 by a task earlier than by the other tasks, a memory barrier is needed before
kono
parents:
diff changeset
658 the atomic read. Finally, to avoid reordering later reads or updates of
kono
parents:
diff changeset
659 volatile objects to before the atomic read, a barrier is needed after the
kono
parents:
diff changeset
660 atomic read.
kono
parents:
diff changeset
661
kono
parents:
diff changeset
662 So, memory barriers are needed before and after atomic reads and updates.
kono
parents:
diff changeset
663 And, in order to simplify the implementation, we use full memory barriers
kono
parents:
diff changeset
664 in all cases, i.e. we enforce sequential consistency for atomic accesses. */
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 /* Return the size of TYPE, which must be a positive power of 2. */
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 static unsigned int
kono
parents:
diff changeset
669 resolve_atomic_size (tree type)
kono
parents:
diff changeset
670 {
kono
parents:
diff changeset
671 unsigned HOST_WIDE_INT size = tree_to_uhwi (TYPE_SIZE_UNIT (type));
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16)
kono
parents:
diff changeset
674 return size;
kono
parents:
diff changeset
675
kono
parents:
diff changeset
676 /* We shouldn't reach here without having already detected that the size
kono
parents:
diff changeset
677 isn't compatible with an atomic access. */
kono
parents:
diff changeset
678 gcc_assert (Serious_Errors_Detected);
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 return 0;
kono
parents:
diff changeset
681 }
kono
parents:
diff changeset
682
kono
parents:
diff changeset
683 /* Build an atomic load for the underlying atomic object in SRC. SYNC is
kono
parents:
diff changeset
684 true if the load requires synchronization. */
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 tree
kono
parents:
diff changeset
687 build_atomic_load (tree src, bool sync)
kono
parents:
diff changeset
688 {
kono
parents:
diff changeset
689 tree ptr_type
kono
parents:
diff changeset
690 = build_pointer_type
kono
parents:
diff changeset
691 (build_qualified_type (void_type_node,
kono
parents:
diff changeset
692 TYPE_QUAL_ATOMIC | TYPE_QUAL_VOLATILE));
kono
parents:
diff changeset
693 tree mem_model
kono
parents:
diff changeset
694 = build_int_cst (integer_type_node,
kono
parents:
diff changeset
695 sync ? MEMMODEL_SEQ_CST : MEMMODEL_RELAXED);
kono
parents:
diff changeset
696 tree orig_src = src;
kono
parents:
diff changeset
697 tree t, addr, val;
kono
parents:
diff changeset
698 unsigned int size;
kono
parents:
diff changeset
699 int fncode;
kono
parents:
diff changeset
700
kono
parents:
diff changeset
701 /* Remove conversions to get the address of the underlying object. */
kono
parents:
diff changeset
702 src = remove_conversions (src, false);
kono
parents:
diff changeset
703 size = resolve_atomic_size (TREE_TYPE (src));
kono
parents:
diff changeset
704 if (size == 0)
kono
parents:
diff changeset
705 return orig_src;
kono
parents:
diff changeset
706
kono
parents:
diff changeset
707 fncode = (int) BUILT_IN_ATOMIC_LOAD_N + exact_log2 (size) + 1;
kono
parents:
diff changeset
708 t = builtin_decl_implicit ((enum built_in_function) fncode);
kono
parents:
diff changeset
709
kono
parents:
diff changeset
710 addr = build_unary_op (ADDR_EXPR, ptr_type, src);
kono
parents:
diff changeset
711 val = build_call_expr (t, 2, addr, mem_model);
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 /* First reinterpret the loaded bits in the original type of the load,
kono
parents:
diff changeset
714 then convert to the expected result type. */
kono
parents:
diff changeset
715 t = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (src), val);
kono
parents:
diff changeset
716 return convert (TREE_TYPE (orig_src), t);
kono
parents:
diff changeset
717 }
kono
parents:
diff changeset
718
kono
parents:
diff changeset
719 /* Build an atomic store from SRC to the underlying atomic object in DEST.
kono
parents:
diff changeset
720 SYNC is true if the store requires synchronization. */
kono
parents:
diff changeset
721
kono
parents:
diff changeset
722 tree
kono
parents:
diff changeset
723 build_atomic_store (tree dest, tree src, bool sync)
kono
parents:
diff changeset
724 {
kono
parents:
diff changeset
725 tree ptr_type
kono
parents:
diff changeset
726 = build_pointer_type
kono
parents:
diff changeset
727 (build_qualified_type (void_type_node,
kono
parents:
diff changeset
728 TYPE_QUAL_ATOMIC | TYPE_QUAL_VOLATILE));
kono
parents:
diff changeset
729 tree mem_model
kono
parents:
diff changeset
730 = build_int_cst (integer_type_node,
kono
parents:
diff changeset
731 sync ? MEMMODEL_SEQ_CST : MEMMODEL_RELAXED);
kono
parents:
diff changeset
732 tree orig_dest = dest;
kono
parents:
diff changeset
733 tree t, int_type, addr;
kono
parents:
diff changeset
734 unsigned int size;
kono
parents:
diff changeset
735 int fncode;
kono
parents:
diff changeset
736
kono
parents:
diff changeset
737 /* Remove conversions to get the address of the underlying object. */
kono
parents:
diff changeset
738 dest = remove_conversions (dest, false);
kono
parents:
diff changeset
739 size = resolve_atomic_size (TREE_TYPE (dest));
kono
parents:
diff changeset
740 if (size == 0)
kono
parents:
diff changeset
741 return build_binary_op (MODIFY_EXPR, NULL_TREE, orig_dest, src);
kono
parents:
diff changeset
742
kono
parents:
diff changeset
743 fncode = (int) BUILT_IN_ATOMIC_STORE_N + exact_log2 (size) + 1;
kono
parents:
diff changeset
744 t = builtin_decl_implicit ((enum built_in_function) fncode);
kono
parents:
diff changeset
745 int_type = gnat_type_for_size (BITS_PER_UNIT * size, 1);
kono
parents:
diff changeset
746
kono
parents:
diff changeset
747 /* First convert the bits to be stored to the original type of the store,
kono
parents:
diff changeset
748 then reinterpret them in the effective type. But if the original type
kono
parents:
diff changeset
749 is a padded type with the same size, convert to the inner type instead,
kono
parents:
diff changeset
750 as we don't want to artificially introduce a CONSTRUCTOR here. */
kono
parents:
diff changeset
751 if (TYPE_IS_PADDING_P (TREE_TYPE (dest))
kono
parents:
diff changeset
752 && TYPE_SIZE (TREE_TYPE (dest))
kono
parents:
diff changeset
753 == TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (dest)))))
kono
parents:
diff changeset
754 src = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (dest))), src);
kono
parents:
diff changeset
755 else
kono
parents:
diff changeset
756 src = convert (TREE_TYPE (dest), src);
kono
parents:
diff changeset
757 src = fold_build1 (VIEW_CONVERT_EXPR, int_type, src);
kono
parents:
diff changeset
758 addr = build_unary_op (ADDR_EXPR, ptr_type, dest);
kono
parents:
diff changeset
759
kono
parents:
diff changeset
760 return build_call_expr (t, 3, addr, src, mem_model);
kono
parents:
diff changeset
761 }
kono
parents:
diff changeset
762
kono
parents:
diff changeset
763 /* Build a load-modify-store sequence from SRC to DEST. GNAT_NODE is used for
kono
parents:
diff changeset
764 the location of the sequence. Note that, even though the load and the store
kono
parents:
diff changeset
765 are both atomic, the sequence itself is not atomic. */
kono
parents:
diff changeset
766
kono
parents:
diff changeset
767 tree
kono
parents:
diff changeset
768 build_load_modify_store (tree dest, tree src, Node_Id gnat_node)
kono
parents:
diff changeset
769 {
kono
parents:
diff changeset
770 /* We will be modifying DEST below so we build a copy. */
kono
parents:
diff changeset
771 dest = copy_node (dest);
kono
parents:
diff changeset
772 tree ref = dest;
kono
parents:
diff changeset
773
kono
parents:
diff changeset
774 while (handled_component_p (ref))
kono
parents:
diff changeset
775 {
kono
parents:
diff changeset
776 /* The load should already have been generated during the translation
kono
parents:
diff changeset
777 of the GNAT destination tree; find it out in the GNU tree. */
kono
parents:
diff changeset
778 if (TREE_CODE (TREE_OPERAND (ref, 0)) == VIEW_CONVERT_EXPR)
kono
parents:
diff changeset
779 {
kono
parents:
diff changeset
780 tree op = TREE_OPERAND (TREE_OPERAND (ref, 0), 0);
kono
parents:
diff changeset
781 if (TREE_CODE (op) == CALL_EXPR && call_is_atomic_load (op))
kono
parents:
diff changeset
782 {
kono
parents:
diff changeset
783 tree type = TREE_TYPE (TREE_OPERAND (ref, 0));
kono
parents:
diff changeset
784 tree t = CALL_EXPR_ARG (op, 0);
kono
parents:
diff changeset
785 tree obj, temp, stmt;
kono
parents:
diff changeset
786
kono
parents:
diff changeset
787 /* Find out the loaded object. */
kono
parents:
diff changeset
788 if (TREE_CODE (t) == NOP_EXPR)
kono
parents:
diff changeset
789 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
790 if (TREE_CODE (t) == ADDR_EXPR)
kono
parents:
diff changeset
791 obj = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
792 else
kono
parents:
diff changeset
793 obj = build1 (INDIRECT_REF, type, t);
kono
parents:
diff changeset
794
kono
parents:
diff changeset
795 /* Drop atomic and volatile qualifiers for the temporary. */
kono
parents:
diff changeset
796 type = TYPE_MAIN_VARIANT (type);
kono
parents:
diff changeset
797
kono
parents:
diff changeset
798 /* And drop BLKmode, if need be, to put it into a register. */
kono
parents:
diff changeset
799 if (TYPE_MODE (type) == BLKmode)
kono
parents:
diff changeset
800 {
kono
parents:
diff changeset
801 unsigned int size = tree_to_uhwi (TYPE_SIZE (type));
kono
parents:
diff changeset
802 type = copy_type (type);
kono
parents:
diff changeset
803 machine_mode mode = int_mode_for_size (size, 0).else_blk ();
kono
parents:
diff changeset
804 SET_TYPE_MODE (type, mode);
kono
parents:
diff changeset
805 }
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 /* Create the temporary by inserting a SAVE_EXPR. */
kono
parents:
diff changeset
808 temp = build1 (SAVE_EXPR, type,
kono
parents:
diff changeset
809 build1 (VIEW_CONVERT_EXPR, type, op));
kono
parents:
diff changeset
810 TREE_OPERAND (ref, 0) = temp;
kono
parents:
diff changeset
811
kono
parents:
diff changeset
812 start_stmt_group ();
kono
parents:
diff changeset
813
kono
parents:
diff changeset
814 /* Build the modify of the temporary. */
kono
parents:
diff changeset
815 stmt = build_binary_op (MODIFY_EXPR, NULL_TREE, dest, src);
kono
parents:
diff changeset
816 add_stmt_with_node (stmt, gnat_node);
kono
parents:
diff changeset
817
kono
parents:
diff changeset
818 /* Build the store to the object. */
kono
parents:
diff changeset
819 stmt = build_atomic_store (obj, temp, false);
kono
parents:
diff changeset
820 add_stmt_with_node (stmt, gnat_node);
kono
parents:
diff changeset
821
kono
parents:
diff changeset
822 return end_stmt_group ();
kono
parents:
diff changeset
823 }
kono
parents:
diff changeset
824 }
kono
parents:
diff changeset
825
kono
parents:
diff changeset
826 TREE_OPERAND (ref, 0) = copy_node (TREE_OPERAND (ref, 0));
kono
parents:
diff changeset
827 ref = TREE_OPERAND (ref, 0);
kono
parents:
diff changeset
828 }
kono
parents:
diff changeset
829
kono
parents:
diff changeset
830 /* Something went wrong earlier if we have not found the atomic load. */
kono
parents:
diff changeset
831 gcc_unreachable ();
kono
parents:
diff changeset
832 }
kono
parents:
diff changeset
833
kono
parents:
diff changeset
834 /* Make a binary operation of kind OP_CODE. RESULT_TYPE is the type
kono
parents:
diff changeset
835 desired for the result. Usually the operation is to be performed
kono
parents:
diff changeset
836 in that type. For INIT_EXPR and MODIFY_EXPR, RESULT_TYPE must be
kono
parents:
diff changeset
837 NULL_TREE. For ARRAY_REF, RESULT_TYPE may be NULL_TREE, in which
kono
parents:
diff changeset
838 case the type to be used will be derived from the operands.
kono
parents:
diff changeset
839 Don't fold the result if NO_FOLD is true.
kono
parents:
diff changeset
840
kono
parents:
diff changeset
841 This function is very much unlike the ones for C and C++ since we
kono
parents:
diff changeset
842 have already done any type conversion and matching required. All we
kono
parents:
diff changeset
843 have to do here is validate the work done by SEM and handle subtypes. */
kono
parents:
diff changeset
844
kono
parents:
diff changeset
845 tree
kono
parents:
diff changeset
846 build_binary_op (enum tree_code op_code, tree result_type,
kono
parents:
diff changeset
847 tree left_operand, tree right_operand,
kono
parents:
diff changeset
848 bool no_fold)
kono
parents:
diff changeset
849 {
kono
parents:
diff changeset
850 tree left_type = TREE_TYPE (left_operand);
kono
parents:
diff changeset
851 tree right_type = TREE_TYPE (right_operand);
kono
parents:
diff changeset
852 tree left_base_type = get_base_type (left_type);
kono
parents:
diff changeset
853 tree right_base_type = get_base_type (right_type);
kono
parents:
diff changeset
854 tree operation_type = result_type;
kono
parents:
diff changeset
855 tree best_type = NULL_TREE;
kono
parents:
diff changeset
856 tree modulus, result;
kono
parents:
diff changeset
857 bool has_side_effects = false;
kono
parents:
diff changeset
858
kono
parents:
diff changeset
859 if (operation_type
kono
parents:
diff changeset
860 && TREE_CODE (operation_type) == RECORD_TYPE
kono
parents:
diff changeset
861 && TYPE_JUSTIFIED_MODULAR_P (operation_type))
kono
parents:
diff changeset
862 operation_type = TREE_TYPE (TYPE_FIELDS (operation_type));
kono
parents:
diff changeset
863
kono
parents:
diff changeset
864 if (operation_type
kono
parents:
diff changeset
865 && TREE_CODE (operation_type) == INTEGER_TYPE
kono
parents:
diff changeset
866 && TYPE_EXTRA_SUBTYPE_P (operation_type))
kono
parents:
diff changeset
867 operation_type = get_base_type (operation_type);
kono
parents:
diff changeset
868
kono
parents:
diff changeset
869 modulus = (operation_type
kono
parents:
diff changeset
870 && TREE_CODE (operation_type) == INTEGER_TYPE
kono
parents:
diff changeset
871 && TYPE_MODULAR_P (operation_type)
kono
parents:
diff changeset
872 ? TYPE_MODULUS (operation_type) : NULL_TREE);
kono
parents:
diff changeset
873
kono
parents:
diff changeset
874 switch (op_code)
kono
parents:
diff changeset
875 {
kono
parents:
diff changeset
876 case INIT_EXPR:
kono
parents:
diff changeset
877 case MODIFY_EXPR:
kono
parents:
diff changeset
878 gcc_checking_assert (!result_type);
kono
parents:
diff changeset
879
kono
parents:
diff changeset
880 /* If there were integral or pointer conversions on the LHS, remove
kono
parents:
diff changeset
881 them; we'll be putting them back below if needed. Likewise for
kono
parents:
diff changeset
882 conversions between array and record types, except for justified
kono
parents:
diff changeset
883 modular types. But don't do this if the right operand is not
kono
parents:
diff changeset
884 BLKmode (for packed arrays) unless we are not changing the mode. */
kono
parents:
diff changeset
885 while ((CONVERT_EXPR_P (left_operand)
kono
parents:
diff changeset
886 || TREE_CODE (left_operand) == VIEW_CONVERT_EXPR)
kono
parents:
diff changeset
887 && (((INTEGRAL_TYPE_P (left_type)
kono
parents:
diff changeset
888 || POINTER_TYPE_P (left_type))
kono
parents:
diff changeset
889 && (INTEGRAL_TYPE_P (TREE_TYPE
kono
parents:
diff changeset
890 (TREE_OPERAND (left_operand, 0)))
kono
parents:
diff changeset
891 || POINTER_TYPE_P (TREE_TYPE
kono
parents:
diff changeset
892 (TREE_OPERAND (left_operand, 0)))))
kono
parents:
diff changeset
893 || (((TREE_CODE (left_type) == RECORD_TYPE
kono
parents:
diff changeset
894 && !TYPE_JUSTIFIED_MODULAR_P (left_type))
kono
parents:
diff changeset
895 || TREE_CODE (left_type) == ARRAY_TYPE)
kono
parents:
diff changeset
896 && ((TREE_CODE (TREE_TYPE
kono
parents:
diff changeset
897 (TREE_OPERAND (left_operand, 0)))
kono
parents:
diff changeset
898 == RECORD_TYPE)
kono
parents:
diff changeset
899 || (TREE_CODE (TREE_TYPE
kono
parents:
diff changeset
900 (TREE_OPERAND (left_operand, 0)))
kono
parents:
diff changeset
901 == ARRAY_TYPE))
kono
parents:
diff changeset
902 && (TYPE_MODE (right_type) == BLKmode
kono
parents:
diff changeset
903 || (TYPE_MODE (left_type)
kono
parents:
diff changeset
904 == TYPE_MODE (TREE_TYPE
kono
parents:
diff changeset
905 (TREE_OPERAND
kono
parents:
diff changeset
906 (left_operand, 0))))))))
kono
parents:
diff changeset
907 {
kono
parents:
diff changeset
908 left_operand = TREE_OPERAND (left_operand, 0);
kono
parents:
diff changeset
909 left_type = TREE_TYPE (left_operand);
kono
parents:
diff changeset
910 }
kono
parents:
diff changeset
911
kono
parents:
diff changeset
912 /* If a class-wide type may be involved, force use of the RHS type. */
kono
parents:
diff changeset
913 if ((TREE_CODE (right_type) == RECORD_TYPE
kono
parents:
diff changeset
914 || TREE_CODE (right_type) == UNION_TYPE)
kono
parents:
diff changeset
915 && TYPE_ALIGN_OK (right_type))
kono
parents:
diff changeset
916 operation_type = right_type;
kono
parents:
diff changeset
917
kono
parents:
diff changeset
918 /* If we are copying between padded objects with compatible types, use
kono
parents:
diff changeset
919 the padded view of the objects, this is very likely more efficient.
kono
parents:
diff changeset
920 Likewise for a padded object that is assigned a constructor, if we
kono
parents:
diff changeset
921 can convert the constructor to the inner type, to avoid putting a
kono
parents:
diff changeset
922 VIEW_CONVERT_EXPR on the LHS. But don't do so if we wouldn't have
kono
parents:
diff changeset
923 actually copied anything. */
kono
parents:
diff changeset
924 else if (TYPE_IS_PADDING_P (left_type)
kono
parents:
diff changeset
925 && TREE_CONSTANT (TYPE_SIZE (left_type))
kono
parents:
diff changeset
926 && ((TREE_CODE (right_operand) == COMPONENT_REF
kono
parents:
diff changeset
927 && TYPE_MAIN_VARIANT (left_type)
kono
parents:
diff changeset
928 == TYPE_MAIN_VARIANT
kono
parents:
diff changeset
929 (TREE_TYPE (TREE_OPERAND (right_operand, 0))))
kono
parents:
diff changeset
930 || (TREE_CODE (right_operand) == CONSTRUCTOR
kono
parents:
diff changeset
931 && !CONTAINS_PLACEHOLDER_P
kono
parents:
diff changeset
932 (DECL_SIZE (TYPE_FIELDS (left_type)))))
kono
parents:
diff changeset
933 && !integer_zerop (TYPE_SIZE (right_type)))
kono
parents:
diff changeset
934 {
kono
parents:
diff changeset
935 /* We make an exception for a BLKmode type padding a non-BLKmode
kono
parents:
diff changeset
936 inner type and do the conversion of the LHS right away, since
kono
parents:
diff changeset
937 unchecked_convert wouldn't do it properly. */
kono
parents:
diff changeset
938 if (TYPE_MODE (left_type) == BLKmode
kono
parents:
diff changeset
939 && TYPE_MODE (right_type) != BLKmode
kono
parents:
diff changeset
940 && TREE_CODE (right_operand) != CONSTRUCTOR)
kono
parents:
diff changeset
941 {
kono
parents:
diff changeset
942 operation_type = right_type;
kono
parents:
diff changeset
943 left_operand = convert (operation_type, left_operand);
kono
parents:
diff changeset
944 left_type = operation_type;
kono
parents:
diff changeset
945 }
kono
parents:
diff changeset
946 else
kono
parents:
diff changeset
947 operation_type = left_type;
kono
parents:
diff changeset
948 }
kono
parents:
diff changeset
949
kono
parents:
diff changeset
950 /* If we have a call to a function that returns with variable size, use
kono
parents:
diff changeset
951 the RHS type in case we want to use the return slot optimization. */
kono
parents:
diff changeset
952 else if (TREE_CODE (right_operand) == CALL_EXPR
kono
parents:
diff changeset
953 && return_type_with_variable_size_p (right_type))
kono
parents:
diff changeset
954 operation_type = right_type;
kono
parents:
diff changeset
955
kono
parents:
diff changeset
956 /* Find the best type to use for copying between aggregate types. */
kono
parents:
diff changeset
957 else if (((TREE_CODE (left_type) == ARRAY_TYPE
kono
parents:
diff changeset
958 && TREE_CODE (right_type) == ARRAY_TYPE)
kono
parents:
diff changeset
959 || (TREE_CODE (left_type) == RECORD_TYPE
kono
parents:
diff changeset
960 && TREE_CODE (right_type) == RECORD_TYPE))
kono
parents:
diff changeset
961 && (best_type = find_common_type (left_type, right_type)))
kono
parents:
diff changeset
962 operation_type = best_type;
kono
parents:
diff changeset
963
kono
parents:
diff changeset
964 /* Otherwise use the LHS type. */
kono
parents:
diff changeset
965 else
kono
parents:
diff changeset
966 operation_type = left_type;
kono
parents:
diff changeset
967
kono
parents:
diff changeset
968 /* Ensure everything on the LHS is valid. If we have a field reference,
kono
parents:
diff changeset
969 strip anything that get_inner_reference can handle. Then remove any
kono
parents:
diff changeset
970 conversions between types having the same code and mode. And mark
kono
parents:
diff changeset
971 VIEW_CONVERT_EXPRs with TREE_ADDRESSABLE. When done, we must have
kono
parents:
diff changeset
972 either an INDIRECT_REF, a NULL_EXPR, a SAVE_EXPR or a DECL node. */
kono
parents:
diff changeset
973 result = left_operand;
kono
parents:
diff changeset
974 while (true)
kono
parents:
diff changeset
975 {
kono
parents:
diff changeset
976 tree restype = TREE_TYPE (result);
kono
parents:
diff changeset
977
kono
parents:
diff changeset
978 if (TREE_CODE (result) == COMPONENT_REF
kono
parents:
diff changeset
979 || TREE_CODE (result) == ARRAY_REF
kono
parents:
diff changeset
980 || TREE_CODE (result) == ARRAY_RANGE_REF)
kono
parents:
diff changeset
981 while (handled_component_p (result))
kono
parents:
diff changeset
982 result = TREE_OPERAND (result, 0);
kono
parents:
diff changeset
983 else if (TREE_CODE (result) == REALPART_EXPR
kono
parents:
diff changeset
984 || TREE_CODE (result) == IMAGPART_EXPR
kono
parents:
diff changeset
985 || (CONVERT_EXPR_P (result)
kono
parents:
diff changeset
986 && (((TREE_CODE (restype)
kono
parents:
diff changeset
987 == TREE_CODE (TREE_TYPE
kono
parents:
diff changeset
988 (TREE_OPERAND (result, 0))))
kono
parents:
diff changeset
989 && (TYPE_MODE (TREE_TYPE
kono
parents:
diff changeset
990 (TREE_OPERAND (result, 0)))
kono
parents:
diff changeset
991 == TYPE_MODE (restype)))
kono
parents:
diff changeset
992 || TYPE_ALIGN_OK (restype))))
kono
parents:
diff changeset
993 result = TREE_OPERAND (result, 0);
kono
parents:
diff changeset
994 else if (TREE_CODE (result) == VIEW_CONVERT_EXPR)
kono
parents:
diff changeset
995 {
kono
parents:
diff changeset
996 TREE_ADDRESSABLE (result) = 1;
kono
parents:
diff changeset
997 result = TREE_OPERAND (result, 0);
kono
parents:
diff changeset
998 }
kono
parents:
diff changeset
999 else
kono
parents:
diff changeset
1000 break;
kono
parents:
diff changeset
1001 }
kono
parents:
diff changeset
1002
kono
parents:
diff changeset
1003 gcc_assert (TREE_CODE (result) == INDIRECT_REF
kono
parents:
diff changeset
1004 || TREE_CODE (result) == NULL_EXPR
kono
parents:
diff changeset
1005 || TREE_CODE (result) == SAVE_EXPR
kono
parents:
diff changeset
1006 || DECL_P (result));
kono
parents:
diff changeset
1007
kono
parents:
diff changeset
1008 /* Convert the right operand to the operation type unless it is
kono
parents:
diff changeset
1009 either already of the correct type or if the type involves a
kono
parents:
diff changeset
1010 placeholder, since the RHS may not have the same record type. */
kono
parents:
diff changeset
1011 if (operation_type != right_type
kono
parents:
diff changeset
1012 && !CONTAINS_PLACEHOLDER_P (TYPE_SIZE (operation_type)))
kono
parents:
diff changeset
1013 {
kono
parents:
diff changeset
1014 right_operand = convert (operation_type, right_operand);
kono
parents:
diff changeset
1015 right_type = operation_type;
kono
parents:
diff changeset
1016 }
kono
parents:
diff changeset
1017
kono
parents:
diff changeset
1018 /* If the left operand is not of the same type as the operation
kono
parents:
diff changeset
1019 type, wrap it up in a VIEW_CONVERT_EXPR. */
kono
parents:
diff changeset
1020 if (left_type != operation_type)
kono
parents:
diff changeset
1021 left_operand = unchecked_convert (operation_type, left_operand, false);
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 has_side_effects = true;
kono
parents:
diff changeset
1024 modulus = NULL_TREE;
kono
parents:
diff changeset
1025 break;
kono
parents:
diff changeset
1026
kono
parents:
diff changeset
1027 case ARRAY_REF:
kono
parents:
diff changeset
1028 if (!operation_type)
kono
parents:
diff changeset
1029 operation_type = TREE_TYPE (left_type);
kono
parents:
diff changeset
1030
kono
parents:
diff changeset
1031 /* ... fall through ... */
kono
parents:
diff changeset
1032
kono
parents:
diff changeset
1033 case ARRAY_RANGE_REF:
kono
parents:
diff changeset
1034 /* First look through conversion between type variants. Note that
kono
parents:
diff changeset
1035 this changes neither the operation type nor the type domain. */
kono
parents:
diff changeset
1036 if (TREE_CODE (left_operand) == VIEW_CONVERT_EXPR
kono
parents:
diff changeset
1037 && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (left_operand, 0)))
kono
parents:
diff changeset
1038 == TYPE_MAIN_VARIANT (left_type))
kono
parents:
diff changeset
1039 {
kono
parents:
diff changeset
1040 left_operand = TREE_OPERAND (left_operand, 0);
kono
parents:
diff changeset
1041 left_type = TREE_TYPE (left_operand);
kono
parents:
diff changeset
1042 }
kono
parents:
diff changeset
1043
kono
parents:
diff changeset
1044 /* For a range, make sure the element type is consistent. */
kono
parents:
diff changeset
1045 if (op_code == ARRAY_RANGE_REF
kono
parents:
diff changeset
1046 && TREE_TYPE (operation_type) != TREE_TYPE (left_type))
kono
parents:
diff changeset
1047 operation_type = build_array_type (TREE_TYPE (left_type),
kono
parents:
diff changeset
1048 TYPE_DOMAIN (operation_type));
kono
parents:
diff changeset
1049
kono
parents:
diff changeset
1050 /* Then convert the right operand to its base type. This will prevent
kono
parents:
diff changeset
1051 unneeded sign conversions when sizetype is wider than integer. */
kono
parents:
diff changeset
1052 right_operand = convert (right_base_type, right_operand);
kono
parents:
diff changeset
1053 right_operand = convert_to_index_type (right_operand);
kono
parents:
diff changeset
1054 modulus = NULL_TREE;
kono
parents:
diff changeset
1055 break;
kono
parents:
diff changeset
1056
kono
parents:
diff changeset
1057 case TRUTH_ANDIF_EXPR:
kono
parents:
diff changeset
1058 case TRUTH_ORIF_EXPR:
kono
parents:
diff changeset
1059 case TRUTH_AND_EXPR:
kono
parents:
diff changeset
1060 case TRUTH_OR_EXPR:
kono
parents:
diff changeset
1061 case TRUTH_XOR_EXPR:
kono
parents:
diff changeset
1062 gcc_checking_assert
kono
parents:
diff changeset
1063 (TREE_CODE (get_base_type (result_type)) == BOOLEAN_TYPE);
kono
parents:
diff changeset
1064 operation_type = left_base_type;
kono
parents:
diff changeset
1065 left_operand = convert (operation_type, left_operand);
kono
parents:
diff changeset
1066 right_operand = convert (operation_type, right_operand);
kono
parents:
diff changeset
1067 break;
kono
parents:
diff changeset
1068
kono
parents:
diff changeset
1069 case GE_EXPR:
kono
parents:
diff changeset
1070 case LE_EXPR:
kono
parents:
diff changeset
1071 case GT_EXPR:
kono
parents:
diff changeset
1072 case LT_EXPR:
kono
parents:
diff changeset
1073 case EQ_EXPR:
kono
parents:
diff changeset
1074 case NE_EXPR:
kono
parents:
diff changeset
1075 gcc_checking_assert
kono
parents:
diff changeset
1076 (TREE_CODE (get_base_type (result_type)) == BOOLEAN_TYPE);
kono
parents:
diff changeset
1077 /* If either operand is a NULL_EXPR, just return a new one. */
kono
parents:
diff changeset
1078 if (TREE_CODE (left_operand) == NULL_EXPR)
kono
parents:
diff changeset
1079 return build2 (op_code, result_type,
kono
parents:
diff changeset
1080 build1 (NULL_EXPR, integer_type_node,
kono
parents:
diff changeset
1081 TREE_OPERAND (left_operand, 0)),
kono
parents:
diff changeset
1082 integer_zero_node);
kono
parents:
diff changeset
1083
kono
parents:
diff changeset
1084 else if (TREE_CODE (right_operand) == NULL_EXPR)
kono
parents:
diff changeset
1085 return build2 (op_code, result_type,
kono
parents:
diff changeset
1086 build1 (NULL_EXPR, integer_type_node,
kono
parents:
diff changeset
1087 TREE_OPERAND (right_operand, 0)),
kono
parents:
diff changeset
1088 integer_zero_node);
kono
parents:
diff changeset
1089
kono
parents:
diff changeset
1090 /* If either object is a justified modular types, get the
kono
parents:
diff changeset
1091 fields from within. */
kono
parents:
diff changeset
1092 if (TREE_CODE (left_type) == RECORD_TYPE
kono
parents:
diff changeset
1093 && TYPE_JUSTIFIED_MODULAR_P (left_type))
kono
parents:
diff changeset
1094 {
kono
parents:
diff changeset
1095 left_operand = convert (TREE_TYPE (TYPE_FIELDS (left_type)),
kono
parents:
diff changeset
1096 left_operand);
kono
parents:
diff changeset
1097 left_type = TREE_TYPE (left_operand);
kono
parents:
diff changeset
1098 left_base_type = get_base_type (left_type);
kono
parents:
diff changeset
1099 }
kono
parents:
diff changeset
1100
kono
parents:
diff changeset
1101 if (TREE_CODE (right_type) == RECORD_TYPE
kono
parents:
diff changeset
1102 && TYPE_JUSTIFIED_MODULAR_P (right_type))
kono
parents:
diff changeset
1103 {
kono
parents:
diff changeset
1104 right_operand = convert (TREE_TYPE (TYPE_FIELDS (right_type)),
kono
parents:
diff changeset
1105 right_operand);
kono
parents:
diff changeset
1106 right_type = TREE_TYPE (right_operand);
kono
parents:
diff changeset
1107 right_base_type = get_base_type (right_type);
kono
parents:
diff changeset
1108 }
kono
parents:
diff changeset
1109
kono
parents:
diff changeset
1110 /* If both objects are arrays, compare them specially. */
kono
parents:
diff changeset
1111 if ((TREE_CODE (left_type) == ARRAY_TYPE
kono
parents:
diff changeset
1112 || (TREE_CODE (left_type) == INTEGER_TYPE
kono
parents:
diff changeset
1113 && TYPE_HAS_ACTUAL_BOUNDS_P (left_type)))
kono
parents:
diff changeset
1114 && (TREE_CODE (right_type) == ARRAY_TYPE
kono
parents:
diff changeset
1115 || (TREE_CODE (right_type) == INTEGER_TYPE
kono
parents:
diff changeset
1116 && TYPE_HAS_ACTUAL_BOUNDS_P (right_type))))
kono
parents:
diff changeset
1117 {
kono
parents:
diff changeset
1118 result = compare_arrays (input_location,
kono
parents:
diff changeset
1119 result_type, left_operand, right_operand);
kono
parents:
diff changeset
1120 if (op_code == NE_EXPR)
kono
parents:
diff changeset
1121 result = invert_truthvalue_loc (EXPR_LOCATION (result), result);
kono
parents:
diff changeset
1122 else
kono
parents:
diff changeset
1123 gcc_assert (op_code == EQ_EXPR);
kono
parents:
diff changeset
1124
kono
parents:
diff changeset
1125 return result;
kono
parents:
diff changeset
1126 }
kono
parents:
diff changeset
1127
kono
parents:
diff changeset
1128 /* Otherwise, the base types must be the same, unless they are both fat
kono
parents:
diff changeset
1129 pointer types or record types. In the latter case, use the best type
kono
parents:
diff changeset
1130 and convert both operands to that type. */
kono
parents:
diff changeset
1131 if (left_base_type != right_base_type)
kono
parents:
diff changeset
1132 {
kono
parents:
diff changeset
1133 if (TYPE_IS_FAT_POINTER_P (left_base_type)
kono
parents:
diff changeset
1134 && TYPE_IS_FAT_POINTER_P (right_base_type))
kono
parents:
diff changeset
1135 {
kono
parents:
diff changeset
1136 gcc_assert (TYPE_MAIN_VARIANT (left_base_type)
kono
parents:
diff changeset
1137 == TYPE_MAIN_VARIANT (right_base_type));
kono
parents:
diff changeset
1138 best_type = left_base_type;
kono
parents:
diff changeset
1139 }
kono
parents:
diff changeset
1140
kono
parents:
diff changeset
1141 else if (TREE_CODE (left_base_type) == RECORD_TYPE
kono
parents:
diff changeset
1142 && TREE_CODE (right_base_type) == RECORD_TYPE)
kono
parents:
diff changeset
1143 {
kono
parents:
diff changeset
1144 /* The only way this is permitted is if both types have the same
kono
parents:
diff changeset
1145 name. In that case, one of them must not be self-referential.
kono
parents:
diff changeset
1146 Use it as the best type. Even better with a fixed size. */
kono
parents:
diff changeset
1147 gcc_assert (TYPE_NAME (left_base_type)
kono
parents:
diff changeset
1148 && TYPE_NAME (left_base_type)
kono
parents:
diff changeset
1149 == TYPE_NAME (right_base_type));
kono
parents:
diff changeset
1150
kono
parents:
diff changeset
1151 if (TREE_CONSTANT (TYPE_SIZE (left_base_type)))
kono
parents:
diff changeset
1152 best_type = left_base_type;
kono
parents:
diff changeset
1153 else if (TREE_CONSTANT (TYPE_SIZE (right_base_type)))
kono
parents:
diff changeset
1154 best_type = right_base_type;
kono
parents:
diff changeset
1155 else if (!CONTAINS_PLACEHOLDER_P (TYPE_SIZE (left_base_type)))
kono
parents:
diff changeset
1156 best_type = left_base_type;
kono
parents:
diff changeset
1157 else if (!CONTAINS_PLACEHOLDER_P (TYPE_SIZE (right_base_type)))
kono
parents:
diff changeset
1158 best_type = right_base_type;
kono
parents:
diff changeset
1159 else
kono
parents:
diff changeset
1160 gcc_unreachable ();
kono
parents:
diff changeset
1161 }
kono
parents:
diff changeset
1162
kono
parents:
diff changeset
1163 else if (POINTER_TYPE_P (left_base_type)
kono
parents:
diff changeset
1164 && POINTER_TYPE_P (right_base_type))
kono
parents:
diff changeset
1165 {
kono
parents:
diff changeset
1166 gcc_assert (TREE_TYPE (left_base_type)
kono
parents:
diff changeset
1167 == TREE_TYPE (right_base_type));
kono
parents:
diff changeset
1168 best_type = left_base_type;
kono
parents:
diff changeset
1169 }
kono
parents:
diff changeset
1170 else
kono
parents:
diff changeset
1171 gcc_unreachable ();
kono
parents:
diff changeset
1172
kono
parents:
diff changeset
1173 left_operand = convert (best_type, left_operand);
kono
parents:
diff changeset
1174 right_operand = convert (best_type, right_operand);
kono
parents:
diff changeset
1175 }
kono
parents:
diff changeset
1176 else
kono
parents:
diff changeset
1177 {
kono
parents:
diff changeset
1178 left_operand = convert (left_base_type, left_operand);
kono
parents:
diff changeset
1179 right_operand = convert (right_base_type, right_operand);
kono
parents:
diff changeset
1180 }
kono
parents:
diff changeset
1181
kono
parents:
diff changeset
1182 /* If both objects are fat pointers, compare them specially. */
kono
parents:
diff changeset
1183 if (TYPE_IS_FAT_POINTER_P (left_base_type))
kono
parents:
diff changeset
1184 {
kono
parents:
diff changeset
1185 result
kono
parents:
diff changeset
1186 = compare_fat_pointers (input_location,
kono
parents:
diff changeset
1187 result_type, left_operand, right_operand);
kono
parents:
diff changeset
1188 if (op_code == NE_EXPR)
kono
parents:
diff changeset
1189 result = invert_truthvalue_loc (EXPR_LOCATION (result), result);
kono
parents:
diff changeset
1190 else
kono
parents:
diff changeset
1191 gcc_assert (op_code == EQ_EXPR);
kono
parents:
diff changeset
1192
kono
parents:
diff changeset
1193 return result;
kono
parents:
diff changeset
1194 }
kono
parents:
diff changeset
1195
kono
parents:
diff changeset
1196 modulus = NULL_TREE;
kono
parents:
diff changeset
1197 break;
kono
parents:
diff changeset
1198
kono
parents:
diff changeset
1199 case LSHIFT_EXPR:
kono
parents:
diff changeset
1200 case RSHIFT_EXPR:
kono
parents:
diff changeset
1201 case LROTATE_EXPR:
kono
parents:
diff changeset
1202 case RROTATE_EXPR:
kono
parents:
diff changeset
1203 /* The RHS of a shift can be any type. Also, ignore any modulus
kono
parents:
diff changeset
1204 (we used to abort, but this is needed for unchecked conversion
kono
parents:
diff changeset
1205 to modular types). Otherwise, processing is the same as normal. */
kono
parents:
diff changeset
1206 gcc_assert (operation_type == left_base_type);
kono
parents:
diff changeset
1207 modulus = NULL_TREE;
kono
parents:
diff changeset
1208 left_operand = convert (operation_type, left_operand);
kono
parents:
diff changeset
1209 break;
kono
parents:
diff changeset
1210
kono
parents:
diff changeset
1211 case BIT_AND_EXPR:
kono
parents:
diff changeset
1212 case BIT_IOR_EXPR:
kono
parents:
diff changeset
1213 case BIT_XOR_EXPR:
kono
parents:
diff changeset
1214 /* For binary modulus, if the inputs are in range, so are the
kono
parents:
diff changeset
1215 outputs. */
kono
parents:
diff changeset
1216 if (modulus && integer_pow2p (modulus))
kono
parents:
diff changeset
1217 modulus = NULL_TREE;
kono
parents:
diff changeset
1218 goto common;
kono
parents:
diff changeset
1219
kono
parents:
diff changeset
1220 case COMPLEX_EXPR:
kono
parents:
diff changeset
1221 gcc_assert (TREE_TYPE (result_type) == left_base_type
kono
parents:
diff changeset
1222 && TREE_TYPE (result_type) == right_base_type);
kono
parents:
diff changeset
1223 left_operand = convert (left_base_type, left_operand);
kono
parents:
diff changeset
1224 right_operand = convert (right_base_type, right_operand);
kono
parents:
diff changeset
1225 break;
kono
parents:
diff changeset
1226
kono
parents:
diff changeset
1227 case TRUNC_DIV_EXPR: case TRUNC_MOD_EXPR:
kono
parents:
diff changeset
1228 case CEIL_DIV_EXPR: case CEIL_MOD_EXPR:
kono
parents:
diff changeset
1229 case FLOOR_DIV_EXPR: case FLOOR_MOD_EXPR:
kono
parents:
diff changeset
1230 case ROUND_DIV_EXPR: case ROUND_MOD_EXPR:
kono
parents:
diff changeset
1231 /* These always produce results lower than either operand. */
kono
parents:
diff changeset
1232 modulus = NULL_TREE;
kono
parents:
diff changeset
1233 goto common;
kono
parents:
diff changeset
1234
kono
parents:
diff changeset
1235 case POINTER_PLUS_EXPR:
kono
parents:
diff changeset
1236 gcc_assert (operation_type == left_base_type
kono
parents:
diff changeset
1237 && sizetype == right_base_type);
kono
parents:
diff changeset
1238 left_operand = convert (operation_type, left_operand);
kono
parents:
diff changeset
1239 right_operand = convert (sizetype, right_operand);
kono
parents:
diff changeset
1240 break;
kono
parents:
diff changeset
1241
kono
parents:
diff changeset
1242 case PLUS_NOMOD_EXPR:
kono
parents:
diff changeset
1243 case MINUS_NOMOD_EXPR:
kono
parents:
diff changeset
1244 if (op_code == PLUS_NOMOD_EXPR)
kono
parents:
diff changeset
1245 op_code = PLUS_EXPR;
kono
parents:
diff changeset
1246 else
kono
parents:
diff changeset
1247 op_code = MINUS_EXPR;
kono
parents:
diff changeset
1248 modulus = NULL_TREE;
kono
parents:
diff changeset
1249
kono
parents:
diff changeset
1250 /* ... fall through ... */
kono
parents:
diff changeset
1251
kono
parents:
diff changeset
1252 case PLUS_EXPR:
kono
parents:
diff changeset
1253 case MINUS_EXPR:
kono
parents:
diff changeset
1254 /* Avoid doing arithmetics in ENUMERAL_TYPE or BOOLEAN_TYPE like the
kono
parents:
diff changeset
1255 other compilers. Contrary to C, Ada doesn't allow arithmetics in
kono
parents:
diff changeset
1256 these types but can generate addition/subtraction for Succ/Pred. */
kono
parents:
diff changeset
1257 if (operation_type
kono
parents:
diff changeset
1258 && (TREE_CODE (operation_type) == ENUMERAL_TYPE
kono
parents:
diff changeset
1259 || TREE_CODE (operation_type) == BOOLEAN_TYPE))
kono
parents:
diff changeset
1260 operation_type = left_base_type = right_base_type
kono
parents:
diff changeset
1261 = gnat_type_for_mode (TYPE_MODE (operation_type),
kono
parents:
diff changeset
1262 TYPE_UNSIGNED (operation_type));
kono
parents:
diff changeset
1263
kono
parents:
diff changeset
1264 /* ... fall through ... */
kono
parents:
diff changeset
1265
kono
parents:
diff changeset
1266 default:
kono
parents:
diff changeset
1267 common:
kono
parents:
diff changeset
1268 /* The result type should be the same as the base types of the
kono
parents:
diff changeset
1269 both operands (and they should be the same). Convert
kono
parents:
diff changeset
1270 everything to the result type. */
kono
parents:
diff changeset
1271
kono
parents:
diff changeset
1272 gcc_assert (operation_type == left_base_type
kono
parents:
diff changeset
1273 && left_base_type == right_base_type);
kono
parents:
diff changeset
1274 left_operand = convert (operation_type, left_operand);
kono
parents:
diff changeset
1275 right_operand = convert (operation_type, right_operand);
kono
parents:
diff changeset
1276 }
kono
parents:
diff changeset
1277
kono
parents:
diff changeset
1278 if (modulus && !integer_pow2p (modulus))
kono
parents:
diff changeset
1279 {
kono
parents:
diff changeset
1280 result = nonbinary_modular_operation (op_code, operation_type,
kono
parents:
diff changeset
1281 left_operand, right_operand);
kono
parents:
diff changeset
1282 modulus = NULL_TREE;
kono
parents:
diff changeset
1283 }
kono
parents:
diff changeset
1284 /* If either operand is a NULL_EXPR, just return a new one. */
kono
parents:
diff changeset
1285 else if (TREE_CODE (left_operand) == NULL_EXPR)
kono
parents:
diff changeset
1286 return build1 (NULL_EXPR, operation_type, TREE_OPERAND (left_operand, 0));
kono
parents:
diff changeset
1287 else if (TREE_CODE (right_operand) == NULL_EXPR)
kono
parents:
diff changeset
1288 return build1 (NULL_EXPR, operation_type, TREE_OPERAND (right_operand, 0));
kono
parents:
diff changeset
1289 else if (op_code == ARRAY_REF || op_code == ARRAY_RANGE_REF)
kono
parents:
diff changeset
1290 {
kono
parents:
diff changeset
1291 result = build4 (op_code, operation_type, left_operand, right_operand,
kono
parents:
diff changeset
1292 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1293 if (!no_fold)
kono
parents:
diff changeset
1294 result = fold (result);
kono
parents:
diff changeset
1295 }
kono
parents:
diff changeset
1296 else if (op_code == INIT_EXPR || op_code == MODIFY_EXPR)
kono
parents:
diff changeset
1297 result = build2 (op_code, void_type_node, left_operand, right_operand);
kono
parents:
diff changeset
1298 else if (no_fold)
kono
parents:
diff changeset
1299 result = build2 (op_code, operation_type, left_operand, right_operand);
kono
parents:
diff changeset
1300 else
kono
parents:
diff changeset
1301 result
kono
parents:
diff changeset
1302 = fold_build2 (op_code, operation_type, left_operand, right_operand);
kono
parents:
diff changeset
1303
kono
parents:
diff changeset
1304 if (TREE_CONSTANT (result))
kono
parents:
diff changeset
1305 ;
kono
parents:
diff changeset
1306 else if (op_code == ARRAY_REF || op_code == ARRAY_RANGE_REF)
kono
parents:
diff changeset
1307 {
kono
parents:
diff changeset
1308 if (TYPE_VOLATILE (operation_type))
kono
parents:
diff changeset
1309 TREE_THIS_VOLATILE (result) = 1;
kono
parents:
diff changeset
1310 }
kono
parents:
diff changeset
1311 else
kono
parents:
diff changeset
1312 TREE_CONSTANT (result)
kono
parents:
diff changeset
1313 |= (TREE_CONSTANT (left_operand) && TREE_CONSTANT (right_operand));
kono
parents:
diff changeset
1314
kono
parents:
diff changeset
1315 TREE_SIDE_EFFECTS (result) |= has_side_effects;
kono
parents:
diff changeset
1316
kono
parents:
diff changeset
1317 /* If we are working with modular types, perform the MOD operation
kono
parents:
diff changeset
1318 if something above hasn't eliminated the need for it. */
kono
parents:
diff changeset
1319 if (modulus)
kono
parents:
diff changeset
1320 {
kono
parents:
diff changeset
1321 modulus = convert (operation_type, modulus);
kono
parents:
diff changeset
1322 if (no_fold)
kono
parents:
diff changeset
1323 result = build2 (FLOOR_MOD_EXPR, operation_type, result, modulus);
kono
parents:
diff changeset
1324 else
kono
parents:
diff changeset
1325 result = fold_build2 (FLOOR_MOD_EXPR, operation_type, result, modulus);
kono
parents:
diff changeset
1326 }
kono
parents:
diff changeset
1327
kono
parents:
diff changeset
1328 if (result_type && result_type != operation_type)
kono
parents:
diff changeset
1329 result = convert (result_type, result);
kono
parents:
diff changeset
1330
kono
parents:
diff changeset
1331 return result;
kono
parents:
diff changeset
1332 }
kono
parents:
diff changeset
1333
kono
parents:
diff changeset
1334 /* Similar, but for unary operations. */
kono
parents:
diff changeset
1335
kono
parents:
diff changeset
1336 tree
kono
parents:
diff changeset
1337 build_unary_op (enum tree_code op_code, tree result_type, tree operand)
kono
parents:
diff changeset
1338 {
kono
parents:
diff changeset
1339 tree type = TREE_TYPE (operand);
kono
parents:
diff changeset
1340 tree base_type = get_base_type (type);
kono
parents:
diff changeset
1341 tree operation_type = result_type;
kono
parents:
diff changeset
1342 tree result;
kono
parents:
diff changeset
1343
kono
parents:
diff changeset
1344 if (operation_type
kono
parents:
diff changeset
1345 && TREE_CODE (operation_type) == RECORD_TYPE
kono
parents:
diff changeset
1346 && TYPE_JUSTIFIED_MODULAR_P (operation_type))
kono
parents:
diff changeset
1347 operation_type = TREE_TYPE (TYPE_FIELDS (operation_type));
kono
parents:
diff changeset
1348
kono
parents:
diff changeset
1349 if (operation_type
kono
parents:
diff changeset
1350 && TREE_CODE (operation_type) == INTEGER_TYPE
kono
parents:
diff changeset
1351 && TYPE_EXTRA_SUBTYPE_P (operation_type))
kono
parents:
diff changeset
1352 operation_type = get_base_type (operation_type);
kono
parents:
diff changeset
1353
kono
parents:
diff changeset
1354 switch (op_code)
kono
parents:
diff changeset
1355 {
kono
parents:
diff changeset
1356 case REALPART_EXPR:
kono
parents:
diff changeset
1357 case IMAGPART_EXPR:
kono
parents:
diff changeset
1358 if (!operation_type)
kono
parents:
diff changeset
1359 result_type = operation_type = TREE_TYPE (type);
kono
parents:
diff changeset
1360 else
kono
parents:
diff changeset
1361 gcc_assert (result_type == TREE_TYPE (type));
kono
parents:
diff changeset
1362
kono
parents:
diff changeset
1363 result = fold_build1 (op_code, operation_type, operand);
kono
parents:
diff changeset
1364 break;
kono
parents:
diff changeset
1365
kono
parents:
diff changeset
1366 case TRUTH_NOT_EXPR:
kono
parents:
diff changeset
1367 gcc_checking_assert
kono
parents:
diff changeset
1368 (TREE_CODE (get_base_type (result_type)) == BOOLEAN_TYPE);
kono
parents:
diff changeset
1369 result = invert_truthvalue_loc (EXPR_LOCATION (operand), operand);
kono
parents:
diff changeset
1370 /* When not optimizing, fold the result as invert_truthvalue_loc
kono
parents:
diff changeset
1371 doesn't fold the result of comparisons. This is intended to undo
kono
parents:
diff changeset
1372 the trick used for boolean rvalues in gnat_to_gnu. */
kono
parents:
diff changeset
1373 if (!optimize)
kono
parents:
diff changeset
1374 result = fold (result);
kono
parents:
diff changeset
1375 break;
kono
parents:
diff changeset
1376
kono
parents:
diff changeset
1377 case ATTR_ADDR_EXPR:
kono
parents:
diff changeset
1378 case ADDR_EXPR:
kono
parents:
diff changeset
1379 switch (TREE_CODE (operand))
kono
parents:
diff changeset
1380 {
kono
parents:
diff changeset
1381 case INDIRECT_REF:
kono
parents:
diff changeset
1382 case UNCONSTRAINED_ARRAY_REF:
kono
parents:
diff changeset
1383 result = TREE_OPERAND (operand, 0);
kono
parents:
diff changeset
1384
kono
parents:
diff changeset
1385 /* Make sure the type here is a pointer, not a reference.
kono
parents:
diff changeset
1386 GCC wants pointer types for function addresses. */
kono
parents:
diff changeset
1387 if (!result_type)
kono
parents:
diff changeset
1388 result_type = build_pointer_type (type);
kono
parents:
diff changeset
1389
kono
parents:
diff changeset
1390 /* If the underlying object can alias everything, propagate the
kono
parents:
diff changeset
1391 property since we are effectively retrieving the object. */
kono
parents:
diff changeset
1392 if (POINTER_TYPE_P (TREE_TYPE (result))
kono
parents:
diff changeset
1393 && TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (result)))
kono
parents:
diff changeset
1394 {
kono
parents:
diff changeset
1395 if (TREE_CODE (result_type) == POINTER_TYPE
kono
parents:
diff changeset
1396 && !TYPE_REF_CAN_ALIAS_ALL (result_type))
kono
parents:
diff changeset
1397 result_type
kono
parents:
diff changeset
1398 = build_pointer_type_for_mode (TREE_TYPE (result_type),
kono
parents:
diff changeset
1399 TYPE_MODE (result_type),
kono
parents:
diff changeset
1400 true);
kono
parents:
diff changeset
1401 else if (TREE_CODE (result_type) == REFERENCE_TYPE
kono
parents:
diff changeset
1402 && !TYPE_REF_CAN_ALIAS_ALL (result_type))
kono
parents:
diff changeset
1403 result_type
kono
parents:
diff changeset
1404 = build_reference_type_for_mode (TREE_TYPE (result_type),
kono
parents:
diff changeset
1405 TYPE_MODE (result_type),
kono
parents:
diff changeset
1406 true);
kono
parents:
diff changeset
1407 }
kono
parents:
diff changeset
1408 break;
kono
parents:
diff changeset
1409
kono
parents:
diff changeset
1410 case NULL_EXPR:
kono
parents:
diff changeset
1411 result = operand;
kono
parents:
diff changeset
1412 TREE_TYPE (result) = type = build_pointer_type (type);
kono
parents:
diff changeset
1413 break;
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 case COMPOUND_EXPR:
kono
parents:
diff changeset
1416 /* Fold a compound expression if it has unconstrained array type
kono
parents:
diff changeset
1417 since the middle-end cannot handle it. But we don't it in the
kono
parents:
diff changeset
1418 general case because it may introduce aliasing issues if the
kono
parents:
diff changeset
1419 first operand is an indirect assignment and the second operand
kono
parents:
diff changeset
1420 the corresponding address, e.g. for an allocator. However do
kono
parents:
diff changeset
1421 it for a return value to expose it for later recognition. */
kono
parents:
diff changeset
1422 if (TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE
kono
parents:
diff changeset
1423 || (TREE_CODE (TREE_OPERAND (operand, 1)) == VAR_DECL
kono
parents:
diff changeset
1424 && DECL_RETURN_VALUE_P (TREE_OPERAND (operand, 1))))
kono
parents:
diff changeset
1425 {
kono
parents:
diff changeset
1426 result = build_unary_op (ADDR_EXPR, result_type,
kono
parents:
diff changeset
1427 TREE_OPERAND (operand, 1));
kono
parents:
diff changeset
1428 result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
kono
parents:
diff changeset
1429 TREE_OPERAND (operand, 0), result);
kono
parents:
diff changeset
1430 break;
kono
parents:
diff changeset
1431 }
kono
parents:
diff changeset
1432 goto common;
kono
parents:
diff changeset
1433
kono
parents:
diff changeset
1434 case ARRAY_REF:
kono
parents:
diff changeset
1435 case ARRAY_RANGE_REF:
kono
parents:
diff changeset
1436 case COMPONENT_REF:
kono
parents:
diff changeset
1437 case BIT_FIELD_REF:
kono
parents:
diff changeset
1438 /* If this is for 'Address, find the address of the prefix and add
kono
parents:
diff changeset
1439 the offset to the field. Otherwise, do this the normal way. */
kono
parents:
diff changeset
1440 if (op_code == ATTR_ADDR_EXPR)
kono
parents:
diff changeset
1441 {
kono
parents:
diff changeset
1442 HOST_WIDE_INT bitsize;
kono
parents:
diff changeset
1443 HOST_WIDE_INT bitpos;
kono
parents:
diff changeset
1444 tree offset, inner;
kono
parents:
diff changeset
1445 machine_mode mode;
kono
parents:
diff changeset
1446 int unsignedp, reversep, volatilep;
kono
parents:
diff changeset
1447
kono
parents:
diff changeset
1448 inner = get_inner_reference (operand, &bitsize, &bitpos, &offset,
kono
parents:
diff changeset
1449 &mode, &unsignedp, &reversep,
kono
parents:
diff changeset
1450 &volatilep);
kono
parents:
diff changeset
1451
kono
parents:
diff changeset
1452 /* If INNER is a padding type whose field has a self-referential
kono
parents:
diff changeset
1453 size, convert to that inner type. We know the offset is zero
kono
parents:
diff changeset
1454 and we need to have that type visible. */
kono
parents:
diff changeset
1455 if (type_is_padding_self_referential (TREE_TYPE (inner)))
kono
parents:
diff changeset
1456 inner = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (inner))),
kono
parents:
diff changeset
1457 inner);
kono
parents:
diff changeset
1458
kono
parents:
diff changeset
1459 /* Compute the offset as a byte offset from INNER. */
kono
parents:
diff changeset
1460 if (!offset)
kono
parents:
diff changeset
1461 offset = size_zero_node;
kono
parents:
diff changeset
1462
kono
parents:
diff changeset
1463 offset = size_binop (PLUS_EXPR, offset,
kono
parents:
diff changeset
1464 size_int (bitpos / BITS_PER_UNIT));
kono
parents:
diff changeset
1465
kono
parents:
diff changeset
1466 /* Take the address of INNER, convert it to a pointer to our type
kono
parents:
diff changeset
1467 and add the offset. */
kono
parents:
diff changeset
1468 inner = build_unary_op (ADDR_EXPR,
kono
parents:
diff changeset
1469 build_pointer_type (TREE_TYPE (operand)),
kono
parents:
diff changeset
1470 inner);
kono
parents:
diff changeset
1471 result = build_binary_op (POINTER_PLUS_EXPR, TREE_TYPE (inner),
kono
parents:
diff changeset
1472 inner, offset);
kono
parents:
diff changeset
1473 break;
kono
parents:
diff changeset
1474 }
kono
parents:
diff changeset
1475 goto common;
kono
parents:
diff changeset
1476
kono
parents:
diff changeset
1477 case CONSTRUCTOR:
kono
parents:
diff changeset
1478 /* If this is just a constructor for a padded record, we can
kono
parents:
diff changeset
1479 just take the address of the single field and convert it to
kono
parents:
diff changeset
1480 a pointer to our type. */
kono
parents:
diff changeset
1481 if (TYPE_IS_PADDING_P (type))
kono
parents:
diff changeset
1482 {
kono
parents:
diff changeset
1483 result
kono
parents:
diff changeset
1484 = build_unary_op (ADDR_EXPR,
kono
parents:
diff changeset
1485 build_pointer_type (TREE_TYPE (operand)),
kono
parents:
diff changeset
1486 CONSTRUCTOR_ELT (operand, 0)->value);
kono
parents:
diff changeset
1487 break;
kono
parents:
diff changeset
1488 }
kono
parents:
diff changeset
1489 goto common;
kono
parents:
diff changeset
1490
kono
parents:
diff changeset
1491 case NOP_EXPR:
kono
parents:
diff changeset
1492 if (AGGREGATE_TYPE_P (type)
kono
parents:
diff changeset
1493 && AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (operand, 0))))
kono
parents:
diff changeset
1494 return build_unary_op (ADDR_EXPR, result_type,
kono
parents:
diff changeset
1495 TREE_OPERAND (operand, 0));
kono
parents:
diff changeset
1496
kono
parents:
diff changeset
1497 /* ... fallthru ... */
kono
parents:
diff changeset
1498
kono
parents:
diff changeset
1499 case VIEW_CONVERT_EXPR:
kono
parents:
diff changeset
1500 /* If this just a variant conversion or if the conversion doesn't
kono
parents:
diff changeset
1501 change the mode, get the result type from this type and go down.
kono
parents:
diff changeset
1502 This is needed for conversions of CONST_DECLs, to eventually get
kono
parents:
diff changeset
1503 to the address of their CORRESPONDING_VARs. */
kono
parents:
diff changeset
1504 if ((TYPE_MAIN_VARIANT (type)
kono
parents:
diff changeset
1505 == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (operand, 0))))
kono
parents:
diff changeset
1506 || (TYPE_MODE (type) != BLKmode
kono
parents:
diff changeset
1507 && (TYPE_MODE (type)
kono
parents:
diff changeset
1508 == TYPE_MODE (TREE_TYPE (TREE_OPERAND (operand, 0))))))
kono
parents:
diff changeset
1509 return build_unary_op (ADDR_EXPR,
kono
parents:
diff changeset
1510 (result_type ? result_type
kono
parents:
diff changeset
1511 : build_pointer_type (type)),
kono
parents:
diff changeset
1512 TREE_OPERAND (operand, 0));
kono
parents:
diff changeset
1513 goto common;
kono
parents:
diff changeset
1514
kono
parents:
diff changeset
1515 case CONST_DECL:
kono
parents:
diff changeset
1516 operand = DECL_CONST_CORRESPONDING_VAR (operand);
kono
parents:
diff changeset
1517
kono
parents:
diff changeset
1518 /* ... fall through ... */
kono
parents:
diff changeset
1519
kono
parents:
diff changeset
1520 default:
kono
parents:
diff changeset
1521 common:
kono
parents:
diff changeset
1522
kono
parents:
diff changeset
1523 /* If we are taking the address of a padded record whose field
kono
parents:
diff changeset
1524 contains a template, take the address of the field. */
kono
parents:
diff changeset
1525 if (TYPE_IS_PADDING_P (type)
kono
parents:
diff changeset
1526 && TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == RECORD_TYPE
kono
parents:
diff changeset
1527 && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (TYPE_FIELDS (type))))
kono
parents:
diff changeset
1528 {
kono
parents:
diff changeset
1529 type = TREE_TYPE (TYPE_FIELDS (type));
kono
parents:
diff changeset
1530 operand = convert (type, operand);
kono
parents:
diff changeset
1531 }
kono
parents:
diff changeset
1532
kono
parents:
diff changeset
1533 gnat_mark_addressable (operand);
kono
parents:
diff changeset
1534 result = build_fold_addr_expr (operand);
kono
parents:
diff changeset
1535 }
kono
parents:
diff changeset
1536
kono
parents:
diff changeset
1537 TREE_CONSTANT (result) = staticp (operand) || TREE_CONSTANT (operand);
kono
parents:
diff changeset
1538 break;
kono
parents:
diff changeset
1539
kono
parents:
diff changeset
1540 case INDIRECT_REF:
kono
parents:
diff changeset
1541 {
kono
parents:
diff changeset
1542 tree t = remove_conversions (operand, false);
kono
parents:
diff changeset
1543 bool can_never_be_null = DECL_P (t) && DECL_CAN_NEVER_BE_NULL_P (t);
kono
parents:
diff changeset
1544
kono
parents:
diff changeset
1545 /* If TYPE is a thin pointer, either first retrieve the base if this
kono
parents:
diff changeset
1546 is an expression with an offset built for the initialization of an
kono
parents:
diff changeset
1547 object with an unconstrained nominal subtype, or else convert to
kono
parents:
diff changeset
1548 the fat pointer. */
kono
parents:
diff changeset
1549 if (TYPE_IS_THIN_POINTER_P (type))
kono
parents:
diff changeset
1550 {
kono
parents:
diff changeset
1551 tree rec_type = TREE_TYPE (type);
kono
parents:
diff changeset
1552
kono
parents:
diff changeset
1553 if (TREE_CODE (operand) == POINTER_PLUS_EXPR
kono
parents:
diff changeset
1554 && TREE_OPERAND (operand, 1)
kono
parents:
diff changeset
1555 == byte_position (DECL_CHAIN (TYPE_FIELDS (rec_type)))
kono
parents:
diff changeset
1556 && TREE_CODE (TREE_OPERAND (operand, 0)) == NOP_EXPR)
kono
parents:
diff changeset
1557 {
kono
parents:
diff changeset
1558 operand = TREE_OPERAND (TREE_OPERAND (operand, 0), 0);
kono
parents:
diff changeset
1559 type = TREE_TYPE (operand);
kono
parents:
diff changeset
1560 }
kono
parents:
diff changeset
1561 else if (TYPE_UNCONSTRAINED_ARRAY (rec_type))
kono
parents:
diff changeset
1562 {
kono
parents:
diff changeset
1563 operand
kono
parents:
diff changeset
1564 = convert (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (rec_type)),
kono
parents:
diff changeset
1565 operand);
kono
parents:
diff changeset
1566 type = TREE_TYPE (operand);
kono
parents:
diff changeset
1567 }
kono
parents:
diff changeset
1568 }
kono
parents:
diff changeset
1569
kono
parents:
diff changeset
1570 /* If we want to refer to an unconstrained array, use the appropriate
kono
parents:
diff changeset
1571 expression. But this will never survive down to the back-end. */
kono
parents:
diff changeset
1572 if (TYPE_IS_FAT_POINTER_P (type))
kono
parents:
diff changeset
1573 {
kono
parents:
diff changeset
1574 result = build1 (UNCONSTRAINED_ARRAY_REF,
kono
parents:
diff changeset
1575 TYPE_UNCONSTRAINED_ARRAY (type), operand);
kono
parents:
diff changeset
1576 TREE_READONLY (result)
kono
parents:
diff changeset
1577 = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
kono
parents:
diff changeset
1578 }
kono
parents:
diff changeset
1579
kono
parents:
diff changeset
1580 /* If we are dereferencing an ADDR_EXPR, return its operand. */
kono
parents:
diff changeset
1581 else if (TREE_CODE (operand) == ADDR_EXPR)
kono
parents:
diff changeset
1582 result = TREE_OPERAND (operand, 0);
kono
parents:
diff changeset
1583
kono
parents:
diff changeset
1584 /* Otherwise, build and fold the indirect reference. */
kono
parents:
diff changeset
1585 else
kono
parents:
diff changeset
1586 {
kono
parents:
diff changeset
1587 result = build_fold_indirect_ref (operand);
kono
parents:
diff changeset
1588 TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
kono
parents:
diff changeset
1589 }
kono
parents:
diff changeset
1590
kono
parents:
diff changeset
1591 if (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type)))
kono
parents:
diff changeset
1592 {
kono
parents:
diff changeset
1593 TREE_SIDE_EFFECTS (result) = 1;
kono
parents:
diff changeset
1594 if (TREE_CODE (result) == INDIRECT_REF)
kono
parents:
diff changeset
1595 TREE_THIS_VOLATILE (result) = TYPE_VOLATILE (TREE_TYPE (result));
kono
parents:
diff changeset
1596 }
kono
parents:
diff changeset
1597
kono
parents:
diff changeset
1598 if ((TREE_CODE (result) == INDIRECT_REF
kono
parents:
diff changeset
1599 || TREE_CODE (result) == UNCONSTRAINED_ARRAY_REF)
kono
parents:
diff changeset
1600 && can_never_be_null)
kono
parents:
diff changeset
1601 TREE_THIS_NOTRAP (result) = 1;
kono
parents:
diff changeset
1602
kono
parents:
diff changeset
1603 break;
kono
parents:
diff changeset
1604 }
kono
parents:
diff changeset
1605
kono
parents:
diff changeset
1606 case NEGATE_EXPR:
kono
parents:
diff changeset
1607 case BIT_NOT_EXPR:
kono
parents:
diff changeset
1608 {
kono
parents:
diff changeset
1609 tree modulus = ((operation_type
kono
parents:
diff changeset
1610 && TREE_CODE (operation_type) == INTEGER_TYPE
kono
parents:
diff changeset
1611 && TYPE_MODULAR_P (operation_type))
kono
parents:
diff changeset
1612 ? TYPE_MODULUS (operation_type) : NULL_TREE);
kono
parents:
diff changeset
1613 int mod_pow2 = modulus && integer_pow2p (modulus);
kono
parents:
diff changeset
1614
kono
parents:
diff changeset
1615 /* If this is a modular type, there are various possibilities
kono
parents:
diff changeset
1616 depending on the operation and whether the modulus is a
kono
parents:
diff changeset
1617 power of two or not. */
kono
parents:
diff changeset
1618
kono
parents:
diff changeset
1619 if (modulus)
kono
parents:
diff changeset
1620 {
kono
parents:
diff changeset
1621 gcc_assert (operation_type == base_type);
kono
parents:
diff changeset
1622 operand = convert (operation_type, operand);
kono
parents:
diff changeset
1623
kono
parents:
diff changeset
1624 /* The fastest in the negate case for binary modulus is
kono
parents:
diff changeset
1625 the straightforward code; the TRUNC_MOD_EXPR below
kono
parents:
diff changeset
1626 is an AND operation. */
kono
parents:
diff changeset
1627 if (op_code == NEGATE_EXPR && mod_pow2)
kono
parents:
diff changeset
1628 result = fold_build2 (TRUNC_MOD_EXPR, operation_type,
kono
parents:
diff changeset
1629 fold_build1 (NEGATE_EXPR, operation_type,
kono
parents:
diff changeset
1630 operand),
kono
parents:
diff changeset
1631 modulus);
kono
parents:
diff changeset
1632
kono
parents:
diff changeset
1633 /* For nonbinary negate case, return zero for zero operand,
kono
parents:
diff changeset
1634 else return the modulus minus the operand. If the modulus
kono
parents:
diff changeset
1635 is a power of two minus one, we can do the subtraction
kono
parents:
diff changeset
1636 as an XOR since it is equivalent and faster on most machines. */
kono
parents:
diff changeset
1637 else if (op_code == NEGATE_EXPR && !mod_pow2)
kono
parents:
diff changeset
1638 {
kono
parents:
diff changeset
1639 if (integer_pow2p (fold_build2 (PLUS_EXPR, operation_type,
kono
parents:
diff changeset
1640 modulus,
kono
parents:
diff changeset
1641 build_int_cst (operation_type,
kono
parents:
diff changeset
1642 1))))
kono
parents:
diff changeset
1643 result = fold_build2 (BIT_XOR_EXPR, operation_type,
kono
parents:
diff changeset
1644 operand, modulus);
kono
parents:
diff changeset
1645 else
kono
parents:
diff changeset
1646 result = fold_build2 (MINUS_EXPR, operation_type,
kono
parents:
diff changeset
1647 modulus, operand);
kono
parents:
diff changeset
1648
kono
parents:
diff changeset
1649 result = fold_build3 (COND_EXPR, operation_type,
kono
parents:
diff changeset
1650 fold_build2 (NE_EXPR,
kono
parents:
diff changeset
1651 boolean_type_node,
kono
parents:
diff changeset
1652 operand,
kono
parents:
diff changeset
1653 build_int_cst
kono
parents:
diff changeset
1654 (operation_type, 0)),
kono
parents:
diff changeset
1655 result, operand);
kono
parents:
diff changeset
1656 }
kono
parents:
diff changeset
1657 else
kono
parents:
diff changeset
1658 {
kono
parents:
diff changeset
1659 /* For the NOT cases, we need a constant equal to
kono
parents:
diff changeset
1660 the modulus minus one. For a binary modulus, we
kono
parents:
diff changeset
1661 XOR against the constant and subtract the operand from
kono
parents:
diff changeset
1662 that constant for nonbinary modulus. */
kono
parents:
diff changeset
1663
kono
parents:
diff changeset
1664 tree cnst = fold_build2 (MINUS_EXPR, operation_type, modulus,
kono
parents:
diff changeset
1665 build_int_cst (operation_type, 1));
kono
parents:
diff changeset
1666
kono
parents:
diff changeset
1667 if (mod_pow2)
kono
parents:
diff changeset
1668 result = fold_build2 (BIT_XOR_EXPR, operation_type,
kono
parents:
diff changeset
1669 operand, cnst);
kono
parents:
diff changeset
1670 else
kono
parents:
diff changeset
1671 result = fold_build2 (MINUS_EXPR, operation_type,
kono
parents:
diff changeset
1672 cnst, operand);
kono
parents:
diff changeset
1673 }
kono
parents:
diff changeset
1674
kono
parents:
diff changeset
1675 break;
kono
parents:
diff changeset
1676 }
kono
parents:
diff changeset
1677 }
kono
parents:
diff changeset
1678
kono
parents:
diff changeset
1679 /* ... fall through ... */
kono
parents:
diff changeset
1680
kono
parents:
diff changeset
1681 default:
kono
parents:
diff changeset
1682 gcc_assert (operation_type == base_type);
kono
parents:
diff changeset
1683 result = fold_build1 (op_code, operation_type,
kono
parents:
diff changeset
1684 convert (operation_type, operand));
kono
parents:
diff changeset
1685 }
kono
parents:
diff changeset
1686
kono
parents:
diff changeset
1687 if (result_type && TREE_TYPE (result) != result_type)
kono
parents:
diff changeset
1688 result = convert (result_type, result);
kono
parents:
diff changeset
1689
kono
parents:
diff changeset
1690 return result;
kono
parents:
diff changeset
1691 }
kono
parents:
diff changeset
1692
kono
parents:
diff changeset
1693 /* Similar, but for COND_EXPR. */
kono
parents:
diff changeset
1694
kono
parents:
diff changeset
1695 tree
kono
parents:
diff changeset
1696 build_cond_expr (tree result_type, tree condition_operand,
kono
parents:
diff changeset
1697 tree true_operand, tree false_operand)
kono
parents:
diff changeset
1698 {
kono
parents:
diff changeset
1699 bool addr_p = false;
kono
parents:
diff changeset
1700 tree result;
kono
parents:
diff changeset
1701
kono
parents:
diff changeset
1702 /* The front-end verified that result, true and false operands have
kono
parents:
diff changeset
1703 same base type. Convert everything to the result type. */
kono
parents:
diff changeset
1704 true_operand = convert (result_type, true_operand);
kono
parents:
diff changeset
1705 false_operand = convert (result_type, false_operand);
kono
parents:
diff changeset
1706
kono
parents:
diff changeset
1707 /* If the result type is unconstrained, take the address of the operands and
kono
parents:
diff changeset
1708 then dereference the result. Likewise if the result type is passed by
kono
parents:
diff changeset
1709 reference, because creating a temporary of this type is not allowed. */
kono
parents:
diff changeset
1710 if (TREE_CODE (result_type) == UNCONSTRAINED_ARRAY_TYPE
kono
parents:
diff changeset
1711 || TYPE_IS_BY_REFERENCE_P (result_type)
kono
parents:
diff changeset
1712 || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (result_type)))
kono
parents:
diff changeset
1713 {
kono
parents:
diff changeset
1714 result_type = build_pointer_type (result_type);
kono
parents:
diff changeset
1715 true_operand = build_unary_op (ADDR_EXPR, result_type, true_operand);
kono
parents:
diff changeset
1716 false_operand = build_unary_op (ADDR_EXPR, result_type, false_operand);
kono
parents:
diff changeset
1717 addr_p = true;
kono
parents:
diff changeset
1718 }
kono
parents:
diff changeset
1719
kono
parents:
diff changeset
1720 result = fold_build3 (COND_EXPR, result_type, condition_operand,
kono
parents:
diff changeset
1721 true_operand, false_operand);
kono
parents:
diff changeset
1722
kono
parents:
diff changeset
1723 /* If we have a common SAVE_EXPR (possibly surrounded by arithmetics)
kono
parents:
diff changeset
1724 in both arms, make sure it gets evaluated by moving it ahead of the
kono
parents:
diff changeset
1725 conditional expression. This is necessary because it is evaluated
kono
parents:
diff changeset
1726 in only one place at run time and would otherwise be uninitialized
kono
parents:
diff changeset
1727 in one of the arms. */
kono
parents:
diff changeset
1728 true_operand = skip_simple_arithmetic (true_operand);
kono
parents:
diff changeset
1729 false_operand = skip_simple_arithmetic (false_operand);
kono
parents:
diff changeset
1730
kono
parents:
diff changeset
1731 if (true_operand == false_operand && TREE_CODE (true_operand) == SAVE_EXPR)
kono
parents:
diff changeset
1732 result = build2 (COMPOUND_EXPR, result_type, true_operand, result);
kono
parents:
diff changeset
1733
kono
parents:
diff changeset
1734 if (addr_p)
kono
parents:
diff changeset
1735 result = build_unary_op (INDIRECT_REF, NULL_TREE, result);
kono
parents:
diff changeset
1736
kono
parents:
diff changeset
1737 return result;
kono
parents:
diff changeset
1738 }
kono
parents:
diff changeset
1739
kono
parents:
diff changeset
1740 /* Similar, but for COMPOUND_EXPR. */
kono
parents:
diff changeset
1741
kono
parents:
diff changeset
1742 tree
kono
parents:
diff changeset
1743 build_compound_expr (tree result_type, tree stmt_operand, tree expr_operand)
kono
parents:
diff changeset
1744 {
kono
parents:
diff changeset
1745 bool addr_p = false;
kono
parents:
diff changeset
1746 tree result;
kono
parents:
diff changeset
1747
kono
parents:
diff changeset
1748 /* If the result type is unconstrained, take the address of the operand and
kono
parents:
diff changeset
1749 then dereference the result. Likewise if the result type is passed by
kono
parents:
diff changeset
1750 reference, but this is natively handled in the gimplifier. */
kono
parents:
diff changeset
1751 if (TREE_CODE (result_type) == UNCONSTRAINED_ARRAY_TYPE
kono
parents:
diff changeset
1752 || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (result_type)))
kono
parents:
diff changeset
1753 {
kono
parents:
diff changeset
1754 result_type = build_pointer_type (result_type);
kono
parents:
diff changeset
1755 expr_operand = build_unary_op (ADDR_EXPR, result_type, expr_operand);
kono
parents:
diff changeset
1756 addr_p = true;
kono
parents:
diff changeset
1757 }
kono
parents:
diff changeset
1758
kono
parents:
diff changeset
1759 result = fold_build2 (COMPOUND_EXPR, result_type, stmt_operand,
kono
parents:
diff changeset
1760 expr_operand);
kono
parents:
diff changeset
1761
kono
parents:
diff changeset
1762 if (addr_p)
kono
parents:
diff changeset
1763 result = build_unary_op (INDIRECT_REF, NULL_TREE, result);
kono
parents:
diff changeset
1764
kono
parents:
diff changeset
1765 return result;
kono
parents:
diff changeset
1766 }
kono
parents:
diff changeset
1767
kono
parents:
diff changeset
1768 /* Conveniently construct a function call expression. FNDECL names the
kono
parents:
diff changeset
1769 function to be called, N is the number of arguments, and the "..."
kono
parents:
diff changeset
1770 parameters are the argument expressions. Unlike build_call_expr
kono
parents:
diff changeset
1771 this doesn't fold the call, hence it will always return a CALL_EXPR. */
kono
parents:
diff changeset
1772
kono
parents:
diff changeset
1773 tree
kono
parents:
diff changeset
1774 build_call_n_expr (tree fndecl, int n, ...)
kono
parents:
diff changeset
1775 {
kono
parents:
diff changeset
1776 va_list ap;
kono
parents:
diff changeset
1777 tree fntype = TREE_TYPE (fndecl);
kono
parents:
diff changeset
1778 tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
kono
parents:
diff changeset
1779
kono
parents:
diff changeset
1780 va_start (ap, n);
kono
parents:
diff changeset
1781 fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap);
kono
parents:
diff changeset
1782 va_end (ap);
kono
parents:
diff changeset
1783 return fn;
kono
parents:
diff changeset
1784 }
kono
parents:
diff changeset
1785
kono
parents:
diff changeset
1786 /* Build a goto to LABEL for a raise, with an optional call to Local_Raise.
kono
parents:
diff changeset
1787 MSG gives the exception's identity for the call to Local_Raise, if any. */
kono
parents:
diff changeset
1788
kono
parents:
diff changeset
1789 static tree
kono
parents:
diff changeset
1790 build_goto_raise (Entity_Id gnat_label, int msg)
kono
parents:
diff changeset
1791 {
kono
parents:
diff changeset
1792 tree gnu_label = gnat_to_gnu_entity (gnat_label, NULL_TREE, false);
kono
parents:
diff changeset
1793 tree gnu_result = build1 (GOTO_EXPR, void_type_node, gnu_label);
kono
parents:
diff changeset
1794 Entity_Id local_raise = Get_Local_Raise_Call_Entity ();
kono
parents:
diff changeset
1795
kono
parents:
diff changeset
1796 /* If Local_Raise is present, build Local_Raise (Exception'Identity). */
kono
parents:
diff changeset
1797 if (Present (local_raise))
kono
parents:
diff changeset
1798 {
kono
parents:
diff changeset
1799 tree gnu_local_raise
kono
parents:
diff changeset
1800 = gnat_to_gnu_entity (local_raise, NULL_TREE, false);
kono
parents:
diff changeset
1801 tree gnu_exception_entity
kono
parents:
diff changeset
1802 = gnat_to_gnu_entity (Get_RT_Exception_Entity (msg), NULL_TREE, false);
kono
parents:
diff changeset
1803 tree gnu_call
kono
parents:
diff changeset
1804 = build_call_n_expr (gnu_local_raise, 1,
kono
parents:
diff changeset
1805 build_unary_op (ADDR_EXPR, NULL_TREE,
kono
parents:
diff changeset
1806 gnu_exception_entity));
kono
parents:
diff changeset
1807 gnu_result
kono
parents:
diff changeset
1808 = build2 (COMPOUND_EXPR, void_type_node, gnu_call, gnu_result);
kono
parents:
diff changeset
1809 }
kono
parents:
diff changeset
1810
kono
parents:
diff changeset
1811 TREE_USED (gnu_label) = 1;
kono
parents:
diff changeset
1812 return gnu_result;
kono
parents:
diff changeset
1813 }
kono
parents:
diff changeset
1814
kono
parents:
diff changeset
1815 /* Expand the SLOC of GNAT_NODE, if present, into tree location information
kono
parents:
diff changeset
1816 pointed to by FILENAME, LINE and COL. Fall back to the current location
kono
parents:
diff changeset
1817 if GNAT_NODE is absent or has no SLOC. */
kono
parents:
diff changeset
1818
kono
parents:
diff changeset
1819 static void
kono
parents:
diff changeset
1820 expand_sloc (Node_Id gnat_node, tree *filename, tree *line, tree *col)
kono
parents:
diff changeset
1821 {
kono
parents:
diff changeset
1822 const char *str;
kono
parents:
diff changeset
1823 int line_number, column_number;
kono
parents:
diff changeset
1824
kono
parents:
diff changeset
1825 if (Debug_Flag_NN || Exception_Locations_Suppressed)
kono
parents:
diff changeset
1826 {
kono
parents:
diff changeset
1827 str = "";
kono
parents:
diff changeset
1828 line_number = 0;
kono
parents:
diff changeset
1829 column_number = 0;
kono
parents:
diff changeset
1830 }
kono
parents:
diff changeset
1831 else if (Present (gnat_node) && Sloc (gnat_node) != No_Location)
kono
parents:
diff changeset
1832 {
kono
parents:
diff changeset
1833 str = Get_Name_String
kono
parents:
diff changeset
1834 (Debug_Source_Name (Get_Source_File_Index (Sloc (gnat_node))));
kono
parents:
diff changeset
1835 line_number = Get_Logical_Line_Number (Sloc (gnat_node));
kono
parents:
diff changeset
1836 column_number = Get_Column_Number (Sloc (gnat_node));
kono
parents:
diff changeset
1837 }
kono
parents:
diff changeset
1838 else
kono
parents:
diff changeset
1839 {
kono
parents:
diff changeset
1840 str = lbasename (LOCATION_FILE (input_location));
kono
parents:
diff changeset
1841 line_number = LOCATION_LINE (input_location);
kono
parents:
diff changeset
1842 column_number = LOCATION_COLUMN (input_location);
kono
parents:
diff changeset
1843 }
kono
parents:
diff changeset
1844
kono
parents:
diff changeset
1845 const int len = strlen (str);
kono
parents:
diff changeset
1846 *filename = build_string (len, str);
kono
parents:
diff changeset
1847 TREE_TYPE (*filename) = build_array_type (char_type_node,
kono
parents:
diff changeset
1848 build_index_type (size_int (len)));
kono
parents:
diff changeset
1849 *line = build_int_cst (NULL_TREE, line_number);
kono
parents:
diff changeset
1850 if (col)
kono
parents:
diff changeset
1851 *col = build_int_cst (NULL_TREE, column_number);
kono
parents:
diff changeset
1852 }
kono
parents:
diff changeset
1853
kono
parents:
diff changeset
1854 /* Build a call to a function that raises an exception and passes file name
kono
parents:
diff changeset
1855 and line number, if requested. MSG says which exception function to call.
kono
parents:
diff changeset
1856 GNAT_NODE is the node conveying the source location for which the error
kono
parents:
diff changeset
1857 should be signaled, or Empty in which case the error is signaled for the
kono
parents:
diff changeset
1858 current location. KIND says which kind of exception node this is for,
kono
parents:
diff changeset
1859 among N_Raise_{Constraint,Storage,Program}_Error. */
kono
parents:
diff changeset
1860
kono
parents:
diff changeset
1861 tree
kono
parents:
diff changeset
1862 build_call_raise (int msg, Node_Id gnat_node, char kind)
kono
parents:
diff changeset
1863 {
kono
parents:
diff changeset
1864 Entity_Id gnat_label = get_exception_label (kind);
kono
parents:
diff changeset
1865 tree fndecl = gnat_raise_decls[msg];
kono
parents:
diff changeset
1866 tree filename, line;
kono
parents:
diff changeset
1867
kono
parents:
diff changeset
1868 /* If this is to be done as a goto, handle that case. */
kono
parents:
diff changeset
1869 if (Present (gnat_label))
kono
parents:
diff changeset
1870 return build_goto_raise (gnat_label, msg);
kono
parents:
diff changeset
1871
kono
parents:
diff changeset
1872 expand_sloc (gnat_node, &filename, &line, NULL);
kono
parents:
diff changeset
1873
kono
parents:
diff changeset
1874 return
kono
parents:
diff changeset
1875 build_call_n_expr (fndecl, 2,
kono
parents:
diff changeset
1876 build1 (ADDR_EXPR,
kono
parents:
diff changeset
1877 build_pointer_type (char_type_node),
kono
parents:
diff changeset
1878 filename),
kono
parents:
diff changeset
1879 line);
kono
parents:
diff changeset
1880 }
kono
parents:
diff changeset
1881
kono
parents:
diff changeset
1882 /* Similar to build_call_raise, with extra information about the column
kono
parents:
diff changeset
1883 where the check failed. */
kono
parents:
diff changeset
1884
kono
parents:
diff changeset
1885 tree
kono
parents:
diff changeset
1886 build_call_raise_column (int msg, Node_Id gnat_node, char kind)
kono
parents:
diff changeset
1887 {
kono
parents:
diff changeset
1888 Entity_Id gnat_label = get_exception_label (kind);
kono
parents:
diff changeset
1889 tree fndecl = gnat_raise_decls_ext[msg];
kono
parents:
diff changeset
1890 tree filename, line, col;
kono
parents:
diff changeset
1891
kono
parents:
diff changeset
1892 /* If this is to be done as a goto, handle that case. */
kono
parents:
diff changeset
1893 if (Present (gnat_label))
kono
parents:
diff changeset
1894 return build_goto_raise (gnat_label, msg);
kono
parents:
diff changeset
1895
kono
parents:
diff changeset
1896 expand_sloc (gnat_node, &filename, &line, &col);
kono
parents:
diff changeset
1897
kono
parents:
diff changeset
1898 return
kono
parents:
diff changeset
1899 build_call_n_expr (fndecl, 3,
kono
parents:
diff changeset
1900 build1 (ADDR_EXPR,
kono
parents:
diff changeset
1901 build_pointer_type (char_type_node),
kono
parents:
diff changeset
1902 filename),
kono
parents:
diff changeset
1903 line, col);
kono
parents:
diff changeset
1904 }
kono
parents:
diff changeset
1905
kono
parents:
diff changeset
1906 /* Similar to build_call_raise_column, for an index or range check exception ,
kono
parents:
diff changeset
1907 with extra information of the form "INDEX out of range FIRST..LAST". */
kono
parents:
diff changeset
1908
kono
parents:
diff changeset
1909 tree
kono
parents:
diff changeset
1910 build_call_raise_range (int msg, Node_Id gnat_node, char kind,
kono
parents:
diff changeset
1911 tree index, tree first, tree last)
kono
parents:
diff changeset
1912 {
kono
parents:
diff changeset
1913 Entity_Id gnat_label = get_exception_label (kind);
kono
parents:
diff changeset
1914 tree fndecl = gnat_raise_decls_ext[msg];
kono
parents:
diff changeset
1915 tree filename, line, col;
kono
parents:
diff changeset
1916
kono
parents:
diff changeset
1917 /* If this is to be done as a goto, handle that case. */
kono
parents:
diff changeset
1918 if (Present (gnat_label))
kono
parents:
diff changeset
1919 return build_goto_raise (gnat_label, msg);
kono
parents:
diff changeset
1920
kono
parents:
diff changeset
1921 expand_sloc (gnat_node, &filename, &line, &col);
kono
parents:
diff changeset
1922
kono
parents:
diff changeset
1923 return
kono
parents:
diff changeset
1924 build_call_n_expr (fndecl, 6,
kono
parents:
diff changeset
1925 build1 (ADDR_EXPR,
kono
parents:
diff changeset
1926 build_pointer_type (char_type_node),
kono
parents:
diff changeset
1927 filename),
kono
parents:
diff changeset
1928 line, col,
kono
parents:
diff changeset
1929 convert (integer_type_node, index),
kono
parents:
diff changeset
1930 convert (integer_type_node, first),
kono
parents:
diff changeset
1931 convert (integer_type_node, last));
kono
parents:
diff changeset
1932 }
kono
parents:
diff changeset
1933
kono
parents:
diff changeset
1934 /* qsort comparer for the bit positions of two constructor elements
kono
parents:
diff changeset
1935 for record components. */
kono
parents:
diff changeset
1936
kono
parents:
diff changeset
1937 static int
kono
parents:
diff changeset
1938 compare_elmt_bitpos (const PTR rt1, const PTR rt2)
kono
parents:
diff changeset
1939 {
kono
parents:
diff changeset
1940 const constructor_elt * const elmt1 = (const constructor_elt *) rt1;
kono
parents:
diff changeset
1941 const constructor_elt * const elmt2 = (const constructor_elt *) rt2;
kono
parents:
diff changeset
1942 const_tree const field1 = elmt1->index;
kono
parents:
diff changeset
1943 const_tree const field2 = elmt2->index;
kono
parents:
diff changeset
1944 const int ret
kono
parents:
diff changeset
1945 = tree_int_cst_compare (bit_position (field1), bit_position (field2));
kono
parents:
diff changeset
1946
kono
parents:
diff changeset
1947 return ret ? ret : (int) (DECL_UID (field1) - DECL_UID (field2));
kono
parents:
diff changeset
1948 }
kono
parents:
diff changeset
1949
kono
parents:
diff changeset
1950 /* Return a CONSTRUCTOR of TYPE whose elements are V. */
kono
parents:
diff changeset
1951
kono
parents:
diff changeset
1952 tree
kono
parents:
diff changeset
1953 gnat_build_constructor (tree type, vec<constructor_elt, va_gc> *v)
kono
parents:
diff changeset
1954 {
kono
parents:
diff changeset
1955 bool allconstant = (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST);
kono
parents:
diff changeset
1956 bool read_only = true;
kono
parents:
diff changeset
1957 bool side_effects = false;
kono
parents:
diff changeset
1958 tree result, obj, val;
kono
parents:
diff changeset
1959 unsigned int n_elmts;
kono
parents:
diff changeset
1960
kono
parents:
diff changeset
1961 /* Scan the elements to see if they are all constant or if any has side
kono
parents:
diff changeset
1962 effects, to let us set global flags on the resulting constructor. Count
kono
parents:
diff changeset
1963 the elements along the way for possible sorting purposes below. */
kono
parents:
diff changeset
1964 FOR_EACH_CONSTRUCTOR_ELT (v, n_elmts, obj, val)
kono
parents:
diff changeset
1965 {
kono
parents:
diff changeset
1966 /* The predicate must be in keeping with output_constructor. */
kono
parents:
diff changeset
1967 if ((!TREE_CONSTANT (val) && !TREE_STATIC (val))
kono
parents:
diff changeset
1968 || (TREE_CODE (type) == RECORD_TYPE
kono
parents:
diff changeset
1969 && CONSTRUCTOR_BITFIELD_P (obj)
kono
parents:
diff changeset
1970 && !initializer_constant_valid_for_bitfield_p (val))
kono
parents:
diff changeset
1971 || !initializer_constant_valid_p (val,
kono
parents:
diff changeset
1972 TREE_TYPE (val),
kono
parents:
diff changeset
1973 TYPE_REVERSE_STORAGE_ORDER (type)))
kono
parents:
diff changeset
1974 allconstant = false;
kono
parents:
diff changeset
1975
kono
parents:
diff changeset
1976 if (!TREE_READONLY (val))
kono
parents:
diff changeset
1977 read_only = false;
kono
parents:
diff changeset
1978
kono
parents:
diff changeset
1979 if (TREE_SIDE_EFFECTS (val))
kono
parents:
diff changeset
1980 side_effects = true;
kono
parents:
diff changeset
1981 }
kono
parents:
diff changeset
1982
kono
parents:
diff changeset
1983 /* For record types with constant components only, sort field list
kono
parents:
diff changeset
1984 by increasing bit position. This is necessary to ensure the
kono
parents:
diff changeset
1985 constructor can be output as static data. */
kono
parents:
diff changeset
1986 if (allconstant && TREE_CODE (type) == RECORD_TYPE && n_elmts > 1)
kono
parents:
diff changeset
1987 v->qsort (compare_elmt_bitpos);
kono
parents:
diff changeset
1988
kono
parents:
diff changeset
1989 result = build_constructor (type, v);
kono
parents:
diff changeset
1990 CONSTRUCTOR_NO_CLEARING (result) = 1;
kono
parents:
diff changeset
1991 TREE_CONSTANT (result) = TREE_STATIC (result) = allconstant;
kono
parents:
diff changeset
1992 TREE_SIDE_EFFECTS (result) = side_effects;
kono
parents:
diff changeset
1993 TREE_READONLY (result) = TYPE_READONLY (type) || read_only || allconstant;
kono
parents:
diff changeset
1994 return result;
kono
parents:
diff changeset
1995 }
kono
parents:
diff changeset
1996
kono
parents:
diff changeset
1997 /* Return a COMPONENT_REF to access FIELD in RECORD, or NULL_TREE if the field
kono
parents:
diff changeset
1998 is not found in the record. Don't fold the result if NO_FOLD is true. */
kono
parents:
diff changeset
1999
kono
parents:
diff changeset
2000 static tree
kono
parents:
diff changeset
2001 build_simple_component_ref (tree record, tree field, bool no_fold)
kono
parents:
diff changeset
2002 {
kono
parents:
diff changeset
2003 tree type = TYPE_MAIN_VARIANT (TREE_TYPE (record));
kono
parents:
diff changeset
2004 tree ref;
kono
parents:
diff changeset
2005
kono
parents:
diff changeset
2006 gcc_assert (RECORD_OR_UNION_TYPE_P (type) && COMPLETE_TYPE_P (type));
kono
parents:
diff changeset
2007
kono
parents:
diff changeset
2008 /* Try to fold a conversion from another record or union type unless the type
kono
parents:
diff changeset
2009 contains a placeholder as it might be needed for a later substitution. */
kono
parents:
diff changeset
2010 if (TREE_CODE (record) == VIEW_CONVERT_EXPR
kono
parents:
diff changeset
2011 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (record, 0)))
kono
parents:
diff changeset
2012 && !type_contains_placeholder_p (type))
kono
parents:
diff changeset
2013 {
kono
parents:
diff changeset
2014 tree op = TREE_OPERAND (record, 0);
kono
parents:
diff changeset
2015
kono
parents:
diff changeset
2016 /* If this is an unpadding operation, convert the underlying object to
kono
parents:
diff changeset
2017 the unpadded type directly. */
kono
parents:
diff changeset
2018 if (TYPE_IS_PADDING_P (type) && field == TYPE_FIELDS (type))
kono
parents:
diff changeset
2019 return convert (TREE_TYPE (field), op);
kono
parents:
diff changeset
2020
kono
parents:
diff changeset
2021 /* Otherwise try to access FIELD directly in the underlying type, but
kono
parents:
diff changeset
2022 make sure that the form of the reference doesn't change too much;
kono
parents:
diff changeset
2023 this can happen for an unconstrained bit-packed array type whose
kono
parents:
diff changeset
2024 constrained form can be an integer type. */
kono
parents:
diff changeset
2025 ref = build_simple_component_ref (op, field, no_fold);
kono
parents:
diff changeset
2026 if (ref && TREE_CODE (TREE_TYPE (ref)) == TREE_CODE (TREE_TYPE (field)))
kono
parents:
diff changeset
2027 return ref;
kono
parents:
diff changeset
2028 }
kono
parents:
diff changeset
2029
kono
parents:
diff changeset
2030 /* If this field is not in the specified record, see if we can find a field
kono
parents:
diff changeset
2031 in the specified record whose original field is the same as this one. */
kono
parents:
diff changeset
2032 if (DECL_CONTEXT (field) != type)
kono
parents:
diff changeset
2033 {
kono
parents:
diff changeset
2034 tree new_field;
kono
parents:
diff changeset
2035
kono
parents:
diff changeset
2036 /* First loop through normal components. */
kono
parents:
diff changeset
2037 for (new_field = TYPE_FIELDS (type);
kono
parents:
diff changeset
2038 new_field;
kono
parents:
diff changeset
2039 new_field = DECL_CHAIN (new_field))
kono
parents:
diff changeset
2040 if (SAME_FIELD_P (field, new_field))
kono
parents:
diff changeset
2041 break;
kono
parents:
diff changeset
2042
kono
parents:
diff changeset
2043 /* Next, loop through DECL_INTERNAL_P components if we haven't found the
kono
parents:
diff changeset
2044 component in the first search. Doing this search in two steps is
kono
parents:
diff changeset
2045 required to avoid hidden homonymous fields in the _Parent field. */
kono
parents:
diff changeset
2046 if (!new_field)
kono
parents:
diff changeset
2047 for (new_field = TYPE_FIELDS (type);
kono
parents:
diff changeset
2048 new_field;
kono
parents:
diff changeset
2049 new_field = DECL_CHAIN (new_field))
kono
parents:
diff changeset
2050 if (DECL_INTERNAL_P (new_field)
kono
parents:
diff changeset
2051 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (new_field)))
kono
parents:
diff changeset
2052 {
kono
parents:
diff changeset
2053 tree field_ref
kono
parents:
diff changeset
2054 = build_simple_component_ref (record, new_field, no_fold);
kono
parents:
diff changeset
2055 ref = build_simple_component_ref (field_ref, field, no_fold);
kono
parents:
diff changeset
2056 if (ref)
kono
parents:
diff changeset
2057 return ref;
kono
parents:
diff changeset
2058 }
kono
parents:
diff changeset
2059
kono
parents:
diff changeset
2060 field = new_field;
kono
parents:
diff changeset
2061 }
kono
parents:
diff changeset
2062
kono
parents:
diff changeset
2063 if (!field)
kono
parents:
diff changeset
2064 return NULL_TREE;
kono
parents:
diff changeset
2065
kono
parents:
diff changeset
2066 /* If the field's offset has overflowed, do not try to access it, as doing
kono
parents:
diff changeset
2067 so may trigger sanity checks deeper in the back-end. Note that we don't
kono
parents:
diff changeset
2068 need to warn since this will be done on trying to declare the object. */
kono
parents:
diff changeset
2069 if (TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST
kono
parents:
diff changeset
2070 && TREE_OVERFLOW (DECL_FIELD_OFFSET (field)))
kono
parents:
diff changeset
2071 return NULL_TREE;
kono
parents:
diff changeset
2072
kono
parents:
diff changeset
2073 ref = build3 (COMPONENT_REF, TREE_TYPE (field), record, field, NULL_TREE);
kono
parents:
diff changeset
2074
kono
parents:
diff changeset
2075 if (TREE_READONLY (record)
kono
parents:
diff changeset
2076 || TREE_READONLY (field)
kono
parents:
diff changeset
2077 || TYPE_READONLY (type))
kono
parents:
diff changeset
2078 TREE_READONLY (ref) = 1;
kono
parents:
diff changeset
2079
kono
parents:
diff changeset
2080 if (TREE_THIS_VOLATILE (record)
kono
parents:
diff changeset
2081 || TREE_THIS_VOLATILE (field)
kono
parents:
diff changeset
2082 || TYPE_VOLATILE (type))
kono
parents:
diff changeset
2083 TREE_THIS_VOLATILE (ref) = 1;
kono
parents:
diff changeset
2084
kono
parents:
diff changeset
2085 if (no_fold)
kono
parents:
diff changeset
2086 return ref;
kono
parents:
diff changeset
2087
kono
parents:
diff changeset
2088 /* The generic folder may punt in this case because the inner array type
kono
parents:
diff changeset
2089 can be self-referential, but folding is in fact not problematic. */
kono
parents:
diff changeset
2090 if (TREE_CODE (record) == CONSTRUCTOR
kono
parents:
diff changeset
2091 && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (record)))
kono
parents:
diff changeset
2092 {
kono
parents:
diff changeset
2093 vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (record);
kono
parents:
diff changeset
2094 unsigned HOST_WIDE_INT idx;
kono
parents:
diff changeset
2095 tree index, value;
kono
parents:
diff changeset
2096 FOR_EACH_CONSTRUCTOR_ELT (elts, idx, index, value)
kono
parents:
diff changeset
2097 if (index == field)
kono
parents:
diff changeset
2098 return value;
kono
parents:
diff changeset
2099 return ref;
kono
parents:
diff changeset
2100 }
kono
parents:
diff changeset
2101
kono
parents:
diff changeset
2102 return fold (ref);
kono
parents:
diff changeset
2103 }
kono
parents:
diff changeset
2104
kono
parents:
diff changeset
2105 /* Likewise, but return NULL_EXPR and generate a Constraint_Error if the
kono
parents:
diff changeset
2106 field is not found in the record. */
kono
parents:
diff changeset
2107
kono
parents:
diff changeset
2108 tree
kono
parents:
diff changeset
2109 build_component_ref (tree record, tree field, bool no_fold)
kono
parents:
diff changeset
2110 {
kono
parents:
diff changeset
2111 tree ref = build_simple_component_ref (record, field, no_fold);
kono
parents:
diff changeset
2112 if (ref)
kono
parents:
diff changeset
2113 return ref;
kono
parents:
diff changeset
2114
kono
parents:
diff changeset
2115 /* Assume this is an invalid user field so raise Constraint_Error. */
kono
parents:
diff changeset
2116 return build1 (NULL_EXPR, TREE_TYPE (field),
kono
parents:
diff changeset
2117 build_call_raise (CE_Discriminant_Check_Failed, Empty,
kono
parents:
diff changeset
2118 N_Raise_Constraint_Error));
kono
parents:
diff changeset
2119 }
kono
parents:
diff changeset
2120
kono
parents:
diff changeset
2121 /* Helper for build_call_alloc_dealloc, with arguments to be interpreted
kono
parents:
diff changeset
2122 identically. Process the case where a GNAT_PROC to call is provided. */
kono
parents:
diff changeset
2123
kono
parents:
diff changeset
2124 static inline tree
kono
parents:
diff changeset
2125 build_call_alloc_dealloc_proc (tree gnu_obj, tree gnu_size, tree gnu_type,
kono
parents:
diff changeset
2126 Entity_Id gnat_proc, Entity_Id gnat_pool)
kono
parents:
diff changeset
2127 {
kono
parents:
diff changeset
2128 tree gnu_proc = gnat_to_gnu (gnat_proc);
kono
parents:
diff changeset
2129 tree gnu_call;
kono
parents:
diff changeset
2130
kono
parents:
diff changeset
2131 /* A storage pool's underlying type is a record type (for both predefined
kono
parents:
diff changeset
2132 storage pools and GNAT simple storage pools). The secondary stack uses
kono
parents:
diff changeset
2133 the same mechanism, but its pool object (SS_Pool) is an integer. */
kono
parents:
diff changeset
2134 if (Is_Record_Type (Underlying_Type (Etype (gnat_pool))))
kono
parents:
diff changeset
2135 {
kono
parents:
diff changeset
2136 /* The size is the third parameter; the alignment is the
kono
parents:
diff changeset
2137 same type. */
kono
parents:
diff changeset
2138 Entity_Id gnat_size_type
kono
parents:
diff changeset
2139 = Etype (Next_Formal (Next_Formal (First_Formal (gnat_proc))));
kono
parents:
diff changeset
2140 tree gnu_size_type = gnat_to_gnu_type (gnat_size_type);
kono
parents:
diff changeset
2141
kono
parents:
diff changeset
2142 tree gnu_pool = gnat_to_gnu (gnat_pool);
kono
parents:
diff changeset
2143 tree gnu_pool_addr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_pool);
kono
parents:
diff changeset
2144 tree gnu_align = size_int (TYPE_ALIGN (gnu_type) / BITS_PER_UNIT);
kono
parents:
diff changeset
2145
kono
parents:
diff changeset
2146 gnu_size = convert (gnu_size_type, gnu_size);
kono
parents:
diff changeset
2147 gnu_align = convert (gnu_size_type, gnu_align);
kono
parents:
diff changeset
2148
kono
parents:
diff changeset
2149 /* The first arg is always the address of the storage pool; next
kono
parents:
diff changeset
2150 comes the address of the object, for a deallocator, then the
kono
parents:
diff changeset
2151 size and alignment. */
kono
parents:
diff changeset
2152 if (gnu_obj)
kono
parents:
diff changeset
2153 gnu_call = build_call_n_expr (gnu_proc, 4, gnu_pool_addr, gnu_obj,
kono
parents:
diff changeset
2154 gnu_size, gnu_align);
kono
parents:
diff changeset
2155 else
kono
parents:
diff changeset
2156 gnu_call = build_call_n_expr (gnu_proc, 3, gnu_pool_addr,
kono
parents:
diff changeset
2157 gnu_size, gnu_align);
kono
parents:
diff changeset
2158 }
kono
parents:
diff changeset
2159
kono
parents:
diff changeset
2160 /* Secondary stack case. */
kono
parents:
diff changeset
2161 else
kono
parents:
diff changeset
2162 {
kono
parents:
diff changeset
2163 /* The size is the second parameter. */
kono
parents:
diff changeset
2164 Entity_Id gnat_size_type
kono
parents:
diff changeset
2165 = Etype (Next_Formal (First_Formal (gnat_proc)));
kono
parents:
diff changeset
2166 tree gnu_size_type = gnat_to_gnu_type (gnat_size_type);
kono
parents:
diff changeset
2167
kono
parents:
diff changeset
2168 gnu_size = convert (gnu_size_type, gnu_size);
kono
parents:
diff changeset
2169
kono
parents:
diff changeset
2170 /* The first arg is the address of the object, for a deallocator,
kono
parents:
diff changeset
2171 then the size. */
kono
parents:
diff changeset
2172 if (gnu_obj)
kono
parents:
diff changeset
2173 gnu_call = build_call_n_expr (gnu_proc, 2, gnu_obj, gnu_size);
kono
parents:
diff changeset
2174 else
kono
parents:
diff changeset
2175 gnu_call = build_call_n_expr (gnu_proc, 1, gnu_size);
kono
parents:
diff changeset
2176 }
kono
parents:
diff changeset
2177
kono
parents:
diff changeset
2178 return gnu_call;
kono
parents:
diff changeset
2179 }
kono
parents:
diff changeset
2180
kono
parents:
diff changeset
2181 /* Helper for build_call_alloc_dealloc, to build and return an allocator for
kono
parents:
diff changeset
2182 DATA_SIZE bytes aimed at containing a DATA_TYPE object, using the default
kono
parents:
diff changeset
2183 __gnat_malloc allocator. Honor DATA_TYPE alignments greater than what the
kono
parents:
diff changeset
2184 latter offers. */
kono
parents:
diff changeset
2185
kono
parents:
diff changeset
2186 static inline tree
kono
parents:
diff changeset
2187 maybe_wrap_malloc (tree data_size, tree data_type, Node_Id gnat_node)
kono
parents:
diff changeset
2188 {
kono
parents:
diff changeset
2189 /* When the DATA_TYPE alignment is stricter than what malloc offers
kono
parents:
diff changeset
2190 (super-aligned case), we allocate an "aligning" wrapper type and return
kono
parents:
diff changeset
2191 the address of its single data field with the malloc's return value
kono
parents:
diff changeset
2192 stored just in front. */
kono
parents:
diff changeset
2193
kono
parents:
diff changeset
2194 unsigned int data_align = TYPE_ALIGN (data_type);
kono
parents:
diff changeset
2195 unsigned int system_allocator_alignment
kono
parents:
diff changeset
2196 = get_target_system_allocator_alignment () * BITS_PER_UNIT;
kono
parents:
diff changeset
2197
kono
parents:
diff changeset
2198 tree aligning_type
kono
parents:
diff changeset
2199 = ((data_align > system_allocator_alignment)
kono
parents:
diff changeset
2200 ? make_aligning_type (data_type, data_align, data_size,
kono
parents:
diff changeset
2201 system_allocator_alignment,
kono
parents:
diff changeset
2202 POINTER_SIZE / BITS_PER_UNIT,
kono
parents:
diff changeset
2203 gnat_node)
kono
parents:
diff changeset
2204 : NULL_TREE);
kono
parents:
diff changeset
2205
kono
parents:
diff changeset
2206 tree size_to_malloc
kono
parents:
diff changeset
2207 = aligning_type ? TYPE_SIZE_UNIT (aligning_type) : data_size;
kono
parents:
diff changeset
2208
kono
parents:
diff changeset
2209 tree malloc_ptr = build_call_n_expr (malloc_decl, 1, size_to_malloc);
kono
parents:
diff changeset
2210
kono
parents:
diff changeset
2211 if (aligning_type)
kono
parents:
diff changeset
2212 {
kono
parents:
diff changeset
2213 /* Latch malloc's return value and get a pointer to the aligning field
kono
parents:
diff changeset
2214 first. */
kono
parents:
diff changeset
2215 tree storage_ptr = gnat_protect_expr (malloc_ptr);
kono
parents:
diff changeset
2216
kono
parents:
diff changeset
2217 tree aligning_record_addr
kono
parents:
diff changeset
2218 = convert (build_pointer_type (aligning_type), storage_ptr);
kono
parents:
diff changeset
2219
kono
parents:
diff changeset
2220 tree aligning_record
kono
parents:
diff changeset
2221 = build_unary_op (INDIRECT_REF, NULL_TREE, aligning_record_addr);
kono
parents:
diff changeset
2222
kono
parents:
diff changeset
2223 tree aligning_field
kono
parents:
diff changeset
2224 = build_component_ref (aligning_record, TYPE_FIELDS (aligning_type),
kono
parents:
diff changeset
2225 false);
kono
parents:
diff changeset
2226
kono
parents:
diff changeset
2227 tree aligning_field_addr
kono
parents:
diff changeset
2228 = build_unary_op (ADDR_EXPR, NULL_TREE, aligning_field);
kono
parents:
diff changeset
2229
kono
parents:
diff changeset
2230 /* Then arrange to store the allocator's return value ahead
kono
parents:
diff changeset
2231 and return. */
kono
parents:
diff changeset
2232 tree storage_ptr_slot_addr
kono
parents:
diff changeset
2233 = build_binary_op (POINTER_PLUS_EXPR, ptr_type_node,
kono
parents:
diff changeset
2234 convert (ptr_type_node, aligning_field_addr),
kono
parents:
diff changeset
2235 size_int (-(HOST_WIDE_INT) POINTER_SIZE
kono
parents:
diff changeset
2236 / BITS_PER_UNIT));
kono
parents:
diff changeset
2237
kono
parents:
diff changeset
2238 tree storage_ptr_slot
kono
parents:
diff changeset
2239 = build_unary_op (INDIRECT_REF, NULL_TREE,
kono
parents:
diff changeset
2240 convert (build_pointer_type (ptr_type_node),
kono
parents:
diff changeset
2241 storage_ptr_slot_addr));
kono
parents:
diff changeset
2242
kono
parents:
diff changeset
2243 return
kono
parents:
diff changeset
2244 build2 (COMPOUND_EXPR, TREE_TYPE (aligning_field_addr),
kono
parents:
diff changeset
2245 build_binary_op (INIT_EXPR, NULL_TREE,
kono
parents:
diff changeset
2246 storage_ptr_slot, storage_ptr),
kono
parents:
diff changeset
2247 aligning_field_addr);
kono
parents:
diff changeset
2248 }
kono
parents:
diff changeset
2249 else
kono
parents:
diff changeset
2250 return malloc_ptr;
kono
parents:
diff changeset
2251 }
kono
parents:
diff changeset
2252
kono
parents:
diff changeset
2253 /* Helper for build_call_alloc_dealloc, to release a DATA_TYPE object
kono
parents:
diff changeset
2254 designated by DATA_PTR using the __gnat_free entry point. */
kono
parents:
diff changeset
2255
kono
parents:
diff changeset
2256 static inline tree
kono
parents:
diff changeset
2257 maybe_wrap_free (tree data_ptr, tree data_type)
kono
parents:
diff changeset
2258 {
kono
parents:
diff changeset
2259 /* In the regular alignment case, we pass the data pointer straight to free.
kono
parents:
diff changeset
2260 In the superaligned case, we need to retrieve the initial allocator
kono
parents:
diff changeset
2261 return value, stored in front of the data block at allocation time. */
kono
parents:
diff changeset
2262
kono
parents:
diff changeset
2263 unsigned int data_align = TYPE_ALIGN (data_type);
kono
parents:
diff changeset
2264 unsigned int system_allocator_alignment
kono
parents:
diff changeset
2265 = get_target_system_allocator_alignment () * BITS_PER_UNIT;
kono
parents:
diff changeset
2266
kono
parents:
diff changeset
2267 tree free_ptr;
kono
parents:
diff changeset
2268
kono
parents:
diff changeset
2269 if (data_align > system_allocator_alignment)
kono
parents:
diff changeset
2270 {
kono
parents:
diff changeset
2271 /* DATA_FRONT_PTR (void *)
kono
parents:
diff changeset
2272 = (void *)DATA_PTR - (void *)sizeof (void *)) */
kono
parents:
diff changeset
2273 tree data_front_ptr
kono
parents:
diff changeset
2274 = build_binary_op
kono
parents:
diff changeset
2275 (POINTER_PLUS_EXPR, ptr_type_node,
kono
parents:
diff changeset
2276 convert (ptr_type_node, data_ptr),
kono
parents:
diff changeset
2277 size_int (-(HOST_WIDE_INT) POINTER_SIZE / BITS_PER_UNIT));
kono
parents:
diff changeset
2278
kono
parents:
diff changeset
2279 /* FREE_PTR (void *) = *(void **)DATA_FRONT_PTR */
kono
parents:
diff changeset
2280 free_ptr
kono
parents:
diff changeset
2281 = build_unary_op
kono
parents:
diff changeset
2282 (INDIRECT_REF, NULL_TREE,
kono
parents:
diff changeset
2283 convert (build_pointer_type (ptr_type_node), data_front_ptr));
kono
parents:
diff changeset
2284 }
kono
parents:
diff changeset
2285 else
kono
parents:
diff changeset
2286 free_ptr = data_ptr;
kono
parents:
diff changeset
2287
kono
parents:
diff changeset
2288 return build_call_n_expr (free_decl, 1, free_ptr);
kono
parents:
diff changeset
2289 }
kono
parents:
diff changeset
2290
kono
parents:
diff changeset
2291 /* Build a GCC tree to call an allocation or deallocation function.
kono
parents:
diff changeset
2292 If GNU_OBJ is nonzero, it is an object to deallocate. Otherwise,
kono
parents:
diff changeset
2293 generate an allocator.
kono
parents:
diff changeset
2294
kono
parents:
diff changeset
2295 GNU_SIZE is the number of bytes to allocate and GNU_TYPE is the contained
kono
parents:
diff changeset
2296 object type, used to determine the to-be-honored address alignment.
kono
parents:
diff changeset
2297 GNAT_PROC, if present, is a procedure to call and GNAT_POOL is the storage
kono
parents:
diff changeset
2298 pool to use. If not present, malloc and free are used. GNAT_NODE is used
kono
parents:
diff changeset
2299 to provide an error location for restriction violation messages. */
kono
parents:
diff changeset
2300
kono
parents:
diff changeset
2301 tree
kono
parents:
diff changeset
2302 build_call_alloc_dealloc (tree gnu_obj, tree gnu_size, tree gnu_type,
kono
parents:
diff changeset
2303 Entity_Id gnat_proc, Entity_Id gnat_pool,
kono
parents:
diff changeset
2304 Node_Id gnat_node)
kono
parents:
diff changeset
2305 {
kono
parents:
diff changeset
2306 /* Explicit proc to call ? This one is assumed to deal with the type
kono
parents:
diff changeset
2307 alignment constraints. */
kono
parents:
diff changeset
2308 if (Present (gnat_proc))
kono
parents:
diff changeset
2309 return build_call_alloc_dealloc_proc (gnu_obj, gnu_size, gnu_type,
kono
parents:
diff changeset
2310 gnat_proc, gnat_pool);
kono
parents:
diff changeset
2311
kono
parents:
diff changeset
2312 /* Otherwise, object to "free" or "malloc" with possible special processing
kono
parents:
diff changeset
2313 for alignments stricter than what the default allocator honors. */
kono
parents:
diff changeset
2314 else if (gnu_obj)
kono
parents:
diff changeset
2315 return maybe_wrap_free (gnu_obj, gnu_type);
kono
parents:
diff changeset
2316 else
kono
parents:
diff changeset
2317 {
kono
parents:
diff changeset
2318 /* Assert that we no longer can be called with this special pool. */
kono
parents:
diff changeset
2319 gcc_assert (gnat_pool != -1);
kono
parents:
diff changeset
2320
kono
parents:
diff changeset
2321 /* Check that we aren't violating the associated restriction. */
kono
parents:
diff changeset
2322 if (!(Nkind (gnat_node) == N_Allocator && Comes_From_Source (gnat_node)))
kono
parents:
diff changeset
2323 {
kono
parents:
diff changeset
2324 Check_No_Implicit_Heap_Alloc (gnat_node);
kono
parents:
diff changeset
2325 if (Has_Task (Etype (gnat_node)))
kono
parents:
diff changeset
2326 Check_No_Implicit_Task_Alloc (gnat_node);
kono
parents:
diff changeset
2327 if (Has_Protected (Etype (gnat_node)))
kono
parents:
diff changeset
2328 Check_No_Implicit_Protected_Alloc (gnat_node);
kono
parents:
diff changeset
2329 }
kono
parents:
diff changeset
2330 return maybe_wrap_malloc (gnu_size, gnu_type, gnat_node);
kono
parents:
diff changeset
2331 }
kono
parents:
diff changeset
2332 }
kono
parents:
diff changeset
2333
kono
parents:
diff changeset
2334 /* Build a GCC tree that corresponds to allocating an object of TYPE whose
kono
parents:
diff changeset
2335 initial value is INIT, if INIT is nonzero. Convert the expression to
kono
parents:
diff changeset
2336 RESULT_TYPE, which must be some pointer type, and return the result.
kono
parents:
diff changeset
2337
kono
parents:
diff changeset
2338 GNAT_PROC and GNAT_POOL optionally give the procedure to call and
kono
parents:
diff changeset
2339 the storage pool to use. GNAT_NODE is used to provide an error
kono
parents:
diff changeset
2340 location for restriction violation messages. If IGNORE_INIT_TYPE is
kono
parents:
diff changeset
2341 true, ignore the type of INIT for the purpose of determining the size;
kono
parents:
diff changeset
2342 this will cause the maximum size to be allocated if TYPE is of
kono
parents:
diff changeset
2343 self-referential size. */
kono
parents:
diff changeset
2344
kono
parents:
diff changeset
2345 tree
kono
parents:
diff changeset
2346 build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
kono
parents:
diff changeset
2347 Entity_Id gnat_pool, Node_Id gnat_node, bool ignore_init_type)
kono
parents:
diff changeset
2348 {
kono
parents:
diff changeset
2349 tree size, storage, storage_deref, storage_init;
kono
parents:
diff changeset
2350
kono
parents:
diff changeset
2351 /* If the initializer, if present, is a NULL_EXPR, just return a new one. */
kono
parents:
diff changeset
2352 if (init && TREE_CODE (init) == NULL_EXPR)
kono
parents:
diff changeset
2353 return build1 (NULL_EXPR, result_type, TREE_OPERAND (init, 0));
kono
parents:
diff changeset
2354
kono
parents:
diff changeset
2355 /* If we are just annotating types, also return a NULL_EXPR. */
kono
parents:
diff changeset
2356 else if (type_annotate_only)
kono
parents:
diff changeset
2357 return build1 (NULL_EXPR, result_type,
kono
parents:
diff changeset
2358 build_call_raise (CE_Range_Check_Failed, gnat_node,
kono
parents:
diff changeset
2359 N_Raise_Constraint_Error));
kono
parents:
diff changeset
2360
kono
parents:
diff changeset
2361 /* If the initializer, if present, is a COND_EXPR, deal with each branch. */
kono
parents:
diff changeset
2362 else if (init && TREE_CODE (init) == COND_EXPR)
kono
parents:
diff changeset
2363 return build3 (COND_EXPR, result_type, TREE_OPERAND (init, 0),
kono
parents:
diff changeset
2364 build_allocator (type, TREE_OPERAND (init, 1), result_type,
kono
parents:
diff changeset
2365 gnat_proc, gnat_pool, gnat_node,
kono
parents:
diff changeset
2366 ignore_init_type),
kono
parents:
diff changeset
2367 build_allocator (type, TREE_OPERAND (init, 2), result_type,
kono
parents:
diff changeset
2368 gnat_proc, gnat_pool, gnat_node,
kono
parents:
diff changeset
2369 ignore_init_type));
kono
parents:
diff changeset
2370
kono
parents:
diff changeset
2371 /* If RESULT_TYPE is a fat or thin pointer, set SIZE to be the sum of the
kono
parents:
diff changeset
2372 sizes of the object and its template. Allocate the whole thing and
kono
parents:
diff changeset
2373 fill in the parts that are known. */
kono
parents:
diff changeset
2374 else if (TYPE_IS_FAT_OR_THIN_POINTER_P (result_type))
kono
parents:
diff changeset
2375 {
kono
parents:
diff changeset
2376 tree storage_type
kono
parents:
diff changeset
2377 = build_unc_object_type_from_ptr (result_type, type,
kono
parents:
diff changeset
2378 get_identifier ("ALLOC"), false);
kono
parents:
diff changeset
2379 tree template_type = TREE_TYPE (TYPE_FIELDS (storage_type));
kono
parents:
diff changeset
2380 tree storage_ptr_type = build_pointer_type (storage_type);
kono
parents:
diff changeset
2381
kono
parents:
diff changeset
2382 size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (storage_type),
kono
parents:
diff changeset
2383 init);
kono
parents:
diff changeset
2384
kono
parents:
diff changeset
2385 /* If the size overflows, pass -1 so Storage_Error will be raised. */
kono
parents:
diff changeset
2386 if (TREE_CODE (size) == INTEGER_CST && !valid_constant_size_p (size))
kono
parents:
diff changeset
2387 size = size_int (-1);
kono
parents:
diff changeset
2388
kono
parents:
diff changeset
2389 storage = build_call_alloc_dealloc (NULL_TREE, size, storage_type,
kono
parents:
diff changeset
2390 gnat_proc, gnat_pool, gnat_node);
kono
parents:
diff changeset
2391 storage = convert (storage_ptr_type, gnat_protect_expr (storage));
kono
parents:
diff changeset
2392 storage_deref = build_unary_op (INDIRECT_REF, NULL_TREE, storage);
kono
parents:
diff changeset
2393 TREE_THIS_NOTRAP (storage_deref) = 1;
kono
parents:
diff changeset
2394
kono
parents:
diff changeset
2395 /* If there is an initializing expression, then make a constructor for
kono
parents:
diff changeset
2396 the entire object including the bounds and copy it into the object.
kono
parents:
diff changeset
2397 If there is no initializing expression, just set the bounds. */
kono
parents:
diff changeset
2398 if (init)
kono
parents:
diff changeset
2399 {
kono
parents:
diff changeset
2400 vec<constructor_elt, va_gc> *v;
kono
parents:
diff changeset
2401 vec_alloc (v, 2);
kono
parents:
diff changeset
2402
kono
parents:
diff changeset
2403 CONSTRUCTOR_APPEND_ELT (v, TYPE_FIELDS (storage_type),
kono
parents:
diff changeset
2404 build_template (template_type, type, init));
kono
parents:
diff changeset
2405 CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (TYPE_FIELDS (storage_type)),
kono
parents:
diff changeset
2406 init);
kono
parents:
diff changeset
2407 storage_init
kono
parents:
diff changeset
2408 = build_binary_op (INIT_EXPR, NULL_TREE, storage_deref,
kono
parents:
diff changeset
2409 gnat_build_constructor (storage_type, v));
kono
parents:
diff changeset
2410 }
kono
parents:
diff changeset
2411 else
kono
parents:
diff changeset
2412 storage_init
kono
parents:
diff changeset
2413 = build_binary_op (INIT_EXPR, NULL_TREE,
kono
parents:
diff changeset
2414 build_component_ref (storage_deref,
kono
parents:
diff changeset
2415 TYPE_FIELDS (storage_type),
kono
parents:
diff changeset
2416 false),
kono
parents:
diff changeset
2417 build_template (template_type, type, NULL_TREE));
kono
parents:
diff changeset
2418
kono
parents:
diff changeset
2419 return build2 (COMPOUND_EXPR, result_type,
kono
parents:
diff changeset
2420 storage_init, convert (result_type, storage));
kono
parents:
diff changeset
2421 }
kono
parents:
diff changeset
2422
kono
parents:
diff changeset
2423 size = TYPE_SIZE_UNIT (type);
kono
parents:
diff changeset
2424
kono
parents:
diff changeset
2425 /* If we have an initializing expression, see if its size is simpler
kono
parents:
diff changeset
2426 than the size from the type. */
kono
parents:
diff changeset
2427 if (!ignore_init_type && init && TYPE_SIZE_UNIT (TREE_TYPE (init))
kono
parents:
diff changeset
2428 && (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (init))) == INTEGER_CST
kono
parents:
diff changeset
2429 || CONTAINS_PLACEHOLDER_P (size)))
kono
parents:
diff changeset
2430 size = TYPE_SIZE_UNIT (TREE_TYPE (init));
kono
parents:
diff changeset
2431
kono
parents:
diff changeset
2432 /* If the size is still self-referential, reference the initializing
kono
parents:
diff changeset
2433 expression, if it is present. If not, this must have been a
kono
parents:
diff changeset
2434 call to allocate a library-level object, in which case we use
kono
parents:
diff changeset
2435 the maximum size. */
kono
parents:
diff changeset
2436 if (CONTAINS_PLACEHOLDER_P (size))
kono
parents:
diff changeset
2437 {
kono
parents:
diff changeset
2438 if (!ignore_init_type && init)
kono
parents:
diff changeset
2439 size = substitute_placeholder_in_expr (size, init);
kono
parents:
diff changeset
2440 else
kono
parents:
diff changeset
2441 size = max_size (size, true);
kono
parents:
diff changeset
2442 }
kono
parents:
diff changeset
2443
kono
parents:
diff changeset
2444 /* If the size overflows, pass -1 so Storage_Error will be raised. */
kono
parents:
diff changeset
2445 if (TREE_CODE (size) == INTEGER_CST && !valid_constant_size_p (size))
kono
parents:
diff changeset
2446 size = size_int (-1);
kono
parents:
diff changeset
2447
kono
parents:
diff changeset
2448 storage = convert (result_type,
kono
parents:
diff changeset
2449 build_call_alloc_dealloc (NULL_TREE, size, type,
kono
parents:
diff changeset
2450 gnat_proc, gnat_pool,
kono
parents:
diff changeset
2451 gnat_node));
kono
parents:
diff changeset
2452
kono
parents:
diff changeset
2453 /* If we have an initial value, protect the new address, assign the value
kono
parents:
diff changeset
2454 and return the address with a COMPOUND_EXPR. */
kono
parents:
diff changeset
2455 if (init)
kono
parents:
diff changeset
2456 {
kono
parents:
diff changeset
2457 storage = gnat_protect_expr (storage);
kono
parents:
diff changeset
2458 storage_deref = build_unary_op (INDIRECT_REF, NULL_TREE, storage);
kono
parents:
diff changeset
2459 TREE_THIS_NOTRAP (storage_deref) = 1;
kono
parents:
diff changeset
2460 storage_init
kono
parents:
diff changeset
2461 = build_binary_op (INIT_EXPR, NULL_TREE, storage_deref, init);
kono
parents:
diff changeset
2462 return build2 (COMPOUND_EXPR, result_type, storage_init, storage);
kono
parents:
diff changeset
2463 }
kono
parents:
diff changeset
2464
kono
parents:
diff changeset
2465 return storage;
kono
parents:
diff changeset
2466 }
kono
parents:
diff changeset
2467
kono
parents:
diff changeset
2468 /* Indicate that we need to take the address of T and that it therefore
kono
parents:
diff changeset
2469 should not be allocated in a register. Return true if successful. */
kono
parents:
diff changeset
2470
kono
parents:
diff changeset
2471 bool
kono
parents:
diff changeset
2472 gnat_mark_addressable (tree t)
kono
parents:
diff changeset
2473 {
kono
parents:
diff changeset
2474 while (true)
kono
parents:
diff changeset
2475 switch (TREE_CODE (t))
kono
parents:
diff changeset
2476 {
kono
parents:
diff changeset
2477 case ADDR_EXPR:
kono
parents:
diff changeset
2478 case COMPONENT_REF:
kono
parents:
diff changeset
2479 case ARRAY_REF:
kono
parents:
diff changeset
2480 case ARRAY_RANGE_REF:
kono
parents:
diff changeset
2481 case REALPART_EXPR:
kono
parents:
diff changeset
2482 case IMAGPART_EXPR:
kono
parents:
diff changeset
2483 case VIEW_CONVERT_EXPR:
kono
parents:
diff changeset
2484 case NON_LVALUE_EXPR:
kono
parents:
diff changeset
2485 CASE_CONVERT:
kono
parents:
diff changeset
2486 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
2487 break;
kono
parents:
diff changeset
2488
kono
parents:
diff changeset
2489 case COMPOUND_EXPR:
kono
parents:
diff changeset
2490 t = TREE_OPERAND (t, 1);
kono
parents:
diff changeset
2491 break;
kono
parents:
diff changeset
2492
kono
parents:
diff changeset
2493 case CONSTRUCTOR:
kono
parents:
diff changeset
2494 TREE_ADDRESSABLE (t) = 1;
kono
parents:
diff changeset
2495 return true;
kono
parents:
diff changeset
2496
kono
parents:
diff changeset
2497 case VAR_DECL:
kono
parents:
diff changeset
2498 case PARM_DECL:
kono
parents:
diff changeset
2499 case RESULT_DECL:
kono
parents:
diff changeset
2500 TREE_ADDRESSABLE (t) = 1;
kono
parents:
diff changeset
2501 return true;
kono
parents:
diff changeset
2502
kono
parents:
diff changeset
2503 case FUNCTION_DECL:
kono
parents:
diff changeset
2504 TREE_ADDRESSABLE (t) = 1;
kono
parents:
diff changeset
2505 return true;
kono
parents:
diff changeset
2506
kono
parents:
diff changeset
2507 case CONST_DECL:
kono
parents:
diff changeset
2508 return DECL_CONST_CORRESPONDING_VAR (t)
kono
parents:
diff changeset
2509 && gnat_mark_addressable (DECL_CONST_CORRESPONDING_VAR (t));
kono
parents:
diff changeset
2510
kono
parents:
diff changeset
2511 default:
kono
parents:
diff changeset
2512 return true;
kono
parents:
diff changeset
2513 }
kono
parents:
diff changeset
2514 }
kono
parents:
diff changeset
2515
kono
parents:
diff changeset
2516 /* Return true if EXP is a stable expression for the purpose of the functions
kono
parents:
diff changeset
2517 below and, therefore, can be returned unmodified by them. We accept things
kono
parents:
diff changeset
2518 that are actual constants or that have already been handled. */
kono
parents:
diff changeset
2519
kono
parents:
diff changeset
2520 static bool
kono
parents:
diff changeset
2521 gnat_stable_expr_p (tree exp)
kono
parents:
diff changeset
2522 {
kono
parents:
diff changeset
2523 enum tree_code code = TREE_CODE (exp);
kono
parents:
diff changeset
2524 return TREE_CONSTANT (exp) || code == NULL_EXPR || code == SAVE_EXPR;
kono
parents:
diff changeset
2525 }
kono
parents:
diff changeset
2526
kono
parents:
diff changeset
2527 /* Save EXP for later use or reuse. This is equivalent to save_expr in tree.c
kono
parents:
diff changeset
2528 but we know how to handle our own nodes. */
kono
parents:
diff changeset
2529
kono
parents:
diff changeset
2530 tree
kono
parents:
diff changeset
2531 gnat_save_expr (tree exp)
kono
parents:
diff changeset
2532 {
kono
parents:
diff changeset
2533 tree type = TREE_TYPE (exp);
kono
parents:
diff changeset
2534 enum tree_code code = TREE_CODE (exp);
kono
parents:
diff changeset
2535
kono
parents:
diff changeset
2536 if (gnat_stable_expr_p (exp))
kono
parents:
diff changeset
2537 return exp;
kono
parents:
diff changeset
2538
kono
parents:
diff changeset
2539 if (code == UNCONSTRAINED_ARRAY_REF)
kono
parents:
diff changeset
2540 {
kono
parents:
diff changeset
2541 tree t = build1 (code, type, gnat_save_expr (TREE_OPERAND (exp, 0)));
kono
parents:
diff changeset
2542 TREE_READONLY (t) = TYPE_READONLY (type);
kono
parents:
diff changeset
2543 return t;
kono
parents:
diff changeset
2544 }
kono
parents:
diff changeset
2545
kono
parents:
diff changeset
2546 /* If this is a COMPONENT_REF of a fat pointer, save the entire fat pointer.
kono
parents:
diff changeset
2547 This may be more efficient, but will also allow us to more easily find
kono
parents:
diff changeset
2548 the match for the PLACEHOLDER_EXPR. */
kono
parents:
diff changeset
2549 if (code == COMPONENT_REF
kono
parents:
diff changeset
2550 && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
kono
parents:
diff changeset
2551 return build3 (code, type, gnat_save_expr (TREE_OPERAND (exp, 0)),
kono
parents:
diff changeset
2552 TREE_OPERAND (exp, 1), NULL_TREE);
kono
parents:
diff changeset
2553
kono
parents:
diff changeset
2554 return save_expr (exp);
kono
parents:
diff changeset
2555 }
kono
parents:
diff changeset
2556
kono
parents:
diff changeset
2557 /* Protect EXP for immediate reuse. This is a variant of gnat_save_expr that
kono
parents:
diff changeset
2558 is optimized under the assumption that EXP's value doesn't change before
kono
parents:
diff changeset
2559 its subsequent reuse(s) except through its potential reevaluation. */
kono
parents:
diff changeset
2560
kono
parents:
diff changeset
2561 tree
kono
parents:
diff changeset
2562 gnat_protect_expr (tree exp)
kono
parents:
diff changeset
2563 {
kono
parents:
diff changeset
2564 tree type = TREE_TYPE (exp);
kono
parents:
diff changeset
2565 enum tree_code code = TREE_CODE (exp);
kono
parents:
diff changeset
2566
kono
parents:
diff changeset
2567 if (gnat_stable_expr_p (exp))
kono
parents:
diff changeset
2568 return exp;
kono
parents:
diff changeset
2569
kono
parents:
diff changeset
2570 /* If EXP has no side effects, we theoretically don't need to do anything.
kono
parents:
diff changeset
2571 However, we may be recursively passed more and more complex expressions
kono
parents:
diff changeset
2572 involving checks which will be reused multiple times and eventually be
kono
parents:
diff changeset
2573 unshared for gimplification; in order to avoid a complexity explosion
kono
parents:
diff changeset
2574 at that point, we protect any expressions more complex than a simple
kono
parents:
diff changeset
2575 arithmetic expression. */
kono
parents:
diff changeset
2576 if (!TREE_SIDE_EFFECTS (exp))
kono
parents:
diff changeset
2577 {
kono
parents:
diff changeset
2578 tree inner = skip_simple_arithmetic (exp);
kono
parents:
diff changeset
2579 if (!EXPR_P (inner) || REFERENCE_CLASS_P (inner))
kono
parents:
diff changeset
2580 return exp;
kono
parents:
diff changeset
2581 }
kono
parents:
diff changeset
2582
kono
parents:
diff changeset
2583 /* If this is a conversion, protect what's inside the conversion. */
kono
parents:
diff changeset
2584 if (code == NON_LVALUE_EXPR
kono
parents:
diff changeset
2585 || CONVERT_EXPR_CODE_P (code)
kono
parents:
diff changeset
2586 || code == VIEW_CONVERT_EXPR)
kono
parents:
diff changeset
2587 return build1 (code, type, gnat_protect_expr (TREE_OPERAND (exp, 0)));
kono
parents:
diff changeset
2588
kono
parents:
diff changeset
2589 /* If we're indirectly referencing something, we only need to protect the
kono
parents:
diff changeset
2590 address since the data itself can't change in these situations. */
kono
parents:
diff changeset
2591 if (code == INDIRECT_REF || code == UNCONSTRAINED_ARRAY_REF)
kono
parents:
diff changeset
2592 {
kono
parents:
diff changeset
2593 tree t = build1 (code, type, gnat_protect_expr (TREE_OPERAND (exp, 0)));
kono
parents:
diff changeset
2594 TREE_READONLY (t) = TYPE_READONLY (type);
kono
parents:
diff changeset
2595 return t;
kono
parents:
diff changeset
2596 }
kono
parents:
diff changeset
2597
kono
parents:
diff changeset
2598 /* Likewise if we're indirectly referencing part of something. */
kono
parents:
diff changeset
2599 if (code == COMPONENT_REF
kono
parents:
diff changeset
2600 && TREE_CODE (TREE_OPERAND (exp, 0)) == INDIRECT_REF)
kono
parents:
diff changeset
2601 return build3 (code, type, gnat_protect_expr (TREE_OPERAND (exp, 0)),
kono
parents:
diff changeset
2602 TREE_OPERAND (exp, 1), NULL_TREE);
kono
parents:
diff changeset
2603
kono
parents:
diff changeset
2604 /* If this is a COMPONENT_REF of a fat pointer, save the entire fat pointer.
kono
parents:
diff changeset
2605 This may be more efficient, but will also allow us to more easily find
kono
parents:
diff changeset
2606 the match for the PLACEHOLDER_EXPR. */
kono
parents:
diff changeset
2607 if (code == COMPONENT_REF
kono
parents:
diff changeset
2608 && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
kono
parents:
diff changeset
2609 return build3 (code, type, gnat_protect_expr (TREE_OPERAND (exp, 0)),
kono
parents:
diff changeset
2610 TREE_OPERAND (exp, 1), NULL_TREE);
kono
parents:
diff changeset
2611
kono
parents:
diff changeset
2612 /* If this is a fat pointer or a scalar, just make a SAVE_EXPR. Likewise
kono
parents:
diff changeset
2613 for a CALL_EXPR as large objects are returned via invisible reference
kono
parents:
diff changeset
2614 in most ABIs so the temporary will directly be filled by the callee. */
kono
parents:
diff changeset
2615 if (TYPE_IS_FAT_POINTER_P (type)
kono
parents:
diff changeset
2616 || !AGGREGATE_TYPE_P (type)
kono
parents:
diff changeset
2617 || code == CALL_EXPR)
kono
parents:
diff changeset
2618 return save_expr (exp);
kono
parents:
diff changeset
2619
kono
parents:
diff changeset
2620 /* Otherwise reference, protect the address and dereference. */
kono
parents:
diff changeset
2621 return
kono
parents:
diff changeset
2622 build_unary_op (INDIRECT_REF, type,
kono
parents:
diff changeset
2623 save_expr (build_unary_op (ADDR_EXPR, NULL_TREE, exp)));
kono
parents:
diff changeset
2624 }
kono
parents:
diff changeset
2625
kono
parents:
diff changeset
2626 /* This is equivalent to stabilize_reference_1 in tree.c but we take an extra
kono
parents:
diff changeset
2627 argument to force evaluation of everything. */
kono
parents:
diff changeset
2628
kono
parents:
diff changeset
2629 static tree
kono
parents:
diff changeset
2630 gnat_stabilize_reference_1 (tree e, void *data)
kono
parents:
diff changeset
2631 {
kono
parents:
diff changeset
2632 const bool force = *(bool *)data;
kono
parents:
diff changeset
2633 enum tree_code code = TREE_CODE (e);
kono
parents:
diff changeset
2634 tree type = TREE_TYPE (e);
kono
parents:
diff changeset
2635 tree result;
kono
parents:
diff changeset
2636
kono
parents:
diff changeset
2637 if (gnat_stable_expr_p (e))
kono
parents:
diff changeset
2638 return e;
kono
parents:
diff changeset
2639
kono
parents:
diff changeset
2640 switch (TREE_CODE_CLASS (code))
kono
parents:
diff changeset
2641 {
kono
parents:
diff changeset
2642 case tcc_exceptional:
kono
parents:
diff changeset
2643 case tcc_declaration:
kono
parents:
diff changeset
2644 case tcc_comparison:
kono
parents:
diff changeset
2645 case tcc_expression:
kono
parents:
diff changeset
2646 case tcc_reference:
kono
parents:
diff changeset
2647 case tcc_vl_exp:
kono
parents:
diff changeset
2648 /* If this is a COMPONENT_REF of a fat pointer, save the entire
kono
parents:
diff changeset
2649 fat pointer. This may be more efficient, but will also allow
kono
parents:
diff changeset
2650 us to more easily find the match for the PLACEHOLDER_EXPR. */
kono
parents:
diff changeset
2651 if (code == COMPONENT_REF
kono
parents:
diff changeset
2652 && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0))))
kono
parents:
diff changeset
2653 result
kono
parents:
diff changeset
2654 = build3 (code, type,
kono
parents:
diff changeset
2655 gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data),
kono
parents:
diff changeset
2656 TREE_OPERAND (e, 1), NULL_TREE);
kono
parents:
diff changeset
2657 /* If the expression has side-effects, then encase it in a SAVE_EXPR
kono
parents:
diff changeset
2658 so that it will only be evaluated once. */
kono
parents:
diff changeset
2659 /* The tcc_reference and tcc_comparison classes could be handled as
kono
parents:
diff changeset
2660 below, but it is generally faster to only evaluate them once. */
kono
parents:
diff changeset
2661 else if (TREE_SIDE_EFFECTS (e) || force)
kono
parents:
diff changeset
2662 return save_expr (e);
kono
parents:
diff changeset
2663 else
kono
parents:
diff changeset
2664 return e;
kono
parents:
diff changeset
2665 break;
kono
parents:
diff changeset
2666
kono
parents:
diff changeset
2667 case tcc_binary:
kono
parents:
diff changeset
2668 /* Recursively stabilize each operand. */
kono
parents:
diff changeset
2669 result
kono
parents:
diff changeset
2670 = build2 (code, type,
kono
parents:
diff changeset
2671 gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data),
kono
parents:
diff changeset
2672 gnat_stabilize_reference_1 (TREE_OPERAND (e, 1), data));
kono
parents:
diff changeset
2673 break;
kono
parents:
diff changeset
2674
kono
parents:
diff changeset
2675 case tcc_unary:
kono
parents:
diff changeset
2676 /* Recursively stabilize each operand. */
kono
parents:
diff changeset
2677 result
kono
parents:
diff changeset
2678 = build1 (code, type,
kono
parents:
diff changeset
2679 gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data));
kono
parents:
diff changeset
2680 break;
kono
parents:
diff changeset
2681
kono
parents:
diff changeset
2682 default:
kono
parents:
diff changeset
2683 gcc_unreachable ();
kono
parents:
diff changeset
2684 }
kono
parents:
diff changeset
2685
kono
parents:
diff changeset
2686 TREE_READONLY (result) = TREE_READONLY (e);
kono
parents:
diff changeset
2687 TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
kono
parents:
diff changeset
2688 TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
kono
parents:
diff changeset
2689
kono
parents:
diff changeset
2690 return result;
kono
parents:
diff changeset
2691 }
kono
parents:
diff changeset
2692
kono
parents:
diff changeset
2693 /* This is equivalent to stabilize_reference in tree.c but we know how to
kono
parents:
diff changeset
2694 handle our own nodes and we take extra arguments. FORCE says whether to
kono
parents:
diff changeset
2695 force evaluation of everything in REF. INIT is set to the first arm of
kono
parents:
diff changeset
2696 a COMPOUND_EXPR present in REF, if any. */
kono
parents:
diff changeset
2697
kono
parents:
diff changeset
2698 tree
kono
parents:
diff changeset
2699 gnat_stabilize_reference (tree ref, bool force, tree *init)
kono
parents:
diff changeset
2700 {
kono
parents:
diff changeset
2701 return
kono
parents:
diff changeset
2702 gnat_rewrite_reference (ref, gnat_stabilize_reference_1, &force, init);
kono
parents:
diff changeset
2703 }
kono
parents:
diff changeset
2704
kono
parents:
diff changeset
2705 /* Rewrite reference REF and call FUNC on each expression within REF in the
kono
parents:
diff changeset
2706 process. DATA is passed unmodified to FUNC. INIT is set to the first
kono
parents:
diff changeset
2707 arm of a COMPOUND_EXPR present in REF, if any. */
kono
parents:
diff changeset
2708
kono
parents:
diff changeset
2709 tree
kono
parents:
diff changeset
2710 gnat_rewrite_reference (tree ref, rewrite_fn func, void *data, tree *init)
kono
parents:
diff changeset
2711 {
kono
parents:
diff changeset
2712 tree type = TREE_TYPE (ref);
kono
parents:
diff changeset
2713 enum tree_code code = TREE_CODE (ref);
kono
parents:
diff changeset
2714 tree result;
kono
parents:
diff changeset
2715
kono
parents:
diff changeset
2716 switch (code)
kono
parents:
diff changeset
2717 {
kono
parents:
diff changeset
2718 case CONST_DECL:
kono
parents:
diff changeset
2719 case VAR_DECL:
kono
parents:
diff changeset
2720 case PARM_DECL:
kono
parents:
diff changeset
2721 case RESULT_DECL:
kono
parents:
diff changeset
2722 /* No action is needed in this case. */
kono
parents:
diff changeset
2723 return ref;
kono
parents:
diff changeset
2724
kono
parents:
diff changeset
2725 CASE_CONVERT:
kono
parents:
diff changeset
2726 case FLOAT_EXPR:
kono
parents:
diff changeset
2727 case FIX_TRUNC_EXPR:
kono
parents:
diff changeset
2728 case REALPART_EXPR:
kono
parents:
diff changeset
2729 case IMAGPART_EXPR:
kono
parents:
diff changeset
2730 case VIEW_CONVERT_EXPR:
kono
parents:
diff changeset
2731 result
kono
parents:
diff changeset
2732 = build1 (code, type,
kono
parents:
diff changeset
2733 gnat_rewrite_reference (TREE_OPERAND (ref, 0), func, data,
kono
parents:
diff changeset
2734 init));
kono
parents:
diff changeset
2735 break;
kono
parents:
diff changeset
2736
kono
parents:
diff changeset
2737 case INDIRECT_REF:
kono
parents:
diff changeset
2738 case UNCONSTRAINED_ARRAY_REF:
kono
parents:
diff changeset
2739 result = build1 (code, type, func (TREE_OPERAND (ref, 0), data));
kono
parents:
diff changeset
2740 break;
kono
parents:
diff changeset
2741
kono
parents:
diff changeset
2742 case COMPONENT_REF:
kono
parents:
diff changeset
2743 result = build3 (COMPONENT_REF, type,
kono
parents:
diff changeset
2744 gnat_rewrite_reference (TREE_OPERAND (ref, 0), func,
kono
parents:
diff changeset
2745 data, init),
kono
parents:
diff changeset
2746 TREE_OPERAND (ref, 1), NULL_TREE);
kono
parents:
diff changeset
2747 break;
kono
parents:
diff changeset
2748
kono
parents:
diff changeset
2749 case BIT_FIELD_REF:
kono
parents:
diff changeset
2750 result = build3 (BIT_FIELD_REF, type,
kono
parents:
diff changeset
2751 gnat_rewrite_reference (TREE_OPERAND (ref, 0), func,
kono
parents:
diff changeset
2752 data, init),
kono
parents:
diff changeset
2753 TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2));
kono
parents:
diff changeset
2754 REF_REVERSE_STORAGE_ORDER (result) = REF_REVERSE_STORAGE_ORDER (ref);
kono
parents:
diff changeset
2755 break;
kono
parents:
diff changeset
2756
kono
parents:
diff changeset
2757 case ARRAY_REF:
kono
parents:
diff changeset
2758 case ARRAY_RANGE_REF:
kono
parents:
diff changeset
2759 result
kono
parents:
diff changeset
2760 = build4 (code, type,
kono
parents:
diff changeset
2761 gnat_rewrite_reference (TREE_OPERAND (ref, 0), func, data,
kono
parents:
diff changeset
2762 init),
kono
parents:
diff changeset
2763 func (TREE_OPERAND (ref, 1), data),
kono
parents:
diff changeset
2764 TREE_OPERAND (ref, 2), NULL_TREE);
kono
parents:
diff changeset
2765 break;
kono
parents:
diff changeset
2766
kono
parents:
diff changeset
2767 case COMPOUND_EXPR:
kono
parents:
diff changeset
2768 gcc_assert (!*init);
kono
parents:
diff changeset
2769 *init = TREE_OPERAND (ref, 0);
kono
parents:
diff changeset
2770 /* We expect only the pattern built in Call_to_gnu. */
kono
parents:
diff changeset
2771 gcc_assert (DECL_P (TREE_OPERAND (ref, 1))
kono
parents:
diff changeset
2772 || (TREE_CODE (TREE_OPERAND (ref, 1)) == COMPONENT_REF
kono
parents:
diff changeset
2773 && DECL_P (TREE_OPERAND (TREE_OPERAND (ref, 1), 0))));
kono
parents:
diff changeset
2774 return TREE_OPERAND (ref, 1);
kono
parents:
diff changeset
2775
kono
parents:
diff changeset
2776 case CALL_EXPR:
kono
parents:
diff changeset
2777 {
kono
parents:
diff changeset
2778 /* This can only be an atomic load. */
kono
parents:
diff changeset
2779 gcc_assert (call_is_atomic_load (ref));
kono
parents:
diff changeset
2780
kono
parents:
diff changeset
2781 /* An atomic load is an INDIRECT_REF of its first argument. */
kono
parents:
diff changeset
2782 tree t = CALL_EXPR_ARG (ref, 0);
kono
parents:
diff changeset
2783 if (TREE_CODE (t) == NOP_EXPR)
kono
parents:
diff changeset
2784 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
2785 if (TREE_CODE (t) == ADDR_EXPR)
kono
parents:
diff changeset
2786 t = build1 (ADDR_EXPR, TREE_TYPE (t),
kono
parents:
diff changeset
2787 gnat_rewrite_reference (TREE_OPERAND (t, 0), func, data,
kono
parents:
diff changeset
2788 init));
kono
parents:
diff changeset
2789 else
kono
parents:
diff changeset
2790 t = func (t, data);
kono
parents:
diff changeset
2791 t = fold_convert (TREE_TYPE (CALL_EXPR_ARG (ref, 0)), t);
kono
parents:
diff changeset
2792
kono
parents:
diff changeset
2793 result = build_call_expr (TREE_OPERAND (CALL_EXPR_FN (ref), 0), 2,
kono
parents:
diff changeset
2794 t, CALL_EXPR_ARG (ref, 1));
kono
parents:
diff changeset
2795 }
kono
parents:
diff changeset
2796 break;
kono
parents:
diff changeset
2797
kono
parents:
diff changeset
2798 case ERROR_MARK:
kono
parents:
diff changeset
2799 case NULL_EXPR:
kono
parents:
diff changeset
2800 return ref;
kono
parents:
diff changeset
2801
kono
parents:
diff changeset
2802 default:
kono
parents:
diff changeset
2803 gcc_unreachable ();
kono
parents:
diff changeset
2804 }
kono
parents:
diff changeset
2805
kono
parents:
diff changeset
2806 /* TREE_THIS_VOLATILE and TREE_SIDE_EFFECTS set on the initial expression
kono
parents:
diff changeset
2807 may not be sustained across some paths, such as the way via build1 for
kono
parents:
diff changeset
2808 INDIRECT_REF. We reset those flags here in the general case, which is
kono
parents:
diff changeset
2809 consistent with the GCC version of this routine.
kono
parents:
diff changeset
2810
kono
parents:
diff changeset
2811 Special care should be taken regarding TREE_SIDE_EFFECTS, because some
kono
parents:
diff changeset
2812 paths introduce side-effects where there was none initially (e.g. if a
kono
parents:
diff changeset
2813 SAVE_EXPR is built) and we also want to keep track of that. */
kono
parents:
diff changeset
2814 TREE_READONLY (result) = TREE_READONLY (ref);
kono
parents:
diff changeset
2815 TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (ref);
kono
parents:
diff changeset
2816 TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
kono
parents:
diff changeset
2817
kono
parents:
diff changeset
2818 if (code == INDIRECT_REF
kono
parents:
diff changeset
2819 || code == UNCONSTRAINED_ARRAY_REF
kono
parents:
diff changeset
2820 || code == ARRAY_REF
kono
parents:
diff changeset
2821 || code == ARRAY_RANGE_REF)
kono
parents:
diff changeset
2822 TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (ref);
kono
parents:
diff changeset
2823
kono
parents:
diff changeset
2824 return result;
kono
parents:
diff changeset
2825 }
kono
parents:
diff changeset
2826
kono
parents:
diff changeset
2827 /* This is equivalent to get_inner_reference in expr.c but it returns the
kono
parents:
diff changeset
2828 ultimate containing object only if the reference (lvalue) is constant,
kono
parents:
diff changeset
2829 i.e. if it doesn't depend on the context in which it is evaluated. */
kono
parents:
diff changeset
2830
kono
parents:
diff changeset
2831 tree
kono
parents:
diff changeset
2832 get_inner_constant_reference (tree exp)
kono
parents:
diff changeset
2833 {
kono
parents:
diff changeset
2834 while (true)
kono
parents:
diff changeset
2835 {
kono
parents:
diff changeset
2836 switch (TREE_CODE (exp))
kono
parents:
diff changeset
2837 {
kono
parents:
diff changeset
2838 case BIT_FIELD_REF:
kono
parents:
diff changeset
2839 break;
kono
parents:
diff changeset
2840
kono
parents:
diff changeset
2841 case COMPONENT_REF:
kono
parents:
diff changeset
2842 if (!TREE_CONSTANT (DECL_FIELD_OFFSET (TREE_OPERAND (exp, 1))))
kono
parents:
diff changeset
2843 return NULL_TREE;
kono
parents:
diff changeset
2844 break;
kono
parents:
diff changeset
2845
kono
parents:
diff changeset
2846 case ARRAY_REF:
kono
parents:
diff changeset
2847 case ARRAY_RANGE_REF:
kono
parents:
diff changeset
2848 {
kono
parents:
diff changeset
2849 if (TREE_OPERAND (exp, 2))
kono
parents:
diff changeset
2850 return NULL_TREE;
kono
parents:
diff changeset
2851
kono
parents:
diff changeset
2852 tree array_type = TREE_TYPE (TREE_OPERAND (exp, 0));
kono
parents:
diff changeset
2853 if (!TREE_CONSTANT (TREE_OPERAND (exp, 1))
kono
parents:
diff changeset
2854 || !TREE_CONSTANT (TYPE_MIN_VALUE (TYPE_DOMAIN (array_type)))
kono
parents:
diff changeset
2855 || !TREE_CONSTANT (TYPE_SIZE_UNIT (TREE_TYPE (array_type))))
kono
parents:
diff changeset
2856 return NULL_TREE;
kono
parents:
diff changeset
2857 }
kono
parents:
diff changeset
2858 break;
kono
parents:
diff changeset
2859
kono
parents:
diff changeset
2860 case REALPART_EXPR:
kono
parents:
diff changeset
2861 case IMAGPART_EXPR:
kono
parents:
diff changeset
2862 case VIEW_CONVERT_EXPR:
kono
parents:
diff changeset
2863 break;
kono
parents:
diff changeset
2864
kono
parents:
diff changeset
2865 default:
kono
parents:
diff changeset
2866 goto done;
kono
parents:
diff changeset
2867 }
kono
parents:
diff changeset
2868
kono
parents:
diff changeset
2869 exp = TREE_OPERAND (exp, 0);
kono
parents:
diff changeset
2870 }
kono
parents:
diff changeset
2871
kono
parents:
diff changeset
2872 done:
kono
parents:
diff changeset
2873 return exp;
kono
parents:
diff changeset
2874 }
kono
parents:
diff changeset
2875
kono
parents:
diff changeset
2876 /* Return true if EXPR is the addition or the subtraction of a constant and,
kono
parents:
diff changeset
2877 if so, set *ADD to the addend, *CST to the constant and *MINUS_P to true
kono
parents:
diff changeset
2878 if this is a subtraction. */
kono
parents:
diff changeset
2879
kono
parents:
diff changeset
2880 bool
kono
parents:
diff changeset
2881 is_simple_additive_expression (tree expr, tree *add, tree *cst, bool *minus_p)
kono
parents:
diff changeset
2882 {
kono
parents:
diff changeset
2883 /* Skip overflow checks. */
kono
parents:
diff changeset
2884 if (TREE_CODE (expr) == COND_EXPR
kono
parents:
diff changeset
2885 && TREE_CODE (COND_EXPR_THEN (expr)) == COMPOUND_EXPR
kono
parents:
diff changeset
2886 && TREE_CODE (TREE_OPERAND (COND_EXPR_THEN (expr), 0)) == CALL_EXPR
kono
parents:
diff changeset
2887 && get_callee_fndecl (TREE_OPERAND (COND_EXPR_THEN (expr), 0))
kono
parents:
diff changeset
2888 == gnat_raise_decls[CE_Overflow_Check_Failed])
kono
parents:
diff changeset
2889 expr = COND_EXPR_ELSE (expr);
kono
parents:
diff changeset
2890
kono
parents:
diff changeset
2891 if (TREE_CODE (expr) == PLUS_EXPR)
kono
parents:
diff changeset
2892 {
kono
parents:
diff changeset
2893 if (TREE_CONSTANT (TREE_OPERAND (expr, 0)))
kono
parents:
diff changeset
2894 {
kono
parents:
diff changeset
2895 *add = TREE_OPERAND (expr, 1);
kono
parents:
diff changeset
2896 *cst = TREE_OPERAND (expr, 0);
kono
parents:
diff changeset
2897 *minus_p = false;
kono
parents:
diff changeset
2898 return true;
kono
parents:
diff changeset
2899 }
kono
parents:
diff changeset
2900 else if (TREE_CONSTANT (TREE_OPERAND (expr, 1)))
kono
parents:
diff changeset
2901 {
kono
parents:
diff changeset
2902 *add = TREE_OPERAND (expr, 0);
kono
parents:
diff changeset
2903 *cst = TREE_OPERAND (expr, 1);
kono
parents:
diff changeset
2904 *minus_p = false;
kono
parents:
diff changeset
2905 return true;
kono
parents:
diff changeset
2906 }
kono
parents:
diff changeset
2907 }
kono
parents:
diff changeset
2908 else if (TREE_CODE (expr) == MINUS_EXPR)
kono
parents:
diff changeset
2909 {
kono
parents:
diff changeset
2910 if (TREE_CONSTANT (TREE_OPERAND (expr, 1)))
kono
parents:
diff changeset
2911 {
kono
parents:
diff changeset
2912 *add = TREE_OPERAND (expr, 0);
kono
parents:
diff changeset
2913 *cst = TREE_OPERAND (expr, 1);
kono
parents:
diff changeset
2914 *minus_p = true;
kono
parents:
diff changeset
2915 return true;
kono
parents:
diff changeset
2916 }
kono
parents:
diff changeset
2917 }
kono
parents:
diff changeset
2918
kono
parents:
diff changeset
2919 return false;
kono
parents:
diff changeset
2920 }
kono
parents:
diff changeset
2921
kono
parents:
diff changeset
2922 /* If EXPR is an expression that is invariant in the current function, in the
kono
parents:
diff changeset
2923 sense that it can be evaluated anywhere in the function and any number of
kono
parents:
diff changeset
2924 times, return EXPR or an equivalent expression. Otherwise return NULL. */
kono
parents:
diff changeset
2925
kono
parents:
diff changeset
2926 tree
kono
parents:
diff changeset
2927 gnat_invariant_expr (tree expr)
kono
parents:
diff changeset
2928 {
kono
parents:
diff changeset
2929 const tree type = TREE_TYPE (expr);
kono
parents:
diff changeset
2930 tree add, cst;
kono
parents:
diff changeset
2931 bool minus_p;
kono
parents:
diff changeset
2932
kono
parents:
diff changeset
2933 expr = remove_conversions (expr, false);
kono
parents:
diff changeset
2934
kono
parents:
diff changeset
2935 /* Look through temporaries created to capture values. */
kono
parents:
diff changeset
2936 while ((TREE_CODE (expr) == CONST_DECL
kono
parents:
diff changeset
2937 || (TREE_CODE (expr) == VAR_DECL && TREE_READONLY (expr)))
kono
parents:
diff changeset
2938 && decl_function_context (expr) == current_function_decl
kono
parents:
diff changeset
2939 && DECL_INITIAL (expr))
kono
parents:
diff changeset
2940 {
kono
parents:
diff changeset
2941 expr = DECL_INITIAL (expr);
kono
parents:
diff changeset
2942 /* Look into CONSTRUCTORs built to initialize padded types. */
kono
parents:
diff changeset
2943 if (TYPE_IS_PADDING_P (TREE_TYPE (expr)))
kono
parents:
diff changeset
2944 expr = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (expr))), expr);
kono
parents:
diff changeset
2945 expr = remove_conversions (expr, false);
kono
parents:
diff changeset
2946 }
kono
parents:
diff changeset
2947
kono
parents:
diff changeset
2948 /* We are only interested in scalar types at the moment and, even if we may
kono
parents:
diff changeset
2949 have gone through padding types in the above loop, we must be back to a
kono
parents:
diff changeset
2950 scalar value at this point. */
kono
parents:
diff changeset
2951 if (AGGREGATE_TYPE_P (TREE_TYPE (expr)))
kono
parents:
diff changeset
2952 return NULL_TREE;
kono
parents:
diff changeset
2953
kono
parents:
diff changeset
2954 if (TREE_CONSTANT (expr))
kono
parents:
diff changeset
2955 return fold_convert (type, expr);
kono
parents:
diff changeset
2956
kono
parents:
diff changeset
2957 /* Deal with addition or subtraction of constants. */
kono
parents:
diff changeset
2958 if (is_simple_additive_expression (expr, &add, &cst, &minus_p))
kono
parents:
diff changeset
2959 {
kono
parents:
diff changeset
2960 add = gnat_invariant_expr (add);
kono
parents:
diff changeset
2961 if (add)
kono
parents:
diff changeset
2962 return
kono
parents:
diff changeset
2963 fold_build2 (minus_p ? MINUS_EXPR : PLUS_EXPR, type,
kono
parents:
diff changeset
2964 fold_convert (type, add), fold_convert (type, cst));
kono
parents:
diff changeset
2965 else
kono
parents:
diff changeset
2966 return NULL_TREE;
kono
parents:
diff changeset
2967 }
kono
parents:
diff changeset
2968
kono
parents:
diff changeset
2969 bool invariant_p = false;
kono
parents:
diff changeset
2970 tree t = expr;
kono
parents:
diff changeset
2971
kono
parents:
diff changeset
2972 while (true)
kono
parents:
diff changeset
2973 {
kono
parents:
diff changeset
2974 switch (TREE_CODE (t))
kono
parents:
diff changeset
2975 {
kono
parents:
diff changeset
2976 case COMPONENT_REF:
kono
parents:
diff changeset
2977 invariant_p |= DECL_INVARIANT_P (TREE_OPERAND (t, 1));
kono
parents:
diff changeset
2978 break;
kono
parents:
diff changeset
2979
kono
parents:
diff changeset
2980 case ARRAY_REF:
kono
parents:
diff changeset
2981 case ARRAY_RANGE_REF:
kono
parents:
diff changeset
2982 if (!TREE_CONSTANT (TREE_OPERAND (t, 1)) || TREE_OPERAND (t, 2))
kono
parents:
diff changeset
2983 return NULL_TREE;
kono
parents:
diff changeset
2984 break;
kono
parents:
diff changeset
2985
kono
parents:
diff changeset
2986 case BIT_FIELD_REF:
kono
parents:
diff changeset
2987 case REALPART_EXPR:
kono
parents:
diff changeset
2988 case IMAGPART_EXPR:
kono
parents:
diff changeset
2989 case VIEW_CONVERT_EXPR:
kono
parents:
diff changeset
2990 CASE_CONVERT:
kono
parents:
diff changeset
2991 break;
kono
parents:
diff changeset
2992
kono
parents:
diff changeset
2993 case INDIRECT_REF:
kono
parents:
diff changeset
2994 if ((!invariant_p && !TREE_READONLY (t)) || TREE_SIDE_EFFECTS (t))
kono
parents:
diff changeset
2995 return NULL_TREE;
kono
parents:
diff changeset
2996 invariant_p = false;
kono
parents:
diff changeset
2997 break;
kono
parents:
diff changeset
2998
kono
parents:
diff changeset
2999 default:
kono
parents:
diff changeset
3000 goto object;
kono
parents:
diff changeset
3001 }
kono
parents:
diff changeset
3002
kono
parents:
diff changeset
3003 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
3004 }
kono
parents:
diff changeset
3005
kono
parents:
diff changeset
3006 object:
kono
parents:
diff changeset
3007 if (TREE_SIDE_EFFECTS (t))
kono
parents:
diff changeset
3008 return NULL_TREE;
kono
parents:
diff changeset
3009
kono
parents:
diff changeset
3010 if (TREE_CODE (t) == CONST_DECL
kono
parents:
diff changeset
3011 && (DECL_EXTERNAL (t)
kono
parents:
diff changeset
3012 || decl_function_context (t) != current_function_decl))
kono
parents:
diff changeset
3013 return fold_convert (type, expr);
kono
parents:
diff changeset
3014
kono
parents:
diff changeset
3015 if (!invariant_p && !TREE_READONLY (t))
kono
parents:
diff changeset
3016 return NULL_TREE;
kono
parents:
diff changeset
3017
kono
parents:
diff changeset
3018 if (TREE_CODE (t) == PARM_DECL)
kono
parents:
diff changeset
3019 return fold_convert (type, expr);
kono
parents:
diff changeset
3020
kono
parents:
diff changeset
3021 if (TREE_CODE (t) == VAR_DECL
kono
parents:
diff changeset
3022 && (DECL_EXTERNAL (t)
kono
parents:
diff changeset
3023 || decl_function_context (t) != current_function_decl))
kono
parents:
diff changeset
3024 return fold_convert (type, expr);
kono
parents:
diff changeset
3025
kono
parents:
diff changeset
3026 return NULL_TREE;
kono
parents:
diff changeset
3027 }