1 /* toir.cc -- Lower D frontend statements to GCC trees. 2 Copyright (C) 2006-2020 Free Software Foundation, Inc. 3 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. 8 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. 13 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/>. */ 17 18 #include "config.h" 19 #include "system.h" 20 #include "coretypes.h" 21 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" 28 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" 38 39 #include "d-tree.h" 40 41 42 /* Update data for defined and undefined labels when leaving a scope. */ 43 44 bool 45 pop_binding_label (Statement * const &, d_label_entry *ent, binding_level *bl) 46 { 47 binding_level *obl = bl->level_chain; 48 49 if (ent->level == bl) 50 { 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; 55 56 ent->level = obl; 57 } 58 else if (ent->fwdrefs) 59 { 60 for (d_label_use_entry *ref = ent->fwdrefs; ref; ref = ref->next) 61 ref->level = obl; 62 } 63 64 return true; 65 } 66 67 /* At the end of a function, all labels declared within the function 68 go out of scope. Queue them in LABELS. */ 69 70 bool 71 pop_label (Statement * const &, d_label_entry *ent, vec<tree> &labels) 72 { 73 if (!ent->bc_label) 74 { 75 /* Put the labels into the "variables" of the top-level block, 76 so debugger can see them. */ 77 if (DECL_NAME (ent->label)) 78 { 79 gcc_assert (DECL_INITIAL (ent->label) != NULL_TREE); 80 labels.safe_push (ent->label); 81 } 82 } 83 84 return true; 85 } 86 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. */ 91 92 void 93 push_binding_level (level_kind kind) 94 { 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; 99 100 current_binding_level = new_level; 101 } 102 103 static int 104 cmp_labels (const void *p1, const void *p2) 105 { 106 const tree *l1 = (const tree *)p1; 107 const tree *l2 = (const tree *)p2; 108 return DECL_UID (*l1) - DECL_UID (*l2); 109 } 110 111 tree 112 pop_binding_level (void) 113 { 114 binding_level *level = current_binding_level; 115 current_binding_level = level->level_chain; 116 117 tree block = make_node (BLOCK); 118 BLOCK_VARS (block) = level->names; 119 BLOCK_SUBBLOCKS (block) = level->blocks; 120 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; 124 125 if (level->kind == level_function) 126 { 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; 130 131 /* Pop all the labels declared in the function. */ 132 if (d_function_chain->labels) 133 { 134 auto_vec<tree> labels; 135 d_function_chain->labels->traverse<vec<tree> &, &pop_label> (labels); 136 d_function_chain->labels->empty (); 137 labels.qsort (cmp_labels); 138 for (unsigned i = 0; i < labels.length (); ++i) 139 { 140 DECL_CHAIN (labels[i]) = BLOCK_VARS (block); 141 BLOCK_VARS (block) = labels[i]; 142 } 143 } 144 } 145 else 146 { 147 /* Any uses of undefined labels, and any defined labels, now operate 148 under constraints of next binding contour. */ 149 if (d_function_chain && d_function_chain->labels) 150 { 151 language_function *f = d_function_chain; 152 f->labels->traverse<binding_level *, &pop_binding_label> (level); 153 } 154 155 current_binding_level->blocks 156 = block_chainon (current_binding_level->blocks, block); 157 } 158 159 TREE_USED (block) = 1; 160 return block; 161 } 162 163 /* Create an empty statement tree rooted at T. */ 164 165 void 166 push_stmt_list (void) 167 { 168 tree t = alloc_stmt_list (); 169 vec_safe_push (d_function_chain->stmt_list, t); 170 d_keep (t); 171 } 172 173 /* Finish the statement tree rooted at T. */ 174 175 tree 176 pop_stmt_list (void) 177 { 178 tree t = d_function_chain->stmt_list->pop (); 179 180 /* If the statement list is completely empty, just return it. This is just 181 as good as build_empty_stmt, with the advantage that statement lists 182 are merged when they are appended to one another. So using the 183 STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P statements. */ 184 if (TREE_SIDE_EFFECTS (t)) 185 { 186 /* If the statement list contained exactly one statement, then extract 187 it immediately. */ 188 tree_stmt_iterator i = tsi_start (t); 189 190 if (tsi_one_before_end_p (i)) 191 { 192 tree u = tsi_stmt (i); 193 tsi_delink (&i); 194 free_stmt_list (t); 195 t = u; 196 } 197 } 198 199 return t; 200 } 201 202 /* T is an expression statement. Add it to the statement-tree. */ 203 204 void 205 add_stmt (tree t) 206 { 207 /* Ignore (void) 0; expression statements received from the frontend. 208 Likewise void_node is used when contracts become nops in release code. */ 209 if (t == void_node || IS_EMPTY_STMT (t)) 210 return; 211 212 /* At this point, we no longer care about the value of expressions, 213 so if there's no side-effects, then don't add it. */ 214 if (!TREE_SIDE_EFFECTS (t)) 215 return; 216 217 if (TREE_CODE (t) == COMPOUND_EXPR) 218 { 219 /* Push out each comma expressions as separate statements. */ 220 add_stmt (TREE_OPERAND (t, 0)); 221 add_stmt (TREE_OPERAND (t, 1)); 222 } 223 else 224 { 225 /* Force the type to be void so we don't need to create a temporary 226 variable to hold the inner expression. */ 227 if (TREE_CODE (t) == CLEANUP_POINT_EXPR) 228 TREE_TYPE (t) = void_type_node; 229 230 /* Append the expression to the statement list. 231 Make sure it has a proper location. */ 232 if (EXPR_P (t) && !EXPR_HAS_LOCATION (t)) 233 SET_EXPR_LOCATION (t, input_location); 234 235 tree stmt_list = d_function_chain->stmt_list->last (); 236 append_to_statement_list_force (t, &stmt_list); 237 } 238 } 239 240 /* Implements the visitor interface to build the GCC trees of all Statement 241 AST classes emitted from the D Front-end. 242 All visit methods accept one parameter S, which holds the frontend AST 243 of the statement to compile. They also don't return any value, instead 244 generated code are pushed to add_stmt(), which appends them to the 245 statement list in the current_binding_level. */ 246 247 class IRVisitor : public Visitor 248 { 249 using Visitor::visit; 250 251 FuncDeclaration *func_; 252 253 /* Stack of labels which are targets for "break" and "continue", 254 linked through TREE_CHAIN. */ 255 tree break_label_; 256 tree continue_label_; 257 258 public: 259 IRVisitor (FuncDeclaration *fd) 260 { 261 this->func_ = fd; 262 this->break_label_ = NULL_TREE; 263 this->continue_label_ = NULL_TREE; 264 } 265 266 /* Helper for generating code for the statement AST class S. 267 Sets up the location of the statement before lowering. */ 268 269 void build_stmt (Statement *s) 270 { 271 location_t saved_location = input_location; 272 input_location = make_location_t (s->loc); 273 s->accept (this); 274 input_location = saved_location; 275 } 276 277 /* Start a new scope for a KIND statement. 278 Each user-declared variable will have a binding contour that begins 279 where the variable is declared and ends at its containing scope. */ 280 281 void start_scope (level_kind kind) 282 { 283 push_binding_level (kind); 284 push_stmt_list (); 285 } 286 287 /* Leave scope pushed by start_scope, returning a new bind_expr if 288 any variables where declared in the scope. */ 289 290 tree end_scope (void) 291 { 292 tree block = pop_binding_level (); 293 tree body = pop_stmt_list (); 294 295 if (! BLOCK_VARS (block)) 296 return body; 297 298 tree bind = build3 (BIND_EXPR, void_type_node, 299 BLOCK_VARS (block), body, block); 300 TREE_SIDE_EFFECTS (bind) = 1; 301 return bind; 302 } 303 304 /* Like end_scope, but also push it into the outer statement-tree. */ 305 306 void finish_scope (void) 307 { 308 tree scope = this->end_scope (); 309 add_stmt (scope); 310 } 311 312 /* Return TRUE if IDENT is the current function return label. */ 313 314 bool is_return_label (Identifier *ident) 315 { 316 if (this->func_->returnLabel) 317 return this->func_->returnLabel->ident == ident; 318 319 return false; 320 } 321 322 /* Define a label, specifying the location in the source file. 323 Return the LABEL_DECL node for the label. */ 324 325 tree define_label (Statement *s, Identifier *ident = NULL) 326 { 327 tree label = this->lookup_label (s, ident); 328 gcc_assert (DECL_INITIAL (label) == NULL_TREE); 329 330 d_label_entry *ent = d_function_chain->labels->get (s); 331 gcc_assert (ent != NULL); 332 333 /* Mark label as having been defined. */ 334 DECL_INITIAL (label) = error_mark_node; 335 336 ent->level = current_binding_level; 337 338 for (d_label_use_entry *ref = ent->fwdrefs; ref ; ref = ref->next) 339 this->check_previous_goto (ent->statement, ref); 340 ent->fwdrefs = NULL; 341 342 return label; 343 } 344 345 /* Emit a LABEL expression. */ 346 347 void do_label (tree label) 348 { 349 /* Don't write out label unless it is marked as used by the frontend. 350 This makes auto-vectorization possible in conditional loops. 351 The only excemption to this is in the LabelStatement visitor, 352 in which all computed labels are marked regardless. */ 353 if (TREE_USED (label)) 354 add_stmt (build1 (LABEL_EXPR, void_type_node, label)); 355 } 356 357 /* Emit a goto expression to LABEL. */ 358 359 void do_jump (tree label) 360 { 361 add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label)); 362 TREE_USED (label) = 1; 363 } 364 365 /* Check that a new jump at statement scope FROM to a label declared in 366 statement scope TO is valid. */ 367 368 void check_goto (Statement *from, Statement *to) 369 { 370 d_label_entry *ent = d_function_chain->labels->get (to); 371 gcc_assert (ent != NULL); 372 373 /* If the label hasn't been defined yet, defer checking. */ 374 if (! DECL_INITIAL (ent->label)) 375 { 376 d_label_use_entry *fwdref = ggc_alloc<d_label_use_entry> (); 377 fwdref->level = current_binding_level; 378 fwdref->statement = from; 379 fwdref->next = ent->fwdrefs; 380 ent->fwdrefs = fwdref; 381 return; 382 } 383 384 if (ent->in_try_scope) 385 error_at (make_location_t (from->loc), 386 "cannot %<goto%> into %<try%> block"); 387 else if (ent->in_catch_scope) 388 error_at (make_location_t (from->loc), 389 "cannot %<goto%> into %<catch%> block"); 390 } 391 392 /* Check that a previously seen jump to a newly defined label is valid. 393 S is the label statement; FWDREF is the jump context. This is called 394 for both user-defined and case labels. */ 395 396 void check_previous_goto (Statement *s, d_label_use_entry *fwdref) 397 { 398 for (binding_level *b = current_binding_level; b ; b = b->level_chain) 399 { 400 if (b == fwdref->level) 401 break; 402 403 if (b->kind == level_try || b->kind == level_catch) 404 { 405 location_t location; 406 407 if (s->isLabelStatement ()) 408 { 409 location = make_location_t (fwdref->statement->loc); 410 if (b->kind == level_try) 411 error_at (location, "cannot %<goto%> into %<try%> block"); 412 else 413 error_at (location, "cannot %<goto%> into %<catch%> block"); 414 } 415 else if (s->isCaseStatement ()) 416 { 417 location = make_location_t (s->loc); 418 error_at (location, "case cannot be in different " 419 "%<try%> block level from %<switch%>"); 420 } 421 else if (s->isDefaultStatement ()) 422 { 423 location = make_location_t (s->loc); 424 error_at (location, "default cannot be in different " 425 "%<try%> block level from %<switch%>"); 426 } 427 else 428 gcc_unreachable (); 429 } 430 } 431 } 432 433 /* Get or build LABEL_DECL using the IDENT and statement block S given. */ 434 435 tree lookup_label (Statement *s, Identifier *ident = NULL) 436 { 437 /* You can't use labels at global scope. */ 438 if (d_function_chain == NULL) 439 { 440 error ("label %s referenced outside of any function", 441 ident ? ident->toChars () : "(unnamed)"); 442 return NULL_TREE; 443 } 444 445 /* Create the label htab for the function on demand. */ 446 if (!d_function_chain->labels) 447 { 448 d_function_chain->labels 449 = hash_map<Statement *, d_label_entry>::create_ggc (13); 450 } 451 452 d_label_entry *ent = d_function_chain->labels->get (s); 453 if (ent != NULL) 454 return ent->label; 455 else 456 { 457 tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE; 458 tree decl = build_decl (make_location_t (s->loc), LABEL_DECL, 459 name, void_type_node); 460 DECL_CONTEXT (decl) = current_function_decl; 461 DECL_MODE (decl) = VOIDmode; 462 463 /* Create new empty slot. */ 464 ent = ggc_cleared_alloc<d_label_entry> (); 465 ent->statement = s; 466 ent->label = decl; 467 468 bool existed = d_function_chain->labels->put (s, *ent); 469 gcc_assert (!existed); 470 471 return decl; 472 } 473 } 474 475 /* Get the LABEL_DECL to represent a break or continue for the 476 statement S given. BC indicates which. */ 477 478 tree lookup_bc_label (Statement *s, bc_kind bc) 479 { 480 tree vec = this->lookup_label (s); 481 482 /* The break and continue labels are put into a TREE_VEC. */ 483 if (TREE_CODE (vec) == LABEL_DECL) 484 { 485 d_label_entry *ent = d_function_chain->labels->get (s); 486 gcc_assert (ent != NULL); 487 488 vec = make_tree_vec (2); 489 TREE_VEC_ELT (vec, bc_break) = ent->label; 490 491 /* Build the continue label. */ 492 tree label = build_decl (make_location_t (s->loc), LABEL_DECL, 493 NULL_TREE, void_type_node); 494 DECL_CONTEXT (label) = current_function_decl; 495 DECL_MODE (label) = VOIDmode; 496 TREE_VEC_ELT (vec, bc_continue) = label; 497 498 ent->label = vec; 499 ent->bc_label = true; 500 } 501 502 return TREE_VEC_ELT (vec, bc); 503 } 504 505 /* Set and return the current break label for the current block. */ 506 507 tree push_break_label (Statement *s) 508 { 509 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break); 510 DECL_CHAIN (label) = this->break_label_; 511 this->break_label_ = label; 512 return label; 513 } 514 515 /* Finish with the current break label. */ 516 517 void pop_break_label (tree label) 518 { 519 gcc_assert (this->break_label_ == label); 520 this->break_label_ = DECL_CHAIN (this->break_label_); 521 this->do_label (label); 522 } 523 524 /* Set and return the continue label for the current block. */ 525 526 tree push_continue_label (Statement *s) 527 { 528 tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue); 529 DECL_CHAIN (label) = this->continue_label_; 530 this->continue_label_ = label; 531 return label; 532 } 533 534 /* Finish with the current continue label. */ 535 536 void pop_continue_label (tree label) 537 { 538 gcc_assert (this->continue_label_ == label); 539 this->continue_label_ = DECL_CHAIN (this->continue_label_); 540 this->do_label (label); 541 } 542 543 /* Visitor interfaces. */ 544 545 546 /* This should be overridden by each statement class. */ 547 548 void visit (Statement *) 549 { 550 gcc_unreachable (); 551 } 552 553 /* The frontend lowers `scope (exit/failure/success)' statements as 554 try/catch/finally. At this point, this statement is just an empty 555 placeholder. Maybe the frontend shouldn't leak these. */ 556 557 void visit (OnScopeStatement *) 558 { 559 } 560 561 /* If statements provide simple conditional execution of statements. */ 562 563 void visit (IfStatement *s) 564 { 565 this->start_scope (level_cond); 566 567 /* Build the outer 'if' condition, which may produce temporaries 568 requiring scope destruction. */ 569 tree ifcond = convert_for_condition (build_expr_dtor (s->condition), 570 s->condition->type); 571 tree ifbody = void_node; 572 tree elsebody = void_node; 573 574 /* Build the 'then' branch. */ 575 if (s->ifbody) 576 { 577 push_stmt_list (); 578 this->build_stmt (s->ifbody); 579 ifbody = pop_stmt_list (); 580 } 581 582 /* Now build the 'else' branch, which may have nested 'else if' parts. */ 583 if (s->elsebody) 584 { 585 push_stmt_list (); 586 this->build_stmt (s->elsebody); 587 elsebody = pop_stmt_list (); 588 } 589 590 /* Wrap up our constructed if condition into a COND_EXPR. */ 591 tree cond = build_vcondition (ifcond, ifbody, elsebody); 592 add_stmt (cond); 593 594 /* Finish the if-then scope. */ 595 this->finish_scope (); 596 } 597 598 /* Should there be any `pragma (...)' statements requiring code generation, 599 here would be the place to do it. For now, all pragmas are handled 600 by the frontend. */ 601 602 void visit (PragmaStatement *) 603 { 604 } 605 606 /* The frontend lowers `while (...)' statements as `for (...)' loops. 607 This visitor is not strictly required other than to enforce that 608 these kinds of statements never reach here. */ 609 610 void visit (WhileStatement *) 611 { 612 gcc_unreachable (); 613 } 614 615 /* Do while statments implement simple loops. The body is executed, then 616 the condition is evaluated. */ 617 618 void visit (DoStatement *s) 619 { 620 tree lbreak = this->push_break_label (s); 621 622 this->start_scope (level_loop); 623 if (s->_body) 624 { 625 tree lcontinue = this->push_continue_label (s); 626 this->build_stmt (s->_body); 627 this->pop_continue_label (lcontinue); 628 } 629 630 /* Build the outer 'while' condition, which may produce temporaries 631 requiring scope destruction. */ 632 tree exitcond = convert_for_condition (build_expr_dtor (s->condition), 633 s->condition->type); 634 add_stmt (build_vcondition (exitcond, void_node, 635 build1 (GOTO_EXPR, void_type_node, lbreak))); 636 TREE_USED (lbreak) = 1; 637 638 tree body = this->end_scope (); 639 add_stmt (build1 (LOOP_EXPR, void_type_node, body)); 640 641 this->pop_break_label (lbreak); 642 } 643 644 /* For statements implement loops with initialization, test, and 645 increment clauses. */ 646 647 void visit (ForStatement *s) 648 { 649 tree lbreak = this->push_break_label (s); 650 this->start_scope (level_loop); 651 652 if (s->_init) 653 this->build_stmt (s->_init); 654 655 if (s->condition) 656 { 657 tree exitcond = convert_for_condition (build_expr_dtor (s->condition), 658 s->condition->type); 659 add_stmt (build_vcondition (exitcond, void_node, 660 build1 (GOTO_EXPR, void_type_node, 661 lbreak))); 662 TREE_USED (lbreak) = 1; 663 } 664 665 if (s->_body) 666 { 667 tree lcontinue = this->push_continue_label (s); 668 this->build_stmt (s->_body); 669 this->pop_continue_label (lcontinue); 670 } 671 672 if (s->increment) 673 { 674 /* Force side effects? */ 675 add_stmt (build_expr_dtor (s->increment)); 676 } 677 678 tree body = this->end_scope (); 679 add_stmt (build1 (LOOP_EXPR, void_type_node, body)); 680 681 this->pop_break_label (lbreak); 682 } 683 684 /* The frontend lowers `foreach (...)' statements as `for (...)' loops. 685 This visitor is not strictly required other than to enforce that 686 these kinds of statements never reach here. */ 687 688 void visit (ForeachStatement *) 689 { 690 gcc_unreachable (); 691 } 692 693 /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)' 694 loops. This visitor is not strictly required other than to enforce that 695 these kinds of statements never reach here. */ 696 697 void visit (ForeachRangeStatement *) 698 { 699 gcc_unreachable (); 700 } 701 702 /* Jump to the associated exit label for the current loop. If IDENT 703 for the Statement is not null, then the label is user defined. */ 704 705 void visit (BreakStatement *s) 706 { 707 if (s->ident) 708 { 709 /* The break label may actually be some levels up. 710 eg: on a try/finally wrapping a loop. */ 711 LabelStatement *label = this->func_->searchLabel (s->ident)->statement; 712 gcc_assert (label != NULL); 713 Statement *stmt = label->statement->getRelatedLabeled (); 714 this->do_jump (this->lookup_bc_label (stmt, bc_break)); 715 } 716 else 717 this->do_jump (this->break_label_); 718 } 719 720 /* Jump to the associated continue label for the current loop. If IDENT 721 for the Statement is not null, then the label is user defined. */ 722 723 void visit (ContinueStatement *s) 724 { 725 if (s->ident) 726 { 727 LabelStatement *label = this->func_->searchLabel (s->ident)->statement; 728 gcc_assert (label != NULL); 729 this->do_jump (this->lookup_bc_label (label->statement, 730 bc_continue)); 731 } 732 else 733 this->do_jump (this->continue_label_); 734 } 735 736 /* A goto statement jumps to the statement identified by the given label. */ 737 738 void visit (GotoStatement *s) 739 { 740 gcc_assert (s->label->statement != NULL); 741 gcc_assert (s->tf == s->label->statement->tf); 742 743 /* If no label found, there was an error. */ 744 tree label = this->lookup_label (s->label->statement, s->label->ident); 745 this->do_jump (label); 746 747 /* Need to error if the goto is jumping into a try or catch block. */ 748 this->check_goto (s, s->label->statement); 749 } 750 751 /* Statements can be labeled. A label is an identifier that precedes 752 a statement. */ 753 754 void visit (LabelStatement *s) 755 { 756 LabelDsymbol *sym; 757 758 if (this->is_return_label (s->ident)) 759 sym = this->func_->returnLabel; 760 else 761 sym = this->func_->searchLabel (s->ident); 762 763 /* If no label found, there was an error. */ 764 tree label = this->define_label (sym->statement, sym->ident); 765 TREE_USED (label) = 1; 766 767 this->do_label (label); 768 769 if (this->is_return_label (s->ident) && this->func_->fensure != NULL) 770 this->build_stmt (this->func_->fensure); 771 else if (s->statement) 772 this->build_stmt (s->statement); 773 } 774 775 /* A switch statement goes to one of a collection of case statements 776 depending on the value of the switch expression. */ 777 778 void visit (SwitchStatement *s) 779 { 780 this->start_scope (level_switch); 781 tree lbreak = this->push_break_label (s); 782 783 tree condition = build_expr_dtor (s->condition); 784 Type *condtype = s->condition->type->toBasetype (); 785 786 /* A switch statement on a string gets turned into a library call, 787 which does a binary lookup on list of string cases. */ 788 if (s->condition->type->isString ()) 789 { 790 Type *etype = condtype->nextOf ()->toBasetype (); 791 libcall_fn libcall; 792 793 switch (etype->ty) 794 { 795 case Tchar: 796 libcall = LIBCALL_SWITCH_STRING; 797 break; 798 799 case Twchar: 800 libcall = LIBCALL_SWITCH_USTRING; 801 break; 802 803 case Tdchar: 804 libcall = LIBCALL_SWITCH_DSTRING; 805 break; 806 807 default: 808 ::error ("switch statement value must be an array of " 809 "some character type, not %s", etype->toChars ()); 810 gcc_unreachable (); 811 } 812 813 /* Apparently the backend is supposed to sort and set the indexes 814 on the case array, have to change them to be usable. */ 815 Type *satype = condtype->sarrayOf (s->cases->dim); 816 vec<constructor_elt, va_gc> *elms = NULL; 817 818 s->cases->sort (); 819 820 for (size_t i = 0; i < s->cases->dim; i++) 821 { 822 CaseStatement *cs = (*s->cases)[i]; 823 cs->index = i; 824 825 if (cs->exp->op != TOKstring) 826 s->error ("case '%s' is not a string", cs->exp->toChars ()); 827 else 828 { 829 tree exp = build_expr (cs->exp, true); 830 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp); 831 } 832 } 833 834 /* Build static declaration to reference constructor. */ 835 tree ctor = build_constructor (build_ctype (satype), elms); 836 tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor); 837 TREE_READONLY (decl) = 1; 838 d_pushdecl (decl); 839 rest_of_decl_compilation (decl, 1, 0); 840 841 /* Pass it as a dynamic array. */ 842 decl = d_array_value (build_ctype (condtype->arrayOf ()), 843 size_int (s->cases->dim), 844 build_address (decl)); 845 846 condition = build_libcall (libcall, Type::tint32, 2, decl, condition); 847 } 848 else if (!condtype->isscalar ()) 849 { 850 error ("cannot handle switch condition of type %s", 851 condtype->toChars ()); 852 gcc_unreachable (); 853 } 854 855 condition = fold (condition); 856 857 /* Build LABEL_DECLs now so they can be refered to by goto case. 858 Also checking the jump from the switch to the label is allowed. */ 859 if (s->cases) 860 { 861 for (size_t i = 0; i < s->cases->dim; i++) 862 { 863 CaseStatement *cs = (*s->cases)[i]; 864 tree caselabel = this->lookup_label (cs); 865 866 /* Write cases as a series of if-then-else blocks. 867 if (condition == case) 868 goto caselabel; */ 869 if (s->hasVars) 870 { 871 tree ifcase = build2 (EQ_EXPR, build_ctype (condtype), 872 condition, build_expr_dtor (cs->exp)); 873 tree ifbody = fold_build1 (GOTO_EXPR, void_type_node, 874 caselabel); 875 tree cond = build_vcondition (ifcase, ifbody, void_node); 876 TREE_USED (caselabel) = 1; 877 LABEL_VARIABLE_CASE (caselabel) = 1; 878 add_stmt (cond); 879 } 880 881 this->check_goto (s, cs); 882 } 883 884 if (s->sdefault) 885 { 886 tree defaultlabel = this->lookup_label (s->sdefault); 887 888 /* The default label is the last 'else' block. */ 889 if (s->hasVars) 890 { 891 this->do_jump (defaultlabel); 892 LABEL_VARIABLE_CASE (defaultlabel) = 1; 893 } 894 895 this->check_goto (s, s->sdefault); 896 } 897 } 898 899 /* Switch body goes in its own statement list. */ 900 push_stmt_list (); 901 if (s->_body) 902 this->build_stmt (s->_body); 903 904 tree casebody = pop_stmt_list (); 905 906 /* Wrap up constructed body into a switch_expr, unless it was 907 converted to an if-then-else expression. */ 908 if (s->hasVars) 909 add_stmt (casebody); 910 else 911 { 912 tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition), 913 condition, casebody); 914 add_stmt (switchexpr); 915 SWITCH_ALL_CASES_P (switchexpr) = 1; 916 } 917 918 SWITCH_BREAK_LABEL_P (lbreak) = 1; 919 920 /* If the switch had any 'break' statements, emit the label now. */ 921 this->pop_break_label (lbreak); 922 this->finish_scope (); 923 } 924 925 /* Declare the case label associated with the current SwitchStatement. */ 926 927 void visit (CaseStatement *s) 928 { 929 /* Emit the case label. */ 930 tree label = this->define_label (s); 931 932 if (LABEL_VARIABLE_CASE (label)) 933 this->do_label (label); 934 else 935 { 936 tree casevalue; 937 if (s->exp->type->isscalar ()) 938 casevalue = build_expr (s->exp); 939 else 940 casevalue = build_integer_cst (s->index, build_ctype (Type::tint32)); 941 942 tree caselabel = build_case_label (casevalue, NULL_TREE, label); 943 add_stmt (caselabel); 944 } 945 946 /* Now do the body. */ 947 if (s->statement) 948 this->build_stmt (s->statement); 949 } 950 951 /* Declare the default label associated with the current SwitchStatement. */ 952 953 void visit (DefaultStatement *s) 954 { 955 /* Emit the default case label. */ 956 tree label = this->define_label (s); 957 958 if (LABEL_VARIABLE_CASE (label)) 959 this->do_label (label); 960 else 961 { 962 tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label); 963 add_stmt (caselabel); 964 } 965 966 /* Now do the body. */ 967 if (s->statement) 968 this->build_stmt (s->statement); 969 } 970 971 /* Implements 'goto default' by jumping to the label associated with 972 the DefaultStatement in a switch block. */ 973 974 void visit (GotoDefaultStatement *s) 975 { 976 tree label = this->lookup_label (s->sw->sdefault); 977 this->do_jump (label); 978 } 979 980 /* Implements 'goto case' by jumping to the label associated with the 981 CaseStatement in a switch block. */ 982 983 void visit (GotoCaseStatement *s) 984 { 985 tree label = this->lookup_label (s->cs); 986 this->do_jump (label); 987 } 988 989 /* Throw a SwitchError exception, called when a switch statement has 990 no DefaultStatement, yet none of the cases match. */ 991 992 void visit (SwitchErrorStatement *s) 993 { 994 add_stmt (d_assert_call (s->loc, LIBCALL_SWITCH_ERROR)); 995 } 996 997 /* A return statement exits the current function and supplies its return 998 value, if the return type is not void. */ 999 1000 void visit (ReturnStatement *s) 1001 { 1002 if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid) 1003 { 1004 /* Return has no value. */ 1005 add_stmt (return_expr (NULL_TREE)); 1006 return; 1007 } 1008 1009 TypeFunction *tf = (TypeFunction *)this->func_->type; 1010 Type *type = this->func_->tintro != NULL 1011 ? this->func_->tintro->nextOf () : tf->nextOf (); 1012 1013 if ((this->func_->isMain () || this->func_->isCMain ()) 1014 && type->toBasetype ()->ty == Tvoid) 1015 type = Type::tint32; 1016 1017 if (this->func_->nrvo_can && this->func_->nrvo_var) 1018 { 1019 /* Just refer to the DECL_RESULT; this differs from using 1020 NULL_TREE in that it indicates that we care about the value 1021 of the DECL_RESULT. */ 1022 tree decl = DECL_RESULT (get_symbol_decl (this->func_)); 1023 add_stmt (return_expr (decl)); 1024 } 1025 else 1026 { 1027 /* Convert for initializing the DECL_RESULT. */ 1028 tree expr = build_return_dtor (s->exp, type, tf); 1029 add_stmt (expr); 1030 } 1031 } 1032 1033 /* Evaluate the enclosed expression, and add it to the statement list. */ 1034 1035 void visit (ExpStatement *s) 1036 { 1037 if (s->exp) 1038 { 1039 /* Expression may produce temporaries requiring scope destruction. */ 1040 tree exp = build_expr_dtor (s->exp); 1041 add_stmt (exp); 1042 } 1043 } 1044 1045 /* Evaluate all enclosed statements. */ 1046 1047 void visit (CompoundStatement *s) 1048 { 1049 if (s->statements == NULL) 1050 return; 1051 1052 for (size_t i = 0; i < s->statements->dim; i++) 1053 { 1054 Statement *statement = (*s->statements)[i]; 1055 1056 if (statement != NULL) 1057 this->build_stmt (statement); 1058 } 1059 } 1060 1061 /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop. 1062 These are compiled down as a `do ... while (0)', where each unrolled loop 1063 is nested inside and given their own continue label to jump to. */ 1064 1065 void visit (UnrolledLoopStatement *s) 1066 { 1067 if (s->statements == NULL) 1068 return; 1069 1070 tree lbreak = this->push_break_label (s); 1071 this->start_scope (level_loop); 1072 1073 for (size_t i = 0; i < s->statements->dim; i++) 1074 { 1075 Statement *statement = (*s->statements)[i]; 1076 1077 if (statement != NULL) 1078 { 1079 tree lcontinue = this->push_continue_label (statement); 1080 this->build_stmt (statement); 1081 this->pop_continue_label (lcontinue); 1082 } 1083 } 1084 1085 this->do_jump (this->break_label_); 1086 1087 tree body = this->end_scope (); 1088 add_stmt (build1 (LOOP_EXPR, void_type_node, body)); 1089 1090 this->pop_break_label (lbreak); 1091 } 1092 1093 /* Start a new scope and visit all nested statements, wrapping 1094 them up into a BIND_EXPR at the end of the scope. */ 1095 1096 void visit (ScopeStatement *s) 1097 { 1098 if (s->statement == NULL) 1099 return; 1100 1101 this->start_scope (level_block); 1102 this->build_stmt (s->statement); 1103 this->finish_scope (); 1104 } 1105 1106 /* A with statement is a way to simplify repeated references to the same 1107 object, where the handle is either a class or struct instance. */ 1108 1109 void visit (WithStatement *s) 1110 { 1111 this->start_scope (level_with); 1112 1113 if (s->wthis) 1114 { 1115 /* Perform initialisation of the 'with' handle. */ 1116 ExpInitializer *ie = s->wthis->_init->isExpInitializer (); 1117 gcc_assert (ie != NULL); 1118 1119 declare_local_var (s->wthis); 1120 tree init = build_expr_dtor (ie->exp); 1121 add_stmt (init); 1122 } 1123 1124 if (s->_body) 1125 this->build_stmt (s->_body); 1126 1127 this->finish_scope (); 1128 } 1129 1130 /* Implements 'throw Object'. Frontend already checks that the object 1131 thrown is a class type, but does not check if it is derived from 1132 Object. Foreign objects are not currently supported at run-time. */ 1133 1134 void visit (ThrowStatement *s) 1135 { 1136 ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle (); 1137 InterfaceDeclaration *id = cd->isInterfaceDeclaration (); 1138 tree arg = build_expr_dtor (s->exp); 1139 1140 if (!global.params.useExceptions) 1141 { 1142 static int warned = 0; 1143 if (!warned) 1144 { 1145 error_at (make_location_t (s->loc), "exception handling disabled; " 1146 "use %<-fexceptions%> to enable"); 1147 warned = 1; 1148 } 1149 } 1150 1151 if (cd->isCPPclass () || (id != NULL && id->isCPPclass ())) 1152 error_at (make_location_t (s->loc), "cannot throw C++ classes"); 1153 else if (cd->com || (id != NULL && id->com)) 1154 error_at (make_location_t (s->loc), "cannot throw COM objects"); 1155 else 1156 arg = build_nop (build_ctype (get_object_type ()), arg); 1157 1158 add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg)); 1159 } 1160 1161 /* Build a try-catch statement, one of the building blocks for exception 1162 handling generated by the frontend. This is also used to implement 1163 `scope (failure)' statements. */ 1164 1165 void visit (TryCatchStatement *s) 1166 { 1167 this->start_scope (level_try); 1168 if (s->_body) 1169 this->build_stmt (s->_body); 1170 1171 tree trybody = this->end_scope (); 1172 1173 /* Try handlers go in their own statement list. */ 1174 push_stmt_list (); 1175 1176 if (s->catches) 1177 { 1178 for (size_t i = 0; i < s->catches->dim; i++) 1179 { 1180 Catch *vcatch = (*s->catches)[i]; 1181 1182 this->start_scope (level_catch); 1183 1184 tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER); 1185 tree catchtype = build_ctype (vcatch->type); 1186 tree object = NULL_TREE; 1187 1188 ehptr = build_call_expr (ehptr, 1, integer_zero_node); 1189 1190 /* Retrieve the internal exception object, which could be for a 1191 D or C++ catch handler. This is different from the generic 1192 exception pointer returned from gcc runtime. */ 1193 Type *tcatch = vcatch->type->toBasetype (); 1194 ClassDeclaration *cd = tcatch->isClassHandle (); 1195 1196 libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH 1197 : LIBCALL_BEGIN_CATCH; 1198 object = build_libcall (libcall, vcatch->type, 1, ehptr); 1199 1200 if (vcatch->var) 1201 { 1202 tree var = get_symbol_decl (vcatch->var); 1203 tree init = build_assign (INIT_EXPR, var, object); 1204 1205 declare_local_var (vcatch->var); 1206 add_stmt (init); 1207 } 1208 else 1209 { 1210 /* Still need to emit a call to __gdc_begin_catch() to 1211 remove the object from the uncaught exceptions list. */ 1212 add_stmt (object); 1213 } 1214 1215 if (vcatch->handler) 1216 this->build_stmt (vcatch->handler); 1217 1218 tree catchbody = this->end_scope (); 1219 1220 /* Need to wrap C++ handlers in a try/finally block to signal 1221 the end catch callback. */ 1222 if (cd->isCPPclass ()) 1223 { 1224 tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH, 1225 Type::tvoid, 0); 1226 catchbody = build2 (TRY_FINALLY_EXPR, void_type_node, 1227 catchbody, endcatch); 1228 } 1229 1230 add_stmt (build2 (CATCH_EXPR, void_type_node, 1231 catchtype, catchbody)); 1232 } 1233 } 1234 1235 tree catches = pop_stmt_list (); 1236 1237 /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a 1238 statement list, however pop_stmt_list may optimize away the list 1239 if there is only a single catch to push. */ 1240 if (TREE_CODE (catches) != STATEMENT_LIST) 1241 { 1242 tree stmt_list = alloc_stmt_list (); 1243 append_to_statement_list_force (catches, &stmt_list); 1244 catches = stmt_list; 1245 } 1246 1247 add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches)); 1248 } 1249 1250 /* Build a try-finally statement, one of the building blocks for exception 1251 handling generated by the frontend. This is also used to implement 1252 `scope (exit)' statements. */ 1253 1254 void visit (TryFinallyStatement *s) 1255 { 1256 this->start_scope (level_try); 1257 if (s->_body) 1258 this->build_stmt (s->_body); 1259 1260 tree trybody = this->end_scope (); 1261 1262 this->start_scope (level_finally); 1263 if (s->finalbody) 1264 this->build_stmt (s->finalbody); 1265 1266 tree finally = this->end_scope (); 1267 1268 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally)); 1269 } 1270 1271 /* The frontend lowers `synchronized (...)' statements as a call to 1272 monitor/critical enter and exit wrapped around try/finally. 1273 This visitor is not strictly required other than to enforce that 1274 these kinds of statements never reach here. */ 1275 1276 void visit (SynchronizedStatement *) 1277 { 1278 gcc_unreachable (); 1279 } 1280 1281 /* D Inline Assembler is not implemented, as it would require writing 1282 an assembly parser for each supported target. Instead we leverage 1283 GCC extended assembler using the GccAsmStatement class. */ 1284 1285 void visit (AsmStatement *) 1286 { 1287 sorry ("D inline assembler statements are not supported in GDC."); 1288 } 1289 1290 /* Build a GCC extended assembler expression, whose components are 1291 an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */ 1292 1293 void visit (GccAsmStatement *s) 1294 { 1295 StringExp *insn = (StringExp *)s->insn; 1296 tree outputs = NULL_TREE; 1297 tree inputs = NULL_TREE; 1298 tree clobbers = NULL_TREE; 1299 tree labels = NULL_TREE; 1300 1301 /* Collect all arguments, which may be input or output operands. */ 1302 if (s->args) 1303 { 1304 for (size_t i = 0; i < s->args->dim; i++) 1305 { 1306 Identifier *name = (*s->names)[i]; 1307 const char *sname = name ? name->toChars () : NULL; 1308 tree id = name ? build_string (strlen (sname), sname) : NULL_TREE; 1309 1310 StringExp *constr = (StringExp *)(*s->constraints)[i]; 1311 const char *cstring = (const char *)(constr->len 1312 ? constr->string : ""); 1313 tree str = build_string (constr->len, cstring); 1314 1315 Expression *earg = (*s->args)[i]; 1316 tree val = build_expr (earg); 1317 1318 if (i < s->outputargs) 1319 { 1320 tree arg = build_tree_list (id, str); 1321 outputs = chainon (outputs, build_tree_list (arg, val)); 1322 } 1323 else 1324 { 1325 tree arg = build_tree_list (id, str); 1326 inputs = chainon (inputs, build_tree_list (arg, val)); 1327 } 1328 } 1329 } 1330 1331 /* Collect all clobber arguments. */ 1332 if (s->clobbers) 1333 { 1334 for (size_t i = 0; i < s->clobbers->dim; i++) 1335 { 1336 StringExp *clobber = (StringExp *)(*s->clobbers)[i]; 1337 const char *cstring = (const char *)(clobber->len 1338 ? clobber->string : ""); 1339 1340 tree val = build_string (clobber->len, cstring); 1341 clobbers = chainon (clobbers, build_tree_list (0, val)); 1342 } 1343 } 1344 1345 /* Collect all goto labels, these should have been already checked 1346 by the front-end, so pass down the label symbol to the back-end. */ 1347 if (s->labels) 1348 { 1349 for (size_t i = 0; i < s->labels->dim; i++) 1350 { 1351 Identifier *ident = (*s->labels)[i]; 1352 GotoStatement *gs = (*s->gotos)[i]; 1353 1354 gcc_assert (gs->label->statement != NULL); 1355 gcc_assert (gs->tf == gs->label->statement->tf); 1356 1357 const char *sident = ident->toChars (); 1358 tree name = build_string (strlen (sident), sident); 1359 tree label = this->lookup_label (gs->label->statement, 1360 gs->label->ident); 1361 TREE_USED (label) = 1; 1362 1363 labels = chainon (labels, build_tree_list (name, label)); 1364 } 1365 } 1366 1367 /* Do some extra validation on all input and output operands. */ 1368 const char *insnstring = (const char *)(insn->len ? insn->string : ""); 1369 tree string = build_string (insn->len, insnstring); 1370 string = resolve_asm_operand_names (string, outputs, inputs, labels); 1371 1372 if (s->args) 1373 { 1374 unsigned noutputs = s->outputargs; 1375 unsigned ninputs = (s->args->dim - noutputs); 1376 const char **oconstraints = XALLOCAVEC (const char *, noutputs); 1377 bool allows_mem, allows_reg, is_inout; 1378 size_t i; 1379 tree t; 1380 1381 for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++) 1382 { 1383 tree output = TREE_VALUE (t); 1384 const char *constraint 1385 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); 1386 1387 oconstraints[i] = constraint; 1388 1389 if (parse_output_constraint (&constraint, i, ninputs, noutputs, 1390 &allows_mem, &allows_reg, &is_inout)) 1391 { 1392 /* If the output argument is going to end up in memory. */ 1393 if (!allows_reg) 1394 d_mark_addressable (output); 1395 } 1396 else 1397 output = error_mark_node; 1398 1399 TREE_VALUE (t) = output; 1400 } 1401 1402 for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++) 1403 { 1404 tree input = TREE_VALUE (t); 1405 const char *constraint 1406 = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); 1407 1408 if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0, 1409 oconstraints, &allows_mem, &allows_reg)) 1410 { 1411 /* If the input argument is going to end up in memory. */ 1412 if (!allows_reg && allows_mem) 1413 d_mark_addressable (input); 1414 } 1415 else 1416 input = error_mark_node; 1417 1418 TREE_VALUE (t) = input; 1419 } 1420 } 1421 1422 tree exp = build5 (ASM_EXPR, void_type_node, string, 1423 outputs, inputs, clobbers, labels); 1424 SET_EXPR_LOCATION (exp, make_location_t (s->loc)); 1425 1426 /* If the extended syntax was not used, mark the ASM_EXPR as being an 1427 ASM_INPUT expression instead of an ASM_OPERAND with no operands. */ 1428 if (s->args == NULL && s->clobbers == NULL) 1429 ASM_INPUT_P (exp) = 1; 1430 1431 /* All asm statements are assumed to have a side effect. As a future 1432 optimization, this could be unset when building in release mode. */ 1433 ASM_VOLATILE_P (exp) = 1; 1434 1435 /* If the function has been annotated with 'pragma(inline)', then mark 1436 the asm expression as being inline as well. */ 1437 if (this->func_->inlining == PINLINEalways) 1438 ASM_INLINE_P (exp) = 1; 1439 1440 add_stmt (exp); 1441 } 1442 1443 /* Import symbols from another module. */ 1444 1445 void visit (ImportStatement *s) 1446 { 1447 if (s->imports == NULL) 1448 return; 1449 1450 for (size_t i = 0; i < s->imports->dim; i++) 1451 { 1452 Dsymbol *dsym = (*s->imports)[i]; 1453 1454 if (dsym != NULL) 1455 build_decl_tree (dsym); 1456 } 1457 } 1458 }; 1459 1460 /* Main entry point for the IRVisitor interface to generate 1461 code for the body of function FD. */ 1462 1463 void 1464 build_function_body (FuncDeclaration *fd) 1465 { 1466 IRVisitor v = IRVisitor (fd); 1467 location_t saved_location = input_location; 1468 input_location = make_location_t (fd->loc); 1469 v.build_stmt (fd->fbody); 1470 input_location = saved_location; 1471 } 1472