Update baseline symbols for hppa-linux.
[official-gcc.git] / gcc / d / toir.cc
blobe387f27760d9cb3b0ea2929572b295d7a4f77a28
1 /* toir.cc -- Lower D frontend statements to GCC trees.
2 Copyright (C) 2006-2022 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 (TREE_CODE (t) == COMPOUND_EXPR)
220 /* Push out each comma expressions as separate statements. */
221 add_stmt (TREE_OPERAND (t, 0));
222 add_stmt (TREE_OPERAND (t, 1));
224 else
226 /* Force the type to be void so we don't need to create a temporary
227 variable to hold the inner expression. */
228 if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
229 TREE_TYPE (t) = void_type_node;
231 /* Append the expression to the statement list.
232 Make sure it has a proper location. */
233 if (EXPR_P (t) && !EXPR_HAS_LOCATION (t))
234 SET_EXPR_LOCATION (t, input_location);
236 tree stmt_list = d_function_chain->stmt_list->last ();
237 append_to_statement_list_force (t, &stmt_list);
241 /* Implements the visitor interface to build the GCC trees of all Statement
242 AST classes emitted from the D Front-end.
243 All visit methods accept one parameter S, which holds the frontend AST
244 of the statement to compile. They also don't return any value, instead
245 generated code are pushed to add_stmt(), which appends them to the
246 statement list in the current_binding_level. */
248 class IRVisitor : public Visitor
250 using Visitor::visit;
252 FuncDeclaration *func_;
254 /* Stack of labels which are targets for "break" and "continue",
255 linked through TREE_CHAIN. */
256 tree break_label_;
257 tree continue_label_;
259 public:
260 IRVisitor (FuncDeclaration *fd)
262 this->func_ = fd;
263 this->break_label_ = NULL_TREE;
264 this->continue_label_ = NULL_TREE;
267 /* Helper for generating code for the statement AST class S.
268 Sets up the location of the statement before lowering. */
270 void build_stmt (Statement *s)
272 location_t saved_location = input_location;
273 input_location = make_location_t (s->loc);
274 s->accept (this);
275 input_location = saved_location;
278 /* Start a new scope for a KIND statement.
279 Each user-declared variable will have a binding contour that begins
280 where the variable is declared and ends at its containing scope. */
282 void start_scope (level_kind kind)
284 push_binding_level (kind);
285 push_stmt_list ();
288 /* Leave scope pushed by start_scope, returning a new bind_expr if
289 any variables where declared in the scope. */
291 tree end_scope (void)
293 tree block = pop_binding_level ();
294 tree body = pop_stmt_list ();
296 if (!BLOCK_VARS (block))
297 return body;
299 tree bind = build3 (BIND_EXPR, void_type_node,
300 BLOCK_VARS (block), body, block);
301 TREE_SIDE_EFFECTS (bind) = 1;
302 return bind;
305 /* Like end_scope, but also push it into the outer statement-tree. */
307 void finish_scope (void)
309 tree scope = this->end_scope ();
310 add_stmt (scope);
313 /* Return TRUE if IDENT is the current function return label. */
315 bool is_return_label (Identifier *ident)
317 if (this->func_->returnLabel)
318 return this->func_->returnLabel->ident == ident;
320 return false;
323 /* Define a label, specifying the location in the source file.
324 Return the LABEL_DECL node for the label. */
326 tree define_label (Statement *s, Identifier *ident = NULL)
328 tree label = this->lookup_label (s, ident);
329 gcc_assert (DECL_INITIAL (label) == NULL_TREE);
331 d_label_entry *ent = d_function_chain->labels->get (s);
332 gcc_assert (ent != NULL);
334 /* Mark label as having been defined. */
335 DECL_INITIAL (label) = error_mark_node;
337 ent->level = current_binding_level;
339 for (d_label_use_entry *ref = ent->fwdrefs; ref ; ref = ref->next)
340 this->check_previous_goto (ent->statement, ref);
341 ent->fwdrefs = NULL;
343 return label;
346 /* Emit a LABEL expression. */
348 void do_label (tree label)
350 /* Don't write out label unless it is marked as used by the frontend.
351 This makes auto-vectorization possible in conditional loops.
352 The only excemption to this is in the LabelStatement visitor,
353 in which all computed labels are marked regardless. */
354 if (TREE_USED (label))
355 add_stmt (build1 (LABEL_EXPR, void_type_node, label));
358 /* Emit a goto expression to LABEL. */
360 void do_jump (tree label)
362 add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label));
363 TREE_USED (label) = 1;
366 /* Check that a new jump at statement scope FROM to a label declared in
367 statement scope TO is valid. */
369 void check_goto (Statement *from, Statement *to)
371 d_label_entry *ent = d_function_chain->labels->get (to);
372 gcc_assert (ent != NULL);
374 /* If the label hasn't been defined yet, defer checking. */
375 if (!DECL_INITIAL (ent->label))
377 d_label_use_entry *fwdref = ggc_alloc <d_label_use_entry> ();
378 fwdref->level = current_binding_level;
379 fwdref->statement = from;
380 fwdref->next = ent->fwdrefs;
381 ent->fwdrefs = fwdref;
382 return;
385 if (ent->in_try_scope)
386 error_at (make_location_t (from->loc),
387 "cannot %<goto%> into %<try%> block");
388 else if (ent->in_catch_scope)
389 error_at (make_location_t (from->loc),
390 "cannot %<goto%> into %<catch%> block");
393 /* Check that a previously seen jump to a newly defined label is valid.
394 S is the label statement; FWDREF is the jump context. This is called
395 for both user-defined and case labels. */
397 void check_previous_goto (Statement *s, d_label_use_entry *fwdref)
399 for (binding_level *b = current_binding_level; b ; b = b->level_chain)
401 if (b == fwdref->level)
402 break;
404 if (b->kind == level_try || b->kind == level_catch)
406 location_t location;
408 if (s->isLabelStatement ())
410 location = make_location_t (fwdref->statement->loc);
411 if (b->kind == level_try)
412 error_at (location, "cannot %<goto%> into %<try%> block");
413 else
414 error_at (location, "cannot %<goto%> into %<catch%> block");
416 else
417 gcc_unreachable ();
422 /* Get or build LABEL_DECL using the IDENT and statement block S given. */
424 tree lookup_label (Statement *s, Identifier *ident = NULL)
426 /* You can't use labels at global scope. */
427 if (d_function_chain == NULL)
429 error ("label %s referenced outside of any function",
430 ident ? ident->toChars () : "(unnamed)");
431 return NULL_TREE;
434 /* Create the label htab for the function on demand. */
435 if (!d_function_chain->labels)
437 d_function_chain->labels
438 = hash_map <Statement *, d_label_entry>::create_ggc (13);
441 d_label_entry *ent = d_function_chain->labels->get (s);
442 if (ent != NULL)
443 return ent->label;
444 else
446 tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE;
447 tree decl = build_decl (make_location_t (s->loc), LABEL_DECL,
448 name, void_type_node);
449 DECL_CONTEXT (decl) = current_function_decl;
450 DECL_MODE (decl) = VOIDmode;
452 /* Create new empty slot. */
453 ent = ggc_cleared_alloc <d_label_entry> ();
454 ent->statement = s;
455 ent->label = decl;
457 bool existed = d_function_chain->labels->put (s, *ent);
458 gcc_assert (!existed);
460 return decl;
464 /* Get the LABEL_DECL to represent a break or continue for the
465 statement S given. BC indicates which. */
467 tree lookup_bc_label (Statement *s, bc_kind bc)
469 tree vec = this->lookup_label (s);
471 /* The break and continue labels are put into a TREE_VEC. */
472 if (TREE_CODE (vec) == LABEL_DECL)
474 d_label_entry *ent = d_function_chain->labels->get (s);
475 gcc_assert (ent != NULL);
477 vec = make_tree_vec (2);
478 TREE_VEC_ELT (vec, bc_break) = ent->label;
480 /* Build the continue label. */
481 tree label = build_decl (make_location_t (s->loc), LABEL_DECL,
482 NULL_TREE, void_type_node);
483 DECL_CONTEXT (label) = current_function_decl;
484 DECL_MODE (label) = VOIDmode;
485 TREE_VEC_ELT (vec, bc_continue) = label;
487 ent->label = vec;
488 ent->bc_label = true;
491 return TREE_VEC_ELT (vec, bc);
494 /* Set and return the current break label for the current block. */
496 tree push_break_label (Statement *s)
498 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break);
499 DECL_CHAIN (label) = this->break_label_;
500 this->break_label_ = label;
501 return label;
504 /* Finish with the current break label. */
506 void pop_break_label (tree label)
508 gcc_assert (this->break_label_ == label);
509 this->break_label_ = DECL_CHAIN (this->break_label_);
510 this->do_label (label);
513 /* Set and return the continue label for the current block. */
515 tree push_continue_label (Statement *s)
517 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue);
518 DECL_CHAIN (label) = this->continue_label_;
519 this->continue_label_ = label;
520 return label;
523 /* Finish with the current continue label. */
525 void pop_continue_label (tree label)
527 gcc_assert (this->continue_label_ == label);
528 this->continue_label_ = DECL_CHAIN (this->continue_label_);
529 this->do_label (label);
532 /* Generate and set a new continue label for the current unrolled loop. */
534 void push_unrolled_continue_label (UnrolledLoopStatement *s)
536 this->push_continue_label (s);
539 /* Finish with the continue label for the unrolled loop. */
541 void pop_unrolled_continue_label (UnrolledLoopStatement *s)
543 Statement *stmt = s->getRelatedLabeled ();
544 d_label_entry *ent = d_function_chain->labels->get (stmt);
545 gcc_assert (ent != NULL && ent->bc_label == true);
547 this->pop_continue_label (TREE_VEC_ELT (ent->label, bc_continue));
549 /* Remove the continue label from the label htab, as a new one must be
550 inserted at the end of every unrolled loop. */
551 ent->label = TREE_VEC_ELT (ent->label, bc_break);
554 /* Visitor interfaces. */
557 /* This should be overridden by each statement class. */
559 void visit (Statement *) final override
561 gcc_unreachable ();
564 /* The frontend lowers `scope (exit/failure/success)' statements as
565 try/catch/finally. At this point, this statement is just an empty
566 placeholder. Maybe the frontend shouldn't leak these. */
568 void visit (ScopeGuardStatement *) final override
572 /* If statements provide simple conditional execution of statements. */
574 void visit (IfStatement *s) final override
576 this->start_scope (level_cond);
578 /* Build the outer `if' condition, which may produce temporaries
579 requiring scope destruction. */
580 tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
581 s->condition->type);
582 tree ifbody = void_node;
583 tree elsebody = void_node;
585 /* Build the `then' branch. */
586 if (s->ifbody)
588 push_stmt_list ();
589 this->build_stmt (s->ifbody);
590 ifbody = pop_stmt_list ();
593 /* Now build the `else' branch, which may have nested `else if' parts. */
594 if (s->elsebody)
596 push_stmt_list ();
597 this->build_stmt (s->elsebody);
598 elsebody = pop_stmt_list ();
601 /* Wrap up our constructed if condition into a COND_EXPR. */
602 tree cond = build_vcondition (ifcond, ifbody, elsebody);
603 add_stmt (cond);
605 /* Finish the if-then scope. */
606 this->finish_scope ();
609 /* Should there be any `pragma (...)' statements requiring code generation,
610 here would be the place to do it. For now, all pragmas are handled
611 by the frontend. */
613 void visit (PragmaStatement *) final override
617 /* The frontend lowers `while (...)' statements as `for (...)' loops.
618 This visitor is not strictly required other than to enforce that
619 these kinds of statements never reach here. */
621 void visit (WhileStatement *) final override
623 gcc_unreachable ();
626 /* Do while statments implement simple loops. The body is executed, then
627 the condition is evaluated. */
629 void visit (DoStatement *s) final override
631 tree lbreak = this->push_break_label (s);
633 this->start_scope (level_loop);
634 if (s->_body)
636 tree lcontinue = this->push_continue_label (s);
637 this->build_stmt (s->_body);
638 this->pop_continue_label (lcontinue);
641 /* Build the outer `while' condition, which may produce temporaries
642 requiring scope destruction. */
643 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
644 s->condition->type);
645 add_stmt (build_vcondition (exitcond, void_node,
646 build1 (GOTO_EXPR, void_type_node, lbreak)));
647 TREE_USED (lbreak) = 1;
649 tree body = this->end_scope ();
650 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
652 this->pop_break_label (lbreak);
655 /* For statements implement loops with initialization, test, and
656 increment clauses. */
658 void visit (ForStatement *s) final override
660 tree lbreak = this->push_break_label (s);
661 this->start_scope (level_loop);
663 if (s->_init)
664 this->build_stmt (s->_init);
666 if (s->condition)
668 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
669 s->condition->type);
670 add_stmt (build_vcondition (exitcond, void_node,
671 build1 (GOTO_EXPR, void_type_node,
672 lbreak)));
673 TREE_USED (lbreak) = 1;
676 if (s->_body)
678 tree lcontinue = this->push_continue_label (s);
679 this->build_stmt (s->_body);
680 this->pop_continue_label (lcontinue);
683 if (s->increment)
685 /* Force side effects? */
686 add_stmt (build_expr_dtor (s->increment));
689 tree body = this->end_scope ();
690 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
692 this->pop_break_label (lbreak);
695 /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
696 This visitor is not strictly required other than to enforce that
697 these kinds of statements never reach here. */
699 void visit (ForeachStatement *) final override
701 gcc_unreachable ();
704 /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
705 loops. This visitor is not strictly required other than to enforce that
706 these kinds of statements never reach here. */
708 void visit (ForeachRangeStatement *) final override
710 gcc_unreachable ();
713 /* Jump to the associated exit label for the current loop. If IDENT
714 for the Statement is not null, then the label is user defined. */
716 void visit (BreakStatement *s) final override
718 if (s->ident)
720 /* The break label may actually be some levels up.
721 eg: on a try/finally wrapping a loop. */
722 LabelDsymbol *sym = this->func_->searchLabel (s->ident, s->loc);
723 LabelStatement *label = sym->statement;
724 gcc_assert (label != NULL);
725 Statement *stmt = label->statement->getRelatedLabeled ();
726 this->do_jump (this->lookup_bc_label (stmt, bc_break));
728 else
729 this->do_jump (this->break_label_);
732 /* Jump to the associated continue label for the current loop. If IDENT
733 for the Statement is not null, then the label is user defined. */
735 void visit (ContinueStatement *s) final override
737 if (s->ident)
739 LabelDsymbol *sym = this->func_->searchLabel (s->ident, s->loc);
740 LabelStatement *label = sym->statement;
741 gcc_assert (label != NULL);
742 this->do_jump (this->lookup_bc_label (label->statement,
743 bc_continue));
745 else
746 this->do_jump (this->continue_label_);
749 /* A goto statement jumps to the statement identified by the given label. */
751 void visit (GotoStatement *s) final override
753 gcc_assert (s->label->statement != NULL);
754 gcc_assert (s->tf == s->label->statement->tf);
756 /* If no label found, there was an error. */
757 tree label = this->lookup_label (s->label->statement, s->label->ident);
758 this->do_jump (label);
760 /* Need to error if the goto is jumping into a try or catch block. */
761 this->check_goto (s, s->label->statement);
764 /* Statements can be labeled. A label is an identifier that precedes
765 a statement. */
767 void visit (LabelStatement *s) final override
769 LabelDsymbol *sym;
771 if (this->is_return_label (s->ident))
772 sym = this->func_->returnLabel;
773 else
774 sym = this->func_->searchLabel (s->ident, s->loc);
776 /* If no label found, there was an error. */
777 tree label = this->define_label (sym->statement, sym->ident);
778 TREE_USED (label) = 1;
780 this->do_label (label);
782 if (this->is_return_label (s->ident) && this->func_->fensure != NULL)
783 this->build_stmt (this->func_->fensure);
784 else if (s->statement)
785 this->build_stmt (s->statement);
788 /* A switch statement goes to one of a collection of case statements
789 depending on the value of the switch expression. */
791 void visit (SwitchStatement *s) final override
793 this->start_scope (level_switch);
794 tree lbreak = this->push_break_label (s);
796 tree condition = build_expr_dtor (s->condition);
797 Type *condtype = s->condition->type->toBasetype ();
799 /* A switch statement on a string gets turned into a library call.
800 It is not lowered during codegen. */
801 if (!condtype->isscalar ())
803 error ("cannot handle switch condition of type %s",
804 condtype->toChars ());
805 gcc_unreachable ();
808 condition = fold (condition);
810 /* Build LABEL_DECLs now so they can be refered to by goto case.
811 Also checking the jump from the switch to the label is allowed. */
812 if (s->cases)
814 for (size_t i = 0; i < s->cases->length; i++)
816 CaseStatement *cs = (*s->cases)[i];
817 tree caselabel = this->lookup_label (cs);
819 /* Write cases as a series of if-then-else blocks.
820 if (condition == case)
821 goto caselabel; */
822 if (s->hasVars)
824 tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
825 condition, build_expr_dtor (cs->exp));
826 tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
827 caselabel);
828 tree cond = build_vcondition (ifcase, ifbody, void_node);
829 TREE_USED (caselabel) = 1;
830 LABEL_VARIABLE_CASE (caselabel) = 1;
831 add_stmt (cond);
834 this->check_goto (s, cs);
837 if (s->sdefault)
839 tree defaultlabel = this->lookup_label (s->sdefault);
841 /* The default label is the last `else' block. */
842 if (s->hasVars)
844 this->do_jump (defaultlabel);
845 LABEL_VARIABLE_CASE (defaultlabel) = 1;
848 this->check_goto (s, s->sdefault);
852 /* Switch body goes in its own statement list. */
853 push_stmt_list ();
854 if (s->_body)
855 this->build_stmt (s->_body);
857 tree casebody = pop_stmt_list ();
859 /* Wrap up constructed body into a switch_expr, unless it was
860 converted to an if-then-else expression. */
861 if (s->hasVars)
862 add_stmt (casebody);
863 else
865 tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
866 condition, casebody);
867 add_stmt (switchexpr);
868 SWITCH_ALL_CASES_P (switchexpr) = 1;
871 SWITCH_BREAK_LABEL_P (lbreak) = 1;
873 /* If the switch had any `break' statements, emit the label now. */
874 this->pop_break_label (lbreak);
875 this->finish_scope ();
878 /* Declare the case label associated with the current SwitchStatement. */
880 void visit (CaseStatement *s) final override
882 /* Emit the case label. */
883 tree label = this->define_label (s);
885 if (LABEL_VARIABLE_CASE (label))
886 this->do_label (label);
887 else
889 tree casevalue;
890 if (s->exp->type->isscalar ())
891 casevalue = build_expr (s->exp);
892 else
893 casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
895 tree caselabel = build_case_label (casevalue, NULL_TREE, label);
896 add_stmt (caselabel);
899 /* Now do the body. */
900 if (s->statement)
901 this->build_stmt (s->statement);
904 /* Declare the default label associated with the current SwitchStatement. */
906 void visit (DefaultStatement *s) final override
908 /* Emit the default case label. */
909 tree label = this->define_label (s);
911 if (LABEL_VARIABLE_CASE (label))
912 this->do_label (label);
913 else
915 tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
916 add_stmt (caselabel);
919 /* Now do the body. */
920 if (s->statement)
921 this->build_stmt (s->statement);
924 /* Implements `goto default' by jumping to the label associated with
925 the DefaultStatement in a switch block. */
927 void visit (GotoDefaultStatement *s) final override
929 tree label = this->lookup_label (s->sw->sdefault);
930 this->do_jump (label);
933 /* Implements `goto case' by jumping to the label associated with the
934 CaseStatement in a switch block. */
936 void visit (GotoCaseStatement *s) final override
938 tree label = this->lookup_label (s->cs);
939 this->do_jump (label);
942 /* Throw a SwitchError exception, called when a switch statement has
943 no DefaultStatement, yet none of the cases match. */
945 void visit (SwitchErrorStatement *s) final override
947 /* A throw SwitchError statement gets turned into a library call.
948 The call is wrapped in the enclosed expression. */
949 gcc_assert (s->exp != NULL);
950 add_stmt (build_expr (s->exp));
953 /* A return statement exits the current function and supplies its return
954 value, if the return type is not void. */
956 void visit (ReturnStatement *s) final override
958 if (s->exp == NULL || s->exp->type->toBasetype ()->ty == TY::Tvoid)
960 /* Return has no value. */
961 add_stmt (return_expr (NULL_TREE));
962 return;
965 TypeFunction *tf = this->func_->type->toTypeFunction ();
966 Type *type = this->func_->tintro != NULL
967 ? this->func_->tintro->nextOf () : tf->nextOf ();
969 if ((this->func_->isMain () || this->func_->isCMain ())
970 && type->toBasetype ()->ty == TY::Tvoid)
971 type = Type::tint32;
973 if (this->func_->shidden)
975 /* Returning by hidden reference, store the result into the retval decl.
976 The result returned then becomes the retval reference itself. */
977 tree decl = DECL_RESULT (get_symbol_decl (this->func_));
978 gcc_assert (!tf->isref ());
980 /* If returning via NRVO, just refer to the DECL_RESULT; this differs
981 from using NULL_TREE in that it indicates that we care about the
982 value of the DECL_RESULT. */
983 if (this->func_->isNRVO () && this->func_->nrvo_var)
985 add_stmt (return_expr (decl));
986 return;
989 /* Detect a call to a constructor function, or if returning a struct
990 literal, write result directly into the return value. */
991 StructLiteralExp *sle = NULL;
992 bool using_rvo_p = false;
994 if (DotVarExp *dve = (s->exp->isCallExp ()
995 ? s->exp->isCallExp ()->e1->isDotVarExp ()
996 : NULL))
998 if (dve->var->isCtorDeclaration ())
1000 if (CommaExp *ce = dve->e1->isCommaExp ())
1002 /* Temporary initialized inside a return expression, and
1003 used as the return value. Replace it with the hidden
1004 reference to allow RVO return. */
1005 DeclarationExp *de = ce->e1->isDeclarationExp ();
1006 VarExp *ve = ce->e2->isVarExp ();
1007 if (de != NULL && ve != NULL
1008 && ve->var == de->declaration
1009 && ve->var->storage_class & STCtemp)
1011 tree var = get_symbol_decl (ve->var);
1012 TREE_ADDRESSABLE (var) = 1;
1013 SET_DECL_VALUE_EXPR (var, decl);
1014 DECL_HAS_VALUE_EXPR_P (var) = 1;
1015 SET_DECL_LANG_NRVO (var, this->func_->shidden);
1016 using_rvo_p = true;
1019 else
1020 sle = dve->e1->isStructLiteralExp ();
1023 else
1024 sle = s->exp->isStructLiteralExp ();
1026 if (sle != NULL)
1028 StructDeclaration *sd = type->baseElemOf ()->isTypeStruct ()->sym;
1029 sle->sym = build_address (this->func_->shidden);
1030 using_rvo_p = true;
1032 /* Fill any alignment holes in the return slot using memset. */
1033 if (!identity_compare_p (sd) || sd->isUnionDeclaration ())
1034 add_stmt (build_memset_call (this->func_->shidden));
1037 if (using_rvo_p == true)
1039 /* Generate: (expr, return <retval>); */
1040 add_stmt (build_expr_dtor (s->exp));
1042 else
1044 /* Generate: (<retval> = expr, return <retval>); */
1045 tree expr = build_expr_dtor (s->exp);
1046 tree init = stabilize_expr (&expr);
1047 expr = convert_for_rvalue (expr, s->exp->type, type);
1048 expr = build_assign (INIT_EXPR, this->func_->shidden, expr);
1049 add_stmt (compound_expr (init, expr));
1052 add_stmt (return_expr (decl));
1054 else if (tf->next->ty == TY::Tnoreturn)
1056 /* Returning an expression that has no value, but has a side effect
1057 that should never return. */
1058 add_stmt (build_expr_dtor (s->exp));
1059 add_stmt (return_expr (NULL_TREE));
1061 else
1063 /* Convert for initializing the DECL_RESULT. */
1064 add_stmt (build_return_dtor (s->exp, type, tf));
1068 /* Evaluate the enclosed expression, and add it to the statement list. */
1070 void visit (ExpStatement *s) final override
1072 if (s->exp)
1074 /* Expression may produce temporaries requiring scope destruction. */
1075 tree exp = build_expr_dtor (s->exp);
1076 add_stmt (exp);
1080 /* Evaluate all enclosed statements. */
1082 void visit (CompoundStatement *s) final override
1084 if (s->statements == NULL)
1085 return;
1087 for (size_t i = 0; i < s->statements->length; i++)
1089 Statement *statement = (*s->statements)[i];
1091 if (statement != NULL)
1092 this->build_stmt (statement);
1096 /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
1097 These are compiled down as a `do ... while (0)', where each unrolled loop
1098 is nested inside and given their own continue label to jump to. */
1100 void visit (UnrolledLoopStatement *s) final override
1102 if (s->statements == NULL)
1103 return;
1105 tree lbreak = this->push_break_label (s);
1106 this->start_scope (level_loop);
1108 for (size_t i = 0; i < s->statements->length; i++)
1110 Statement *statement = (*s->statements)[i];
1112 if (statement != NULL)
1114 this->push_unrolled_continue_label (s);
1115 this->build_stmt (statement);
1116 this->pop_unrolled_continue_label (s);
1120 this->do_jump (this->break_label_);
1122 tree body = this->end_scope ();
1123 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
1125 this->pop_break_label (lbreak);
1128 /* Start a new scope and visit all nested statements, wrapping
1129 them up into a BIND_EXPR at the end of the scope. */
1131 void visit (ScopeStatement *s) final override
1133 if (s->statement == NULL)
1134 return;
1136 this->start_scope (level_block);
1137 this->build_stmt (s->statement);
1138 this->finish_scope ();
1141 /* A with statement is a way to simplify repeated references to the same
1142 object, where the handle is either a class or struct instance. */
1144 void visit (WithStatement *s) final override
1146 this->start_scope (level_with);
1148 if (s->wthis)
1150 /* Perform initialisation of the `with' handle. */
1151 ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
1152 gcc_assert (ie != NULL);
1154 declare_local_var (s->wthis);
1155 tree init = build_expr_dtor (ie->exp);
1156 add_stmt (init);
1159 if (s->_body)
1160 this->build_stmt (s->_body);
1162 this->finish_scope ();
1165 /* Implements `throw Object'. Frontend already checks that the object
1166 thrown is a class type, but does not check if it is derived from
1167 Object. Foreign objects are not currently supported at run-time. */
1169 void visit (ThrowStatement *s) final override
1171 ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
1172 InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
1173 tree arg = build_expr_dtor (s->exp);
1175 if (!global.params.useExceptions)
1177 static int warned = 0;
1178 if (!warned)
1180 error_at (make_location_t (s->loc), "exception handling disabled; "
1181 "use %<-fexceptions%> to enable");
1182 warned = 1;
1186 if (cd->isCPPclass () || (id != NULL && id->isCPPclass ()))
1187 error_at (make_location_t (s->loc), "cannot throw C++ classes");
1188 else if (cd->com || (id != NULL && id->com))
1189 error_at (make_location_t (s->loc), "cannot throw COM objects");
1190 else
1191 arg = build_nop (build_ctype (get_object_type ()), arg);
1193 add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
1196 /* Build a try-catch statement, one of the building blocks for exception
1197 handling generated by the frontend. This is also used to implement
1198 `scope (failure)' statements. */
1200 void visit (TryCatchStatement *s) final override
1202 this->start_scope (level_try);
1203 if (s->_body)
1204 this->build_stmt (s->_body);
1206 tree trybody = this->end_scope ();
1208 /* Try handlers go in their own statement list. */
1209 push_stmt_list ();
1211 if (s->catches)
1213 for (size_t i = 0; i < s->catches->length; i++)
1215 Catch *vcatch = (*s->catches)[i];
1217 this->start_scope (level_catch);
1219 tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
1220 tree catchtype = build_ctype (vcatch->type);
1221 tree object = NULL_TREE;
1223 ehptr = build_call_expr (ehptr, 1, integer_zero_node);
1225 /* Retrieve the internal exception object, which could be for a
1226 D or C++ catch handler. This is different from the generic
1227 exception pointer returned from gcc runtime. */
1228 Type *tcatch = vcatch->type->toBasetype ();
1229 ClassDeclaration *cd = tcatch->isClassHandle ();
1231 libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1232 : LIBCALL_BEGIN_CATCH;
1233 object = build_libcall (libcall, vcatch->type, 1, ehptr);
1235 if (vcatch->var)
1237 tree var = get_symbol_decl (vcatch->var);
1238 tree init = build_assign (INIT_EXPR, var, object);
1240 declare_local_var (vcatch->var);
1241 add_stmt (init);
1243 else
1245 /* Still need to emit a call to __gdc_begin_catch() to
1246 remove the object from the uncaught exceptions list. */
1247 add_stmt (object);
1250 if (vcatch->handler)
1251 this->build_stmt (vcatch->handler);
1253 tree catchbody = this->end_scope ();
1255 /* Need to wrap C++ handlers in a try/finally block to signal
1256 the end catch callback. */
1257 if (cd->isCPPclass ())
1259 tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
1260 Type::tvoid, 0);
1261 catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
1262 catchbody, endcatch);
1265 add_stmt (build2 (CATCH_EXPR, void_type_node,
1266 catchtype, catchbody));
1270 tree catches = pop_stmt_list ();
1272 /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
1273 statement list, however pop_stmt_list may optimize away the list
1274 if there is only a single catch to push. */
1275 if (TREE_CODE (catches) != STATEMENT_LIST)
1277 tree stmt_list = alloc_stmt_list ();
1278 append_to_statement_list_force (catches, &stmt_list);
1279 catches = stmt_list;
1282 add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
1285 /* Build a try-finally statement, one of the building blocks for exception
1286 handling generated by the frontend. This is also used to implement
1287 `scope (exit)' statements. */
1289 void visit (TryFinallyStatement *s) final override
1291 this->start_scope (level_try);
1292 if (s->_body)
1293 this->build_stmt (s->_body);
1295 tree trybody = this->end_scope ();
1297 this->start_scope (level_finally);
1298 if (s->finalbody)
1299 this->build_stmt (s->finalbody);
1301 tree finally = this->end_scope ();
1303 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
1306 /* The frontend lowers `synchronized (...)' statements as a call to
1307 monitor/critical enter and exit wrapped around try/finally.
1308 This visitor is not strictly required other than to enforce that
1309 these kinds of statements never reach here. */
1311 void visit (SynchronizedStatement *) final override
1313 gcc_unreachable ();
1316 /* D Inline Assembler is not implemented, as it would require writing
1317 an assembly parser for each supported target. Instead we leverage
1318 GCC extended assembler using the GccAsmStatement class. */
1320 void visit (AsmStatement *) final override
1322 sorry ("D inline assembler statements are not supported in GDC.");
1325 /* Build a GCC extended assembler expression, whose components are
1326 an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */
1328 void visit (GccAsmStatement *s) final override
1330 StringExp *insn = s->insn->toStringExp ();
1331 tree outputs = NULL_TREE;
1332 tree inputs = NULL_TREE;
1333 tree clobbers = NULL_TREE;
1334 tree labels = NULL_TREE;
1336 /* Collect all arguments, which may be input or output operands. */
1337 if (s->args)
1339 for (size_t i = 0; i < s->args->length; i++)
1341 Identifier *name = (*s->names)[i];
1342 const char *sname = name ? name->toChars () : NULL;
1343 tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
1345 StringExp *constr = (*s->constraints)[i]->toStringExp ();
1346 const char *cstring = (const char *)(constr->len
1347 ? constr->string : "");
1348 tree str = build_string (constr->len, cstring);
1350 Expression *earg = (*s->args)[i];
1351 tree val = build_expr (earg);
1353 if (i < s->outputargs)
1355 tree arg = build_tree_list (id, str);
1356 outputs = chainon (outputs, build_tree_list (arg, val));
1358 else
1360 tree arg = build_tree_list (id, str);
1361 inputs = chainon (inputs, build_tree_list (arg, val));
1366 /* Collect all clobber arguments. */
1367 if (s->clobbers)
1369 for (size_t i = 0; i < s->clobbers->length; i++)
1371 StringExp *clobber = (*s->clobbers)[i]->toStringExp ();
1372 const char *cstring = (const char *)(clobber->len
1373 ? clobber->string : "");
1375 tree val = build_string (clobber->len, cstring);
1376 clobbers = chainon (clobbers, build_tree_list (0, val));
1380 /* Collect all goto labels, these should have been already checked
1381 by the front-end, so pass down the label symbol to the back-end. */
1382 if (s->labels)
1384 for (size_t i = 0; i < s->labels->length; i++)
1386 Identifier *ident = (*s->labels)[i];
1387 GotoStatement *gs = (*s->gotos)[i];
1389 gcc_assert (gs->label->statement != NULL);
1390 gcc_assert (gs->tf == gs->label->statement->tf);
1392 const char *sident = ident->toChars ();
1393 tree name = build_string (strlen (sident), sident);
1394 tree label = this->lookup_label (gs->label->statement,
1395 gs->label->ident);
1396 TREE_USED (label) = 1;
1398 labels = chainon (labels, build_tree_list (name, label));
1402 /* Do some extra validation on all input and output operands. */
1403 const char *insnstring = (const char *)(insn->len ? insn->string : "");
1404 tree string = build_string (insn->len, insnstring);
1405 string = resolve_asm_operand_names (string, outputs, inputs, labels);
1407 if (s->args)
1409 unsigned noutputs = s->outputargs;
1410 unsigned ninputs = (s->args->length - noutputs);
1411 const char **oconstraints = XALLOCAVEC (const char *, noutputs);
1412 bool allows_mem, allows_reg, is_inout;
1413 size_t i;
1414 tree t;
1416 for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1418 tree output = TREE_VALUE (t);
1419 const char *constraint
1420 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1422 oconstraints[i] = constraint;
1424 if (parse_output_constraint (&constraint, i, ninputs, noutputs,
1425 &allows_mem, &allows_reg, &is_inout))
1427 /* If the output argument is going to end up in memory. */
1428 if (!allows_reg)
1429 d_mark_addressable (output);
1431 else
1432 output = error_mark_node;
1434 TREE_VALUE (t) = output;
1437 for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1439 tree input = TREE_VALUE (t);
1440 const char *constraint
1441 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1443 if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
1444 oconstraints, &allows_mem, &allows_reg))
1446 /* If the input argument is going to end up in memory. */
1447 if (!allows_reg && allows_mem)
1448 d_mark_addressable (input);
1450 else
1451 input = error_mark_node;
1453 TREE_VALUE (t) = input;
1457 tree exp = build5 (ASM_EXPR, void_type_node, string,
1458 outputs, inputs, clobbers, labels);
1459 SET_EXPR_LOCATION (exp, make_location_t (s->loc));
1461 /* If the extended syntax was not used, mark the ASM_EXPR as being an
1462 ASM_INPUT expression instead of an ASM_OPERAND with no operands. */
1463 if (s->args == NULL && s->clobbers == NULL)
1464 ASM_INPUT_P (exp) = 1;
1466 /* All asm statements are assumed to have a side effect. As a future
1467 optimization, this could be unset when building in release mode. */
1468 ASM_VOLATILE_P (exp) = 1;
1470 /* If the function has been annotated with `pragma(inline)', then mark
1471 the asm expression as being inline as well. */
1472 if (this->func_->inlining == PINLINE::always)
1473 ASM_INLINE_P (exp) = 1;
1475 add_stmt (exp);
1478 /* Import symbols from another module. */
1480 void visit (ImportStatement *s) final override
1482 if (s->imports == NULL)
1483 return;
1485 for (size_t i = 0; i < s->imports->length; i++)
1487 Dsymbol *dsym = (*s->imports)[i];
1489 if (dsym != NULL)
1490 build_decl_tree (dsym);
1495 /* Main entry point for the IRVisitor interface to generate
1496 code for the body of function FD. */
1498 void
1499 build_function_body (FuncDeclaration *fd)
1501 IRVisitor v = IRVisitor (fd);
1502 location_t saved_location = input_location;
1503 input_location = make_location_t (fd->loc);
1504 v.build_stmt (fd->fbody);
1505 input_location = saved_location;