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)
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/>. */
20 #include "coretypes.h"
22 #include "dmd/aggregate.h"
23 #include "dmd/declaration.h"
24 #include "dmd/expression.h"
25 #include "dmd/identifier.h"
27 #include "dmd/statement.h"
30 #include "tree-iterator.h"
33 #include "fold-const.h"
34 #include "diagnostic.h"
35 #include "stringpool.h"
42 /* Update data for defined and undefined labels when leaving a scope. */
45 pop_binding_label (Statement
* const &, d_label_entry
*ent
, binding_level
*bl
)
47 binding_level
*obl
= bl
->level_chain
;
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;
58 else if (ent
->fwdrefs
)
60 for (d_label_use_entry
*ref
= ent
->fwdrefs
; ref
; ref
= ref
->next
)
67 /* At the end of a function, all labels declared within the function
68 go out of scope. Queue them in LABELS. */
71 pop_label (Statement
* const &, d_label_entry
*ent
, vec
<tree
> &labels
)
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
);
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. */
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
;
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
);
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
];
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;
164 /* Create an empty statement tree rooted at T. */
167 push_stmt_list (void)
169 tree t
= alloc_stmt_list ();
170 vec_safe_push (d_function_chain
->stmt_list
, t
);
174 /* Finish the statement tree rooted at T. */
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
189 tree_stmt_iterator i
= tsi_start (t
);
191 if (tsi_one_before_end_p (i
))
193 tree u
= tsi_stmt (i
);
203 /* T is an expression statement. Add it to the statement-tree. */
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
))
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
))
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));
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. */
257 tree continue_label_
;
260 IRVisitor (FuncDeclaration
*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
);
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
);
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
))
299 tree bind
= build3 (BIND_EXPR
, void_type_node
,
300 BLOCK_VARS (block
), body
, block
);
301 TREE_SIDE_EFFECTS (bind
) = 1;
305 /* Like end_scope, but also push it into the outer statement-tree. */
307 void finish_scope (void)
309 tree scope
= this->end_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
;
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
);
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
;
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
)
404 if (b
->kind
== level_try
|| b
->kind
== level_catch
)
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");
414 error_at (location
, "cannot %<goto%> into %<catch%> block");
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)");
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
);
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
> ();
457 bool existed
= d_function_chain
->labels
->put (s
, *ent
);
458 gcc_assert (!existed
);
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
;
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
;
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
;
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
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
),
582 tree ifbody
= void_node
;
583 tree elsebody
= void_node
;
585 /* Build the `then' branch, don't do code generation when the condition
586 is `if (__ctfe)', as that is always false at run-time. */
587 if (s
->ifbody
&& !s
->isIfCtfeBlock ())
590 this->build_stmt (s
->ifbody
);
591 ifbody
= pop_stmt_list ();
594 /* Now build the `else' branch, which may have nested `else if' parts. */
598 this->build_stmt (s
->elsebody
);
599 elsebody
= pop_stmt_list ();
602 /* Wrap up our constructed if condition into a COND_EXPR. */
603 tree cond
= build_vcondition (ifcond
, ifbody
, elsebody
);
606 /* Finish the if-then scope. */
607 this->finish_scope ();
610 /* Should there be any `pragma (...)' statements requiring code generation,
611 here would be the place to do it. For now, all pragmas are handled
614 void visit (PragmaStatement
*) final override
618 /* The frontend lowers `while (...)' statements as `for (...)' loops.
619 This visitor is not strictly required other than to enforce that
620 these kinds of statements never reach here. */
622 void visit (WhileStatement
*) final override
627 /* Do while statments implement simple loops. The body is executed, then
628 the condition is evaluated. */
630 void visit (DoStatement
*s
) final override
632 tree lbreak
= this->push_break_label (s
);
634 this->start_scope (level_loop
);
637 tree lcontinue
= this->push_continue_label (s
);
638 this->build_stmt (s
->_body
);
639 this->pop_continue_label (lcontinue
);
642 /* Build the outer `while' condition, which may produce temporaries
643 requiring scope destruction. */
644 tree exitcond
= convert_for_condition (build_expr_dtor (s
->condition
),
646 add_stmt (build_vcondition (exitcond
, void_node
,
647 build1 (GOTO_EXPR
, void_type_node
, lbreak
)));
648 TREE_USED (lbreak
) = 1;
650 tree body
= this->end_scope ();
651 add_stmt (build1 (LOOP_EXPR
, void_type_node
, body
));
653 this->pop_break_label (lbreak
);
656 /* For statements implement loops with initialization, test, and
657 increment clauses. */
659 void visit (ForStatement
*s
) final override
661 tree lbreak
= this->push_break_label (s
);
662 this->start_scope (level_loop
);
665 this->build_stmt (s
->_init
);
669 tree exitcond
= convert_for_condition (build_expr_dtor (s
->condition
),
671 add_stmt (build_vcondition (exitcond
, void_node
,
672 build1 (GOTO_EXPR
, void_type_node
,
674 TREE_USED (lbreak
) = 1;
679 tree lcontinue
= this->push_continue_label (s
);
680 this->build_stmt (s
->_body
);
681 this->pop_continue_label (lcontinue
);
686 /* Force side effects? */
687 add_stmt (build_expr_dtor (s
->increment
));
690 tree body
= this->end_scope ();
691 add_stmt (build1 (LOOP_EXPR
, void_type_node
, body
));
693 this->pop_break_label (lbreak
);
696 /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
697 This visitor is not strictly required other than to enforce that
698 these kinds of statements never reach here. */
700 void visit (ForeachStatement
*) final override
705 /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
706 loops. This visitor is not strictly required other than to enforce that
707 these kinds of statements never reach here. */
709 void visit (ForeachRangeStatement
*) final override
714 /* Jump to the associated exit label for the current loop. If IDENT
715 for the Statement is not null, then the label is user defined. */
717 void visit (BreakStatement
*s
) final override
721 /* The break label may actually be some levels up.
722 eg: on a try/finally wrapping a loop. */
723 LabelDsymbol
*sym
= this->func_
->searchLabel (s
->ident
, s
->loc
);
724 LabelStatement
*label
= sym
->statement
;
725 gcc_assert (label
!= NULL
);
726 Statement
*stmt
= label
->statement
->getRelatedLabeled ();
727 this->do_jump (this->lookup_bc_label (stmt
, bc_break
));
730 this->do_jump (this->break_label_
);
733 /* Jump to the associated continue label for the current loop. If IDENT
734 for the Statement is not null, then the label is user defined. */
736 void visit (ContinueStatement
*s
) final override
740 LabelDsymbol
*sym
= this->func_
->searchLabel (s
->ident
, s
->loc
);
741 LabelStatement
*label
= sym
->statement
;
742 gcc_assert (label
!= NULL
);
743 this->do_jump (this->lookup_bc_label (label
->statement
,
747 this->do_jump (this->continue_label_
);
750 /* A goto statement jumps to the statement identified by the given label. */
752 void visit (GotoStatement
*s
) final override
754 gcc_assert (s
->label
->statement
!= NULL
);
755 gcc_assert (s
->tf
== s
->label
->statement
->tf
);
757 /* If no label found, there was an error. */
758 tree label
= this->lookup_label (s
->label
->statement
, s
->label
->ident
);
759 this->do_jump (label
);
761 /* Need to error if the goto is jumping into a try or catch block. */
762 this->check_goto (s
, s
->label
->statement
);
765 /* Statements can be labeled. A label is an identifier that precedes
768 void visit (LabelStatement
*s
) final override
772 if (this->is_return_label (s
->ident
))
773 sym
= this->func_
->returnLabel
;
775 sym
= this->func_
->searchLabel (s
->ident
, s
->loc
);
777 /* If no label found, there was an error. */
778 tree label
= this->define_label (sym
->statement
, sym
->ident
);
779 TREE_USED (label
) = 1;
781 this->do_label (label
);
783 if (this->is_return_label (s
->ident
) && this->func_
->fensure () != NULL
)
784 this->build_stmt (this->func_
->fensure ());
785 else if (s
->statement
)
786 this->build_stmt (s
->statement
);
789 /* A switch statement goes to one of a collection of case statements
790 depending on the value of the switch expression. */
792 void visit (SwitchStatement
*s
) final override
794 this->start_scope (level_switch
);
795 tree lbreak
= this->push_break_label (s
);
797 tree condition
= build_expr_dtor (s
->condition
);
798 Type
*condtype
= s
->condition
->type
->toBasetype ();
800 /* A switch statement on a string gets turned into a library call.
801 It is not lowered during codegen. */
802 if (!condtype
->isscalar ())
804 error ("cannot handle switch condition of type %s",
805 condtype
->toChars ());
809 condition
= fold (condition
);
811 /* Build LABEL_DECLs now so they can be refered to by goto case.
812 Also checking the jump from the switch to the label is allowed. */
815 for (size_t i
= 0; i
< s
->cases
->length
; i
++)
817 CaseStatement
*cs
= (*s
->cases
)[i
];
818 tree caselabel
= this->lookup_label (cs
);
820 /* Write cases as a series of if-then-else blocks.
821 if (condition == case)
825 tree ifcase
= build2 (EQ_EXPR
, build_ctype (condtype
),
826 condition
, build_expr_dtor (cs
->exp
));
827 tree ifbody
= fold_build1 (GOTO_EXPR
, void_type_node
,
829 tree cond
= build_vcondition (ifcase
, ifbody
, void_node
);
830 TREE_USED (caselabel
) = 1;
831 LABEL_VARIABLE_CASE (caselabel
) = 1;
835 this->check_goto (s
, cs
);
840 tree defaultlabel
= this->lookup_label (s
->sdefault
);
842 /* The default label is the last `else' block. */
845 this->do_jump (defaultlabel
);
846 LABEL_VARIABLE_CASE (defaultlabel
) = 1;
849 this->check_goto (s
, s
->sdefault
);
853 /* Switch body goes in its own statement list. */
856 this->build_stmt (s
->_body
);
858 tree casebody
= pop_stmt_list ();
860 /* Wrap up constructed body into a switch_expr, unless it was
861 converted to an if-then-else expression. */
866 tree switchexpr
= build2 (SWITCH_EXPR
, TREE_TYPE (condition
),
867 condition
, casebody
);
868 add_stmt (switchexpr
);
869 SWITCH_ALL_CASES_P (switchexpr
) = 1;
872 SWITCH_BREAK_LABEL_P (lbreak
) = 1;
874 /* If the switch had any `break' statements, emit the label now. */
875 this->pop_break_label (lbreak
);
876 this->finish_scope ();
879 /* Declare the case label associated with the current SwitchStatement. */
881 void visit (CaseStatement
*s
) final override
883 /* Emit the case label. */
884 tree label
= this->define_label (s
);
886 if (LABEL_VARIABLE_CASE (label
))
887 this->do_label (label
);
891 if (s
->exp
->type
->isscalar ())
892 casevalue
= build_expr (s
->exp
);
894 casevalue
= build_integer_cst (s
->index
, build_ctype (Type::tint32
));
896 tree caselabel
= build_case_label (casevalue
, NULL_TREE
, label
);
897 add_stmt (caselabel
);
900 /* Now do the body. */
902 this->build_stmt (s
->statement
);
905 /* Declare the default label associated with the current SwitchStatement. */
907 void visit (DefaultStatement
*s
) final override
909 /* Emit the default case label. */
910 tree label
= this->define_label (s
);
912 if (LABEL_VARIABLE_CASE (label
))
913 this->do_label (label
);
916 tree caselabel
= build_case_label (NULL_TREE
, NULL_TREE
, label
);
917 add_stmt (caselabel
);
920 /* Now do the body. */
922 this->build_stmt (s
->statement
);
925 /* Implements `goto default' by jumping to the label associated with
926 the DefaultStatement in a switch block. */
928 void visit (GotoDefaultStatement
*s
) final override
930 tree label
= this->lookup_label (s
->sw
->sdefault
);
931 this->do_jump (label
);
934 /* Implements `goto case' by jumping to the label associated with the
935 CaseStatement in a switch block. */
937 void visit (GotoCaseStatement
*s
) final override
939 tree label
= this->lookup_label (s
->cs
);
940 this->do_jump (label
);
943 /* Throw a SwitchError exception, called when a switch statement has
944 no DefaultStatement, yet none of the cases match. */
946 void visit (SwitchErrorStatement
*s
) final override
948 /* A throw SwitchError statement gets turned into a library call.
949 The call is wrapped in the enclosed expression. */
950 gcc_assert (s
->exp
!= NULL
);
951 add_stmt (build_expr (s
->exp
));
954 /* A return statement exits the current function and supplies its return
955 value, if the return type is not void. */
957 void visit (ReturnStatement
*s
) final override
959 if (s
->exp
== NULL
|| s
->exp
->type
->toBasetype ()->ty
== TY::Tvoid
)
961 /* Return has no value. */
962 add_stmt (return_expr (NULL_TREE
));
966 TypeFunction
*tf
= this->func_
->type
->toTypeFunction ();
967 Type
*type
= this->func_
->tintro
!= NULL
968 ? this->func_
->tintro
->nextOf () : tf
->nextOf ();
970 if ((this->func_
->isMain () || this->func_
->isCMain ())
971 && type
->toBasetype ()->ty
== TY::Tvoid
)
974 if (this->func_
->shidden
)
976 /* Returning by hidden reference, store the result into the retval decl.
977 The result returned then becomes the retval reference itself. */
978 tree decl
= DECL_RESULT (get_symbol_decl (this->func_
));
979 gcc_assert (!tf
->isref ());
981 /* If returning via NRVO, just refer to the DECL_RESULT; this differs
982 from using NULL_TREE in that it indicates that we care about the
983 value of the DECL_RESULT. */
984 if (this->func_
->isNRVO () && this->func_
->nrvo_var
)
986 add_stmt (return_expr (decl
));
990 /* Detect a call to a constructor function, or if returning a struct
991 literal, write result directly into the return value. */
992 StructLiteralExp
*sle
= NULL
;
993 bool using_rvo_p
= false;
995 if (DotVarExp
*dve
= (s
->exp
->isCallExp ()
996 ? s
->exp
->isCallExp ()->e1
->isDotVarExp ()
999 if (dve
->var
->isCtorDeclaration ())
1001 if (CommaExp
*ce
= dve
->e1
->isCommaExp ())
1003 /* Temporary initialized inside a return expression, and
1004 used as the return value. Replace it with the hidden
1005 reference to allow RVO return. */
1006 DeclarationExp
*de
= ce
->e1
->isDeclarationExp ();
1007 VarExp
*ve
= ce
->e2
->isVarExp ();
1008 if (de
!= NULL
&& ve
!= NULL
1009 && ve
->var
== de
->declaration
1010 && ve
->var
->storage_class
& STCtemp
)
1012 tree var
= get_symbol_decl (ve
->var
);
1013 TREE_ADDRESSABLE (var
) = 1;
1014 SET_DECL_VALUE_EXPR (var
, decl
);
1015 DECL_HAS_VALUE_EXPR_P (var
) = 1;
1016 SET_DECL_LANG_NRVO (var
, this->func_
->shidden
);
1021 sle
= dve
->e1
->isStructLiteralExp ();
1025 sle
= s
->exp
->isStructLiteralExp ();
1029 StructDeclaration
*sd
= type
->baseElemOf ()->isTypeStruct ()->sym
;
1030 sle
->sym
= build_address (this->func_
->shidden
);
1033 /* Fill any alignment holes in the return slot using memset. */
1034 if (!identity_compare_p (sd
) || sd
->isUnionDeclaration ())
1035 add_stmt (build_memset_call (this->func_
->shidden
));
1038 if (using_rvo_p
== true)
1040 /* Generate: (expr, return <retval>); */
1041 add_stmt (build_expr_dtor (s
->exp
));
1045 /* Generate: (<retval> = expr, return <retval>); */
1046 tree expr
= build_expr_dtor (s
->exp
);
1047 tree init
= stabilize_expr (&expr
);
1048 expr
= convert_for_rvalue (expr
, s
->exp
->type
, type
);
1049 expr
= build_assign (INIT_EXPR
, this->func_
->shidden
, expr
);
1050 add_stmt (compound_expr (init
, expr
));
1053 add_stmt (return_expr (decl
));
1055 else if (tf
->next
->ty
== TY::Tnoreturn
)
1057 /* Returning an expression that has no value, but has a side effect
1058 that should never return. */
1059 add_stmt (build_expr_dtor (s
->exp
));
1060 add_stmt (return_expr (NULL_TREE
));
1064 /* Convert for initializing the DECL_RESULT. */
1065 add_stmt (build_return_dtor (s
->exp
, type
, tf
));
1069 /* Evaluate the enclosed expression, and add it to the statement list. */
1071 void visit (ExpStatement
*s
) final override
1075 /* Expression may produce temporaries requiring scope destruction. */
1076 tree exp
= build_expr_dtor (s
->exp
);
1081 /* Evaluate all enclosed statements. */
1083 void visit (CompoundStatement
*s
) final override
1085 if (s
->statements
== NULL
)
1088 for (size_t i
= 0; i
< s
->statements
->length
; i
++)
1090 Statement
*statement
= (*s
->statements
)[i
];
1092 if (statement
!= NULL
)
1093 this->build_stmt (statement
);
1097 /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
1098 These are compiled down as a `do ... while (0)', where each unrolled loop
1099 is nested inside and given their own continue label to jump to. */
1101 void visit (UnrolledLoopStatement
*s
) final override
1103 if (s
->statements
== NULL
)
1106 tree lbreak
= this->push_break_label (s
);
1107 this->start_scope (level_loop
);
1109 for (size_t i
= 0; i
< s
->statements
->length
; i
++)
1111 Statement
*statement
= (*s
->statements
)[i
];
1113 if (statement
!= NULL
)
1115 this->push_unrolled_continue_label (s
);
1116 this->build_stmt (statement
);
1117 this->pop_unrolled_continue_label (s
);
1121 this->do_jump (this->break_label_
);
1123 tree body
= this->end_scope ();
1124 add_stmt (build1 (LOOP_EXPR
, void_type_node
, body
));
1126 this->pop_break_label (lbreak
);
1129 /* Start a new scope and visit all nested statements, wrapping
1130 them up into a BIND_EXPR at the end of the scope. */
1132 void visit (ScopeStatement
*s
) final override
1134 if (s
->statement
== NULL
)
1137 this->start_scope (level_block
);
1138 this->build_stmt (s
->statement
);
1139 this->finish_scope ();
1142 /* A with statement is a way to simplify repeated references to the same
1143 object, where the handle is either a class or struct instance. */
1145 void visit (WithStatement
*s
) final override
1147 this->start_scope (level_with
);
1151 /* Perform initialisation of the `with' handle. */
1152 ExpInitializer
*ie
= s
->wthis
->_init
->isExpInitializer ();
1153 gcc_assert (ie
!= NULL
);
1155 declare_local_var (s
->wthis
);
1156 tree init
= build_expr_dtor (ie
->exp
);
1161 this->build_stmt (s
->_body
);
1163 this->finish_scope ();
1166 /* Implements `throw Object'. Frontend already checks that the object
1167 thrown is a class type, but does not check if it is derived from
1168 Object. Foreign objects are not currently supported at run-time. */
1170 void visit (ThrowStatement
*s
) final override
1172 ClassDeclaration
*cd
= s
->exp
->type
->toBasetype ()->isClassHandle ();
1173 InterfaceDeclaration
*id
= cd
->isInterfaceDeclaration ();
1174 tree arg
= build_expr_dtor (s
->exp
);
1176 if (!global
.params
.useExceptions
)
1178 static int warned
= 0;
1181 error_at (make_location_t (s
->loc
), "exception handling disabled; "
1182 "use %<-fexceptions%> to enable");
1187 if (cd
->isCPPclass () || (id
!= NULL
&& id
->isCPPclass ()))
1188 error_at (make_location_t (s
->loc
), "cannot throw C++ classes");
1189 else if (cd
->com
|| (id
!= NULL
&& id
->com
))
1190 error_at (make_location_t (s
->loc
), "cannot throw COM objects");
1192 arg
= build_nop (build_ctype (get_object_type ()), arg
);
1194 add_stmt (build_libcall (LIBCALL_THROW
, Type::tvoid
, 1, arg
));
1197 /* Build a try-catch statement, one of the building blocks for exception
1198 handling generated by the frontend. This is also used to implement
1199 `scope (failure)' statements. */
1201 void visit (TryCatchStatement
*s
) final override
1203 this->start_scope (level_try
);
1205 this->build_stmt (s
->_body
);
1207 tree trybody
= this->end_scope ();
1209 /* Try handlers go in their own statement list. */
1214 for (size_t i
= 0; i
< s
->catches
->length
; i
++)
1216 Catch
*vcatch
= (*s
->catches
)[i
];
1218 this->start_scope (level_catch
);
1220 tree ehptr
= builtin_decl_explicit (BUILT_IN_EH_POINTER
);
1221 tree catchtype
= build_ctype (vcatch
->type
);
1222 tree object
= NULL_TREE
;
1224 ehptr
= build_call_expr (ehptr
, 1, integer_zero_node
);
1226 /* Retrieve the internal exception object, which could be for a
1227 D or C++ catch handler. This is different from the generic
1228 exception pointer returned from gcc runtime. */
1229 Type
*tcatch
= vcatch
->type
->toBasetype ();
1230 ClassDeclaration
*cd
= tcatch
->isClassHandle ();
1232 libcall_fn libcall
= (cd
->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
1233 : LIBCALL_BEGIN_CATCH
;
1234 object
= build_libcall (libcall
, vcatch
->type
, 1, ehptr
);
1238 tree var
= get_symbol_decl (vcatch
->var
);
1239 tree init
= build_assign (INIT_EXPR
, var
, object
);
1241 declare_local_var (vcatch
->var
);
1246 /* Still need to emit a call to __gdc_begin_catch() to
1247 remove the object from the uncaught exceptions list. */
1251 if (vcatch
->handler
)
1252 this->build_stmt (vcatch
->handler
);
1254 tree catchbody
= this->end_scope ();
1256 /* Need to wrap C++ handlers in a try/finally block to signal
1257 the end catch callback. */
1258 if (cd
->isCPPclass ())
1260 tree endcatch
= build_libcall (LIBCALL_CXA_END_CATCH
,
1262 catchbody
= build2 (TRY_FINALLY_EXPR
, void_type_node
,
1263 catchbody
, endcatch
);
1266 add_stmt (build2 (CATCH_EXPR
, void_type_node
,
1267 catchtype
, catchbody
));
1271 tree catches
= pop_stmt_list ();
1273 /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
1274 statement list, however pop_stmt_list may optimize away the list
1275 if there is only a single catch to push. */
1276 if (TREE_CODE (catches
) != STATEMENT_LIST
)
1278 tree stmt_list
= alloc_stmt_list ();
1279 append_to_statement_list_force (catches
, &stmt_list
);
1280 catches
= stmt_list
;
1283 add_stmt (build2 (TRY_CATCH_EXPR
, void_type_node
, trybody
, catches
));
1286 /* Build a try-finally statement, one of the building blocks for exception
1287 handling generated by the frontend. This is also used to implement
1288 `scope (exit)' statements. */
1290 void visit (TryFinallyStatement
*s
) final override
1292 this->start_scope (level_try
);
1294 this->build_stmt (s
->_body
);
1296 tree trybody
= this->end_scope ();
1298 this->start_scope (level_finally
);
1300 this->build_stmt (s
->finalbody
);
1302 tree finally
= this->end_scope ();
1304 add_stmt (build2 (TRY_FINALLY_EXPR
, void_type_node
, trybody
, finally
));
1307 /* The frontend lowers `synchronized (...)' statements as a call to
1308 monitor/critical enter and exit wrapped around try/finally.
1309 This visitor is not strictly required other than to enforce that
1310 these kinds of statements never reach here. */
1312 void visit (SynchronizedStatement
*) final override
1317 /* D Inline Assembler is not implemented, as it would require writing
1318 an assembly parser for each supported target. Instead we leverage
1319 GCC extended assembler using the GccAsmStatement class. */
1321 void visit (AsmStatement
*) final override
1323 sorry ("D inline assembler statements are not supported in GDC.");
1326 /* Build a GCC extended assembler expression, whose components are
1327 an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */
1329 void visit (GccAsmStatement
*s
) final override
1331 StringExp
*insn
= s
->insn
->toStringExp ();
1332 tree outputs
= NULL_TREE
;
1333 tree inputs
= NULL_TREE
;
1334 tree clobbers
= NULL_TREE
;
1335 tree labels
= NULL_TREE
;
1337 /* Collect all arguments, which may be input or output operands. */
1340 for (size_t i
= 0; i
< s
->args
->length
; i
++)
1342 Identifier
*name
= (*s
->names
)[i
];
1343 const char *sname
= name
? name
->toChars () : NULL
;
1344 tree id
= name
? build_string (strlen (sname
), sname
) : NULL_TREE
;
1346 StringExp
*constr
= (*s
->constraints
)[i
]->toStringExp ();
1347 const char *cstring
= (const char *)(constr
->len
1348 ? constr
->string
: "");
1349 tree str
= build_string (constr
->len
, cstring
);
1351 Expression
*earg
= (*s
->args
)[i
];
1352 tree val
= build_expr (earg
);
1354 if (i
< s
->outputargs
)
1356 tree arg
= build_tree_list (id
, str
);
1357 outputs
= chainon (outputs
, build_tree_list (arg
, val
));
1361 tree arg
= build_tree_list (id
, str
);
1362 inputs
= chainon (inputs
, build_tree_list (arg
, val
));
1367 /* Collect all clobber arguments. */
1370 for (size_t i
= 0; i
< s
->clobbers
->length
; i
++)
1372 StringExp
*clobber
= (*s
->clobbers
)[i
]->toStringExp ();
1373 const char *cstring
= (const char *)(clobber
->len
1374 ? clobber
->string
: "");
1376 tree val
= build_string (clobber
->len
, cstring
);
1377 clobbers
= chainon (clobbers
, build_tree_list (0, val
));
1381 /* Collect all goto labels, these should have been already checked
1382 by the front-end, so pass down the label symbol to the back-end. */
1385 for (size_t i
= 0; i
< s
->labels
->length
; i
++)
1387 Identifier
*ident
= (*s
->labels
)[i
];
1388 GotoStatement
*gs
= (*s
->gotos
)[i
];
1390 gcc_assert (gs
->label
->statement
!= NULL
);
1391 gcc_assert (gs
->tf
== gs
->label
->statement
->tf
);
1393 const char *sident
= ident
->toChars ();
1394 tree name
= build_string (strlen (sident
), sident
);
1395 tree label
= this->lookup_label (gs
->label
->statement
,
1397 TREE_USED (label
) = 1;
1399 labels
= chainon (labels
, build_tree_list (name
, label
));
1403 /* Do some extra validation on all input and output operands. */
1404 const char *insnstring
= (const char *)(insn
->len
? insn
->string
: "");
1405 tree string
= build_string (insn
->len
, insnstring
);
1406 string
= resolve_asm_operand_names (string
, outputs
, inputs
, labels
);
1410 unsigned noutputs
= s
->outputargs
;
1411 unsigned ninputs
= (s
->args
->length
- noutputs
);
1412 const char **oconstraints
= XALLOCAVEC (const char *, noutputs
);
1413 bool allows_mem
, allows_reg
, is_inout
;
1417 for (i
= 0, t
= outputs
; t
!= NULL_TREE
; t
= TREE_CHAIN (t
), i
++)
1419 tree output
= TREE_VALUE (t
);
1420 const char *constraint
1421 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t
)));
1423 oconstraints
[i
] = constraint
;
1425 if (parse_output_constraint (&constraint
, i
, ninputs
, noutputs
,
1426 &allows_mem
, &allows_reg
, &is_inout
))
1428 /* If the output argument is going to end up in memory. */
1430 d_mark_addressable (output
);
1433 output
= error_mark_node
;
1435 TREE_VALUE (t
) = output
;
1438 for (i
= 0, t
= inputs
; t
!= NULL_TREE
; t
= TREE_CHAIN (t
), i
++)
1440 tree input
= TREE_VALUE (t
);
1441 const char *constraint
1442 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t
)));
1444 if (parse_input_constraint (&constraint
, i
, ninputs
, noutputs
, 0,
1445 oconstraints
, &allows_mem
, &allows_reg
))
1447 /* If the input argument is going to end up in memory. */
1448 if (!allows_reg
&& allows_mem
)
1449 d_mark_addressable (input
);
1452 input
= error_mark_node
;
1454 TREE_VALUE (t
) = input
;
1458 tree exp
= build5 (ASM_EXPR
, void_type_node
, string
,
1459 outputs
, inputs
, clobbers
, labels
);
1460 SET_EXPR_LOCATION (exp
, make_location_t (s
->loc
));
1462 /* If the extended syntax was not used, mark the ASM_EXPR as being an
1463 ASM_INPUT expression instead of an ASM_OPERAND with no operands. */
1464 if (s
->args
== NULL
&& s
->clobbers
== NULL
)
1465 ASM_INPUT_P (exp
) = 1;
1467 /* All asm statements are assumed to have a side effect. As a future
1468 optimization, this could be unset when building in release mode. */
1469 ASM_VOLATILE_P (exp
) = 1;
1471 /* If the function has been annotated with `pragma(inline)', then mark
1472 the asm expression as being inline as well. */
1473 if (this->func_
->inlining
== PINLINE::always
)
1474 ASM_INLINE_P (exp
) = 1;
1479 /* Import symbols from another module. */
1481 void visit (ImportStatement
*s
) final override
1483 if (s
->imports
== NULL
)
1486 for (size_t i
= 0; i
< s
->imports
->length
; i
++)
1488 Dsymbol
*dsym
= (*s
->imports
)[i
];
1491 build_decl_tree (dsym
);
1496 /* Main entry point for the IRVisitor interface to generate
1497 code for the body of function FD. */
1500 build_function_body (FuncDeclaration
*fd
)
1502 IRVisitor v
= IRVisitor (fd
);
1503 location_t saved_location
= input_location
;
1504 input_location
= make_location_t (fd
->loc
);
1505 v
.build_stmt (fd
->fbody
);
1506 input_location
= saved_location
;