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-2024 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
10This file is part of GCC.
11
12GCC is free software; you can redistribute it and/or modify it under
13the terms of the GNU General Public License as published by the Free
14Software Foundation; either version 3, or (at your option) any later
15version.
16
17GCC is distributed in the hope that it will be useful, but WITHOUT ANY
18WARRANTY; without even the implied warranty of MERCHANTABILITY or
19FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20for more details.
21
22You should have received a copy of the GNU General Public License
23along 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
47/* The gimplification pass converts the language-dependent trees
48 (ld-trees) emitted by the parser into language-independent trees
49 (li-trees) that are the target of SSA analysis and transformations.
50
51 Language-independent trees are based on the SIMPLE intermediate
52 representation used in the McCAT compiler framework:
53
54 "Designing the McCAT Compiler Based on a Family of Structured
55 Intermediate Representations,"
56 L. Hendren, C. Donawa, M. Emami, G. Gao, Justiani, and B. Sridharan,
57 Proceedings of the 5th International Workshop on Languages and
58 Compilers for Parallel Computing, no. 757 in Lecture Notes in
59 Computer Science, New Haven, Connecticut, pp. 406-420,
60 Springer-Verlag, August 3-5, 1992.
61
62 http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html
63
64 Basically, we walk down gimplifying the nodes that we encounter. As we
65 walk back up, we check that they fit our constraints, and copy them
66 into temporaries if not. */
67
68/* Callback for c_genericize. */
69
70static tree
71ubsan_walk_array_refs_r (tree *tp, int *walk_subtrees, void *data)
72{
73 hash_set<tree> *pset = (hash_set<tree> *) data;
74
75 if (TREE_CODE (*tp) == BIND_EXPR)
76 {
77 /* Since walk_tree doesn't call the callback function on the decls
78 in BIND_EXPR_VARS, we have to walk them manually, so we can avoid
79 instrumenting DECL_INITIAL of TREE_STATIC vars. */
80 *walk_subtrees = 0;
81 for (tree decl = BIND_EXPR_VARS (*tp); decl; decl = DECL_CHAIN (decl))
82 {
83 if (TREE_STATIC (decl))
84 continue;
85 walk_tree (&DECL_INITIAL (decl), ubsan_walk_array_refs_r, pset,
86 pset);
87 walk_tree (&DECL_SIZE (decl), ubsan_walk_array_refs_r, pset, pset);
88 walk_tree (&DECL_SIZE_UNIT (decl), ubsan_walk_array_refs_r, pset,
89 pset);
90 }
91 walk_tree (&BIND_EXPR_BODY (*tp), ubsan_walk_array_refs_r, pset, pset);
92 }
93 else if (TREE_CODE (*tp) == ADDR_EXPR
94 && TREE_CODE (TREE_OPERAND (*tp, 0)) == ARRAY_REF)
95 {
96 ubsan_maybe_instrument_array_ref (&TREE_OPERAND (*tp, 0), true);
97 /* Make sure ubsan_maybe_instrument_array_ref is not called again
98 on the ARRAY_REF, the above call might not instrument anything
99 as the index might be constant or masked, so ensure it is not
100 walked again and walk its subtrees manually. */
101 tree aref = TREE_OPERAND (*tp, 0);
102 pset->add (k: aref);
103 *walk_subtrees = 0;
104 walk_tree (&TREE_OPERAND (aref, 0), ubsan_walk_array_refs_r, pset, pset);
105 walk_tree (&TREE_OPERAND (aref, 1), ubsan_walk_array_refs_r, pset, pset);
106 walk_tree (&TREE_OPERAND (aref, 2), ubsan_walk_array_refs_r, pset, pset);
107 walk_tree (&TREE_OPERAND (aref, 3), ubsan_walk_array_refs_r, pset, pset);
108 }
109 else if (TREE_CODE (*tp) == ARRAY_REF)
110 ubsan_maybe_instrument_array_ref (tp, false);
111 else if (TREE_CODE (*tp) == MODIFY_EXPR)
112 {
113 /* Since r7-1900, we gimplify RHS before LHS. Consider
114 a[b] |= c;
115 wherein we can have a single shared tree a[b] in both LHS and RHS.
116 If we only instrument the LHS and the access is invalid, the program
117 could crash before emitting a UBSan error. So instrument the RHS
118 first. */
119 *walk_subtrees = 0;
120 walk_tree (&TREE_OPERAND (*tp, 1), ubsan_walk_array_refs_r, pset, pset);
121 walk_tree (&TREE_OPERAND (*tp, 0), ubsan_walk_array_refs_r, pset, pset);
122 }
123 return NULL_TREE;
124}
125
126/* Gimplification of statement trees. */
127
128/* Local declarations. */
129
130enum bc_t { bc_break = 0, bc_continue = 1 };
131
132/* Stack of labels which are targets for "break" or "continue",
133 linked through TREE_CHAIN. */
134static tree bc_label[2];
135
136/* Begin a scope which can be exited by a break or continue statement. BC
137 indicates which.
138
139 Just creates a label with location LOCATION and pushes it into the current
140 context. */
141
142static tree
143begin_bc_block (enum bc_t bc, location_t location)
144{
145 tree label = create_artificial_label (location);
146 DECL_CHAIN (label) = bc_label[bc];
147 bc_label[bc] = label;
148 if (bc == bc_break)
149 LABEL_DECL_BREAK (label) = true;
150 else
151 LABEL_DECL_CONTINUE (label) = true;
152 return label;
153}
154
155/* Finish a scope which can be exited by a break or continue statement.
156 LABEL was returned from the most recent call to begin_bc_block. BLOCK is
157 an expression for the contents of the scope.
158
159 If we saw a break (or continue) in the scope, append a LABEL_EXPR to
160 BLOCK. Otherwise, just forget the label. */
161
162static void
163finish_bc_block (tree *block, enum bc_t bc, tree label)
164{
165 gcc_assert (label == bc_label[bc]);
166
167 if (TREE_USED (label))
168 append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
169 block);
170
171 bc_label[bc] = DECL_CHAIN (label);
172 DECL_CHAIN (label) = NULL_TREE;
173}
174
175/* Allow saving and restoring break/continue state. */
176
177void
178save_bc_state (bc_state_t *state)
179{
180 state->bc_label[bc_break] = bc_label[bc_break];
181 state->bc_label[bc_continue] = bc_label[bc_continue];
182 bc_label[bc_break] = NULL_TREE;
183 bc_label[bc_continue] = NULL_TREE;
184}
185
186void
187restore_bc_state (bc_state_t *state)
188{
189 gcc_assert (bc_label[bc_break] == NULL);
190 gcc_assert (bc_label[bc_continue] == NULL);
191 bc_label[bc_break] = state->bc_label[bc_break];
192 bc_label[bc_continue] = state->bc_label[bc_continue];
193}
194
195/* Get the LABEL_EXPR to represent a break or continue statement
196 in the current block scope. BC indicates which. */
197
198static tree
199get_bc_label (enum bc_t bc)
200{
201 tree label = bc_label[bc];
202 gcc_assert (label);
203
204 /* Mark the label used for finish_bc_block. */
205 TREE_USED (label) = 1;
206 return label;
207}
208
209/* Return the location from EXPR, or OR_LOC if the former is unknown. */
210
211location_t
212expr_loc_or_loc (const_tree expr, location_t or_loc)
213{
214 tree t = CONST_CAST_TREE (expr);
215 location_t loc = UNKNOWN_LOCATION;
216 if (t)
217 loc = EXPR_LOCATION (t);
218 if (loc == UNKNOWN_LOCATION)
219 loc = or_loc;
220 return loc;
221}
222
223/* Build a generic representation of one of the C loop forms. COND is the
224 loop condition or NULL_TREE. BODY is the (possibly compound) statement
225 controlled by the loop. INCR is the increment expression of a for-loop,
226 or NULL_TREE. COND_IS_FIRST indicates whether the condition is
227 evaluated before the loop body as in while and for loops, or after the
228 loop body as in do-while loops. */
229
230static void
231genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
232 tree incr, bool cond_is_first, int *walk_subtrees,
233 void *data, walk_tree_fn func, walk_tree_lh lh)
234{
235 tree blab, clab;
236 tree entry = NULL, exit = NULL, t;
237 tree stmt_list = NULL;
238 location_t cond_locus = expr_loc_or_loc (expr: cond, or_loc: start_locus);
239 location_t incr_locus = expr_loc_or_loc (expr: incr, or_loc: start_locus);
240
241 protected_set_expr_location_if_unset (incr, start_locus);
242
243 walk_tree_1 (&cond, func, data, NULL, lh);
244 walk_tree_1 (&incr, func, data, NULL, lh);
245
246 blab = begin_bc_block (bc: bc_break, location: start_locus);
247 clab = begin_bc_block (bc: bc_continue, location: start_locus);
248
249 walk_tree_1 (&body, func, data, NULL, lh);
250 *walk_subtrees = 0;
251
252 /* If condition is zero don't generate a loop construct. */
253 if (cond && integer_zerop (cond))
254 {
255 if (cond_is_first)
256 {
257 t = build1_loc (loc: start_locus, code: GOTO_EXPR, void_type_node,
258 arg1: get_bc_label (bc: bc_break));
259 append_to_statement_list (t, &stmt_list);
260 }
261 }
262 else
263 {
264 /* Expand to gotos. */
265 tree top = build1 (LABEL_EXPR, void_type_node,
266 create_artificial_label (start_locus));
267
268 /* If we have an exit condition, then we build an IF with gotos either
269 out of the loop, or to the top of it. If there's no exit condition,
270 then we just build a jump back to the top. */
271 exit = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top));
272
273 if (cond && !integer_nonzerop (cond))
274 {
275 /* Canonicalize the loop condition to the end. This means
276 generating a branch to the loop condition. Reuse the
277 continue label, if there is no incr expression. */
278 if (cond_is_first)
279 {
280 if (incr)
281 {
282 entry = build1 (LABEL_EXPR, void_type_node,
283 create_artificial_label (start_locus));
284 t = build1_loc (loc: start_locus, code: GOTO_EXPR, void_type_node,
285 LABEL_EXPR_LABEL (entry));
286 }
287 else
288 t = build1_loc (loc: start_locus, code: GOTO_EXPR, void_type_node,
289 arg1: get_bc_label (bc: bc_continue));
290 append_to_statement_list (t, &stmt_list);
291 }
292
293 t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc: bc_break));
294 exit = fold_build3_loc (cond_locus,
295 COND_EXPR, void_type_node, cond, exit, t);
296 }
297 else
298 {
299 /* For the backward-goto's location of an unconditional loop
300 use the beginning of the body, or, if there is none, the
301 top of the loop. */
302 location_t loc = expr_loc_or_loc (expr: expr_first (body),
303 or_loc: start_locus);
304 SET_EXPR_LOCATION (exit, loc);
305 }
306 append_to_statement_list (top, &stmt_list);
307 }
308
309 append_to_statement_list (body, &stmt_list);
310 if (c_dialect_cxx ()
311 && stmt_list
312 && TREE_CODE (stmt_list) == STATEMENT_LIST)
313 {
314 tree_stmt_iterator tsi = tsi_last (t: stmt_list);
315 if (!tsi_end_p (i: tsi))
316 {
317 tree t = *tsi;
318 while (TREE_CODE (t) == CLEANUP_POINT_EXPR
319 || TREE_CODE (t) == EXPR_STMT
320 || CONVERT_EXPR_CODE_P (TREE_CODE (t)))
321 t = TREE_OPERAND (t, 0);
322 /* For C++, if iteration statement body ends with fallthrough
323 statement, mark it such that we diagnose it even if next
324 statement would be labeled statement with case/default label. */
325 if (TREE_CODE (t) == CALL_EXPR
326 && !CALL_EXPR_FN (t)
327 && CALL_EXPR_IFN (t) == IFN_FALLTHROUGH)
328 TREE_NOTHROW (t) = 1;
329 }
330 }
331 finish_bc_block (block: &stmt_list, bc: bc_continue, label: clab);
332 if (incr)
333 {
334 if (MAY_HAVE_DEBUG_MARKER_STMTS && incr_locus != UNKNOWN_LOCATION)
335 {
336 tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
337 SET_EXPR_LOCATION (d, expr_loc_or_loc (incr, start_locus));
338 append_to_statement_list (d, &stmt_list);
339 }
340 append_to_statement_list (incr, &stmt_list);
341 }
342 append_to_statement_list (entry, &stmt_list);
343
344 if (MAY_HAVE_DEBUG_MARKER_STMTS && cond_locus != UNKNOWN_LOCATION)
345 {
346 tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
347 SET_EXPR_LOCATION (d, cond_locus);
348 append_to_statement_list (d, &stmt_list);
349 }
350 append_to_statement_list (exit, &stmt_list);
351 finish_bc_block (block: &stmt_list, bc: bc_break, label: blab);
352 if (!stmt_list)
353 stmt_list = build_empty_stmt (start_locus);
354
355 *stmt_p = stmt_list;
356}
357
358/* Genericize a FOR_STMT node *STMT_P. */
359
360static void
361genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data,
362 walk_tree_fn func, walk_tree_lh lh)
363{
364 tree stmt = *stmt_p;
365 tree expr = NULL;
366 tree loop;
367 tree init = FOR_INIT_STMT (stmt);
368
369 if (init)
370 {
371 walk_tree_1 (&init, func, data, NULL, lh);
372 append_to_statement_list (init, &expr);
373 }
374
375 genericize_c_loop (stmt_p: &loop, EXPR_LOCATION (stmt), FOR_COND (stmt),
376 FOR_BODY (stmt), FOR_EXPR (stmt), cond_is_first: 1, walk_subtrees,
377 data, func, lh);
378 append_to_statement_list (loop, &expr);
379 if (expr == NULL_TREE)
380 expr = loop;
381 *stmt_p = expr;
382}
383
384/* Genericize a WHILE_STMT node *STMT_P. */
385
386static void
387genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data,
388 walk_tree_fn func, walk_tree_lh lh)
389{
390 tree stmt = *stmt_p;
391 genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt),
392 WHILE_BODY (stmt), NULL_TREE, cond_is_first: 1, walk_subtrees,
393 data, func, lh);
394}
395
396/* Genericize a DO_STMT node *STMT_P. */
397
398static void
399genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data,
400 walk_tree_fn func, walk_tree_lh lh)
401{
402 tree stmt = *stmt_p;
403 genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt),
404 DO_BODY (stmt), NULL_TREE, cond_is_first: 0, walk_subtrees,
405 data, func, lh);
406}
407
408/* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */
409
410static void
411genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data,
412 walk_tree_fn func, walk_tree_lh lh)
413{
414 tree stmt = *stmt_p;
415 tree break_block, body, cond, type;
416 location_t stmt_locus = EXPR_LOCATION (stmt);
417
418 body = SWITCH_STMT_BODY (stmt);
419 if (!body)
420 body = build_empty_stmt (stmt_locus);
421 cond = SWITCH_STMT_COND (stmt);
422 type = SWITCH_STMT_TYPE (stmt);
423
424 walk_tree_1 (&cond, func, data, NULL, lh);
425
426 break_block = begin_bc_block (bc: bc_break, location: stmt_locus);
427
428 walk_tree_1 (&body, func, data, NULL, lh);
429 walk_tree_1 (&type, func, data, NULL, lh);
430 *walk_subtrees = 0;
431
432 if (TREE_USED (break_block))
433 SWITCH_BREAK_LABEL_P (break_block) = 1;
434 finish_bc_block (block: &body, bc: bc_break, label: break_block);
435 *stmt_p = build2_loc (loc: stmt_locus, code: SWITCH_EXPR, type, arg0: cond, arg1: body);
436 SWITCH_ALL_CASES_P (*stmt_p) = SWITCH_STMT_ALL_CASES_P (stmt);
437 gcc_checking_assert (!SWITCH_STMT_NO_BREAK_P (stmt)
438 || !TREE_USED (break_block));
439}
440
441/* Genericize a CONTINUE_STMT node *STMT_P. */
442
443static void
444genericize_continue_stmt (tree *stmt_p)
445{
446 tree stmt_list = NULL;
447 tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN);
448 tree label = get_bc_label (bc: bc_continue);
449 location_t location = EXPR_LOCATION (*stmt_p);
450 tree jump = build1_loc (loc: location, code: GOTO_EXPR, void_type_node, arg1: label);
451 append_to_statement_list_force (pred, &stmt_list);
452 append_to_statement_list (jump, &stmt_list);
453 *stmt_p = stmt_list;
454}
455
456/* Genericize a BREAK_STMT node *STMT_P. */
457
458static void
459genericize_break_stmt (tree *stmt_p)
460{
461 tree label = get_bc_label (bc: bc_break);
462 location_t location = EXPR_LOCATION (*stmt_p);
463 *stmt_p = build1_loc (loc: location, code: GOTO_EXPR, void_type_node, arg1: label);
464}
465
466/* Genericize a OMP_FOR node *STMT_P. */
467
468static void
469genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data,
470 walk_tree_fn func, walk_tree_lh lh)
471{
472 tree stmt = *stmt_p;
473 location_t locus = EXPR_LOCATION (stmt);
474 tree clab = begin_bc_block (bc: bc_continue, location: locus);
475
476 walk_tree_1 (&OMP_FOR_BODY (stmt), func, data, NULL, lh);
477 if (TREE_CODE (stmt) != OMP_TASKLOOP)
478 walk_tree_1 (&OMP_FOR_CLAUSES (stmt), func, data, NULL, lh);
479 walk_tree_1 (&OMP_FOR_INIT (stmt), func, data, NULL, lh);
480 walk_tree_1 (&OMP_FOR_COND (stmt), func, data, NULL, lh);
481 walk_tree_1 (&OMP_FOR_INCR (stmt), func, data, NULL, lh);
482 walk_tree_1 (&OMP_FOR_PRE_BODY (stmt), func, data, NULL, lh);
483 *walk_subtrees = 0;
484
485 finish_bc_block (block: &OMP_FOR_BODY (stmt), bc: bc_continue, label: clab);
486}
487
488
489/* Lower structured control flow tree nodes, such as loops. The
490 STMT_P, WALK_SUBTREES, and DATA arguments are as for the walk_tree_fn
491 type. FUNC and LH are language-specific functions passed to walk_tree_1
492 for node visiting and traversal, respectively; they are used to do
493 subtree processing in a language-dependent way. */
494
495tree
496c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, void *data,
497 walk_tree_fn func, walk_tree_lh lh)
498{
499 tree stmt = *stmt_p;
500
501 switch (TREE_CODE (stmt))
502 {
503 case FOR_STMT:
504 genericize_for_stmt (stmt_p, walk_subtrees, data, func, lh);
505 break;
506
507 case WHILE_STMT:
508 genericize_while_stmt (stmt_p, walk_subtrees, data, func, lh);
509 break;
510
511 case DO_STMT:
512 genericize_do_stmt (stmt_p, walk_subtrees, data, func, lh);
513 break;
514
515 case SWITCH_STMT:
516 genericize_switch_stmt (stmt_p, walk_subtrees, data, func, lh);
517 break;
518
519 case CONTINUE_STMT:
520 genericize_continue_stmt (stmt_p);
521 break;
522
523 case BREAK_STMT:
524 genericize_break_stmt (stmt_p);
525 break;
526
527 case OMP_FOR:
528 case OMP_SIMD:
529 case OMP_DISTRIBUTE:
530 case OMP_LOOP:
531 case OMP_TASKLOOP:
532 case OACC_LOOP:
533 genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh);
534 break;
535
536 case STATEMENT_LIST:
537 if (TREE_SIDE_EFFECTS (stmt))
538 {
539 tree_stmt_iterator i;
540 int nondebug_stmts = 0;
541 bool clear_side_effects = true;
542 /* Genericization can clear TREE_SIDE_EFFECTS, e.g. when
543 transforming an IF_STMT into COND_EXPR. If such stmt
544 appears in a STATEMENT_LIST that contains only that
545 stmt and some DEBUG_BEGIN_STMTs, without -g where the
546 STATEMENT_LIST wouldn't be present at all the resulting
547 expression wouldn't have TREE_SIDE_EFFECTS set, so make sure
548 to clear it even on the STATEMENT_LIST in such cases. */
549 hash_set<tree> *pset = (c_dialect_cxx ()
550 ? nullptr
551 : static_cast<hash_set<tree> *>(data));
552 for (i = tsi_start (t: stmt); !tsi_end_p (i); tsi_next (i: &i))
553 {
554 tree t = tsi_stmt (i);
555 if (TREE_CODE (t) != DEBUG_BEGIN_STMT && nondebug_stmts < 2)
556 nondebug_stmts++;
557 walk_tree_1 (tsi_stmt_ptr (i), func, data, pset, lh);
558 if (TREE_CODE (t) != DEBUG_BEGIN_STMT
559 && (nondebug_stmts > 1 || TREE_SIDE_EFFECTS (tsi_stmt (i))))
560 clear_side_effects = false;
561 }
562 if (clear_side_effects)
563 TREE_SIDE_EFFECTS (stmt) = 0;
564 *walk_subtrees = 0;
565 }
566 break;
567
568 default:
569 break;
570 }
571
572 return NULL;
573}
574
575
576/* Wrapper for c_genericize_control_stmt to allow it to be used as a walk_tree
577 callback. This is appropriate for C; C++ calls c_genericize_control_stmt
578 directly. */
579
580static tree
581c_genericize_control_r (tree *stmt_p, int *walk_subtrees, void *data)
582{
583 c_genericize_control_stmt (stmt_p, walk_subtrees, data,
584 func: c_genericize_control_r, NULL);
585 return NULL;
586}
587
588/* Convert the tree representation of FNDECL from C frontend trees to
589 GENERIC. */
590
591void
592c_genericize (tree fndecl)
593{
594 dump_file_info *dfi;
595 FILE *dump_orig;
596 dump_flags_t local_dump_flags;
597 struct cgraph_node *cgn;
598
599 if (flag_sanitize & SANITIZE_BOUNDS)
600 {
601 hash_set<tree> pset;
602 walk_tree (&DECL_SAVED_TREE (fndecl), ubsan_walk_array_refs_r, &pset,
603 &pset);
604 }
605
606 /* Genericize loops and other structured control constructs. The C++
607 front end has already done this in lang-specific code. */
608 if (!c_dialect_cxx ())
609 {
610 bc_state_t save_state;
611 push_cfun (DECL_STRUCT_FUNCTION (fndecl));
612 save_bc_state (state: &save_state);
613 hash_set<tree> pset;
614 walk_tree (&DECL_SAVED_TREE (fndecl), c_genericize_control_r, &pset,
615 &pset);
616 restore_bc_state (state: &save_state);
617 pop_cfun ();
618 }
619
620 if (warn_duplicated_branches)
621 walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
622 do_warn_duplicated_branches_r, NULL);
623
624 /* Dump the C-specific tree IR. */
625 dfi = g->get_dumps ()->get_dump_file_info (phase: TDI_original);
626 dump_orig = dfi->pstream;
627 local_dump_flags = dfi->pflags;
628 if (dump_orig)
629 {
630 fprintf (stream: dump_orig, format: "\n;; Function %s",
631 lang_hooks.decl_printable_name (fndecl, 2));
632 fprintf (stream: dump_orig, format: " (%s)\n",
633 (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
634 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
635 fprintf (stream: dump_orig, format: ";; enabled by -%s\n", dump_flag_name (TDI_original));
636 fprintf (stream: dump_orig, format: "\n");
637
638 if (local_dump_flags & TDF_RAW)
639 dump_node (DECL_SAVED_TREE (fndecl),
640 TDF_SLIM | local_dump_flags, dump_orig);
641 else
642 print_c_tree (file: dump_orig, DECL_SAVED_TREE (fndecl));
643 fprintf (stream: dump_orig, format: "\n");
644 }
645
646 /* Dump all nested functions now. */
647 cgn = cgraph_node::get_create (fndecl);
648 for (cgn = first_nested_function (node: cgn);
649 cgn; cgn = next_nested_function (node: cgn))
650 c_genericize (fndecl: cgn->decl);
651}
652
653static void
654add_block_to_enclosing (tree block)
655{
656 unsigned i;
657 tree enclosing;
658 gbind *bind;
659 vec<gbind *> stack = gimple_bind_expr_stack ();
660
661 FOR_EACH_VEC_ELT (stack, i, bind)
662 if (gimple_bind_block (bind_stmt: bind))
663 break;
664
665 enclosing = gimple_bind_block (bind_stmt: bind);
666 BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block);
667}
668
669/* Genericize a scope by creating a new BIND_EXPR.
670 BLOCK is either a BLOCK representing the scope or a chain of _DECLs.
671 In the latter case, we need to create a new BLOCK and add it to the
672 BLOCK_SUBBLOCKS of the enclosing block.
673 BODY is a chain of C _STMT nodes for the contents of the scope, to be
674 genericized. */
675
676tree
677c_build_bind_expr (location_t loc, tree block, tree body)
678{
679 tree decls, bind;
680
681 if (block == NULL_TREE)
682 decls = NULL_TREE;
683 else if (TREE_CODE (block) == BLOCK)
684 decls = BLOCK_VARS (block);
685 else
686 {
687 decls = block;
688 if (DECL_ARTIFICIAL (decls))
689 block = NULL_TREE;
690 else
691 {
692 block = make_node (BLOCK);
693 BLOCK_VARS (block) = decls;
694 add_block_to_enclosing (block);
695 }
696 }
697
698 if (!body)
699 body = build_empty_stmt (loc);
700 if (decls || block)
701 {
702 bind = build3 (BIND_EXPR, void_type_node, decls, body, block);
703 TREE_SIDE_EFFECTS (bind) = 1;
704 SET_EXPR_LOCATION (bind, loc);
705 }
706 else
707 bind = body;
708
709 return bind;
710}
711
712/* Helper for c_gimplify_expr: test if target supports fma-like FN. */
713
714static bool
715fma_supported_p (enum internal_fn fn, tree type)
716{
717 return direct_internal_fn_supported_p (fn, type, OPTIMIZE_FOR_BOTH);
718}
719
720/* Gimplification of expression trees. */
721
722/* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in
723 gimplify_expr. */
724
725int
726c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
727 gimple_seq *post_p ATTRIBUTE_UNUSED)
728{
729 enum tree_code code = TREE_CODE (*expr_p);
730
731 switch (code)
732 {
733 case LSHIFT_EXPR:
734 case RSHIFT_EXPR:
735 case LROTATE_EXPR:
736 case RROTATE_EXPR:
737 {
738 /* We used to convert the right operand of a shift-expression
739 to an integer_type_node in the FEs. But it is unnecessary
740 and not desirable for diagnostics and sanitizers. We keep
741 this here to not pessimize the code, but we convert to an
742 unsigned type, because negative shift counts are undefined
743 anyway.
744 We should get rid of this conversion when we have a proper
745 type demotion/promotion pass. */
746 tree *op1_p = &TREE_OPERAND (*expr_p, 1);
747 if (!VECTOR_TYPE_P (TREE_TYPE (*op1_p))
748 && !types_compatible_p (TYPE_MAIN_VARIANT (TREE_TYPE (*op1_p)),
749 unsigned_type_node)
750 && !types_compatible_p (TYPE_MAIN_VARIANT (TREE_TYPE (*op1_p)),
751 integer_type_node))
752 /* Make sure to unshare the result, tree sharing is invalid
753 during gimplification. */
754 *op1_p = unshare_expr (convert (unsigned_type_node, *op1_p));
755 break;
756 }
757
758 case PREINCREMENT_EXPR:
759 case PREDECREMENT_EXPR:
760 case POSTINCREMENT_EXPR:
761 case POSTDECREMENT_EXPR:
762 {
763 tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 0));
764 if (INTEGRAL_TYPE_P (type) && c_promoting_integer_type_p (type))
765 {
766 if (!TYPE_OVERFLOW_WRAPS (type))
767 type = unsigned_type_for (type);
768 return gimplify_self_mod_expr (expr_p, pre_p, post_p, 1, type);
769 }
770 break;
771 }
772
773 case PLUS_EXPR:
774 case MINUS_EXPR:
775 {
776 tree type = TREE_TYPE (*expr_p);
777 /* For -ffp-contract=on we need to attempt FMA contraction only
778 during initial gimplification. Late contraction across statement
779 boundaries would violate language semantics. */
780 if (SCALAR_FLOAT_TYPE_P (type)
781 && flag_fp_contract_mode == FP_CONTRACT_ON
782 && cfun && !(cfun->curr_properties & PROP_gimple_any)
783 && fma_supported_p (fn: IFN_FMA, type))
784 {
785 bool neg_mul = false, neg_add = code == MINUS_EXPR;
786
787 tree *op0_p = &TREE_OPERAND (*expr_p, 0);
788 tree *op1_p = &TREE_OPERAND (*expr_p, 1);
789
790 /* Look for ±(x * y) ± z, swapping operands if necessary. */
791 if (TREE_CODE (*op0_p) == NEGATE_EXPR
792 && TREE_CODE (TREE_OPERAND (*op0_p, 0)) == MULT_EXPR)
793 /* '*EXPR_P' is '-(x * y) ± z'. This is fine. */;
794 else if (TREE_CODE (*op0_p) != MULT_EXPR)
795 {
796 std::swap (a&: op0_p, b&: op1_p);
797 std::swap (a&: neg_mul, b&: neg_add);
798 }
799 if (TREE_CODE (*op0_p) == NEGATE_EXPR)
800 {
801 op0_p = &TREE_OPERAND (*op0_p, 0);
802 neg_mul = !neg_mul;
803 }
804 if (TREE_CODE (*op0_p) != MULT_EXPR)
805 break;
806 auto_vec<tree, 3> ops (3);
807 ops.quick_push (TREE_OPERAND (*op0_p, 0));
808 ops.quick_push (TREE_OPERAND (*op0_p, 1));
809 ops.quick_push (obj: *op1_p);
810
811 enum internal_fn ifn = IFN_FMA;
812 if (neg_mul)
813 {
814 if (fma_supported_p (fn: IFN_FNMA, type))
815 ifn = IFN_FNMA;
816 else
817 ops[0] = build1 (NEGATE_EXPR, type, ops[0]);
818 }
819 if (neg_add)
820 {
821 enum internal_fn ifn2 = ifn == IFN_FMA ? IFN_FMS : IFN_FNMS;
822 if (fma_supported_p (fn: ifn2, type))
823 ifn = ifn2;
824 else
825 ops[2] = build1 (NEGATE_EXPR, type, ops[2]);
826 }
827 /* Avoid gimplify_arg: it emits all side effects into *PRE_P. */
828 for (auto &&op : ops)
829 if (gimplify_expr (&op, pre_p, post_p, is_gimple_val, fb_rvalue)
830 == GS_ERROR)
831 return GS_ERROR;
832
833 gcall *call = gimple_build_call_internal_vec (ifn, ops);
834 gimple_seq_add_stmt_without_update (pre_p, call);
835 *expr_p = create_tmp_var (type);
836 gimple_call_set_lhs (gs: call, lhs: *expr_p);
837 return GS_ALL_DONE;
838 }
839 break;
840 }
841
842 case CALL_EXPR:
843 {
844 tree fndecl = get_callee_fndecl (*expr_p);
845 if (fndecl
846 && fndecl_built_in_p (node: fndecl, name1: BUILT_IN_CLZG, names: BUILT_IN_CTZG)
847 && call_expr_nargs (*expr_p) == 2
848 && TREE_CODE (CALL_EXPR_ARG (*expr_p, 1)) != INTEGER_CST)
849 {
850 tree a = save_expr (CALL_EXPR_ARG (*expr_p, 0));
851 tree c = build_call_expr_loc (EXPR_LOCATION (*expr_p),
852 fndecl, 1, a);
853 *expr_p = build3_loc (EXPR_LOCATION (*expr_p), code: COND_EXPR,
854 integer_type_node,
855 arg0: build2_loc (EXPR_LOCATION (*expr_p),
856 code: NE_EXPR, boolean_type_node, arg0: a,
857 arg1: build_zero_cst (TREE_TYPE (a))),
858 arg1: c, CALL_EXPR_ARG (*expr_p, 1));
859 return GS_OK;
860 }
861 break;
862 }
863
864 default:;
865 }
866
867 return GS_UNHANDLED;
868}
869

source code of gcc/c-family/c-gimplify.cc