1/* C++-specific tree lowering bits; see also c-gimplify.c and tree-gimple.c. 2 3 Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 4 Contributed by Jason Merrill <jason@redhat.com> 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13GCC is distributed in the hope that it will be useful, but WITHOUT ANY 14WARRANTY; without even the implied warranty of MERCHANTABILITY or 15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16for more details. 17 18You should have received a copy of the GNU General Public License 19along with GCC; see the file COPYING. If not, write to the Free 20Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 2102110-1301, USA. */ 22 23#include "config.h" 24#include "system.h" 25#include "coretypes.h" 26#include "tm.h" 27#include "tree.h" 28#include "cp-tree.h" 29#include "c-common.h" 30#include "toplev.h" 31#include "tree-gimple.h" 32#include "hashtab.h" 33#include "pointer-set.h" 34#include "flags.h" 35 36/* Local declarations. */ 37 38enum bc_t { bc_break = 0, bc_continue = 1 }; 39 40/* Stack of labels which are targets for "break" or "continue", 41 linked through TREE_CHAIN. */ 42static tree bc_label[2]; 43 44/* Begin a scope which can be exited by a break or continue statement. BC 45 indicates which. 46 47 Just creates a label and pushes it into the current context. */ 48 49static tree 50begin_bc_block (enum bc_t bc) 51{ 52 tree label = create_artificial_label (); 53 TREE_CHAIN (label) = bc_label[bc]; 54 bc_label[bc] = label; 55 return label; 56} 57 58/* Finish a scope which can be exited by a break or continue statement. 59 LABEL was returned from the most recent call to begin_bc_block. BODY is 60 an expression for the contents of the scope. 61 62 If we saw a break (or continue) in the scope, append a LABEL_EXPR to 63 body. Otherwise, just forget the label. */ 64 65static tree 66finish_bc_block (enum bc_t bc, tree label, tree body) 67{ 68 gcc_assert (label == bc_label[bc]); 69 70 if (TREE_USED (label)) 71 { 72 tree t, sl = NULL; 73 74 t = build1 (LABEL_EXPR, void_type_node, label); 75 76 append_to_statement_list (body, &sl); 77 append_to_statement_list (t, &sl); 78 body = sl; 79 } 80 81 bc_label[bc] = TREE_CHAIN (label); 82 TREE_CHAIN (label) = NULL_TREE; 83 return body; 84} 85 86/* Build a GOTO_EXPR to represent a break or continue statement. BC 87 indicates which. */ 88 89static tree 90build_bc_goto (enum bc_t bc) 91{ 92 tree label = bc_label[bc]; 93 94 if (label == NULL_TREE) 95 { 96 if (bc == bc_break) 97 error ("break statement not within loop or switch"); 98 else 99 error ("continue statement not within loop or switch"); 100 101 return NULL_TREE; 102 } 103 104 /* Mark the label used for finish_bc_block. */ 105 TREE_USED (label) = 1; 106 return build1 (GOTO_EXPR, void_type_node, label); 107} 108 109/* Genericize a TRY_BLOCK. */ 110 111static void 112genericize_try_block (tree *stmt_p) 113{ 114 tree body = TRY_STMTS (*stmt_p); 115 tree cleanup = TRY_HANDLERS (*stmt_p); 116 117 gimplify_stmt (&body); 118 119 if (CLEANUP_P (*stmt_p)) 120 /* A cleanup is an expression, so it doesn't need to be genericized. */; 121 else 122 gimplify_stmt (&cleanup); 123 124 *stmt_p = build2 (TRY_CATCH_EXPR, void_type_node, body, cleanup); 125} 126 127/* Genericize a HANDLER by converting to a CATCH_EXPR. */ 128 129static void 130genericize_catch_block (tree *stmt_p) 131{ 132 tree type = HANDLER_TYPE (*stmt_p); 133 tree body = HANDLER_BODY (*stmt_p); 134 135 gimplify_stmt (&body); 136 137 /* FIXME should the caught type go in TREE_TYPE? */ 138 *stmt_p = build2 (CATCH_EXPR, void_type_node, type, body); 139} 140 141/* Genericize an EH_SPEC_BLOCK by converting it to a 142 TRY_CATCH_EXPR/EH_FILTER_EXPR pair. */ 143 144static void 145genericize_eh_spec_block (tree *stmt_p) 146{ 147 tree body = EH_SPEC_STMTS (*stmt_p); 148 tree allowed = EH_SPEC_RAISES (*stmt_p); 149 tree failure = build_call (call_unexpected_node, 150 tree_cons (NULL_TREE, build_exc_ptr (), 151 NULL_TREE)); 152 gimplify_stmt (&body); 153 154 *stmt_p = gimple_build_eh_filter (body, allowed, failure); 155} 156 157/* Genericize an IF_STMT by turning it into a COND_EXPR. */ 158 159static void 160gimplify_if_stmt (tree *stmt_p) 161{ 162 tree stmt, cond, then_, else_; 163 164 stmt = *stmt_p; 165 cond = IF_COND (stmt); 166 then_ = THEN_CLAUSE (stmt); 167 else_ = ELSE_CLAUSE (stmt); 168 169 if (!then_) 170 then_ = build_empty_stmt (); 171 if (!else_) 172 else_ = build_empty_stmt (); 173 174 if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_)) 175 stmt = then_; 176 else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_)) 177 stmt = else_; 178 else 179 stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_); 180 *stmt_p = stmt; 181} 182 183/* Build a generic representation of one of the C loop forms. COND is the 184 loop condition or NULL_TREE. BODY is the (possibly compound) statement 185 controlled by the loop. INCR is the increment expression of a for-loop, 186 or NULL_TREE. COND_IS_FIRST indicates whether the condition is 187 evaluated before the loop body as in while and for loops, or after the 188 loop body as in do-while loops. */ 189 190static tree 191gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first) 192{ 193 tree top, entry, exit, cont_block, break_block, stmt_list, t; 194 location_t stmt_locus; 195 196 stmt_locus = input_location; 197 stmt_list = NULL_TREE; 198 entry = NULL_TREE; 199 200 break_block = begin_bc_block (bc_break); 201 cont_block = begin_bc_block (bc_continue); 202 203 /* If condition is zero don't generate a loop construct. */ 204 if (cond && integer_zerop (cond)) 205 { 206 top = NULL_TREE; 207 exit = NULL_TREE; 208 if (cond_is_first) 209 { 210 t = build_bc_goto (bc_break); 211 append_to_statement_list (t, &stmt_list); 212 } 213 } 214 else 215 { 216 /* If we use a LOOP_EXPR here, we have to feed the whole thing 217 back through the main gimplifier to lower it. Given that we 218 have to gimplify the loop body NOW so that we can resolve 219 break/continue stmts, seems easier to just expand to gotos. */ 220 top = build1 (LABEL_EXPR, void_type_node, NULL_TREE); 221 222 /* If we have an exit condition, then we build an IF with gotos either 223 out of the loop, or to the top of it. If there's no exit condition, 224 then we just build a jump back to the top. */ 225 exit = build_and_jump (&LABEL_EXPR_LABEL (top)); 226 if (cond && !integer_nonzerop (cond)) 227 { 228 t = build_bc_goto (bc_break); 229 exit = fold_build3 (COND_EXPR, void_type_node, cond, exit, t); 230 gimplify_stmt (&exit); 231 232 if (cond_is_first) 233 { 234 if (incr) 235 { 236 entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE); 237 t = build_and_jump (&LABEL_EXPR_LABEL (entry)); 238 } 239 else 240 t = build_bc_goto (bc_continue); 241 append_to_statement_list (t, &stmt_list); 242 } 243 } 244 } 245 246 gimplify_stmt (&body); 247 gimplify_stmt (&incr); 248 249 body = finish_bc_block (bc_continue, cont_block, body); 250 251 append_to_statement_list (top, &stmt_list); 252 append_to_statement_list (body, &stmt_list); 253 append_to_statement_list (incr, &stmt_list); 254 append_to_statement_list (entry, &stmt_list); 255 append_to_statement_list (exit, &stmt_list); 256 257 annotate_all_with_locus (&stmt_list, stmt_locus); 258 259 return finish_bc_block (bc_break, break_block, stmt_list); 260} 261 262/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the 263 prequeue and hand off to gimplify_cp_loop. */ 264 265static void 266gimplify_for_stmt (tree *stmt_p, tree *pre_p) 267{ 268 tree stmt = *stmt_p; 269 270 if (FOR_INIT_STMT (stmt)) 271 gimplify_and_add (FOR_INIT_STMT (stmt), pre_p); 272 273 *stmt_p = gimplify_cp_loop (FOR_COND (stmt), FOR_BODY (stmt), 274 FOR_EXPR (stmt), 1); 275} 276 277/* Gimplify a WHILE_STMT node. */ 278 279static void 280gimplify_while_stmt (tree *stmt_p) 281{ 282 tree stmt = *stmt_p; 283 *stmt_p = gimplify_cp_loop (WHILE_COND (stmt), WHILE_BODY (stmt), 284 NULL_TREE, 1); 285} 286 287/* Gimplify a DO_STMT node. */ 288 289static void 290gimplify_do_stmt (tree *stmt_p) 291{ 292 tree stmt = *stmt_p; 293 *stmt_p = gimplify_cp_loop (DO_COND (stmt), DO_BODY (stmt), 294 NULL_TREE, 0); 295} 296 297/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */ 298 299static void 300gimplify_switch_stmt (tree *stmt_p) 301{ 302 tree stmt = *stmt_p; 303 tree break_block, body; 304 location_t stmt_locus = input_location; 305 306 break_block = begin_bc_block (bc_break); 307 308 body = SWITCH_STMT_BODY (stmt); 309 if (!body) 310 body = build_empty_stmt (); 311 312 *stmt_p = build3 (SWITCH_EXPR, SWITCH_STMT_TYPE (stmt), 313 SWITCH_STMT_COND (stmt), body, NULL_TREE); 314 SET_EXPR_LOCATION (*stmt_p, stmt_locus); 315 gimplify_stmt (stmt_p); 316 317 *stmt_p = finish_bc_block (bc_break, break_block, *stmt_p); 318} 319 320/* Hook into the middle of gimplifying an OMP_FOR node. This is required 321 in order to properly gimplify CONTINUE statements. Here we merely 322 manage the continue stack; the rest of the job is performed by the 323 regular gimplifier. */ 324 325static enum gimplify_status 326cp_gimplify_omp_for (tree *expr_p) 327{ 328 tree for_stmt = *expr_p; 329 tree cont_block; 330 331 /* Protect ourselves from recursion. */ 332 if (OMP_FOR_GIMPLIFYING_P (for_stmt)) 333 return GS_UNHANDLED; 334 OMP_FOR_GIMPLIFYING_P (for_stmt) = 1; 335 336 /* Note that while technically the continue label is enabled too soon 337 here, we should have already diagnosed invalid continues nested within 338 statement expressions within the INIT, COND, or INCR expressions. */ 339 cont_block = begin_bc_block (bc_continue); 340 341 gimplify_stmt (expr_p); 342 343 OMP_FOR_BODY (for_stmt) 344 = finish_bc_block (bc_continue, cont_block, OMP_FOR_BODY (for_stmt)); 345 OMP_FOR_GIMPLIFYING_P (for_stmt) = 0; 346 347 return GS_ALL_DONE; 348} 349 350/* Gimplify an EXPR_STMT node. */ 351 352static void 353gimplify_expr_stmt (tree *stmt_p) 354{ 355 tree stmt = EXPR_STMT_EXPR (*stmt_p); 356 357 if (stmt == error_mark_node) 358 stmt = NULL; 359 360 /* Gimplification of a statement expression will nullify the 361 statement if all its side effects are moved to *PRE_P and *POST_P. 362 363 In this case we will not want to emit the gimplified statement. 364 However, we may still want to emit a warning, so we do that before 365 gimplification. */ 366 if (stmt && (extra_warnings || warn_unused_value)) 367 { 368 if (!TREE_SIDE_EFFECTS (stmt)) 369 { 370 if (!IS_EMPTY_STMT (stmt) 371 && !VOID_TYPE_P (TREE_TYPE (stmt)) 372 && !TREE_NO_WARNING (stmt)) 373 warning (OPT_Wextra, "statement with no effect"); 374 } 375 else if (warn_unused_value) 376 warn_if_unused_value (stmt, input_location); 377 } 378 379 if (stmt == NULL_TREE) 380 stmt = alloc_stmt_list (); 381 382 *stmt_p = stmt; 383} 384 385/* Gimplify initialization from an AGGR_INIT_EXPR. */ 386 387static void 388cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p) 389{ 390 tree from = TREE_OPERAND (*expr_p, 1); 391 tree to = TREE_OPERAND (*expr_p, 0); 392 tree sub; 393 394 /* What about code that pulls out the temp and uses it elsewhere? I 395 think that such code never uses the TARGET_EXPR as an initializer. If 396 I'm wrong, we'll abort because the temp won't have any RTL. In that 397 case, I guess we'll need to replace references somehow. */ 398 if (TREE_CODE (from) == TARGET_EXPR) 399 from = TARGET_EXPR_INITIAL (from); 400 401 /* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them 402 inside the TARGET_EXPR. */ 403 sub = expr_last (from); 404 405 /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and 406 replace the slot operand with our target. 407 408 Should we add a target parm to gimplify_expr instead? No, as in this 409 case we want to replace the INIT_EXPR. */ 410 if (TREE_CODE (sub) == AGGR_INIT_EXPR) 411 { 412 gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); 413 TREE_OPERAND (sub, 2) = to; 414 *expr_p = from; 415 416 /* The initialization is now a side-effect, so the container can 417 become void. */ 418 if (from != sub) 419 TREE_TYPE (from) = void_type_node; 420 } 421} 422 423/* Gimplify a MUST_NOT_THROW_EXPR. */ 424 425static void 426gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p) 427{ 428 tree stmt = *expr_p; 429 tree temp = voidify_wrapper_expr (stmt, NULL); 430 tree body = TREE_OPERAND (stmt, 0); 431 432 gimplify_stmt (&body); 433 434 stmt = gimple_build_eh_filter (body, NULL_TREE, 435 build_call (terminate_node, NULL_TREE)); 436 437 if (temp) 438 { 439 append_to_statement_list (stmt, pre_p); 440 *expr_p = temp; 441 } 442 else 443 *expr_p = stmt; 444} 445 446/* Do C++-specific gimplification. Args are as for gimplify_expr. */ 447 448int 449cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) 450{ 451 int saved_stmts_are_full_exprs_p = 0; 452 enum tree_code code = TREE_CODE (*expr_p); 453 enum gimplify_status ret; 454 455 if (STATEMENT_CODE_P (code)) 456 { 457 saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); 458 current_stmt_tree ()->stmts_are_full_exprs_p 459 = STMT_IS_FULL_EXPR_P (*expr_p); 460 } 461 462 switch (code) 463 { 464 case PTRMEM_CST: 465 *expr_p = cplus_expand_constant (*expr_p); 466 ret = GS_OK; 467 break; 468 469 case AGGR_INIT_EXPR: 470 simplify_aggr_init_expr (expr_p); 471 ret = GS_OK; 472 break; 473 474 case THROW_EXPR: 475 /* FIXME communicate throw type to backend, probably by moving 476 THROW_EXPR into ../tree.def. */ 477 *expr_p = TREE_OPERAND (*expr_p, 0); 478 ret = GS_OK; 479 break; 480 481 case MUST_NOT_THROW_EXPR: 482 gimplify_must_not_throw_expr (expr_p, pre_p); 483 ret = GS_OK; 484 break; 485 486 /* We used to do this for MODIFY_EXPR as well, but that's unsafe; the 487 LHS of an assignment might also be involved in the RHS, as in bug 488 25979. */ 489 case INIT_EXPR: 490 cp_gimplify_init_expr (expr_p, pre_p, post_p); 491 ret = GS_OK; 492 break; 493 494 case EMPTY_CLASS_EXPR: 495 /* We create an empty CONSTRUCTOR with RECORD_TYPE. */ 496 *expr_p = build_constructor (TREE_TYPE (*expr_p), NULL); 497 ret = GS_OK; 498 break; 499 500 case BASELINK: 501 *expr_p = BASELINK_FUNCTIONS (*expr_p); 502 ret = GS_OK; 503 break; 504 505 case TRY_BLOCK: 506 genericize_try_block (expr_p); 507 ret = GS_OK; 508 break; 509 510 case HANDLER: 511 genericize_catch_block (expr_p); 512 ret = GS_OK; 513 break; 514 515 case EH_SPEC_BLOCK: 516 genericize_eh_spec_block (expr_p); 517 ret = GS_OK; 518 break; 519 520 case USING_STMT: 521 /* Just ignore for now. Eventually we will want to pass this on to 522 the debugger. */ 523 *expr_p = build_empty_stmt (); 524 ret = GS_ALL_DONE; 525 break; 526 527 case IF_STMT: 528 gimplify_if_stmt (expr_p); 529 ret = GS_OK; 530 break; 531 532 case FOR_STMT: 533 gimplify_for_stmt (expr_p, pre_p); 534 ret = GS_ALL_DONE; 535 break; 536 537 case WHILE_STMT: 538 gimplify_while_stmt (expr_p); 539 ret = GS_ALL_DONE; 540 break; 541 542 case DO_STMT: 543 gimplify_do_stmt (expr_p); 544 ret = GS_ALL_DONE; 545 break; 546 547 case SWITCH_STMT: 548 gimplify_switch_stmt (expr_p); 549 ret = GS_ALL_DONE; 550 break; 551 552 case OMP_FOR: 553 ret = cp_gimplify_omp_for (expr_p); 554 break; 555 556 case CONTINUE_STMT: 557 *expr_p = build_bc_goto (bc_continue); 558 ret = GS_ALL_DONE; 559 break; 560 561 case BREAK_STMT: 562 *expr_p = build_bc_goto (bc_break); 563 ret = GS_ALL_DONE; 564 break; 565 566 case EXPR_STMT: 567 gimplify_expr_stmt (expr_p); 568 ret = GS_OK; 569 break; 570 571 case UNARY_PLUS_EXPR: 572 { 573 tree arg = TREE_OPERAND (*expr_p, 0); 574 tree type = TREE_TYPE (*expr_p); 575 *expr_p = (TREE_TYPE (arg) != type) ? fold_convert (type, arg) 576 : arg; 577 ret = GS_OK; 578 } 579 break; 580 581 default: 582 ret = c_gimplify_expr (expr_p, pre_p, post_p); 583 break; 584 } 585 586 /* Restore saved state. */ 587 if (STATEMENT_CODE_P (code)) 588 current_stmt_tree ()->stmts_are_full_exprs_p 589 = saved_stmts_are_full_exprs_p; 590 591 return ret; 592} 593 594static inline bool 595is_invisiref_parm (tree t) 596{ 597 return ((TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL) 598 && DECL_BY_REFERENCE (t)); 599} 600 601/* Return true if the uid in both int tree maps are equal. */ 602 603int 604cxx_int_tree_map_eq (const void *va, const void *vb) 605{ 606 const struct cxx_int_tree_map *a = (const struct cxx_int_tree_map *) va; 607 const struct cxx_int_tree_map *b = (const struct cxx_int_tree_map *) vb; 608 return (a->uid == b->uid); 609} 610 611/* Hash a UID in a cxx_int_tree_map. */ 612 613unsigned int 614cxx_int_tree_map_hash (const void *item) 615{ 616 return ((const struct cxx_int_tree_map *)item)->uid; 617} 618 619/* Perform any pre-gimplification lowering of C++ front end trees to 620 GENERIC. */ 621 622static tree 623cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) 624{ 625 tree stmt = *stmt_p; 626 struct pointer_set_t *p_set = (struct pointer_set_t*) data; 627 628 if (is_invisiref_parm (stmt) 629 /* Don't dereference parms in a thunk, pass the references through. */ 630 && !(DECL_THUNK_P (current_function_decl) 631 && TREE_CODE (stmt) == PARM_DECL)) 632 { 633 *stmt_p = convert_from_reference (stmt); 634 *walk_subtrees = 0; 635 return NULL; 636 } 637 638 /* Map block scope extern declarations to visible declarations with the 639 same name and type in outer scopes if any. */ 640 if (cp_function_chain->extern_decl_map 641 && (TREE_CODE (stmt) == FUNCTION_DECL || TREE_CODE (stmt) == VAR_DECL) 642 && DECL_EXTERNAL (stmt)) 643 { 644 struct cxx_int_tree_map *h, in; 645 in.uid = DECL_UID (stmt); 646 h = (struct cxx_int_tree_map *) 647 htab_find_with_hash (cp_function_chain->extern_decl_map, 648 &in, in.uid); 649 if (h) 650 { 651 *stmt_p = h->to; 652 *walk_subtrees = 0; 653 return NULL; 654 } 655 } 656 657 /* Other than invisiref parms, don't walk the same tree twice. */ 658 if (pointer_set_contains (p_set, stmt)) 659 { 660 *walk_subtrees = 0; 661 return NULL_TREE; 662 } 663 664 if (TREE_CODE (stmt) == ADDR_EXPR 665 && is_invisiref_parm (TREE_OPERAND (stmt, 0))) 666 { 667 *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0)); 668 *walk_subtrees = 0; 669 } 670 else if (TREE_CODE (stmt) == RETURN_EXPR 671 && TREE_OPERAND (stmt, 0) 672 && is_invisiref_parm (TREE_OPERAND (stmt, 0))) 673 /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */ 674 *walk_subtrees = 0; 675 else if (TREE_CODE (stmt) == OMP_CLAUSE) 676 switch (OMP_CLAUSE_CODE (stmt)) 677 { 678 case OMP_CLAUSE_PRIVATE: 679 case OMP_CLAUSE_SHARED: 680 case OMP_CLAUSE_FIRSTPRIVATE: 681 case OMP_CLAUSE_LASTPRIVATE: 682 case OMP_CLAUSE_COPYIN: 683 case OMP_CLAUSE_COPYPRIVATE: 684 /* Don't dereference an invisiref in OpenMP clauses. */ 685 if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) 686 *walk_subtrees = 0; 687 break; 688 case OMP_CLAUSE_REDUCTION: 689 gcc_assert (!is_invisiref_parm (OMP_CLAUSE_DECL (stmt))); 690 break; 691 default: 692 break; 693 } 694 else if (IS_TYPE_OR_DECL_P (stmt)) 695 *walk_subtrees = 0; 696 697 /* Due to the way voidify_wrapper_expr is written, we don't get a chance 698 to lower this construct before scanning it, so we need to lower these 699 before doing anything else. */ 700 else if (TREE_CODE (stmt) == CLEANUP_STMT) 701 *stmt_p = build2 (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR 702 : TRY_FINALLY_EXPR, 703 void_type_node, 704 CLEANUP_BODY (stmt), 705 CLEANUP_EXPR (stmt)); 706 707 pointer_set_insert (p_set, *stmt_p); 708 709 return NULL; 710} 711 712void 713cp_genericize (tree fndecl) 714{ 715 tree t; 716 struct pointer_set_t *p_set; 717 718 /* Fix up the types of parms passed by invisible reference. */ 719 for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t)) 720 if (TREE_ADDRESSABLE (TREE_TYPE (t))) 721 { 722 /* If a function's arguments are copied to create a thunk, 723 then DECL_BY_REFERENCE will be set -- but the type of the 724 argument will be a pointer type, so we will never get 725 here. */ 726 gcc_assert (!DECL_BY_REFERENCE (t)); 727 gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t)); 728 TREE_TYPE (t) = DECL_ARG_TYPE (t); 729 DECL_BY_REFERENCE (t) = 1; 730 TREE_ADDRESSABLE (t) = 0; 731 relayout_decl (t); 732 } 733 734 /* Do the same for the return value. */ 735 if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl)))) 736 { 737 t = DECL_RESULT (fndecl); 738 TREE_TYPE (t) = build_reference_type (TREE_TYPE (t)); 739 DECL_BY_REFERENCE (t) = 1; 740 TREE_ADDRESSABLE (t) = 0; 741 relayout_decl (t); 742 } 743 744 /* If we're a clone, the body is already GIMPLE. */ 745 if (DECL_CLONED_FUNCTION_P (fndecl)) 746 return; 747 748 /* We do want to see every occurrence of the parms, so we can't just use 749 walk_tree's hash functionality. */ 750 p_set = pointer_set_create (); 751 walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, p_set, NULL); 752 pointer_set_destroy (p_set); 753 754 /* Do everything else. */ 755 c_genericize (fndecl); 756 757 gcc_assert (bc_label[bc_break] == NULL); 758 gcc_assert (bc_label[bc_continue] == NULL); 759} 760 761/* Build code to apply FN to each member of ARG1 and ARG2. FN may be 762 NULL if there is in fact nothing to do. ARG2 may be null if FN 763 actually only takes one argument. */ 764 765static tree 766cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) 767{ 768 tree defparm, parm; 769 int i; 770 771 if (fn == NULL) 772 return NULL; 773 774 defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))); 775 if (arg2) 776 defparm = TREE_CHAIN (defparm); 777 778 if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE) 779 { 780 tree inner_type = TREE_TYPE (arg1); 781 tree start1, end1, p1; 782 tree start2 = NULL, p2 = NULL; 783 tree ret = NULL, lab, t; 784 785 start1 = arg1; 786 start2 = arg2; 787 do 788 { 789 inner_type = TREE_TYPE (inner_type); 790 start1 = build4 (ARRAY_REF, inner_type, start1, 791 size_zero_node, NULL, NULL); 792 if (arg2) 793 start2 = build4 (ARRAY_REF, inner_type, start2, 794 size_zero_node, NULL, NULL); 795 } 796 while (TREE_CODE (inner_type) == ARRAY_TYPE); 797 start1 = build_fold_addr_expr (start1); 798 if (arg2) 799 start2 = build_fold_addr_expr (start2); 800 801 end1 = TYPE_SIZE_UNIT (TREE_TYPE (arg1)); 802 end1 = fold_convert (TREE_TYPE (start1), end1); 803 end1 = build2 (PLUS_EXPR, TREE_TYPE (start1), start1, end1); 804 805 p1 = create_tmp_var (TREE_TYPE (start1), NULL); 806 t = build2 (MODIFY_EXPR, void_type_node, p1, start1); 807 append_to_statement_list (t, &ret); 808 809 if (arg2) 810 { 811 p2 = create_tmp_var (TREE_TYPE (start2), NULL); 812 t = build2 (MODIFY_EXPR, void_type_node, p2, start2); 813 append_to_statement_list (t, &ret); 814 } 815 816 lab = create_artificial_label (); 817 t = build1 (LABEL_EXPR, void_type_node, lab); 818 append_to_statement_list (t, &ret); 819 820 t = tree_cons (NULL, p1, NULL); 821 if (arg2) 822 t = tree_cons (NULL, p2, t); 823 /* Handle default arguments. */ 824 i = 1 + (arg2 != NULL); 825 for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm)) 826 t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm), 827 TREE_PURPOSE (parm), 828 fn, i++), t); 829 t = build_call (fn, nreverse (t)); 830 append_to_statement_list (t, &ret); 831 832 t = fold_convert (TREE_TYPE (p1), TYPE_SIZE_UNIT (inner_type)); 833 t = build2 (PLUS_EXPR, TREE_TYPE (p1), p1, t); 834 t = build2 (MODIFY_EXPR, void_type_node, p1, t); 835 append_to_statement_list (t, &ret); 836 837 if (arg2) 838 { 839 t = fold_convert (TREE_TYPE (p2), TYPE_SIZE_UNIT (inner_type)); 840 t = build2 (PLUS_EXPR, TREE_TYPE (p2), p2, t); 841 t = build2 (MODIFY_EXPR, void_type_node, p2, t); 842 append_to_statement_list (t, &ret); 843 } 844 845 t = build2 (NE_EXPR, boolean_type_node, p1, end1); 846 t = build3 (COND_EXPR, void_type_node, t, build_and_jump (&lab), NULL); 847 append_to_statement_list (t, &ret); 848 849 return ret; 850 } 851 else 852 { 853 tree t = tree_cons (NULL, build_fold_addr_expr (arg1), NULL); 854 if (arg2) 855 t = tree_cons (NULL, build_fold_addr_expr (arg2), t); 856 /* Handle default arguments. */ 857 i = 1 + (arg2 != NULL); 858 for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm)) 859 t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm), 860 TREE_PURPOSE (parm), 861 fn, i++), t); 862 return build_call (fn, nreverse (t)); 863 } 864} 865 866/* Return code to initialize DECL with its default constructor, or 867 NULL if there's nothing to do. */ 868 869tree 870cxx_omp_clause_default_ctor (tree clause, tree decl) 871{ 872 tree info = CP_OMP_CLAUSE_INFO (clause); 873 tree ret = NULL; 874 875 if (info) 876 ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), decl, NULL); 877 878 return ret; 879} 880 881/* Return code to initialize DST with a copy constructor from SRC. */ 882 883tree 884cxx_omp_clause_copy_ctor (tree clause, tree dst, tree src) 885{ 886 tree info = CP_OMP_CLAUSE_INFO (clause); 887 tree ret = NULL; 888 889 if (info) 890 ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), dst, src); 891 if (ret == NULL) 892 ret = build2 (MODIFY_EXPR, void_type_node, dst, src); 893 894 return ret; 895} 896 897/* Similarly, except use an assignment operator instead. */ 898 899tree 900cxx_omp_clause_assign_op (tree clause, tree dst, tree src) 901{ 902 tree info = CP_OMP_CLAUSE_INFO (clause); 903 tree ret = NULL; 904 905 if (info) 906 ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 2), dst, src); 907 if (ret == NULL) 908 ret = build2 (MODIFY_EXPR, void_type_node, dst, src); 909 910 return ret; 911} 912 913/* Return code to destroy DECL. */ 914 915tree 916cxx_omp_clause_dtor (tree clause, tree decl) 917{ 918 tree info = CP_OMP_CLAUSE_INFO (clause); 919 tree ret = NULL; 920 921 if (info) 922 ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 1), decl, NULL); 923 924 return ret; 925} 926 927/* True if OpenMP should privatize what this DECL points to rather 928 than the DECL itself. */ 929 930bool 931cxx_omp_privatize_by_reference (tree decl) 932{ 933 return is_invisiref_parm (decl); 934} 935