tree-optimization/112450 - avoid AVX512 style masking for BImode masks
[official-gcc.git] / gcc / d / toir.cc
blobf87e094afcaa88d7ef7239d2d55a0f8b3661fb4e
1 /* toir.cc -- Lower D frontend statements to GCC trees.
2 Copyright (C) 2006-2023 Free Software Foundation, Inc.
4 GCC is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
9 GCC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with GCC; see the file COPYING3. If not see
16 <http://www.gnu.org/licenses/>. */
18 #include "config.h"
19 #include "system.h"
20 #include "coretypes.h"
22 #include "dmd/aggregate.h"
23 #include "dmd/declaration.h"
24 #include "dmd/expression.h"
25 #include "dmd/identifier.h"
26 #include "dmd/init.h"
27 #include "dmd/statement.h"
29 #include "tree.h"
30 #include "tree-iterator.h"
31 #include "options.h"
32 #include "stmt.h"
33 #include "fold-const.h"
34 #include "diagnostic.h"
35 #include "stringpool.h"
36 #include "function.h"
37 #include "toplev.h"
39 #include "d-tree.h"
42 /* Update data for defined and undefined labels when leaving a scope. */
44 bool
45 pop_binding_label (Statement * const &, d_label_entry *ent, binding_level *bl)
47 binding_level *obl = bl->level_chain;
49 if (ent->level == bl)
51 if (bl->kind == level_try)
52 ent->in_try_scope = true;
53 else if (bl->kind == level_catch)
54 ent->in_catch_scope = true;
56 ent->level = obl;
58 else if (ent->fwdrefs)
60 for (d_label_use_entry *ref = ent->fwdrefs; ref; ref = ref->next)
61 ref->level = obl;
64 return true;
67 /* At the end of a function, all labels declared within the function
68 go out of scope. Queue them in LABELS. */
70 bool
71 pop_label (Statement * const &, d_label_entry *ent, vec <tree> &labels)
73 if (!ent->bc_label)
75 /* Put the labels into the "variables" of the top-level block,
76 so debugger can see them. */
77 if (DECL_NAME (ent->label))
79 gcc_assert (DECL_INITIAL (ent->label) != NULL_TREE);
80 labels.safe_push (ent->label);
84 return true;
87 /* The D front-end does not use the 'binding level' system for a symbol table,
88 however it has been the goto structure for tracking code flow.
89 Primarily it is only needed to get debugging information for local variables
90 and otherwise support the back-end. */
92 void
93 push_binding_level (level_kind kind)
95 /* Add it to the front of currently active scopes stack. */
96 binding_level *new_level = ggc_cleared_alloc <binding_level> ();
97 new_level->level_chain = current_binding_level;
98 new_level->kind = kind;
100 current_binding_level = new_level;
103 static int
104 cmp_labels (const void *p1, const void *p2)
106 const tree *l1 = (const tree *) p1;
107 const tree *l2 = (const tree *) p2;
108 return DECL_UID (*l1) - DECL_UID (*l2);
111 tree
112 pop_binding_level (void)
114 binding_level *level = current_binding_level;
115 current_binding_level = level->level_chain;
117 tree block = make_node (BLOCK);
118 BLOCK_VARS (block) = level->names;
119 BLOCK_SUBBLOCKS (block) = level->blocks;
121 /* In each subblock, record that this is its superior. */
122 for (tree t = level->blocks; t; t = BLOCK_CHAIN (t))
123 BLOCK_SUPERCONTEXT (t) = block;
125 if (level->kind == level_function)
127 /* Dispose of the block that we just made inside some higher level. */
128 DECL_INITIAL (current_function_decl) = block;
129 BLOCK_SUPERCONTEXT (block) = current_function_decl;
131 /* Pop all the labels declared in the function. */
132 if (d_function_chain->labels)
134 auto_vec <tree> labels;
135 d_function_chain->labels->traverse <vec <tree> &,
136 &pop_label> (labels);
137 d_function_chain->labels->empty ();
138 labels.qsort (cmp_labels);
139 for (unsigned i = 0; i < labels.length (); ++i)
141 DECL_CHAIN (labels[i]) = BLOCK_VARS (block);
142 BLOCK_VARS (block) = labels[i];
146 else
148 /* Any uses of undefined labels, and any defined labels, now operate
149 under constraints of next binding contour. */
150 if (d_function_chain && d_function_chain->labels)
152 language_function *f = d_function_chain;
153 f->labels->traverse <binding_level *, &pop_binding_label> (level);
156 current_binding_level->blocks
157 = block_chainon (current_binding_level->blocks, block);
160 TREE_USED (block) = 1;
161 return block;
164 /* Create an empty statement tree rooted at T. */
166 void
167 push_stmt_list (void)
169 tree t = alloc_stmt_list ();
170 vec_safe_push (d_function_chain->stmt_list, t);
171 d_keep (t);
174 /* Finish the statement tree rooted at T. */
176 tree
177 pop_stmt_list (void)
179 tree t = d_function_chain->stmt_list->pop ();
181 /* If the statement list is completely empty, just return it. This is just
182 as good as build_empty_stmt, with the advantage that statement lists
183 are merged when they are appended to one another. So using the
184 STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P statements. */
185 if (TREE_SIDE_EFFECTS (t))
187 /* If the statement list contained exactly one statement, then extract
188 it immediately. */
189 tree_stmt_iterator i = tsi_start (t);
191 if (tsi_one_before_end_p (i))
193 tree u = tsi_stmt (i);
194 tsi_delink (&i);
195 free_stmt_list (t);
196 t = u;
200 return t;
203 /* T is an expression statement. Add it to the statement-tree. */
205 void
206 add_stmt (tree t)
208 /* Ignore (void) 0; expression statements received from the frontend.
209 Likewise void_node is used when contracts become nops in release code. */
210 if (t == void_node || IS_EMPTY_STMT (t))
211 return;
213 /* At this point, we no longer care about the value of expressions,
214 so if there's no side-effects, then don't add it. */
215 if (!TREE_SIDE_EFFECTS (t))
216 return;
218 /* If a call expression has no side effects, and there's no explicit
219 `cast(void)', then issue a warning about the unused return value. */
220 if (TREE_CODE (t) == INDIRECT_REF)
222 t = TREE_OPERAND (t, 0);
224 if (TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
225 warning (OPT_Wunused_value, "value computed is not used");
228 if (TREE_CODE (t) == CALL_EXPR && CALL_EXPR_FN (t) != NULL_TREE
229 && CALL_EXPR_WARN_IF_UNUSED (t))
231 tree callee = CALL_EXPR_FN (t);
233 /* It's a call to a function or function pointer. */
234 if (TREE_CODE (callee) == ADDR_EXPR
235 && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (callee, 0)))
236 callee = TREE_OPERAND (callee, 0);
238 /* It's a call to a delegate object. */
239 if (TREE_CODE (callee) == COMPONENT_REF
240 && TREE_CODE (TREE_TYPE (TREE_OPERAND (callee, 0))) == RECORD_TYPE
241 && TYPE_DELEGATE (TREE_TYPE (TREE_OPERAND (callee, 0))))
242 callee = TREE_OPERAND (callee, 0);
244 warning (OPT_Wunused_value,
245 "calling %qE without side effects discards return value "
246 "of type %qT; prepend a %<cast(void)%> if intentional",
247 callee, TREE_TYPE (t));
250 if (TREE_CODE (t) == COMPOUND_EXPR)
252 /* Push out each comma expressions as separate statements. */
253 add_stmt (TREE_OPERAND (t, 0));
254 add_stmt (TREE_OPERAND (t, 1));
256 else
258 /* Force the type to be void so we don't need to create a temporary
259 variable to hold the inner expression. */
260 if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
261 TREE_TYPE (t) = void_type_node;
263 /* Append the expression to the statement list.
264 Make sure it has a proper location. */
265 if (EXPR_P (t) && !EXPR_HAS_LOCATION (t))
266 SET_EXPR_LOCATION (t, input_location);
268 tree stmt_list = d_function_chain->stmt_list->last ();
269 append_to_statement_list_force (t, &stmt_list);
273 /* Implements the visitor interface to build the GCC trees of all Statement
274 AST classes emitted from the D Front-end.
275 All visit methods accept one parameter S, which holds the frontend AST
276 of the statement to compile. They also don't return any value, instead
277 generated code are pushed to add_stmt(), which appends them to the
278 statement list in the current_binding_level. */
280 class IRVisitor : public Visitor
282 using Visitor::visit;
284 FuncDeclaration *func_;
286 /* Stack of labels which are targets for "break" and "continue",
287 linked through TREE_CHAIN. */
288 tree break_label_;
289 tree continue_label_;
291 public:
292 IRVisitor (FuncDeclaration *fd)
294 this->func_ = fd;
295 this->break_label_ = NULL_TREE;
296 this->continue_label_ = NULL_TREE;
299 /* Helper for generating code for the statement AST class S.
300 Sets up the location of the statement before lowering. */
302 void build_stmt (Statement *s)
304 location_t saved_location = input_location;
305 input_location = make_location_t (s->loc);
306 s->accept (this);
307 input_location = saved_location;
310 /* Start a new scope for a KIND statement.
311 Each user-declared variable will have a binding contour that begins
312 where the variable is declared and ends at its containing scope. */
314 void start_scope (level_kind kind)
316 push_binding_level (kind);
317 push_stmt_list ();
320 /* Leave scope pushed by start_scope, returning a new bind_expr if
321 any variables where declared in the scope. */
323 tree end_scope (void)
325 tree block = pop_binding_level ();
326 tree body = pop_stmt_list ();
328 if (!BLOCK_VARS (block))
329 return body;
331 tree bind = build3 (BIND_EXPR, void_type_node,
332 BLOCK_VARS (block), body, block);
333 TREE_SIDE_EFFECTS (bind) = 1;
334 return bind;
337 /* Like end_scope, but also push it into the outer statement-tree. */
339 void finish_scope (void)
341 tree scope = this->end_scope ();
342 add_stmt (scope);
345 /* Return TRUE if IDENT is the current function return label. */
347 bool is_return_label (Identifier *ident)
349 if (this->func_->returnLabel)
350 return this->func_->returnLabel->ident == ident;
352 return false;
355 /* Define a label, specifying the location in the source file.
356 Return the LABEL_DECL node for the label. */
358 tree define_label (Statement *s, Identifier *ident = NULL)
360 tree label = this->lookup_label (s, ident);
361 gcc_assert (DECL_INITIAL (label) == NULL_TREE);
363 d_label_entry *ent = d_function_chain->labels->get (s);
364 gcc_assert (ent != NULL);
366 /* Mark label as having been defined. */
367 DECL_INITIAL (label) = error_mark_node;
369 ent->level = current_binding_level;
371 for (d_label_use_entry *ref = ent->fwdrefs; ref ; ref = ref->next)
372 this->check_previous_goto (ent->statement, ref);
373 ent->fwdrefs = NULL;
375 return label;
378 /* Emit a LABEL expression. */
380 void do_label (tree label)
382 /* Don't write out label unless it is marked as used by the frontend.
383 This makes auto-vectorization possible in conditional loops.
384 The only excemption to this is in the LabelStatement visitor,
385 in which all computed labels are marked regardless. */
386 if (TREE_USED (label))
387 add_stmt (build1 (LABEL_EXPR, void_type_node, label));
390 /* Emit a goto expression to LABEL. */
392 void do_jump (tree label)
394 add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label));
395 TREE_USED (label) = 1;
398 /* Check that a new jump at statement scope FROM to a label declared in
399 statement scope TO is valid. */
401 void check_goto (Statement *from, Statement *to)
403 d_label_entry *ent = d_function_chain->labels->get (to);
404 gcc_assert (ent != NULL);
406 /* If the label hasn't been defined yet, defer checking. */
407 if (!DECL_INITIAL (ent->label))
409 d_label_use_entry *fwdref = ggc_alloc <d_label_use_entry> ();
410 fwdref->level = current_binding_level;
411 fwdref->statement = from;
412 fwdref->next = ent->fwdrefs;
413 ent->fwdrefs = fwdref;
414 return;
417 if (ent->in_try_scope)
418 error_at (make_location_t (from->loc),
419 "cannot %<goto%> into %<try%> block");
420 else if (ent->in_catch_scope)
421 error_at (make_location_t (from->loc),
422 "cannot %<goto%> into %<catch%> block");
425 /* Check that a previously seen jump to a newly defined label is valid.
426 S is the label statement; FWDREF is the jump context. This is called
427 for both user-defined and case labels. */
429 void check_previous_goto (Statement *s, d_label_use_entry *fwdref)
431 for (binding_level *b = current_binding_level; b ; b = b->level_chain)
433 if (b == fwdref->level)
434 break;
436 if (b->kind == level_try || b->kind == level_catch)
438 location_t location;
440 if (s->isLabelStatement ())
442 location = make_location_t (fwdref->statement->loc);
443 if (b->kind == level_try)
444 error_at (location, "cannot %<goto%> into %<try%> block");
445 else
446 error_at (location, "cannot %<goto%> into %<catch%> block");
448 else
449 gcc_unreachable ();
454 /* Get or build LABEL_DECL using the IDENT and statement block S given. */
456 tree lookup_label (Statement *s, Identifier *ident = NULL)
458 /* You can't use labels at global scope. */
459 if (d_function_chain == NULL)
461 error ("label %s referenced outside of any function",
462 ident ? ident->toChars () : "(unnamed)");
463 return NULL_TREE;
466 /* Create the label htab for the function on demand. */
467 if (!d_function_chain->labels)
469 d_function_chain->labels
470 = hash_map <Statement *, d_label_entry>::create_ggc (13);
473 d_label_entry *ent = d_function_chain->labels->get (s);
474 if (ent != NULL)
475 return ent->label;
476 else
478 tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE;
479 tree decl = build_decl (make_location_t (s->loc), LABEL_DECL,
480 name, void_type_node);
481 DECL_CONTEXT (decl) = current_function_decl;
482 DECL_MODE (decl) = VOIDmode;
484 /* Create new empty slot. */
485 ent = ggc_cleared_alloc <d_label_entry> ();
486 ent->statement = s;
487 ent->label = decl;
489 bool existed = d_function_chain->labels->put (s, *ent);
490 gcc_assert (!existed);
492 return decl;
496 /* Get the LABEL_DECL to represent a break or continue for the
497 statement S given. BC indicates which. */
499 tree lookup_bc_label (Statement *s, bc_kind bc)
501 tree vec = this->lookup_label (s);
503 /* The break and continue labels are put into a TREE_VEC. */
504 if (TREE_CODE (vec) == LABEL_DECL)
506 d_label_entry *ent = d_function_chain->labels->get (s);
507 gcc_assert (ent != NULL);
509 vec = make_tree_vec (2);
510 TREE_VEC_ELT (vec, bc_break) = ent->label;
512 /* Build the continue label. */
513 tree label = build_decl (make_location_t (s->loc), LABEL_DECL,
514 NULL_TREE, void_type_node);
515 DECL_CONTEXT (label) = current_function_decl;
516 DECL_MODE (label) = VOIDmode;
517 TREE_VEC_ELT (vec, bc_continue) = label;
519 ent->label = vec;
520 ent->bc_label = true;
523 return TREE_VEC_ELT (vec, bc);
526 /* Set and return the current break label for the current block. */
528 tree push_break_label (Statement *s)
530 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break);
531 DECL_CHAIN (label) = this->break_label_;
532 this->break_label_ = label;
533 return label;
536 /* Finish with the current break label. */
538 void pop_break_label (tree label)
540 gcc_assert (this->break_label_ == label);
541 this->break_label_ = DECL_CHAIN (this->break_label_);
542 this->do_label (label);
545 /* Set and return the continue label for the current block. */
547 tree push_continue_label (Statement *s)
549 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue);
550 DECL_CHAIN (label) = this->continue_label_;
551 this->continue_label_ = label;
552 return label;
555 /* Finish with the current continue label. */
557 void pop_continue_label (tree label)
559 gcc_assert (this->continue_label_ == label);
560 this->continue_label_ = DECL_CHAIN (this->continue_label_);
561 this->do_label (label);
564 /* Generate and set a new continue label for the current unrolled loop. */
566 void push_unrolled_continue_label (UnrolledLoopStatement *s)
568 this->push_continue_label (s);
571 /* Finish with the continue label for the unrolled loop. */
573 void pop_unrolled_continue_label (UnrolledLoopStatement *s)
575 Statement *stmt = s->getRelatedLabeled ();
576 d_label_entry *ent = d_function_chain->labels->get (stmt);
577 gcc_assert (ent != NULL && ent->bc_label == true);
579 this->pop_continue_label (TREE_VEC_ELT (ent->label, bc_continue));
581 /* Remove the continue label from the label htab, as a new one must be
582 inserted at the end of every unrolled loop. */
583 ent->label = TREE_VEC_ELT (ent->label, bc_break);
586 /* Visitor interfaces. */
589 /* This should be overridden by each statement class. */
591 void visit (Statement *) final override
593 gcc_unreachable ();
596 /* The frontend lowers `scope (exit/failure/success)' statements as
597 try/catch/finally. At this point, this statement is just an empty
598 placeholder. Maybe the frontend shouldn't leak these. */
600 void visit (ScopeGuardStatement *) final override
604 /* If statements provide simple conditional execution of statements. */
606 void visit (IfStatement *s) final override
608 this->start_scope (level_cond);
610 /* Build the outer `if' condition, which may produce temporaries
611 requiring scope destruction. */
612 tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
613 s->condition->type);
614 tree ifbody = void_node;
615 tree elsebody = void_node;
617 /* Build the `then' branch, don't do code generation when the condition
618 is `if (__ctfe)', as that is always false at run-time. */
619 if (s->ifbody && !s->isIfCtfeBlock ())
621 push_stmt_list ();
622 this->build_stmt (s->ifbody);
623 ifbody = pop_stmt_list ();
626 /* Now build the `else' branch, which may have nested `else if' parts. */
627 if (s->elsebody)
629 push_stmt_list ();
630 this->build_stmt (s->elsebody);
631 elsebody = pop_stmt_list ();
634 /* Wrap up our constructed if condition into a COND_EXPR. */
635 tree cond = build_vcondition (ifcond, ifbody, elsebody);
636 add_stmt (cond);
638 /* Finish the if-then scope. */
639 this->finish_scope ();
642 /* Should there be any `pragma (...)' statements requiring code generation,
643 here would be the place to do it. For now, all pragmas are handled
644 by the frontend. */
646 void visit (PragmaStatement *) final override
650 /* The frontend lowers `while (...)' statements as `for (...)' loops.
651 This visitor is not strictly required other than to enforce that
652 these kinds of statements never reach here. */
654 void visit (WhileStatement *) final override
656 gcc_unreachable ();
659 /* Do while statments implement simple loops. The body is executed, then
660 the condition is evaluated. */
662 void visit (DoStatement *s) final override
664 tree lbreak = this->push_break_label (s);
666 this->start_scope (level_loop);
667 if (s->_body)
669 tree lcontinue = this->push_continue_label (s);
670 this->build_stmt (s->_body);
671 this->pop_continue_label (lcontinue);
674 /* Build the outer `while' condition, which may produce temporaries
675 requiring scope destruction. */
676 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
677 s->condition->type);
678 add_stmt (build_vcondition (exitcond, void_node,
679 build1 (GOTO_EXPR, void_type_node, lbreak)));
680 TREE_USED (lbreak) = 1;
682 tree body = this->end_scope ();
683 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
685 this->pop_break_label (lbreak);
688 /* For statements implement loops with initialization, test, and
689 increment clauses. */
691 void visit (ForStatement *s) final override
693 tree lbreak = this->push_break_label (s);
694 this->start_scope (level_loop);
696 if (s->_init)
697 this->build_stmt (s->_init);
699 if (s->condition)
701 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
702 s->condition->type);
703 add_stmt (build_vcondition (exitcond, void_node,
704 build1 (GOTO_EXPR, void_type_node,
705 lbreak)));
706 TREE_USED (lbreak) = 1;
709 if (s->_body)
711 tree lcontinue = this->push_continue_label (s);
712 this->build_stmt (s->_body);
713 this->pop_continue_label (lcontinue);
716 if (s->increment)
718 /* Force side effects? */
719 add_stmt (build_expr_dtor (s->increment));
722 tree body = this->end_scope ();
723 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
725 this->pop_break_label (lbreak);
728 /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
729 This visitor is not strictly required other than to enforce that
730 these kinds of statements never reach here. */
732 void visit (ForeachStatement *) final override
734 gcc_unreachable ();
737 /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
738 loops. This visitor is not strictly required other than to enforce that
739 these kinds of statements never reach here. */
741 void visit (ForeachRangeStatement *) final override
743 gcc_unreachable ();
746 /* Jump to the associated exit label for the current loop. If IDENT
747 for the Statement is not null, then the label is user defined. */
749 void visit (BreakStatement *s) final override
751 if (s->ident)
753 /* The break label may actually be some levels up.
754 eg: on a try/finally wrapping a loop. */
755 LabelDsymbol *sym = this->func_->searchLabel (s->ident, s->loc);
756 LabelStatement *label = sym->statement;
757 gcc_assert (label != NULL);
758 Statement *stmt = label->statement->getRelatedLabeled ();
759 this->do_jump (this->lookup_bc_label (stmt, bc_break));
761 else
762 this->do_jump (this->break_label_);
765 /* Jump to the associated continue label for the current loop. If IDENT
766 for the Statement is not null, then the label is user defined. */
768 void visit (ContinueStatement *s) final override
770 if (s->ident)
772 LabelDsymbol *sym = this->func_->searchLabel (s->ident, s->loc);
773 LabelStatement *label = sym->statement;
774 gcc_assert (label != NULL);
775 this->do_jump (this->lookup_bc_label (label->statement,
776 bc_continue));
778 else
779 this->do_jump (this->continue_label_);
782 /* A goto statement jumps to the statement identified by the given label. */
784 void visit (GotoStatement *s) final override
786 gcc_assert (s->label->statement != NULL);
787 gcc_assert (s->tf == s->label->statement->tf);
789 /* If no label found, there was an error. */
790 tree label = this->lookup_label (s->label->statement, s->label->ident);
791 this->do_jump (label);
793 /* Need to error if the goto is jumping into a try or catch block. */
794 this->check_goto (s, s->label->statement);
797 /* Statements can be labeled. A label is an identifier that precedes
798 a statement. */
800 void visit (LabelStatement *s) final override
802 LabelDsymbol *sym;
804 if (this->is_return_label (s->ident))
805 sym = this->func_->returnLabel;
806 else
807 sym = this->func_->searchLabel (s->ident, s->loc);
809 /* If no label found, there was an error. */
810 tree label = this->define_label (sym->statement, sym->ident);
811 TREE_USED (label) = 1;
813 this->do_label (label);
815 if (this->is_return_label (s->ident) && this->func_->fensure () != NULL)
816 this->build_stmt (this->func_->fensure ());
817 else if (s->statement)
818 this->build_stmt (s->statement);
821 /* A switch statement goes to one of a collection of case statements
822 depending on the value of the switch expression. */
824 void visit (SwitchStatement *s) final override
826 this->start_scope (level_switch);
827 tree lbreak = this->push_break_label (s);
829 tree condition = build_expr_dtor (s->condition);
830 Type *condtype = s->condition->type->toBasetype ();
832 /* A switch statement on a string gets turned into a library call.
833 It is not lowered during codegen. */
834 if (!condtype->isscalar ())
836 error ("cannot handle switch condition of type %s",
837 condtype->toChars ());
838 gcc_unreachable ();
841 condition = fold (condition);
843 /* Build LABEL_DECLs now so they can be refered to by goto case.
844 Also checking the jump from the switch to the label is allowed. */
845 if (s->cases)
847 for (size_t i = 0; i < s->cases->length; i++)
849 CaseStatement *cs = (*s->cases)[i];
850 tree caselabel = this->lookup_label (cs);
852 /* Write cases as a series of if-then-else blocks.
853 if (condition == case)
854 goto caselabel; */
855 if (s->hasVars)
857 tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
858 condition, build_expr_dtor (cs->exp));
859 tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
860 caselabel);
861 tree cond = build_vcondition (ifcase, ifbody, void_node);
862 TREE_USED (caselabel) = 1;
863 LABEL_VARIABLE_CASE (caselabel) = 1;
864 add_stmt (cond);
867 this->check_goto (s, cs);
870 if (s->sdefault)
872 tree defaultlabel = this->lookup_label (s->sdefault);
874 /* The default label is the last `else' block. */
875 if (s->hasVars)
877 this->do_jump (defaultlabel);
878 LABEL_VARIABLE_CASE (defaultlabel) = 1;
881 this->check_goto (s, s->sdefault);
885 /* Switch body goes in its own statement list. */
886 push_stmt_list ();
887 if (s->_body)
888 this->build_stmt (s->_body);
890 tree casebody = pop_stmt_list ();
892 /* Wrap up constructed body into a switch_expr, unless it was
893 converted to an if-then-else expression. */
894 if (s->hasVars)
895 add_stmt (casebody);
896 else
898 tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
899 condition, casebody);
900 add_stmt (switchexpr);
901 SWITCH_ALL_CASES_P (switchexpr) = 1;
904 SWITCH_BREAK_LABEL_P (lbreak) = 1;
906 /* If the switch had any `break' statements, emit the label now. */
907 this->pop_break_label (lbreak);
908 this->finish_scope ();
911 /* Declare the case label associated with the current SwitchStatement. */
913 void visit (CaseStatement *s) final override
915 /* Emit the case label. */
916 tree label = this->define_label (s);
918 if (LABEL_VARIABLE_CASE (label))
919 this->do_label (label);
920 else
922 tree casevalue;
923 if (s->exp->type->isscalar ())
924 casevalue = build_expr (s->exp);
925 else
926 casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
928 tree caselabel = build_case_label (casevalue, NULL_TREE, label);
929 add_stmt (caselabel);
932 /* Now do the body. */
933 if (s->statement)
934 this->build_stmt (s->statement);
937 /* Declare the default label associated with the current SwitchStatement. */
939 void visit (DefaultStatement *s) final override
941 /* Emit the default case label. */
942 tree label = this->define_label (s);
944 if (LABEL_VARIABLE_CASE (label))
945 this->do_label (label);
946 else
948 tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
949 add_stmt (caselabel);
952 /* Now do the body. */
953 if (s->statement)
954 this->build_stmt (s->statement);
957 /* Implements `goto default' by jumping to the label associated with
958 the DefaultStatement in a switch block. */
960 void visit (GotoDefaultStatement *s) final override
962 tree label = this->lookup_label (s->sw->sdefault);
963 this->do_jump (label);
966 /* Implements `goto case' by jumping to the label associated with the
967 CaseStatement in a switch block. */
969 void visit (GotoCaseStatement *s) final override
971 tree label = this->lookup_label (s->cs);
972 this->do_jump (label);
975 /* Throw a SwitchError exception, called when a switch statement has
976 no DefaultStatement, yet none of the cases match. */
978 void visit (SwitchErrorStatement *s) final override
980 /* A throw SwitchError statement gets turned into a library call.
981 The call is wrapped in the enclosed expression. */
982 gcc_assert (s->exp != NULL);
983 add_stmt (build_expr (s->exp));
986 /* A return statement exits the current function and supplies its return
987 value, if the return type is not void. */
989 void visit (ReturnStatement *s) final override
991 if (s->exp == NULL || s->exp->type->toBasetype ()->ty == TY::Tvoid)
993 /* Return has no value. */
994 add_stmt (return_expr (NULL_TREE));
995 return;
998 TypeFunction *tf = this->func_->type->toTypeFunction ();
999 Type *type = this->func_->tintro != NULL
1000 ? this->func_->tintro->nextOf () : tf->nextOf ();
1002 if ((this->func_->isMain () || this->func_->isCMain ())
1003 && type->toBasetype ()->ty == TY::Tvoid)
1004 type = Type::tint32;
1006 if (this->func_->shidden)
1008 /* Returning by hidden reference, store the result into the retval decl.
1009 The result returned then becomes the retval reference itself. */
1010 tree decl = DECL_RESULT (get_symbol_decl (this->func_));
1011 gcc_assert (!tf->isref ());
1013 /* If returning via NRVO, just refer to the DECL_RESULT; this differs
1014 from using NULL_TREE in that it indicates that we care about the
1015 value of the DECL_RESULT. */
1016 if (this->func_->isNRVO () && this->func_->nrvo_var)
1018 add_stmt (return_expr (decl));
1019 return;
1022 /* Detect a call to a constructor function, or if returning a struct
1023 literal, write result directly into the return value. */
1024 StructLiteralExp *sle = NULL;
1025 bool using_rvo_p = false;
1027 if (DotVarExp *dve = (s->exp->isCallExp ()
1028 ? s->exp->isCallExp ()->e1->isDotVarExp ()
1029 : NULL))
1031 if (dve->var->isCtorDeclaration ())
1033 if (CommaExp *ce = dve->e1->isCommaExp ())
1035 /* Temporary initialized inside a return expression, and
1036 used as the return value. Replace it with the hidden
1037 reference to allow RVO return. */
1038 DeclarationExp *de = ce->e1->isDeclarationExp ();
1039 VarExp *ve = ce->e2->isVarExp ();
1040 if (de != NULL && ve != NULL
1041 && ve->var == de->declaration
1042 && ve->var->storage_class & STCtemp)
1044 tree var = get_symbol_decl (ve->var);
1045 TREE_ADDRESSABLE (var) = 1;
1046 SET_DECL_VALUE_EXPR (var, decl);
1047 DECL_HAS_VALUE_EXPR_P (var) = 1;
1048 SET_DECL_LANG_NRVO (var, this->func_->shidden);
1049 using_rvo_p = true;
1052 else
1053 sle = dve->e1->isStructLiteralExp ();
1056 else
1057 sle = s->exp->isStructLiteralExp ();
1059 if (sle != NULL)
1061 StructDeclaration *sd = type->baseElemOf ()->isTypeStruct ()->sym;
1062 sle->sym = build_address (this->func_->shidden);
1063 using_rvo_p = true;
1065 /* Fill any alignment holes in the return slot using memset. */
1066 if (!identity_compare_p (sd) || sd->isUnionDeclaration ())
1067 add_stmt (build_memset_call (this->func_->shidden));
1070 if (using_rvo_p == true)
1072 /* Generate: (expr, return <retval>); */
1073 add_stmt (build_expr_dtor (s->exp));
1075 else
1077 /* Generate: (<retval> = expr, return <retval>); */
1078 tree expr = build_expr_dtor (s->exp);
1079 tree init = stabilize_expr (&expr);
1080 expr = convert_for_rvalue (expr, s->exp->type, type);
1081 expr = build_assign (INIT_EXPR, this->func_->shidden, expr);
1082 add_stmt (compound_expr (init, expr));
1085 add_stmt (return_expr (decl));
1087 else if (tf->next->ty == TY::Tnoreturn)
1089 /* Returning an expression that has no value, but has a side effect
1090 that should never return. */
1091 add_stmt (build_expr_dtor (s->exp));
1092 add_stmt (return_expr (NULL_TREE));
1094 else
1096 /* Convert for initializing the DECL_RESULT. */
1097 add_stmt (build_return_dtor (s->exp, type, tf));
1101 /* Evaluate the enclosed expression, and add it to the statement list. */
1103 void visit (ExpStatement *s) final override
1105 if (s->exp)
1107 /* Expression may produce temporaries requiring scope destruction. */
1108 tree exp = build_expr_dtor (s->exp);
1109 add_stmt (exp);
1113 /* Evaluate all enclosed statements. */
1115 void visit (CompoundStatement *s) final override
1117 if (s->statements == NULL)
1118 return;
1120 for (size_t i = 0; i < s->statements->length; i++)
1122 Statement *statement = (*s->statements)[i];
1124 if (statement != NULL)
1125 this->build_stmt (statement);
1129 /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
1130 These are compiled down as a `do ... while (0)', where each unrolled loop
1131 is nested inside and given their own continue label to jump to. */
1133 void visit (UnrolledLoopStatement *s) final override
1135 if (s->statements == NULL)
1136 return;
1138 tree lbreak = this->push_break_label (s);
1139 this->start_scope (level_loop);
1141 for (size_t i = 0; i < s->statements->length; i++)
1143 Statement *statement = (*s->statements)[i];
1145 if (statement != NULL)
1147 this->push_unrolled_continue_label (s);
1148 this->build_stmt (statement);
1149 this->pop_unrolled_continue_label (s);
1153 this->do_jump (this->break_label_);
1155 tree body = this->end_scope ();
1156 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
1158 this->pop_break_label (lbreak);
1161 /* Start a new scope and visit all nested statements, wrapping
1162 them up into a BIND_EXPR at the end of the scope. */
1164 void visit (ScopeStatement *s) final override
1166 if (s->statement == NULL)
1167 return;
1169 this->start_scope (level_block);
1170 this->build_stmt (s->statement);
1171 this->finish_scope ();
1174 /* A with statement is a way to simplify repeated references to the same
1175 object, where the handle is either a class or struct instance. */
1177 void visit (WithStatement *s) final override
1179 this->start_scope (level_with);
1181 if (s->wthis)
1183 /* Perform initialisation of the `with' handle. */
1184 ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
1185 gcc_assert (ie != NULL);
1187 declare_local_var (s->wthis);
1188 tree init = build_expr_dtor (ie->exp);
1189 add_stmt (init);
1192 if (s->_body)
1193 this->build_stmt (s->_body);
1195 this->finish_scope ();
1198 /* Implements `throw Object'. Frontend already checks that the object
1199 thrown is a class type, but does not check if it is derived from
1200 Object. Foreign objects are not currently supported at run-time. */
1202 void visit (ThrowStatement *s) final override
1204 ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
1205 InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
1206 tree arg = build_expr_dtor (s->exp);
1208 if (!global.params.useExceptions)
1210 static int warned = 0;
1211 if (!warned)
1213 error_at (make_location_t (s->loc), "exception handling disabled; "
1214 "use %<-fexceptions%> to enable");
1215 warned = 1;
1219 if (cd->isCPPclass () || (id != NULL && id->isCPPclass ()))
1220 error_at (make_location_t (s->loc), "cannot throw C++ classes");
1221 else if (cd->com || (id != NULL && id->com))
1222 error_at (make_location_t (s->loc), "cannot throw COM objects");
1223 else
1224 arg = build_nop (build_ctype (get_object_type ()), arg);
1226 add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
1229 /* Build a try-catch statement, one of the building blocks for exception
1230 handling generated by the frontend. This is also used to implement
1231 `scope (failure)' statements. */
1233 void visit (TryCatchStatement *s) final override
1235 this->start_scope (level_try);
1236 if (s->_body)
1237 this->build_stmt (s->_body);
1239 tree trybody = this->end_scope ();
1241 /* Try handlers go in their own statement list. */
1242 push_stmt_list ();
1244 if (s->catches)
1246 for (size_t i = 0; i < s->catches->length; i++)
1248 Catch *vcatch = (*s->catches)[i];
1250 this->start_scope (level_catch);
1252 tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
1253 tree catchtype = build_ctype (vcatch->type);
1254 tree object = NULL_TREE;
1256 ehptr = build_call_expr (ehptr, 1, integer_zero_node);
1258 /* Retrieve the internal exception object, which could be for a
1259 D or C++ catch handler. This is different from the generic
1260 exception pointer returned from gcc runtime. */
1261 Type *tcatch = vcatch->type->toBasetype ();
1262 ClassDeclaration *cd = tcatch->isClassHandle ();
1264 libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1265 : LIBCALL_BEGIN_CATCH;
1266 object = build_libcall (libcall, vcatch->type, 1, ehptr);
1268 if (vcatch->var)
1270 tree var = get_symbol_decl (vcatch->var);
1271 tree init = build_assign (INIT_EXPR, var, object);
1273 declare_local_var (vcatch->var);
1274 add_stmt (init);
1276 else
1278 /* Still need to emit a call to __gdc_begin_catch() to
1279 remove the object from the uncaught exceptions list. */
1280 add_stmt (object);
1283 if (vcatch->handler)
1284 this->build_stmt (vcatch->handler);
1286 tree catchbody = this->end_scope ();
1288 /* Need to wrap C++ handlers in a try/finally block to signal
1289 the end catch callback. */
1290 if (cd->isCPPclass ())
1292 tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
1293 Type::tvoid, 0);
1294 catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
1295 catchbody, endcatch);
1298 add_stmt (build2 (CATCH_EXPR, void_type_node,
1299 catchtype, catchbody));
1303 tree catches = pop_stmt_list ();
1305 /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
1306 statement list, however pop_stmt_list may optimize away the list
1307 if there is only a single catch to push. */
1308 if (TREE_CODE (catches) != STATEMENT_LIST)
1310 tree stmt_list = alloc_stmt_list ();
1311 append_to_statement_list_force (catches, &stmt_list);
1312 catches = stmt_list;
1315 add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
1318 /* Build a try-finally statement, one of the building blocks for exception
1319 handling generated by the frontend. This is also used to implement
1320 `scope (exit)' statements. */
1322 void visit (TryFinallyStatement *s) final override
1324 this->start_scope (level_try);
1325 if (s->_body)
1326 this->build_stmt (s->_body);
1328 tree trybody = this->end_scope ();
1330 this->start_scope (level_finally);
1331 if (s->finalbody)
1332 this->build_stmt (s->finalbody);
1334 tree finally = this->end_scope ();
1336 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
1339 /* The frontend lowers `synchronized (...)' statements as a call to
1340 monitor/critical enter and exit wrapped around try/finally.
1341 This visitor is not strictly required other than to enforce that
1342 these kinds of statements never reach here. */
1344 void visit (SynchronizedStatement *) final override
1346 gcc_unreachable ();
1349 /* D Inline Assembler is not implemented, as it would require writing
1350 an assembly parser for each supported target. Instead we leverage
1351 GCC extended assembler using the GccAsmStatement class. */
1353 void visit (AsmStatement *) final override
1355 sorry ("D inline assembler statements are not supported in GDC.");
1358 /* Build a GCC extended assembler expression, whose components are
1359 an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */
1361 void visit (GccAsmStatement *s) final override
1363 StringExp *insn = s->insn->toStringExp ();
1364 tree outputs = NULL_TREE;
1365 tree inputs = NULL_TREE;
1366 tree clobbers = NULL_TREE;
1367 tree labels = NULL_TREE;
1369 /* Collect all arguments, which may be input or output operands. */
1370 if (s->args)
1372 for (size_t i = 0; i < s->args->length; i++)
1374 Identifier *name = (*s->names)[i];
1375 const char *sname = name ? name->toChars () : NULL;
1376 tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
1378 StringExp *constr = (*s->constraints)[i]->toStringExp ();
1379 const char *cstring = (const char *)(constr->len
1380 ? constr->string : "");
1381 tree str = build_string (constr->len, cstring);
1383 Expression *earg = (*s->args)[i];
1384 tree val = build_expr (earg);
1386 if (i < s->outputargs)
1388 tree arg = build_tree_list (id, str);
1389 outputs = chainon (outputs, build_tree_list (arg, val));
1391 else
1393 tree arg = build_tree_list (id, str);
1394 inputs = chainon (inputs, build_tree_list (arg, val));
1399 /* Collect all clobber arguments. */
1400 if (s->clobbers)
1402 for (size_t i = 0; i < s->clobbers->length; i++)
1404 StringExp *clobber = (*s->clobbers)[i]->toStringExp ();
1405 const char *cstring = (const char *)(clobber->len
1406 ? clobber->string : "");
1408 tree val = build_string (clobber->len, cstring);
1409 clobbers = chainon (clobbers, build_tree_list (0, val));
1413 /* Collect all goto labels, these should have been already checked
1414 by the front-end, so pass down the label symbol to the back-end. */
1415 if (s->labels)
1417 for (size_t i = 0; i < s->labels->length; i++)
1419 Identifier *ident = (*s->labels)[i];
1420 GotoStatement *gs = (*s->gotos)[i];
1422 gcc_assert (gs->label->statement != NULL);
1423 gcc_assert (gs->tf == gs->label->statement->tf);
1425 const char *sident = ident->toChars ();
1426 tree name = build_string (strlen (sident), sident);
1427 tree label = this->lookup_label (gs->label->statement,
1428 gs->label->ident);
1429 TREE_USED (label) = 1;
1431 labels = chainon (labels, build_tree_list (name, label));
1435 /* Do some extra validation on all input and output operands. */
1436 const char *insnstring = (const char *)(insn->len ? insn->string : "");
1437 tree string = build_string (insn->len, insnstring);
1438 string = resolve_asm_operand_names (string, outputs, inputs, labels);
1440 if (s->args)
1442 unsigned noutputs = s->outputargs;
1443 unsigned ninputs = (s->args->length - noutputs);
1444 const char **oconstraints = XALLOCAVEC (const char *, noutputs);
1445 bool allows_mem, allows_reg, is_inout;
1446 size_t i;
1447 tree t;
1449 for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1451 tree output = TREE_VALUE (t);
1452 const char *constraint
1453 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1455 oconstraints[i] = constraint;
1457 if (parse_output_constraint (&constraint, i, ninputs, noutputs,
1458 &allows_mem, &allows_reg, &is_inout))
1460 /* If the output argument is going to end up in memory. */
1461 if (!allows_reg)
1462 d_mark_addressable (output);
1464 else
1465 output = error_mark_node;
1467 TREE_VALUE (t) = output;
1470 for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1472 tree input = TREE_VALUE (t);
1473 const char *constraint
1474 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1476 if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
1477 oconstraints, &allows_mem, &allows_reg))
1479 /* If the input argument is going to end up in memory. */
1480 if (!allows_reg && allows_mem)
1481 d_mark_addressable (input);
1483 else
1484 input = error_mark_node;
1486 TREE_VALUE (t) = input;
1490 tree exp = build5 (ASM_EXPR, void_type_node, string,
1491 outputs, inputs, clobbers, labels);
1492 SET_EXPR_LOCATION (exp, make_location_t (s->loc));
1494 /* If the extended syntax was not used, mark the ASM_EXPR as being an
1495 ASM_INPUT expression instead of an ASM_OPERAND with no operands. */
1496 if (s->args == NULL && s->clobbers == NULL)
1497 ASM_INPUT_P (exp) = 1;
1499 /* All asm statements are assumed to have a side effect. As a future
1500 optimization, this could be unset when building in release mode. */
1501 ASM_VOLATILE_P (exp) = 1;
1503 /* If the function has been annotated with `pragma(inline)', then mark
1504 the asm expression as being inline as well. */
1505 if (this->func_->inlining == PINLINE::always)
1506 ASM_INLINE_P (exp) = 1;
1508 add_stmt (exp);
1511 /* Import symbols from another module. */
1513 void visit (ImportStatement *s) final override
1515 if (s->imports == NULL)
1516 return;
1518 for (size_t i = 0; i < s->imports->length; i++)
1520 Dsymbol *dsym = (*s->imports)[i];
1522 if (dsym != NULL)
1523 build_decl_tree (dsym);
1528 /* Main entry point for the IRVisitor interface to generate
1529 code for the body of function FD. */
1531 void
1532 build_function_body (FuncDeclaration *fd)
1534 IRVisitor v = IRVisitor (fd);
1535 location_t saved_location = input_location;
1536 input_location = make_location_t (fd->loc);
1537 v.build_stmt (fd->fbody);
1538 input_location = saved_location;