testsuite: Use posix_memalign on AIX for tsvc
[official-gcc.git] / gcc / d / toir.cc
blob1c9da101f3995a76da8aaf0df7d285ccff739fb8
1 /* toir.cc -- Lower D frontend statements to GCC trees.
2 Copyright (C) 2006-2021 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 if (s->isCaseStatement ())
418 location = make_location_t (s->loc);
419 error_at (location, "case cannot be in different "
420 "%<try%> block level from %<switch%>");
422 else if (s->isDefaultStatement ())
424 location = make_location_t (s->loc);
425 error_at (location, "default cannot be in different "
426 "%<try%> block level from %<switch%>");
428 else
429 gcc_unreachable ();
434 /* Get or build LABEL_DECL using the IDENT and statement block S given. */
436 tree lookup_label (Statement *s, Identifier *ident = NULL)
438 /* You can't use labels at global scope. */
439 if (d_function_chain == NULL)
441 error ("label %s referenced outside of any function",
442 ident ? ident->toChars () : "(unnamed)");
443 return NULL_TREE;
446 /* Create the label htab for the function on demand. */
447 if (!d_function_chain->labels)
449 d_function_chain->labels
450 = hash_map <Statement *, d_label_entry>::create_ggc (13);
453 d_label_entry *ent = d_function_chain->labels->get (s);
454 if (ent != NULL)
455 return ent->label;
456 else
458 tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE;
459 tree decl = build_decl (make_location_t (s->loc), LABEL_DECL,
460 name, void_type_node);
461 DECL_CONTEXT (decl) = current_function_decl;
462 DECL_MODE (decl) = VOIDmode;
464 /* Create new empty slot. */
465 ent = ggc_cleared_alloc <d_label_entry> ();
466 ent->statement = s;
467 ent->label = decl;
469 bool existed = d_function_chain->labels->put (s, *ent);
470 gcc_assert (!existed);
472 return decl;
476 /* Get the LABEL_DECL to represent a break or continue for the
477 statement S given. BC indicates which. */
479 tree lookup_bc_label (Statement *s, bc_kind bc)
481 tree vec = this->lookup_label (s);
483 /* The break and continue labels are put into a TREE_VEC. */
484 if (TREE_CODE (vec) == LABEL_DECL)
486 d_label_entry *ent = d_function_chain->labels->get (s);
487 gcc_assert (ent != NULL);
489 vec = make_tree_vec (2);
490 TREE_VEC_ELT (vec, bc_break) = ent->label;
492 /* Build the continue label. */
493 tree label = build_decl (make_location_t (s->loc), LABEL_DECL,
494 NULL_TREE, void_type_node);
495 DECL_CONTEXT (label) = current_function_decl;
496 DECL_MODE (label) = VOIDmode;
497 TREE_VEC_ELT (vec, bc_continue) = label;
499 ent->label = vec;
500 ent->bc_label = true;
503 return TREE_VEC_ELT (vec, bc);
506 /* Set and return the current break label for the current block. */
508 tree push_break_label (Statement *s)
510 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break);
511 DECL_CHAIN (label) = this->break_label_;
512 this->break_label_ = label;
513 return label;
516 /* Finish with the current break label. */
518 void pop_break_label (tree label)
520 gcc_assert (this->break_label_ == label);
521 this->break_label_ = DECL_CHAIN (this->break_label_);
522 this->do_label (label);
525 /* Set and return the continue label for the current block. */
527 tree push_continue_label (Statement *s)
529 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue);
530 DECL_CHAIN (label) = this->continue_label_;
531 this->continue_label_ = label;
532 return label;
535 /* Finish with the current continue label. */
537 void pop_continue_label (tree label)
539 gcc_assert (this->continue_label_ == label);
540 this->continue_label_ = DECL_CHAIN (this->continue_label_);
541 this->do_label (label);
544 /* Visitor interfaces. */
547 /* This should be overridden by each statement class. */
549 void visit (Statement *)
551 gcc_unreachable ();
554 /* The frontend lowers `scope (exit/failure/success)' statements as
555 try/catch/finally. At this point, this statement is just an empty
556 placeholder. Maybe the frontend shouldn't leak these. */
558 void visit (ScopeGuardStatement *)
562 /* If statements provide simple conditional execution of statements. */
564 void visit (IfStatement *s)
566 this->start_scope (level_cond);
568 /* Build the outer `if' condition, which may produce temporaries
569 requiring scope destruction. */
570 tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
571 s->condition->type);
572 tree ifbody = void_node;
573 tree elsebody = void_node;
575 /* Build the `then' branch. */
576 if (s->ifbody)
578 push_stmt_list ();
579 this->build_stmt (s->ifbody);
580 ifbody = pop_stmt_list ();
583 /* Now build the `else' branch, which may have nested `else if' parts. */
584 if (s->elsebody)
586 push_stmt_list ();
587 this->build_stmt (s->elsebody);
588 elsebody = pop_stmt_list ();
591 /* Wrap up our constructed if condition into a COND_EXPR. */
592 tree cond = build_vcondition (ifcond, ifbody, elsebody);
593 add_stmt (cond);
595 /* Finish the if-then scope. */
596 this->finish_scope ();
599 /* Should there be any `pragma (...)' statements requiring code generation,
600 here would be the place to do it. For now, all pragmas are handled
601 by the frontend. */
603 void visit (PragmaStatement *)
607 /* The frontend lowers `while (...)' statements as `for (...)' loops.
608 This visitor is not strictly required other than to enforce that
609 these kinds of statements never reach here. */
611 void visit (WhileStatement *)
613 gcc_unreachable ();
616 /* Do while statments implement simple loops. The body is executed, then
617 the condition is evaluated. */
619 void visit (DoStatement *s)
621 tree lbreak = this->push_break_label (s);
623 this->start_scope (level_loop);
624 if (s->_body)
626 tree lcontinue = this->push_continue_label (s);
627 this->build_stmt (s->_body);
628 this->pop_continue_label (lcontinue);
631 /* Build the outer `while' condition, which may produce temporaries
632 requiring scope destruction. */
633 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
634 s->condition->type);
635 add_stmt (build_vcondition (exitcond, void_node,
636 build1 (GOTO_EXPR, void_type_node, lbreak)));
637 TREE_USED (lbreak) = 1;
639 tree body = this->end_scope ();
640 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
642 this->pop_break_label (lbreak);
645 /* For statements implement loops with initialization, test, and
646 increment clauses. */
648 void visit (ForStatement *s)
650 tree lbreak = this->push_break_label (s);
651 this->start_scope (level_loop);
653 if (s->_init)
654 this->build_stmt (s->_init);
656 if (s->condition)
658 tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
659 s->condition->type);
660 add_stmt (build_vcondition (exitcond, void_node,
661 build1 (GOTO_EXPR, void_type_node,
662 lbreak)));
663 TREE_USED (lbreak) = 1;
666 if (s->_body)
668 tree lcontinue = this->push_continue_label (s);
669 this->build_stmt (s->_body);
670 this->pop_continue_label (lcontinue);
673 if (s->increment)
675 /* Force side effects? */
676 add_stmt (build_expr_dtor (s->increment));
679 tree body = this->end_scope ();
680 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
682 this->pop_break_label (lbreak);
685 /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
686 This visitor is not strictly required other than to enforce that
687 these kinds of statements never reach here. */
689 void visit (ForeachStatement *)
691 gcc_unreachable ();
694 /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
695 loops. This visitor is not strictly required other than to enforce that
696 these kinds of statements never reach here. */
698 void visit (ForeachRangeStatement *)
700 gcc_unreachable ();
703 /* Jump to the associated exit label for the current loop. If IDENT
704 for the Statement is not null, then the label is user defined. */
706 void visit (BreakStatement *s)
708 if (s->ident)
710 /* The break label may actually be some levels up.
711 eg: on a try/finally wrapping a loop. */
712 LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
713 gcc_assert (label != NULL);
714 Statement *stmt = label->statement->getRelatedLabeled ();
715 this->do_jump (this->lookup_bc_label (stmt, bc_break));
717 else
718 this->do_jump (this->break_label_);
721 /* Jump to the associated continue label for the current loop. If IDENT
722 for the Statement is not null, then the label is user defined. */
724 void visit (ContinueStatement *s)
726 if (s->ident)
728 LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
729 gcc_assert (label != NULL);
730 this->do_jump (this->lookup_bc_label (label->statement,
731 bc_continue));
733 else
734 this->do_jump (this->continue_label_);
737 /* A goto statement jumps to the statement identified by the given label. */
739 void visit (GotoStatement *s)
741 gcc_assert (s->label->statement != NULL);
742 gcc_assert (s->tf == s->label->statement->tf);
744 /* If no label found, there was an error. */
745 tree label = this->lookup_label (s->label->statement, s->label->ident);
746 this->do_jump (label);
748 /* Need to error if the goto is jumping into a try or catch block. */
749 this->check_goto (s, s->label->statement);
752 /* Statements can be labeled. A label is an identifier that precedes
753 a statement. */
755 void visit (LabelStatement *s)
757 LabelDsymbol *sym;
759 if (this->is_return_label (s->ident))
760 sym = this->func_->returnLabel;
761 else
762 sym = this->func_->searchLabel (s->ident);
764 /* If no label found, there was an error. */
765 tree label = this->define_label (sym->statement, sym->ident);
766 TREE_USED (label) = 1;
768 this->do_label (label);
770 if (this->is_return_label (s->ident) && this->func_->fensure != NULL)
771 this->build_stmt (this->func_->fensure);
772 else if (s->statement)
773 this->build_stmt (s->statement);
776 /* A switch statement goes to one of a collection of case statements
777 depending on the value of the switch expression. */
779 void visit (SwitchStatement *s)
781 this->start_scope (level_switch);
782 tree lbreak = this->push_break_label (s);
784 tree condition = build_expr_dtor (s->condition);
785 Type *condtype = s->condition->type->toBasetype ();
787 /* A switch statement on a string gets turned into a library call,
788 which does a binary lookup on list of string cases. */
789 if (s->condition->type->isString ())
791 Type *etype = condtype->nextOf ()->toBasetype ();
792 libcall_fn libcall;
794 switch (etype->ty)
796 case Tchar:
797 libcall = LIBCALL_SWITCH_STRING;
798 break;
800 case Twchar:
801 libcall = LIBCALL_SWITCH_USTRING;
802 break;
804 case Tdchar:
805 libcall = LIBCALL_SWITCH_DSTRING;
806 break;
808 default:
809 ::error ("switch statement value must be an array of "
810 "some character type, not %s", etype->toChars ());
811 gcc_unreachable ();
814 /* Apparently the backend is supposed to sort and set the indexes
815 on the case array, have to change them to be usable. */
816 Type *satype = condtype->sarrayOf (s->cases->length);
817 vec <constructor_elt, va_gc> *elms = NULL;
819 s->cases->sort ();
821 for (size_t i = 0; i < s->cases->length; i++)
823 CaseStatement *cs = (*s->cases)[i];
824 cs->index = i;
826 if (cs->exp->op != TOKstring)
827 s->error ("case '%s' is not a string", cs->exp->toChars ());
828 else
830 tree exp = build_expr (cs->exp, true);
831 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
835 /* Build static declaration to reference constructor. */
836 tree ctor = build_constructor (build_ctype (satype), elms);
837 tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
838 TREE_READONLY (decl) = 1;
839 d_pushdecl (decl);
840 rest_of_decl_compilation (decl, 1, 0);
842 /* Pass it as a dynamic array. */
843 decl = d_array_value (build_ctype (condtype->arrayOf ()),
844 size_int (s->cases->length),
845 build_address (decl));
847 condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
849 else if (!condtype->isscalar ())
851 error ("cannot handle switch condition of type %s",
852 condtype->toChars ());
853 gcc_unreachable ();
856 condition = fold (condition);
858 /* Build LABEL_DECLs now so they can be refered to by goto case.
859 Also checking the jump from the switch to the label is allowed. */
860 if (s->cases)
862 for (size_t i = 0; i < s->cases->length; i++)
864 CaseStatement *cs = (*s->cases)[i];
865 tree caselabel = this->lookup_label (cs);
867 /* Write cases as a series of if-then-else blocks.
868 if (condition == case)
869 goto caselabel; */
870 if (s->hasVars)
872 tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
873 condition, build_expr_dtor (cs->exp));
874 tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
875 caselabel);
876 tree cond = build_vcondition (ifcase, ifbody, void_node);
877 TREE_USED (caselabel) = 1;
878 LABEL_VARIABLE_CASE (caselabel) = 1;
879 add_stmt (cond);
882 this->check_goto (s, cs);
885 if (s->sdefault)
887 tree defaultlabel = this->lookup_label (s->sdefault);
889 /* The default label is the last `else' block. */
890 if (s->hasVars)
892 this->do_jump (defaultlabel);
893 LABEL_VARIABLE_CASE (defaultlabel) = 1;
896 this->check_goto (s, s->sdefault);
900 /* Switch body goes in its own statement list. */
901 push_stmt_list ();
902 if (s->_body)
903 this->build_stmt (s->_body);
905 tree casebody = pop_stmt_list ();
907 /* Wrap up constructed body into a switch_expr, unless it was
908 converted to an if-then-else expression. */
909 if (s->hasVars)
910 add_stmt (casebody);
911 else
913 tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
914 condition, casebody);
915 add_stmt (switchexpr);
916 SWITCH_ALL_CASES_P (switchexpr) = 1;
919 SWITCH_BREAK_LABEL_P (lbreak) = 1;
921 /* If the switch had any `break' statements, emit the label now. */
922 this->pop_break_label (lbreak);
923 this->finish_scope ();
926 /* Declare the case label associated with the current SwitchStatement. */
928 void visit (CaseStatement *s)
930 /* Emit the case label. */
931 tree label = this->define_label (s);
933 if (LABEL_VARIABLE_CASE (label))
934 this->do_label (label);
935 else
937 tree casevalue;
938 if (s->exp->type->isscalar ())
939 casevalue = build_expr (s->exp);
940 else
941 casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
943 tree caselabel = build_case_label (casevalue, NULL_TREE, label);
944 add_stmt (caselabel);
947 /* Now do the body. */
948 if (s->statement)
949 this->build_stmt (s->statement);
952 /* Declare the default label associated with the current SwitchStatement. */
954 void visit (DefaultStatement *s)
956 /* Emit the default case label. */
957 tree label = this->define_label (s);
959 if (LABEL_VARIABLE_CASE (label))
960 this->do_label (label);
961 else
963 tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
964 add_stmt (caselabel);
967 /* Now do the body. */
968 if (s->statement)
969 this->build_stmt (s->statement);
972 /* Implements `goto default' by jumping to the label associated with
973 the DefaultStatement in a switch block. */
975 void visit (GotoDefaultStatement *s)
977 tree label = this->lookup_label (s->sw->sdefault);
978 this->do_jump (label);
981 /* Implements `goto case' by jumping to the label associated with the
982 CaseStatement in a switch block. */
984 void visit (GotoCaseStatement *s)
986 tree label = this->lookup_label (s->cs);
987 this->do_jump (label);
990 /* Throw a SwitchError exception, called when a switch statement has
991 no DefaultStatement, yet none of the cases match. */
993 void visit (SwitchErrorStatement *s)
995 add_stmt (build_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
998 /* A return statement exits the current function and supplies its return
999 value, if the return type is not void. */
1001 void visit (ReturnStatement *s)
1003 if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
1005 /* Return has no value. */
1006 add_stmt (return_expr (NULL_TREE));
1007 return;
1010 TypeFunction *tf = this->func_->type->toTypeFunction ();
1011 Type *type = this->func_->tintro != NULL
1012 ? this->func_->tintro->nextOf () : tf->nextOf ();
1014 if ((this->func_->isMain () || this->func_->isCMain ())
1015 && type->toBasetype ()->ty == Tvoid)
1016 type = Type::tint32;
1018 if (this->func_->shidden)
1020 /* Returning by hidden reference, store the result into the retval decl.
1021 The result returned then becomes the retval reference itself. */
1022 tree decl = DECL_RESULT (get_symbol_decl (this->func_));
1023 gcc_assert (!tf->isref);
1025 /* If returning via NRVO, just refer to the DECL_RESULT; this differs
1026 from using NULL_TREE in that it indicates that we care about the
1027 value of the DECL_RESULT. */
1028 if (this->func_->nrvo_can && this->func_->nrvo_var)
1030 add_stmt (return_expr (decl));
1031 return;
1034 /* Detect a call to a constructor function, or if returning a struct
1035 literal, write result directly into the return value. */
1036 StructLiteralExp *sle = NULL;
1037 bool using_rvo_p = false;
1039 if (DotVarExp *dve = (s->exp->op == TOKcall
1040 && s->exp->isCallExp ()->e1->op == TOKdotvar
1041 ? s->exp->isCallExp ()->e1->isDotVarExp ()
1042 : NULL))
1044 if (dve->var->isCtorDeclaration ())
1046 if (CommaExp *ce = dve->e1->isCommaExp ())
1048 /* Temporary initialized inside a return expression, and
1049 used as the return value. Replace it with the hidden
1050 reference to allow RVO return. */
1051 DeclarationExp *de = ce->e1->isDeclarationExp ();
1052 VarExp *ve = ce->e2->isVarExp ();
1053 if (de != NULL && ve != NULL
1054 && ve->var == de->declaration
1055 && ve->var->storage_class & STCtemp)
1057 tree var = get_symbol_decl (ve->var);
1058 TREE_ADDRESSABLE (var) = 1;
1059 SET_DECL_VALUE_EXPR (var, decl);
1060 DECL_HAS_VALUE_EXPR_P (var) = 1;
1061 SET_DECL_LANG_NRVO (var, this->func_->shidden);
1062 using_rvo_p = true;
1065 else
1066 sle = dve->e1->isStructLiteralExp ();
1069 else
1070 sle = s->exp->isStructLiteralExp ();
1072 if (sle != NULL)
1074 StructDeclaration *sd = type->baseElemOf ()->isTypeStruct ()->sym;
1075 sle->sym = build_address (this->func_->shidden);
1076 using_rvo_p = true;
1078 /* Fill any alignment holes in the return slot using memset. */
1079 if (!identity_compare_p (sd) || sd->isUnionDeclaration ())
1080 add_stmt (build_memset_call (this->func_->shidden));
1083 if (using_rvo_p == true)
1085 /* Generate: (expr, return <retval>); */
1086 add_stmt (build_expr_dtor (s->exp));
1088 else
1090 /* Generate: (<retval> = expr, return <retval>); */
1091 tree expr = build_expr_dtor (s->exp);
1092 tree init = stabilize_expr (&expr);
1093 expr = build_assign (INIT_EXPR, this->func_->shidden, expr);
1094 add_stmt (compound_expr (init, expr));
1097 add_stmt (return_expr (decl));
1099 else if (tf->next->ty == Tnoreturn)
1101 /* Returning an expression that has no value, but has a side effect
1102 that should never return. */
1103 add_stmt (build_expr_dtor (s->exp));
1104 add_stmt (return_expr (NULL_TREE));
1106 else
1108 /* Convert for initializing the DECL_RESULT. */
1109 add_stmt (build_return_dtor (s->exp, type, tf));
1113 /* Evaluate the enclosed expression, and add it to the statement list. */
1115 void visit (ExpStatement *s)
1117 if (s->exp)
1119 /* Expression may produce temporaries requiring scope destruction. */
1120 tree exp = build_expr_dtor (s->exp);
1121 add_stmt (exp);
1125 /* Evaluate all enclosed statements. */
1127 void visit (CompoundStatement *s)
1129 if (s->statements == NULL)
1130 return;
1132 for (size_t i = 0; i < s->statements->length; i++)
1134 Statement *statement = (*s->statements)[i];
1136 if (statement != NULL)
1137 this->build_stmt (statement);
1141 /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
1142 These are compiled down as a `do ... while (0)', where each unrolled loop
1143 is nested inside and given their own continue label to jump to. */
1145 void visit (UnrolledLoopStatement *s)
1147 if (s->statements == NULL)
1148 return;
1150 tree lbreak = this->push_break_label (s);
1151 this->start_scope (level_loop);
1153 for (size_t i = 0; i < s->statements->length; i++)
1155 Statement *statement = (*s->statements)[i];
1157 if (statement != NULL)
1159 tree lcontinue = this->push_continue_label (statement);
1160 this->build_stmt (statement);
1161 this->pop_continue_label (lcontinue);
1165 this->do_jump (this->break_label_);
1167 tree body = this->end_scope ();
1168 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
1170 this->pop_break_label (lbreak);
1173 /* Start a new scope and visit all nested statements, wrapping
1174 them up into a BIND_EXPR at the end of the scope. */
1176 void visit (ScopeStatement *s)
1178 if (s->statement == NULL)
1179 return;
1181 this->start_scope (level_block);
1182 this->build_stmt (s->statement);
1183 this->finish_scope ();
1186 /* A with statement is a way to simplify repeated references to the same
1187 object, where the handle is either a class or struct instance. */
1189 void visit (WithStatement *s)
1191 this->start_scope (level_with);
1193 if (s->wthis)
1195 /* Perform initialisation of the `with' handle. */
1196 ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
1197 gcc_assert (ie != NULL);
1199 declare_local_var (s->wthis);
1200 tree init = build_expr_dtor (ie->exp);
1201 add_stmt (init);
1204 if (s->_body)
1205 this->build_stmt (s->_body);
1207 this->finish_scope ();
1210 /* Implements `throw Object'. Frontend already checks that the object
1211 thrown is a class type, but does not check if it is derived from
1212 Object. Foreign objects are not currently supported at run-time. */
1214 void visit (ThrowStatement *s)
1216 ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
1217 InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
1218 tree arg = build_expr_dtor (s->exp);
1220 if (!global.params.useExceptions)
1222 static int warned = 0;
1223 if (!warned)
1225 error_at (make_location_t (s->loc), "exception handling disabled; "
1226 "use %<-fexceptions%> to enable");
1227 warned = 1;
1231 if (cd->isCPPclass () || (id != NULL && id->isCPPclass ()))
1232 error_at (make_location_t (s->loc), "cannot throw C++ classes");
1233 else if (cd->com || (id != NULL && id->com))
1234 error_at (make_location_t (s->loc), "cannot throw COM objects");
1235 else
1236 arg = build_nop (build_ctype (get_object_type ()), arg);
1238 add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
1241 /* Build a try-catch statement, one of the building blocks for exception
1242 handling generated by the frontend. This is also used to implement
1243 `scope (failure)' statements. */
1245 void visit (TryCatchStatement *s)
1247 this->start_scope (level_try);
1248 if (s->_body)
1249 this->build_stmt (s->_body);
1251 tree trybody = this->end_scope ();
1253 /* Try handlers go in their own statement list. */
1254 push_stmt_list ();
1256 if (s->catches)
1258 for (size_t i = 0; i < s->catches->length; i++)
1260 Catch *vcatch = (*s->catches)[i];
1262 this->start_scope (level_catch);
1264 tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
1265 tree catchtype = build_ctype (vcatch->type);
1266 tree object = NULL_TREE;
1268 ehptr = build_call_expr (ehptr, 1, integer_zero_node);
1270 /* Retrieve the internal exception object, which could be for a
1271 D or C++ catch handler. This is different from the generic
1272 exception pointer returned from gcc runtime. */
1273 Type *tcatch = vcatch->type->toBasetype ();
1274 ClassDeclaration *cd = tcatch->isClassHandle ();
1276 libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1277 : LIBCALL_BEGIN_CATCH;
1278 object = build_libcall (libcall, vcatch->type, 1, ehptr);
1280 if (vcatch->var)
1282 tree var = get_symbol_decl (vcatch->var);
1283 tree init = build_assign (INIT_EXPR, var, object);
1285 declare_local_var (vcatch->var);
1286 add_stmt (init);
1288 else
1290 /* Still need to emit a call to __gdc_begin_catch() to
1291 remove the object from the uncaught exceptions list. */
1292 add_stmt (object);
1295 if (vcatch->handler)
1296 this->build_stmt (vcatch->handler);
1298 tree catchbody = this->end_scope ();
1300 /* Need to wrap C++ handlers in a try/finally block to signal
1301 the end catch callback. */
1302 if (cd->isCPPclass ())
1304 tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
1305 Type::tvoid, 0);
1306 catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
1307 catchbody, endcatch);
1310 add_stmt (build2 (CATCH_EXPR, void_type_node,
1311 catchtype, catchbody));
1315 tree catches = pop_stmt_list ();
1317 /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
1318 statement list, however pop_stmt_list may optimize away the list
1319 if there is only a single catch to push. */
1320 if (TREE_CODE (catches) != STATEMENT_LIST)
1322 tree stmt_list = alloc_stmt_list ();
1323 append_to_statement_list_force (catches, &stmt_list);
1324 catches = stmt_list;
1327 add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
1330 /* Build a try-finally statement, one of the building blocks for exception
1331 handling generated by the frontend. This is also used to implement
1332 `scope (exit)' statements. */
1334 void visit (TryFinallyStatement *s)
1336 this->start_scope (level_try);
1337 if (s->_body)
1338 this->build_stmt (s->_body);
1340 tree trybody = this->end_scope ();
1342 this->start_scope (level_finally);
1343 if (s->finalbody)
1344 this->build_stmt (s->finalbody);
1346 tree finally = this->end_scope ();
1348 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
1351 /* The frontend lowers `synchronized (...)' statements as a call to
1352 monitor/critical enter and exit wrapped around try/finally.
1353 This visitor is not strictly required other than to enforce that
1354 these kinds of statements never reach here. */
1356 void visit (SynchronizedStatement *)
1358 gcc_unreachable ();
1361 /* D Inline Assembler is not implemented, as it would require writing
1362 an assembly parser for each supported target. Instead we leverage
1363 GCC extended assembler using the GccAsmStatement class. */
1365 void visit (AsmStatement *)
1367 sorry ("D inline assembler statements are not supported in GDC.");
1370 /* Build a GCC extended assembler expression, whose components are
1371 an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */
1373 void visit (GccAsmStatement *s)
1375 StringExp *insn = s->insn->toStringExp ();
1376 tree outputs = NULL_TREE;
1377 tree inputs = NULL_TREE;
1378 tree clobbers = NULL_TREE;
1379 tree labels = NULL_TREE;
1381 /* Collect all arguments, which may be input or output operands. */
1382 if (s->args)
1384 for (size_t i = 0; i < s->args->length; i++)
1386 Identifier *name = (*s->names)[i];
1387 const char *sname = name ? name->toChars () : NULL;
1388 tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
1390 StringExp *constr = (*s->constraints)[i]->toStringExp ();
1391 const char *cstring = (const char *)(constr->len
1392 ? constr->string : "");
1393 tree str = build_string (constr->len, cstring);
1395 Expression *earg = (*s->args)[i];
1396 tree val = build_expr (earg);
1398 if (i < s->outputargs)
1400 tree arg = build_tree_list (id, str);
1401 outputs = chainon (outputs, build_tree_list (arg, val));
1403 else
1405 tree arg = build_tree_list (id, str);
1406 inputs = chainon (inputs, build_tree_list (arg, val));
1411 /* Collect all clobber arguments. */
1412 if (s->clobbers)
1414 for (size_t i = 0; i < s->clobbers->length; i++)
1416 StringExp *clobber = (*s->clobbers)[i]->toStringExp ();
1417 const char *cstring = (const char *)(clobber->len
1418 ? clobber->string : "");
1420 tree val = build_string (clobber->len, cstring);
1421 clobbers = chainon (clobbers, build_tree_list (0, val));
1425 /* Collect all goto labels, these should have been already checked
1426 by the front-end, so pass down the label symbol to the back-end. */
1427 if (s->labels)
1429 for (size_t i = 0; i < s->labels->length; i++)
1431 Identifier *ident = (*s->labels)[i];
1432 GotoStatement *gs = (*s->gotos)[i];
1434 gcc_assert (gs->label->statement != NULL);
1435 gcc_assert (gs->tf == gs->label->statement->tf);
1437 const char *sident = ident->toChars ();
1438 tree name = build_string (strlen (sident), sident);
1439 tree label = this->lookup_label (gs->label->statement,
1440 gs->label->ident);
1441 TREE_USED (label) = 1;
1443 labels = chainon (labels, build_tree_list (name, label));
1447 /* Do some extra validation on all input and output operands. */
1448 const char *insnstring = (const char *)(insn->len ? insn->string : "");
1449 tree string = build_string (insn->len, insnstring);
1450 string = resolve_asm_operand_names (string, outputs, inputs, labels);
1452 if (s->args)
1454 unsigned noutputs = s->outputargs;
1455 unsigned ninputs = (s->args->length - noutputs);
1456 const char **oconstraints = XALLOCAVEC (const char *, noutputs);
1457 bool allows_mem, allows_reg, is_inout;
1458 size_t i;
1459 tree t;
1461 for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1463 tree output = TREE_VALUE (t);
1464 const char *constraint
1465 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1467 oconstraints[i] = constraint;
1469 if (parse_output_constraint (&constraint, i, ninputs, noutputs,
1470 &allows_mem, &allows_reg, &is_inout))
1472 /* If the output argument is going to end up in memory. */
1473 if (!allows_reg)
1474 d_mark_addressable (output);
1476 else
1477 output = error_mark_node;
1479 TREE_VALUE (t) = output;
1482 for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
1484 tree input = TREE_VALUE (t);
1485 const char *constraint
1486 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
1488 if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
1489 oconstraints, &allows_mem, &allows_reg))
1491 /* If the input argument is going to end up in memory. */
1492 if (!allows_reg && allows_mem)
1493 d_mark_addressable (input);
1495 else
1496 input = error_mark_node;
1498 TREE_VALUE (t) = input;
1502 tree exp = build5 (ASM_EXPR, void_type_node, string,
1503 outputs, inputs, clobbers, labels);
1504 SET_EXPR_LOCATION (exp, make_location_t (s->loc));
1506 /* If the extended syntax was not used, mark the ASM_EXPR as being an
1507 ASM_INPUT expression instead of an ASM_OPERAND with no operands. */
1508 if (s->args == NULL && s->clobbers == NULL)
1509 ASM_INPUT_P (exp) = 1;
1511 /* All asm statements are assumed to have a side effect. As a future
1512 optimization, this could be unset when building in release mode. */
1513 ASM_VOLATILE_P (exp) = 1;
1515 /* If the function has been annotated with `pragma(inline)', then mark
1516 the asm expression as being inline as well. */
1517 if (this->func_->inlining == PINLINEalways)
1518 ASM_INLINE_P (exp) = 1;
1520 add_stmt (exp);
1523 /* Import symbols from another module. */
1525 void visit (ImportStatement *s)
1527 if (s->imports == NULL)
1528 return;
1530 for (size_t i = 0; i < s->imports->length; i++)
1532 Dsymbol *dsym = (*s->imports)[i];
1534 if (dsym != NULL)
1535 build_decl_tree (dsym);
1540 /* Main entry point for the IRVisitor interface to generate
1541 code for the body of function FD. */
1543 void
1544 build_function_body (FuncDeclaration *fd)
1546 IRVisitor v = IRVisitor (fd);
1547 location_t saved_location = input_location;
1548 input_location = make_location_t (fd->loc);
1549 v.build_stmt (fd->fbody);
1550 input_location = saved_location;