Branch data Line data Source code
1 : : /* Tree lowering pass. This pass gimplifies the tree representation built
2 : : by the C-based front ends. The structure of gimplified, or
3 : : language-independent, trees is dictated by the grammar described in this
4 : : file.
5 : : Copyright (C) 2002-2025 Free Software Foundation, Inc.
6 : : Lowering of expressions contributed by Sebastian Pop <s.pop@laposte.net>
7 : : Re-written to support lowering of whole function trees, documentation
8 : : and miscellaneous cleanups by Diego Novillo <dnovillo@redhat.com>
9 : :
10 : : This file is part of GCC.
11 : :
12 : : GCC is free software; you can redistribute it and/or modify it under
13 : : the terms of the GNU General Public License as published by the Free
14 : : Software Foundation; either version 3, or (at your option) any later
15 : : version.
16 : :
17 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
18 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 : : for more details.
21 : :
22 : : You should have received a copy of the GNU General Public License
23 : : along with GCC; see the file COPYING3. If not see
24 : : <http://www.gnu.org/licenses/>. */
25 : :
26 : : #include "config.h"
27 : : #include "system.h"
28 : : #include "coretypes.h"
29 : : #include "tm.h"
30 : : #include "function.h"
31 : : #include "basic-block.h"
32 : : #include "tree.h"
33 : : #include "tree-iterator.h"
34 : : #include "predict.h"
35 : : #include "gimple.h"
36 : : #include "cgraph.h"
37 : : #include "c-pretty-print.h"
38 : : #include "gimplify.h"
39 : : #include "langhooks.h"
40 : : #include "dumpfile.h"
41 : : #include "c-ubsan.h"
42 : : #include "tree-nested.h"
43 : : #include "context.h"
44 : : #include "tree-pass.h"
45 : : #include "internal-fn.h"
46 : : #include "omp-general.h"
47 : :
48 : : /* The gimplification pass converts the language-dependent trees
49 : : (ld-trees) emitted by the parser into language-independent trees
50 : : (li-trees) that are the target of SSA analysis and transformations.
51 : :
52 : : Language-independent trees are based on the SIMPLE intermediate
53 : : representation used in the McCAT compiler framework:
54 : :
55 : : "Designing the McCAT Compiler Based on a Family of Structured
56 : : Intermediate Representations,"
57 : : L. Hendren, C. Donawa, M. Emami, G. Gao, Justiani, and B. Sridharan,
58 : : Proceedings of the 5th International Workshop on Languages and
59 : : Compilers for Parallel Computing, no. 757 in Lecture Notes in
60 : : Computer Science, New Haven, Connecticut, pp. 406-420,
61 : : Springer-Verlag, August 3-5, 1992.
62 : :
63 : : http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html
64 : :
65 : : Basically, we walk down gimplifying the nodes that we encounter. As we
66 : : walk back up, we check that they fit our constraints, and copy them
67 : : into temporaries if not. */
68 : :
69 : : /* Callback for c_genericize. */
70 : :
71 : : static tree
72 : 1256618 : ubsan_walk_array_refs_r (tree *tp, int *walk_subtrees, void *data)
73 : : {
74 : 1256618 : hash_set<tree> *pset = (hash_set<tree> *) data;
75 : :
76 : 1256618 : if (TREE_CODE (*tp) == BIND_EXPR)
77 : : {
78 : : /* Since walk_tree doesn't call the callback function on the decls
79 : : in BIND_EXPR_VARS, we have to walk them manually, so we can avoid
80 : : instrumenting DECL_INITIAL of TREE_STATIC vars. */
81 : 64438 : *walk_subtrees = 0;
82 : 80204 : for (tree decl = BIND_EXPR_VARS (*tp); decl; decl = DECL_CHAIN (decl))
83 : : {
84 : 15766 : if (TREE_STATIC (decl))
85 : 150 : continue;
86 : 15616 : walk_tree (&DECL_INITIAL (decl), ubsan_walk_array_refs_r, pset,
87 : : pset);
88 : 15616 : walk_tree (&DECL_SIZE (decl), ubsan_walk_array_refs_r, pset, pset);
89 : 15616 : walk_tree (&DECL_SIZE_UNIT (decl), ubsan_walk_array_refs_r, pset,
90 : : pset);
91 : : }
92 : 64438 : walk_tree (&BIND_EXPR_BODY (*tp), ubsan_walk_array_refs_r, pset, pset);
93 : : }
94 : 1192180 : else if (TREE_CODE (*tp) == ADDR_EXPR
95 : 1192180 : && TREE_CODE (TREE_OPERAND (*tp, 0)) == ARRAY_REF)
96 : : {
97 : 259 : ubsan_maybe_instrument_array_ref (&TREE_OPERAND (*tp, 0), true);
98 : : /* Make sure ubsan_maybe_instrument_array_ref is not called again
99 : : on the ARRAY_REF, the above call might not instrument anything
100 : : as the index might be constant or masked, so ensure it is not
101 : : walked again and walk its subtrees manually. */
102 : 259 : tree aref = TREE_OPERAND (*tp, 0);
103 : 259 : pset->add (aref);
104 : 259 : *walk_subtrees = 0;
105 : 259 : walk_tree (&TREE_OPERAND (aref, 0), ubsan_walk_array_refs_r, pset, pset);
106 : 259 : walk_tree (&TREE_OPERAND (aref, 1), ubsan_walk_array_refs_r, pset, pset);
107 : 259 : walk_tree (&TREE_OPERAND (aref, 2), ubsan_walk_array_refs_r, pset, pset);
108 : 259 : walk_tree (&TREE_OPERAND (aref, 3), ubsan_walk_array_refs_r, pset, pset);
109 : : }
110 : 1191921 : else if (TREE_CODE (*tp) == ARRAY_REF)
111 : 3990 : ubsan_maybe_instrument_array_ref (tp, false);
112 : 1187931 : else if (TREE_CODE (*tp) == MODIFY_EXPR)
113 : : {
114 : : /* Since r7-1900, we gimplify RHS before LHS. Consider
115 : : a[b] |= c;
116 : : wherein we can have a single shared tree a[b] in both LHS and RHS.
117 : : If we only instrument the LHS and the access is invalid, the program
118 : : could crash before emitting a UBSan error. So instrument the RHS
119 : : first. */
120 : 65987 : *walk_subtrees = 0;
121 : 65987 : walk_tree (&TREE_OPERAND (*tp, 1), ubsan_walk_array_refs_r, pset, pset);
122 : 65987 : walk_tree (&TREE_OPERAND (*tp, 0), ubsan_walk_array_refs_r, pset, pset);
123 : : }
124 : 1256618 : return NULL_TREE;
125 : : }
126 : :
127 : : /* Gimplification of statement trees. */
128 : :
129 : : /* Local declarations. */
130 : :
131 : : enum bc_t { bc_break = 0, bc_continue = 1 };
132 : :
133 : : /* Stack of labels which are targets for "break" or "continue",
134 : : linked through TREE_CHAIN. */
135 : : static tree bc_label[2];
136 : :
137 : : /* Hash map from loop/switch names (identified by LABEL_DECL) to
138 : : corresponding break and (if any) continue labels. */
139 : : static bc_hash_map_t *bc_hash_map;
140 : :
141 : : /* Begin a scope which can be exited by a break or continue statement. BC
142 : : indicates which.
143 : :
144 : : Just creates a label with location LOCATION and pushes it into the current
145 : : context. */
146 : :
147 : : static tree
148 : 7174558 : begin_bc_block (enum bc_t bc, location_t location)
149 : : {
150 : 7174558 : tree label = create_artificial_label (location);
151 : 7174558 : DECL_CHAIN (label) = bc_label[bc];
152 : 7174558 : bc_label[bc] = label;
153 : 7174558 : if (bc == bc_break)
154 : 3739900 : LABEL_DECL_BREAK (label) = true;
155 : : else
156 : 3434658 : LABEL_DECL_CONTINUE (label) = true;
157 : 7174558 : return label;
158 : : }
159 : :
160 : : /* Finish a scope which can be exited by a break or continue statement.
161 : : LABEL was returned from the most recent call to begin_bc_block. BLOCK is
162 : : an expression for the contents of the scope.
163 : :
164 : : If we saw a break (or continue) in the scope, append a LABEL_EXPR to
165 : : BLOCK. Otherwise, just forget the label. */
166 : :
167 : : static void
168 : 7174558 : finish_bc_block (tree *block, enum bc_t bc, tree label)
169 : : {
170 : 7174558 : gcc_assert (label == bc_label[bc]);
171 : :
172 : 7174558 : if (TREE_USED (label))
173 : 2897816 : append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
174 : : block);
175 : :
176 : 7174558 : bc_label[bc] = DECL_CHAIN (label);
177 : 7174558 : DECL_CHAIN (label) = NULL_TREE;
178 : 7174558 : }
179 : :
180 : : /* For named loop or switch with NAME, remember corresponding break
181 : : label BLAB and continue label CLAB. */
182 : :
183 : : static void
184 : 51 : note_named_bc (tree name, tree blab, tree clab)
185 : : {
186 : 51 : if (bc_hash_map == NULL)
187 : 15 : bc_hash_map = new bc_hash_map_t (32);
188 : 51 : bc_hash_map->put (name, std::make_pair (blab, clab));
189 : 51 : }
190 : :
191 : : /* Remove NAME from the map after processing body of the loop or
192 : : switch. */
193 : :
194 : : static void
195 : 51 : release_named_bc (tree name)
196 : : {
197 : 0 : bc_hash_map->remove (name);
198 : 0 : }
199 : :
200 : : /* Allow saving and restoring break/continue state. */
201 : :
202 : : void
203 : 77462406 : save_bc_state (bc_state_t *state)
204 : : {
205 : 77462406 : state->bc_label[bc_break] = bc_label[bc_break];
206 : 77462406 : state->bc_label[bc_continue] = bc_label[bc_continue];
207 : 77462406 : state->bc_hash_map = bc_hash_map;
208 : 77462406 : bc_label[bc_break] = NULL_TREE;
209 : 77462406 : bc_label[bc_continue] = NULL_TREE;
210 : 77462406 : bc_hash_map = NULL;
211 : 77462406 : }
212 : :
213 : : void
214 : 77462406 : restore_bc_state (bc_state_t *state)
215 : : {
216 : 77462406 : gcc_assert (bc_label[bc_break] == NULL);
217 : 77462406 : gcc_assert (bc_label[bc_continue] == NULL);
218 : 77462406 : gcc_assert (bc_hash_map == NULL);
219 : 77462406 : bc_label[bc_break] = state->bc_label[bc_break];
220 : 77462406 : bc_label[bc_continue] = state->bc_label[bc_continue];
221 : 77462406 : bc_hash_map = state->bc_hash_map;
222 : 77462406 : }
223 : :
224 : : /* Get the LABEL_EXPR to represent a break or continue statement
225 : : in the current block scope. BC indicates which. */
226 : :
227 : : static tree
228 : 4022706 : get_bc_label (enum bc_t bc)
229 : : {
230 : 4022706 : tree label = bc_label[bc];
231 : 4022706 : gcc_assert (label);
232 : :
233 : : /* Mark the label used for finish_bc_block. */
234 : 4022706 : TREE_USED (label) = 1;
235 : 4022706 : return label;
236 : : }
237 : :
238 : : /* Return the location from EXPR, or OR_LOC if the former is unknown. */
239 : :
240 : : location_t
241 : 8154203 : expr_loc_or_loc (const_tree expr, location_t or_loc)
242 : : {
243 : 8154203 : tree t = CONST_CAST_TREE (expr);
244 : 8154203 : location_t loc = UNKNOWN_LOCATION;
245 : 8154203 : if (t)
246 : 6248146 : loc = EXPR_LOCATION (t);
247 : 5113490 : if (loc == UNKNOWN_LOCATION)
248 : 4334902 : loc = or_loc;
249 : 8154203 : return loc;
250 : : }
251 : :
252 : : /* Build a generic representation of one of the C loop forms. COND is the
253 : : loop condition or NULL_TREE. BODY is the (possibly compound) statement
254 : : controlled by the loop. INCR is the increment expression of a for-loop,
255 : : or NULL_TREE. COND_IS_FIRST indicates whether the condition is
256 : : evaluated before the loop body as in while and for loops, or after the
257 : : loop body as in do-while loops. COND_PREP and COND_CLEANUP are used
258 : : for C++ for/while loops with variable declaration as condition. COND_PREP
259 : : is a BIND_EXPR with the declaration and initialization of the condition
260 : : variable, into which COND, BODY, continue label if needed and INCR if
261 : : non-NULL should be appended, and COND_CLEANUP is number of nested
262 : : CLEANUP_STMT -> TRY_FINALLY_EXPR statements at the end. If non-NULL,
263 : : COND, BODY, continue label if needed and INCR if non-NULL should be
264 : : appended to the body of the COND_CLEANUP's nested TRY_FINALLY_EXPR. */
265 : :
266 : : static void
267 : 3392286 : genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
268 : : tree incr, tree name, tree cond_prep, tree cond_cleanup,
269 : : bool cond_is_first, int *walk_subtrees, void *data,
270 : : walk_tree_fn func, walk_tree_lh lh)
271 : : {
272 : 3392286 : tree blab, clab;
273 : 3392286 : tree entry = NULL, exit = NULL, t;
274 : 3392286 : tree stmt_list = NULL, outer_stmt_list = NULL_TREE, *stmt_list_p = NULL;
275 : 3392286 : location_t cond_locus = expr_loc_or_loc (cond, start_locus);
276 : 3392286 : location_t incr_locus = expr_loc_or_loc (incr, start_locus);
277 : :
278 : 3392286 : protected_set_expr_location_if_unset (incr, start_locus);
279 : :
280 : 3392286 : walk_tree_1 (&cond_prep, func, data, NULL, lh);
281 : 3392286 : walk_tree_1 (&cond, func, data, NULL, lh);
282 : 3392286 : walk_tree_1 (&incr, func, data, NULL, lh);
283 : :
284 : 3392286 : blab = begin_bc_block (bc_break, start_locus);
285 : 3392286 : clab = begin_bc_block (bc_continue, start_locus);
286 : 3392286 : if (name)
287 : 39 : note_named_bc (name, blab, clab);
288 : :
289 : 3392286 : walk_tree_1 (&body, func, data, NULL, lh);
290 : 3392286 : *walk_subtrees = 0;
291 : :
292 : 3392286 : if (name)
293 : 39 : release_named_bc (name);
294 : :
295 : 3392286 : if (cond_prep)
296 : : {
297 : : /* The C++ cases of
298 : : while (A x = 42) body;
299 : : for (; A x = 42; expr) body;
300 : : This should be expanded into:
301 : :
302 : : top:
303 : : COND_PREP
304 : :
305 : : with either
306 : :
307 : : if (COND); else break;
308 : : BODY;
309 : : cont:
310 : : EXPR;
311 : : goto top;
312 : :
313 : : appended into COND_PREP body or body of some TRY_FINALLY_EXPRs
314 : : at the end of COND_PREP. */
315 : 10017 : gcc_assert (cond_is_first && TREE_CODE (cond_prep) == BIND_EXPR);
316 : 10017 : tree top = build1 (LABEL_EXPR, void_type_node,
317 : : create_artificial_label (start_locus));
318 : 10017 : exit = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top));
319 : 10017 : append_to_statement_list (top, &outer_stmt_list);
320 : 10017 : append_to_statement_list (cond_prep, &outer_stmt_list);
321 : 10017 : stmt_list_p = &BIND_EXPR_BODY (cond_prep);
322 : 10017 : if (cond_cleanup)
323 : 206 : for (unsigned depth = tree_to_uhwi (cond_cleanup); depth; --depth)
324 : : {
325 : 109 : t = tsi_stmt (tsi_last (*stmt_list_p));
326 : 109 : gcc_assert (TREE_CODE (t) == TRY_FINALLY_EXPR);
327 : 109 : stmt_list_p = &TREE_OPERAND (t, 0);
328 : : }
329 : 10017 : stmt_list = *stmt_list_p;
330 : 10017 : *stmt_list_p = NULL_TREE;
331 : 10017 : tree after_cond = create_artificial_label (cond_locus);
332 : 10017 : tree goto_after_cond = build1 (GOTO_EXPR, void_type_node, after_cond);
333 : 10017 : t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break));
334 : 10017 : t = fold_build3_loc (cond_locus, COND_EXPR, void_type_node, cond,
335 : : goto_after_cond, t);
336 : 10017 : append_to_statement_list (t, &stmt_list);
337 : 10017 : t = build1 (LABEL_EXPR, void_type_node, after_cond);
338 : 10017 : append_to_statement_list (t, &stmt_list);
339 : : }
340 : 3382269 : else if (cond && integer_zerop (cond))
341 : : {
342 : : /* If condition is zero don't generate a loop construct. */
343 : 1084516 : if (cond_is_first)
344 : : {
345 : 286 : t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
346 : : get_bc_label (bc_break));
347 : 286 : append_to_statement_list (t, &stmt_list);
348 : : }
349 : : }
350 : : else
351 : : {
352 : : /* Expand to gotos. */
353 : 2297753 : tree top = build1 (LABEL_EXPR, void_type_node,
354 : : create_artificial_label (start_locus));
355 : :
356 : : /* If we have an exit condition, then we build an IF with gotos either
357 : : out of the loop, or to the top of it. If there's no exit condition,
358 : : then we just build a jump back to the top. */
359 : 2297753 : exit = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top));
360 : :
361 : 2297753 : if (cond && !integer_nonzerop (cond))
362 : : {
363 : : /* Canonicalize the loop condition to the end. This means
364 : : generating a branch to the loop condition. Reuse the
365 : : continue label, if there is no incr expression. */
366 : 2182486 : if (cond_is_first)
367 : : {
368 : 2031310 : if (incr)
369 : : {
370 : 1545310 : entry = build1 (LABEL_EXPR, void_type_node,
371 : : create_artificial_label (start_locus));
372 : 3090620 : t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
373 : 1545310 : LABEL_EXPR_LABEL (entry));
374 : : }
375 : : else
376 : 486000 : t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
377 : : get_bc_label (bc_continue));
378 : 2031310 : append_to_statement_list (t, &stmt_list);
379 : : }
380 : :
381 : 2182486 : t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break));
382 : 2182486 : exit = fold_build3_loc (cond_locus,
383 : : COND_EXPR, void_type_node, cond, exit, t);
384 : : }
385 : : else
386 : : {
387 : : /* For the backward-goto's location of an unconditional loop
388 : : use the beginning of the body, or, if there is none, the
389 : : top of the loop. */
390 : 115267 : location_t loc = expr_loc_or_loc (expr_first (body),
391 : : start_locus);
392 : 115267 : SET_EXPR_LOCATION (exit, loc);
393 : : }
394 : 2297753 : append_to_statement_list (top, &stmt_list);
395 : : }
396 : :
397 : 3392286 : append_to_statement_list (body, &stmt_list);
398 : 3392286 : if (c_dialect_cxx ()
399 : 2931439 : && stmt_list
400 : 2929542 : && TREE_CODE (stmt_list) == STATEMENT_LIST)
401 : : {
402 : 2929542 : tree_stmt_iterator tsi = tsi_last (stmt_list);
403 : 2929542 : if (!tsi_end_p (tsi))
404 : : {
405 : 2929542 : tree t = *tsi;
406 : 2929542 : while (TREE_CODE (t) == CLEANUP_POINT_EXPR
407 : : || TREE_CODE (t) == EXPR_STMT
408 : 5374187 : || CONVERT_EXPR_CODE_P (TREE_CODE (t)))
409 : 2444645 : t = TREE_OPERAND (t, 0);
410 : : /* For C++, if iteration statement body ends with fallthrough
411 : : statement, mark it such that we diagnose it even if next
412 : : statement would be labeled statement with case/default label. */
413 : 2929542 : if (TREE_CODE (t) == CALL_EXPR
414 : 123280 : && !CALL_EXPR_FN (t)
415 : 2929554 : && CALL_EXPR_IFN (t) == IFN_FALLTHROUGH)
416 : 12 : TREE_NOTHROW (t) = 1;
417 : : }
418 : : }
419 : 3392286 : finish_bc_block (&stmt_list, bc_continue, clab);
420 : 3392286 : if (incr)
421 : : {
422 : 1552717 : if (MAY_HAVE_DEBUG_MARKER_STMTS && incr_locus != UNKNOWN_LOCATION)
423 : : {
424 : 1254364 : tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
425 : 1254364 : SET_EXPR_LOCATION (d, expr_loc_or_loc (incr, start_locus));
426 : 1254364 : append_to_statement_list (d, &stmt_list);
427 : : }
428 : 1552717 : append_to_statement_list (incr, &stmt_list);
429 : : }
430 : 3392286 : append_to_statement_list (entry, &stmt_list);
431 : :
432 : 3392286 : if (MAY_HAVE_DEBUG_MARKER_STMTS && cond_locus != UNKNOWN_LOCATION)
433 : : {
434 : 2869725 : tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
435 : 2869725 : SET_EXPR_LOCATION (d, cond_locus);
436 : 2869725 : append_to_statement_list (d, &stmt_list);
437 : : }
438 : 3392286 : append_to_statement_list (exit, &stmt_list);
439 : 3392286 : if (stmt_list_p)
440 : : {
441 : 10017 : *stmt_list_p = stmt_list;
442 : 10017 : stmt_list = outer_stmt_list;
443 : : }
444 : 3392286 : finish_bc_block (&stmt_list, bc_break, blab);
445 : 3392286 : if (!stmt_list)
446 : 3681 : stmt_list = build_empty_stmt (start_locus);
447 : :
448 : 3392286 : *stmt_p = stmt_list;
449 : 3392286 : }
450 : :
451 : : /* Genericize a FOR_STMT node *STMT_P. */
452 : :
453 : : static void
454 : 1619422 : genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data,
455 : : walk_tree_fn func, walk_tree_lh lh)
456 : : {
457 : 1619422 : tree stmt = *stmt_p;
458 : 1619422 : tree expr = NULL;
459 : 1619422 : tree loop;
460 : 1619422 : tree init = FOR_INIT_STMT (stmt);
461 : :
462 : 1619422 : if (init)
463 : : {
464 : 0 : walk_tree_1 (&init, func, data, NULL, lh);
465 : 0 : append_to_statement_list (init, &expr);
466 : : }
467 : :
468 : 3238844 : genericize_c_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt),
469 : 1619422 : FOR_BODY (stmt), FOR_EXPR (stmt), FOR_NAME (stmt),
470 : 1619422 : FOR_COND_PREP (stmt), FOR_COND_CLEANUP (stmt), 1,
471 : : walk_subtrees, data, func, lh);
472 : 1619422 : append_to_statement_list (loop, &expr);
473 : 1619422 : if (expr == NULL_TREE)
474 : 0 : expr = loop;
475 : 1619422 : *stmt_p = expr;
476 : 1619422 : }
477 : :
478 : : /* Genericize a WHILE_STMT node *STMT_P. */
479 : :
480 : : static void
481 : 537062 : genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data,
482 : : walk_tree_fn func, walk_tree_lh lh)
483 : : {
484 : 537062 : tree stmt = *stmt_p;
485 : 1074124 : genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt),
486 : 537062 : WHILE_BODY (stmt), NULL_TREE, WHILE_NAME (stmt),
487 : 537062 : WHILE_COND_PREP (stmt), WHILE_COND_CLEANUP (stmt), 1,
488 : : walk_subtrees, data, func, lh);
489 : 537062 : }
490 : :
491 : : /* Genericize a DO_STMT node *STMT_P. */
492 : :
493 : : static void
494 : 1235802 : genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data,
495 : : walk_tree_fn func, walk_tree_lh lh)
496 : : {
497 : 1235802 : tree stmt = *stmt_p;
498 : 2471604 : genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt),
499 : 1235802 : DO_BODY (stmt), NULL_TREE, DO_NAME (stmt),
500 : : NULL_TREE, NULL_TREE, 0, walk_subtrees, data, func, lh);
501 : 1235802 : }
502 : :
503 : : /* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */
504 : :
505 : : static void
506 : 347614 : genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data,
507 : : walk_tree_fn func, walk_tree_lh lh)
508 : : {
509 : 347614 : tree stmt = *stmt_p;
510 : 347614 : tree blab, body, cond, type;
511 : 347614 : location_t stmt_locus = EXPR_LOCATION (stmt);
512 : :
513 : 347614 : body = SWITCH_STMT_BODY (stmt);
514 : 347614 : if (!body)
515 : 0 : body = build_empty_stmt (stmt_locus);
516 : 347614 : cond = SWITCH_STMT_COND (stmt);
517 : 347614 : type = SWITCH_STMT_TYPE (stmt);
518 : :
519 : 347614 : walk_tree_1 (&cond, func, data, NULL, lh);
520 : :
521 : 347614 : blab = begin_bc_block (bc_break, stmt_locus);
522 : 347614 : if (SWITCH_STMT_NAME (stmt))
523 : 12 : note_named_bc (SWITCH_STMT_NAME (stmt), blab, NULL_TREE);
524 : :
525 : 347614 : walk_tree_1 (&body, func, data, NULL, lh);
526 : :
527 : 347614 : if (SWITCH_STMT_NAME (stmt))
528 : 12 : release_named_bc (SWITCH_STMT_NAME (stmt));
529 : :
530 : 347614 : walk_tree_1 (&type, func, data, NULL, lh);
531 : 347614 : *walk_subtrees = 0;
532 : :
533 : 347614 : if (TREE_USED (blab))
534 : 158323 : SWITCH_BREAK_LABEL_P (blab) = 1;
535 : 347614 : finish_bc_block (&body, bc_break, blab);
536 : 347614 : *stmt_p = build2_loc (stmt_locus, SWITCH_EXPR, type, cond, body);
537 : 347614 : SWITCH_ALL_CASES_P (*stmt_p) = SWITCH_STMT_ALL_CASES_P (stmt);
538 : 347614 : gcc_checking_assert (!SWITCH_STMT_NO_BREAK_P (stmt)
539 : : || !TREE_USED (blab));
540 : 347614 : }
541 : :
542 : : /* Genericize a CONTINUE_STMT node *STMT_P. */
543 : :
544 : : static void
545 : 16565 : genericize_continue_stmt (tree *stmt_p)
546 : : {
547 : 16565 : tree stmt_list = NULL;
548 : 16565 : tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN);
549 : 16565 : tree label;
550 : 16565 : if (CONTINUE_NAME (*stmt_p))
551 : : {
552 : 42 : tree_pair *slot = bc_hash_map->get (CONTINUE_NAME (*stmt_p));
553 : 42 : gcc_checking_assert (slot);
554 : 42 : label = slot->second;
555 : 42 : TREE_USED (label) = 1;
556 : : }
557 : : else
558 : 16523 : label = get_bc_label (bc_continue);
559 : 16565 : location_t location = EXPR_LOCATION (*stmt_p);
560 : 16565 : tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label);
561 : 16565 : append_to_statement_list_force (pred, &stmt_list);
562 : 16565 : append_to_statement_list (jump, &stmt_list);
563 : 16565 : *stmt_p = stmt_list;
564 : 16565 : }
565 : :
566 : : /* Genericize a BREAK_STMT node *STMT_P. */
567 : :
568 : : static void
569 : 1327447 : genericize_break_stmt (tree *stmt_p)
570 : : {
571 : 1327447 : tree label;
572 : 1327447 : if (BREAK_NAME (*stmt_p))
573 : : {
574 : 53 : tree_pair *slot = bc_hash_map->get (BREAK_NAME (*stmt_p));
575 : 53 : gcc_checking_assert (slot);
576 : 53 : label = slot->first;
577 : 53 : TREE_USED (label) = 1;
578 : : }
579 : : else
580 : 1327394 : label = get_bc_label (bc_break);
581 : 1327447 : location_t location = EXPR_LOCATION (*stmt_p);
582 : 1327447 : *stmt_p = build1_loc (location, GOTO_EXPR, void_type_node, label);
583 : 1327447 : }
584 : :
585 : : /* Genericize a OMP_FOR node *STMT_P. */
586 : :
587 : : static void
588 : 42372 : genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data,
589 : : walk_tree_fn func, walk_tree_lh lh)
590 : : {
591 : 42372 : tree stmt = *stmt_p;
592 : 42372 : location_t locus = EXPR_LOCATION (stmt);
593 : 42372 : tree clab = begin_bc_block (bc_continue, locus);
594 : :
595 : 42372 : walk_tree_1 (&OMP_FOR_BODY (stmt), func, data, NULL, lh);
596 : 42372 : if (TREE_CODE (stmt) != OMP_TASKLOOP)
597 : 40966 : walk_tree_1 (&OMP_FOR_CLAUSES (stmt), func, data, NULL, lh);
598 : 42372 : walk_tree_1 (&OMP_FOR_INIT (stmt), func, data, NULL, lh);
599 : 42372 : walk_tree_1 (&OMP_FOR_COND (stmt), func, data, NULL, lh);
600 : 42372 : walk_tree_1 (&OMP_FOR_INCR (stmt), func, data, NULL, lh);
601 : 42372 : walk_tree_1 (&OMP_FOR_PRE_BODY (stmt), func, data, NULL, lh);
602 : 42372 : *walk_subtrees = 0;
603 : :
604 : 42372 : finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab);
605 : 42372 : }
606 : :
607 : : /* Genericize a OMP_METADIRECTIVE node *STMT_P. */
608 : :
609 : : static void
610 : 24 : genericize_omp_metadirective_stmt (tree *stmt_p, int *walk_subtrees,
611 : : void *data, walk_tree_fn func,
612 : : walk_tree_lh lh)
613 : : {
614 : 24 : tree stmt = *stmt_p;
615 : :
616 : 24 : for (tree variant = OMP_METADIRECTIVE_VARIANTS (stmt);
617 : 94 : variant != NULL_TREE;
618 : 70 : variant = TREE_CHAIN (variant))
619 : : {
620 : 70 : walk_tree_1 (&OMP_METADIRECTIVE_VARIANT_DIRECTIVE (variant),
621 : : func, data, NULL, lh);
622 : 70 : walk_tree_1 (&OMP_METADIRECTIVE_VARIANT_BODY (variant),
623 : : func, data, NULL, lh);
624 : : }
625 : :
626 : 24 : *walk_subtrees = 0;
627 : 24 : }
628 : :
629 : : /* Lower structured control flow tree nodes, such as loops. The
630 : : STMT_P, WALK_SUBTREES, and DATA arguments are as for the walk_tree_fn
631 : : type. FUNC and LH are language-specific functions passed to walk_tree_1
632 : : for node visiting and traversal, respectively; they are used to do
633 : : subtree processing in a language-dependent way. */
634 : :
635 : : tree
636 : 698624965 : c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, void *data,
637 : : walk_tree_fn func, walk_tree_lh lh)
638 : : {
639 : 698624965 : tree stmt = *stmt_p;
640 : :
641 : 698624965 : switch (TREE_CODE (stmt))
642 : : {
643 : 1619422 : case FOR_STMT:
644 : 1619422 : genericize_for_stmt (stmt_p, walk_subtrees, data, func, lh);
645 : 1619422 : break;
646 : :
647 : 537062 : case WHILE_STMT:
648 : 537062 : genericize_while_stmt (stmt_p, walk_subtrees, data, func, lh);
649 : 537062 : break;
650 : :
651 : 1235802 : case DO_STMT:
652 : 1235802 : genericize_do_stmt (stmt_p, walk_subtrees, data, func, lh);
653 : 1235802 : break;
654 : :
655 : 347614 : case SWITCH_STMT:
656 : 347614 : genericize_switch_stmt (stmt_p, walk_subtrees, data, func, lh);
657 : 347614 : break;
658 : :
659 : 16565 : case CONTINUE_STMT:
660 : 16565 : genericize_continue_stmt (stmt_p);
661 : 16565 : break;
662 : :
663 : 1327447 : case BREAK_STMT:
664 : 1327447 : genericize_break_stmt (stmt_p);
665 : 1327447 : break;
666 : :
667 : 42372 : case OMP_FOR:
668 : 42372 : case OMP_SIMD:
669 : 42372 : case OMP_DISTRIBUTE:
670 : 42372 : case OMP_LOOP:
671 : 42372 : case OMP_TASKLOOP:
672 : 42372 : case OMP_TILE:
673 : 42372 : case OMP_UNROLL:
674 : 42372 : case OACC_LOOP:
675 : 42372 : genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh);
676 : 42372 : break;
677 : :
678 : 24 : case OMP_METADIRECTIVE:
679 : 24 : genericize_omp_metadirective_stmt (stmt_p, walk_subtrees, data, func,
680 : : lh);
681 : 24 : break;
682 : :
683 : 52870623 : case STATEMENT_LIST:
684 : 52870623 : if (TREE_SIDE_EFFECTS (stmt))
685 : : {
686 : 50534291 : tree_stmt_iterator i;
687 : 50534291 : int nondebug_stmts = 0;
688 : 50534291 : bool clear_side_effects = true;
689 : : /* Genericization can clear TREE_SIDE_EFFECTS, e.g. when
690 : : transforming an IF_STMT into COND_EXPR. If such stmt
691 : : appears in a STATEMENT_LIST that contains only that
692 : : stmt and some DEBUG_BEGIN_STMTs, without -g where the
693 : : STATEMENT_LIST wouldn't be present at all the resulting
694 : : expression wouldn't have TREE_SIDE_EFFECTS set, so make sure
695 : : to clear it even on the STATEMENT_LIST in such cases. */
696 : 46946918 : hash_set<tree> *pset = (c_dialect_cxx ()
697 : 50534291 : ? nullptr
698 : : : static_cast<hash_set<tree> *>(data));
699 : 218278890 : for (i = tsi_start (stmt); !tsi_end_p (i); tsi_next (&i))
700 : : {
701 : 167744599 : tree t = tsi_stmt (i);
702 : 167744599 : if (TREE_CODE (t) != DEBUG_BEGIN_STMT && nondebug_stmts < 2)
703 : 78694415 : nondebug_stmts++;
704 : 167744599 : walk_tree_1 (tsi_stmt_ptr (i), func, data, pset, lh);
705 : 167744599 : if (TREE_CODE (t) != DEBUG_BEGIN_STMT
706 : 167744599 : && (nondebug_stmts > 1 || TREE_SIDE_EFFECTS (tsi_stmt (i))))
707 : : clear_side_effects = false;
708 : : }
709 : 50534291 : if (clear_side_effects)
710 : 375 : TREE_SIDE_EFFECTS (stmt) = 0;
711 : 50534291 : *walk_subtrees = 0;
712 : : }
713 : : break;
714 : :
715 : : default:
716 : : break;
717 : : }
718 : :
719 : 698624965 : return NULL;
720 : : }
721 : :
722 : :
723 : : /* Wrapper for c_genericize_control_stmt to allow it to be used as a walk_tree
724 : : callback. This is appropriate for C; C++ calls c_genericize_control_stmt
725 : : directly. */
726 : :
727 : : static tree
728 : 644942716 : c_genericize_control_r (tree *stmt_p, int *walk_subtrees, void *data)
729 : : {
730 : 644942716 : tree stmt = *stmt_p;
731 : : /* Mark stores to parts of complex automatic non-addressable
732 : : variables as DECL_NOT_GIMPLE_REG_P for -O0. This can't be
733 : : done during gimplification. See PR119120. */
734 : 644942716 : if (TREE_CODE (stmt) == MODIFY_EXPR
735 : 36631000 : && (TREE_CODE (TREE_OPERAND (stmt, 0)) == REALPART_EXPR
736 : 36629928 : || TREE_CODE (TREE_OPERAND (stmt, 0)) == IMAGPART_EXPR)
737 : 2156 : && !optimize
738 : 138 : && DECL_P (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0))
739 : 644942840 : && is_gimple_reg (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0)))
740 : 63 : DECL_NOT_GIMPLE_REG_P (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0)) = 1;
741 : :
742 : 644942716 : c_genericize_control_stmt (stmt_p, walk_subtrees, data,
743 : : c_genericize_control_r, NULL);
744 : 644942716 : return NULL;
745 : : }
746 : :
747 : : /* Convert the tree representation of FNDECL from C frontend trees to
748 : : GENERIC. */
749 : :
750 : : void
751 : 77462406 : c_genericize (tree fndecl)
752 : : {
753 : 77462406 : dump_file_info *dfi;
754 : 77462406 : FILE *dump_orig;
755 : 77462406 : dump_flags_t local_dump_flags;
756 : 77462406 : struct cgraph_node *cgn;
757 : :
758 : 77462406 : if (flag_sanitize & SANITIZE_BOUNDS)
759 : : {
760 : 66435 : hash_set<tree> pset;
761 : 66435 : walk_tree (&DECL_SAVED_TREE (fndecl), ubsan_walk_array_refs_r, &pset,
762 : : &pset);
763 : 66435 : }
764 : :
765 : : /* Genericize loops and other structured control constructs. The C++
766 : : front end has already done this in lang-specific code. */
767 : 77462406 : if (!c_dialect_cxx ())
768 : : {
769 : 35371913 : bc_state_t save_state;
770 : 35371913 : push_cfun (DECL_STRUCT_FUNCTION (fndecl));
771 : 35371913 : save_bc_state (&save_state);
772 : 35371913 : hash_set<tree> pset;
773 : 35371913 : walk_tree (&DECL_SAVED_TREE (fndecl), c_genericize_control_r, &pset,
774 : : &pset);
775 : 35371928 : delete bc_hash_map;
776 : 35371913 : bc_hash_map = NULL;
777 : 35371913 : restore_bc_state (&save_state);
778 : 35371913 : pop_cfun ();
779 : 35371913 : }
780 : :
781 : 77462406 : if (warn_duplicated_branches)
782 : 133 : walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
783 : : do_warn_duplicated_branches_r, NULL);
784 : :
785 : : /* Dump the C-specific tree IR. */
786 : 77462406 : dfi = g->get_dumps ()->get_dump_file_info (TDI_original);
787 : 77462406 : dump_orig = dfi->pstream;
788 : 77462406 : local_dump_flags = dfi->pflags;
789 : 77462406 : if (dump_orig)
790 : : {
791 : 5885 : fprintf (dump_orig, "\n;; Function %s",
792 : 5885 : lang_hooks.decl_printable_name (fndecl, 2));
793 : 5885 : fprintf (dump_orig, " (%s)\n",
794 : 5885 : (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
795 : 59 : : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
796 : 5885 : fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original));
797 : 5885 : fprintf (dump_orig, "\n");
798 : :
799 : 5885 : if (local_dump_flags & TDF_RAW)
800 : 1 : dump_node (DECL_SAVED_TREE (fndecl),
801 : : TDF_SLIM | local_dump_flags, dump_orig);
802 : : else
803 : 5884 : print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl), local_dump_flags);
804 : 5885 : fprintf (dump_orig, "\n");
805 : : }
806 : :
807 : : /* Dump all nested functions now. */
808 : 77462406 : cgn = cgraph_node::get_create (fndecl);
809 : 77463932 : for (cgn = first_nested_function (cgn);
810 : 77463932 : cgn; cgn = next_nested_function (cgn))
811 : 1526 : c_genericize (cgn->decl);
812 : 77462406 : }
813 : :
814 : : static void
815 : 0 : add_block_to_enclosing (tree block)
816 : : {
817 : 0 : unsigned i;
818 : 0 : tree enclosing;
819 : 0 : gbind *bind;
820 : 0 : vec<gbind *> stack = gimple_bind_expr_stack ();
821 : :
822 : 0 : FOR_EACH_VEC_ELT (stack, i, bind)
823 : 0 : if (gimple_bind_block (bind))
824 : : break;
825 : :
826 : 0 : enclosing = gimple_bind_block (bind);
827 : 0 : BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block);
828 : 0 : }
829 : :
830 : : /* Genericize a scope by creating a new BIND_EXPR.
831 : : BLOCK is either a BLOCK representing the scope or a chain of _DECLs.
832 : : In the latter case, we need to create a new BLOCK and add it to the
833 : : BLOCK_SUBBLOCKS of the enclosing block.
834 : : BODY is a chain of C _STMT nodes for the contents of the scope, to be
835 : : genericized. */
836 : :
837 : : tree
838 : 134654380 : c_build_bind_expr (location_t loc, tree block, tree body)
839 : : {
840 : 134654380 : tree decls, bind;
841 : :
842 : 134654380 : if (block == NULL_TREE)
843 : : decls = NULL_TREE;
844 : 58226947 : else if (TREE_CODE (block) == BLOCK)
845 : 58226947 : decls = BLOCK_VARS (block);
846 : : else
847 : : {
848 : 0 : decls = block;
849 : 0 : if (DECL_ARTIFICIAL (decls))
850 : : block = NULL_TREE;
851 : : else
852 : : {
853 : 0 : block = make_node (BLOCK);
854 : 0 : BLOCK_VARS (block) = decls;
855 : 0 : add_block_to_enclosing (block);
856 : : }
857 : : }
858 : :
859 : 134654380 : if (!body)
860 : 0 : body = build_empty_stmt (loc);
861 : 134654380 : if (decls || block)
862 : : {
863 : 58226947 : bind = build3 (BIND_EXPR, void_type_node, decls, body, block);
864 : 58226947 : TREE_SIDE_EFFECTS (bind) = 1;
865 : 58226947 : SET_EXPR_LOCATION (bind, loc);
866 : : }
867 : : else
868 : : bind = body;
869 : :
870 : 134654380 : return bind;
871 : : }
872 : :
873 : : /* Helper for c_gimplify_expr: test if target supports fma-like FN. */
874 : :
875 : : static bool
876 : 24 : fma_supported_p (enum internal_fn fn, tree type)
877 : : {
878 : 22 : return direct_internal_fn_supported_p (fn, type, OPTIMIZE_FOR_BOTH);
879 : : }
880 : :
881 : : /* Gimplification of expression trees. */
882 : :
883 : : /* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in
884 : : gimplify_expr. */
885 : :
886 : : int
887 : 265045188 : c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
888 : : gimple_seq *post_p ATTRIBUTE_UNUSED)
889 : : {
890 : 265045188 : enum tree_code code = TREE_CODE (*expr_p);
891 : :
892 : 265045188 : switch (code)
893 : : {
894 : 335943 : case LSHIFT_EXPR:
895 : 335943 : case RSHIFT_EXPR:
896 : 335943 : case LROTATE_EXPR:
897 : 335943 : case RROTATE_EXPR:
898 : 335943 : {
899 : : /* We used to convert the right operand of a shift-expression
900 : : to an integer_type_node in the FEs. But it is unnecessary
901 : : and not desirable for diagnostics and sanitizers. We keep
902 : : this here to not pessimize the code, but we convert to an
903 : : unsigned type, because negative shift counts are undefined
904 : : anyway.
905 : : We should get rid of this conversion when we have a proper
906 : : type demotion/promotion pass. */
907 : 335943 : tree *op1_p = &TREE_OPERAND (*expr_p, 1);
908 : 335943 : if (!error_operand_p (*op1_p)
909 : 335942 : && !VECTOR_TYPE_P (TREE_TYPE (*op1_p))
910 : 334226 : && !types_compatible_p (TYPE_MAIN_VARIANT (TREE_TYPE (*op1_p)),
911 : : unsigned_type_node)
912 : 631099 : && !types_compatible_p (TYPE_MAIN_VARIANT (TREE_TYPE (*op1_p)),
913 : : integer_type_node))
914 : : /* Make sure to unshare the result, tree sharing is invalid
915 : : during gimplification. */
916 : 13480 : *op1_p = unshare_expr (convert (unsigned_type_node, *op1_p));
917 : : break;
918 : : }
919 : :
920 : 1135934 : case PREINCREMENT_EXPR:
921 : 1135934 : case PREDECREMENT_EXPR:
922 : 1135934 : case POSTINCREMENT_EXPR:
923 : 1135934 : case POSTDECREMENT_EXPR:
924 : 1135934 : {
925 : 1135934 : tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 0));
926 : 1135934 : if (INTEGRAL_TYPE_P (type) && c_promoting_integer_type_p (type))
927 : : {
928 : 5975 : if (!TYPE_OVERFLOW_WRAPS (type))
929 : 3385 : type = unsigned_type_for (type);
930 : 5975 : return gimplify_self_mod_expr (expr_p, pre_p, post_p, 1, type);
931 : : }
932 : : break;
933 : : }
934 : :
935 : 7617698 : case PLUS_EXPR:
936 : 7617698 : case MINUS_EXPR:
937 : 7617698 : {
938 : 7617698 : tree type = TREE_TYPE (*expr_p);
939 : : /* For -ffp-contract=on we need to attempt FMA contraction only
940 : : during initial gimplification. Late contraction across statement
941 : : boundaries would violate language semantics. */
942 : 7617698 : if (SCALAR_FLOAT_TYPE_P (type)
943 : 956124 : && flag_fp_contract_mode == FP_CONTRACT_ON
944 : 22 : && cfun && !(cfun->curr_properties & PROP_gimple_any)
945 : 7617720 : && fma_supported_p (IFN_FMA, type))
946 : : {
947 : 22 : bool neg_mul = false, neg_add = code == MINUS_EXPR;
948 : :
949 : 22 : tree *op0_p = &TREE_OPERAND (*expr_p, 0);
950 : 22 : tree *op1_p = &TREE_OPERAND (*expr_p, 1);
951 : :
952 : : /* Look for ±(x * y) ± z, swapping operands if necessary. */
953 : 22 : if (TREE_CODE (*op0_p) == NEGATE_EXPR
954 : 22 : && TREE_CODE (TREE_OPERAND (*op0_p, 0)) == MULT_EXPR)
955 : : /* '*EXPR_P' is '-(x * y) ± z'. This is fine. */;
956 : 22 : else if (TREE_CODE (*op0_p) != MULT_EXPR)
957 : : {
958 : : std::swap (op0_p, op1_p);
959 : : std::swap (neg_mul, neg_add);
960 : : }
961 : 22 : if (TREE_CODE (*op0_p) == NEGATE_EXPR)
962 : : {
963 : 0 : op0_p = &TREE_OPERAND (*op0_p, 0);
964 : 0 : neg_mul = !neg_mul;
965 : : }
966 : 22 : if (TREE_CODE (*op0_p) != MULT_EXPR)
967 : : break;
968 : 12 : auto_vec<tree, 3> ops (3);
969 : 12 : ops.quick_push (TREE_OPERAND (*op0_p, 0));
970 : 12 : ops.quick_push (TREE_OPERAND (*op0_p, 1));
971 : 12 : ops.quick_push (*op1_p);
972 : :
973 : 12 : enum internal_fn ifn = IFN_FMA;
974 : 12 : if (neg_mul)
975 : : {
976 : 0 : if (fma_supported_p (IFN_FNMA, type))
977 : : ifn = IFN_FNMA;
978 : : else
979 : 0 : ops[0] = build1 (NEGATE_EXPR, type, ops[0]);
980 : : }
981 : 12 : if (neg_add)
982 : : {
983 : 2 : enum internal_fn ifn2 = ifn == IFN_FMA ? IFN_FMS : IFN_FNMS;
984 : 2 : if (fma_supported_p (ifn2, type))
985 : : ifn = ifn2;
986 : : else
987 : 0 : ops[2] = build1 (NEGATE_EXPR, type, ops[2]);
988 : : }
989 : : /* Avoid gimplify_arg: it emits all side effects into *PRE_P. */
990 : 72 : for (auto &&op : ops)
991 : 36 : if (gimplify_expr (&op, pre_p, post_p, is_gimple_val, fb_rvalue)
992 : : == GS_ERROR)
993 : : return GS_ERROR;
994 : :
995 : 12 : gcall *call = gimple_build_call_internal_vec (ifn, ops);
996 : 12 : gimple_seq_add_stmt_without_update (pre_p, call);
997 : 12 : *expr_p = create_tmp_var (type);
998 : 12 : gimple_call_set_lhs (call, *expr_p);
999 : 12 : return GS_ALL_DONE;
1000 : 12 : }
1001 : : break;
1002 : : }
1003 : :
1004 : 3725167 : case CALL_EXPR:
1005 : 3725167 : {
1006 : 3725167 : tree fndecl = get_callee_fndecl (*expr_p);
1007 : 3725167 : if (fndecl
1008 : 3475847 : && fndecl_built_in_p (fndecl, BUILT_IN_CLZG, BUILT_IN_CTZG)
1009 : 52 : && call_expr_nargs (*expr_p) == 2
1010 : 3725219 : && TREE_CODE (CALL_EXPR_ARG (*expr_p, 1)) != INTEGER_CST)
1011 : : {
1012 : 52 : tree a = save_expr (CALL_EXPR_ARG (*expr_p, 0));
1013 : 52 : tree c = build_call_expr_loc (EXPR_LOCATION (*expr_p),
1014 : : fndecl, 1, a);
1015 : 104 : *expr_p = build3_loc (EXPR_LOCATION (*expr_p), COND_EXPR,
1016 : : integer_type_node,
1017 : 52 : build2_loc (EXPR_LOCATION (*expr_p),
1018 : : NE_EXPR, boolean_type_node, a,
1019 : 52 : build_zero_cst (TREE_TYPE (a))),
1020 : 52 : c, CALL_EXPR_ARG (*expr_p, 1));
1021 : 52 : return GS_OK;
1022 : : }
1023 : : break;
1024 : : }
1025 : :
1026 : : default:;
1027 : : }
1028 : :
1029 : : return GS_UNHANDLED;
1030 : : }
|