1169689Skan/* Tree lowering pass. Lowers GIMPLE into unstructured form. 2169689Skan 3169689Skan Copyright (C) 2003, 2005 Free Software Foundation, Inc. 4169689Skan 5169689SkanThis file is part of GCC. 6169689Skan 7169689SkanGCC is free software; you can redistribute it and/or modify it under 8169689Skanthe terms of the GNU General Public License as published by the Free 9169689SkanSoftware Foundation; either version 2, or (at your option) any later 10169689Skanversion. 11169689Skan 12169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 13169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 14169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15169689Skanfor more details. 16169689Skan 17169689SkanYou should have received a copy of the GNU General Public License 18169689Skanalong with GCC; see the file COPYING. If not, write to the Free 19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20169689Skan02110-1301, USA. */ 21169689Skan 22169689Skan#include "config.h" 23169689Skan#include "system.h" 24169689Skan#include "coretypes.h" 25169689Skan#include "tm.h" 26169689Skan#include "tree.h" 27169689Skan#include "rtl.h" 28169689Skan#include "varray.h" 29169689Skan#include "tree-gimple.h" 30169689Skan#include "tree-inline.h" 31169689Skan#include "diagnostic.h" 32169689Skan#include "langhooks.h" 33169689Skan#include "langhooks-def.h" 34169689Skan#include "tree-flow.h" 35169689Skan#include "timevar.h" 36169689Skan#include "except.h" 37169689Skan#include "hashtab.h" 38169689Skan#include "flags.h" 39169689Skan#include "function.h" 40169689Skan#include "expr.h" 41169689Skan#include "toplev.h" 42169689Skan#include "tree-pass.h" 43169689Skan 44169689Skanstruct lower_data 45169689Skan{ 46169689Skan /* Block the current statement belongs to. */ 47169689Skan tree block; 48169689Skan 49169689Skan /* A TREE_LIST of label and return statements to be moved to the end 50169689Skan of the function. */ 51169689Skan tree return_statements; 52169689Skan 53169689Skan /* True if the function calls __builtin_setjmp. */ 54169689Skan bool calls_builtin_setjmp; 55169689Skan}; 56169689Skan 57169689Skanstatic void lower_stmt (tree_stmt_iterator *, struct lower_data *); 58169689Skanstatic void lower_bind_expr (tree_stmt_iterator *, struct lower_data *); 59169689Skanstatic void lower_cond_expr (tree_stmt_iterator *, struct lower_data *); 60169689Skanstatic void lower_return_expr (tree_stmt_iterator *, struct lower_data *); 61169689Skanstatic void lower_builtin_setjmp (tree_stmt_iterator *); 62169689Skan 63169689Skan/* Lower the body of current_function_decl. */ 64169689Skan 65169689Skanstatic unsigned int 66169689Skanlower_function_body (void) 67169689Skan{ 68169689Skan struct lower_data data; 69169689Skan tree *body_p = &DECL_SAVED_TREE (current_function_decl); 70169689Skan tree bind = *body_p; 71169689Skan tree_stmt_iterator i; 72169689Skan tree t, x; 73169689Skan 74169689Skan gcc_assert (TREE_CODE (bind) == BIND_EXPR); 75169689Skan 76169689Skan memset (&data, 0, sizeof (data)); 77169689Skan data.block = DECL_INITIAL (current_function_decl); 78169689Skan BLOCK_SUBBLOCKS (data.block) = NULL_TREE; 79169689Skan BLOCK_CHAIN (data.block) = NULL_TREE; 80169689Skan TREE_ASM_WRITTEN (data.block) = 1; 81169689Skan 82169689Skan *body_p = alloc_stmt_list (); 83169689Skan i = tsi_start (*body_p); 84169689Skan tsi_link_after (&i, bind, TSI_NEW_STMT); 85169689Skan lower_bind_expr (&i, &data); 86169689Skan 87169689Skan i = tsi_last (*body_p); 88169689Skan 89169689Skan /* If the function falls off the end, we need a null return statement. 90169689Skan If we've already got one in the return_statements list, we don't 91169689Skan need to do anything special. Otherwise build one by hand. */ 92169689Skan if (block_may_fallthru (*body_p) 93169689Skan && (data.return_statements == NULL 94169689Skan || TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL)) 95169689Skan { 96169689Skan x = build1 (RETURN_EXPR, void_type_node, NULL); 97169689Skan SET_EXPR_LOCATION (x, cfun->function_end_locus); 98169689Skan tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 99169689Skan } 100169689Skan 101169689Skan /* If we lowered any return statements, emit the representative 102169689Skan at the end of the function. */ 103169689Skan for (t = data.return_statements ; t ; t = TREE_CHAIN (t)) 104169689Skan { 105169689Skan x = build1 (LABEL_EXPR, void_type_node, TREE_PURPOSE (t)); 106169689Skan tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 107169689Skan 108169689Skan /* Remove the line number from the representative return statement. 109169689Skan It now fills in for many such returns. Failure to remove this 110169689Skan will result in incorrect results for coverage analysis. */ 111169689Skan x = TREE_VALUE (t); 112169689Skan#ifdef USE_MAPPED_LOCATION 113169689Skan SET_EXPR_LOCATION (x, UNKNOWN_LOCATION); 114169689Skan#else 115169689Skan SET_EXPR_LOCUS (x, NULL); 116169689Skan#endif 117169689Skan tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 118169689Skan } 119169689Skan 120169689Skan /* If the function calls __builtin_setjmp, we need to emit the computed 121169689Skan goto that will serve as the unique dispatcher for all the receivers. */ 122169689Skan if (data.calls_builtin_setjmp) 123169689Skan { 124169689Skan tree disp_label, disp_var, arg; 125169689Skan 126169689Skan /* Build 'DISP_LABEL:' and insert. */ 127169689Skan disp_label = create_artificial_label (); 128169689Skan /* This mark will create forward edges from every call site. */ 129169689Skan DECL_NONLOCAL (disp_label) = 1; 130169689Skan current_function_has_nonlocal_label = 1; 131169689Skan x = build1 (LABEL_EXPR, void_type_node, disp_label); 132169689Skan tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 133169689Skan 134169689Skan /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);' 135169689Skan and insert. */ 136169689Skan disp_var = create_tmp_var (ptr_type_node, "setjmpvar"); 137169689Skan t = build_addr (disp_label, current_function_decl); 138169689Skan arg = tree_cons (NULL, t, NULL); 139169689Skan t = implicit_built_in_decls[BUILT_IN_SETJMP_DISPATCHER]; 140169689Skan t = build_function_call_expr (t,arg); 141169689Skan x = build2 (MODIFY_EXPR, void_type_node, disp_var, t); 142169689Skan 143169689Skan /* Build 'goto DISP_VAR;' and insert. */ 144169689Skan tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 145169689Skan x = build1 (GOTO_EXPR, void_type_node, disp_var); 146169689Skan tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 147169689Skan } 148169689Skan 149169689Skan gcc_assert (data.block == DECL_INITIAL (current_function_decl)); 150169689Skan BLOCK_SUBBLOCKS (data.block) 151169689Skan = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); 152169689Skan 153169689Skan clear_block_marks (data.block); 154169689Skan return 0; 155169689Skan} 156169689Skan 157169689Skanstruct tree_opt_pass pass_lower_cf = 158169689Skan{ 159169689Skan "lower", /* name */ 160169689Skan NULL, /* gate */ 161169689Skan lower_function_body, /* execute */ 162169689Skan NULL, /* sub */ 163169689Skan NULL, /* next */ 164169689Skan 0, /* static_pass_number */ 165169689Skan 0, /* tv_id */ 166169689Skan PROP_gimple_any, /* properties_required */ 167169689Skan PROP_gimple_lcf, /* properties_provided */ 168169689Skan 0, /* properties_destroyed */ 169169689Skan 0, /* todo_flags_start */ 170169689Skan TODO_dump_func, /* todo_flags_finish */ 171169689Skan 0 /* letter */ 172169689Skan}; 173169689Skan 174169689Skan 175169689Skan/* Lower the EXPR. Unlike gimplification the statements are not relowered 176169689Skan when they are changed -- if this has to be done, the lowering routine must 177169689Skan do it explicitly. DATA is passed through the recursion. */ 178169689Skan 179169689Skanstatic void 180169689Skanlower_stmt_body (tree expr, struct lower_data *data) 181169689Skan{ 182169689Skan tree_stmt_iterator tsi; 183169689Skan 184169689Skan for (tsi = tsi_start (expr); !tsi_end_p (tsi); ) 185169689Skan lower_stmt (&tsi, data); 186169689Skan} 187169689Skan 188169689Skan 189169689Skan/* Lower the OpenMP directive statement pointed by TSI. DATA is 190169689Skan passed through the recursion. */ 191169689Skan 192169689Skanstatic void 193169689Skanlower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data) 194169689Skan{ 195169689Skan tree stmt; 196169689Skan 197169689Skan stmt = tsi_stmt (*tsi); 198169689Skan 199169689Skan lower_stmt_body (OMP_BODY (stmt), data); 200169689Skan tsi_link_before (tsi, stmt, TSI_SAME_STMT); 201169689Skan tsi_link_before (tsi, OMP_BODY (stmt), TSI_SAME_STMT); 202169689Skan OMP_BODY (stmt) = NULL_TREE; 203169689Skan tsi_delink (tsi); 204169689Skan} 205169689Skan 206169689Skan 207169689Skan/* Lower statement TSI. DATA is passed through the recursion. */ 208169689Skan 209169689Skanstatic void 210169689Skanlower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) 211169689Skan{ 212169689Skan tree stmt = tsi_stmt (*tsi); 213169689Skan 214169689Skan if (EXPR_HAS_LOCATION (stmt) && data) 215169689Skan TREE_BLOCK (stmt) = data->block; 216169689Skan 217169689Skan switch (TREE_CODE (stmt)) 218169689Skan { 219169689Skan case BIND_EXPR: 220169689Skan lower_bind_expr (tsi, data); 221169689Skan return; 222169689Skan case COND_EXPR: 223169689Skan lower_cond_expr (tsi, data); 224169689Skan return; 225169689Skan case RETURN_EXPR: 226169689Skan lower_return_expr (tsi, data); 227169689Skan return; 228169689Skan 229169689Skan case TRY_FINALLY_EXPR: 230169689Skan case TRY_CATCH_EXPR: 231169689Skan lower_stmt_body (TREE_OPERAND (stmt, 0), data); 232169689Skan lower_stmt_body (TREE_OPERAND (stmt, 1), data); 233169689Skan break; 234169689Skan case CATCH_EXPR: 235169689Skan lower_stmt_body (CATCH_BODY (stmt), data); 236169689Skan break; 237169689Skan case EH_FILTER_EXPR: 238169689Skan lower_stmt_body (EH_FILTER_FAILURE (stmt), data); 239169689Skan break; 240169689Skan 241169689Skan case NOP_EXPR: 242169689Skan case ASM_EXPR: 243169689Skan case GOTO_EXPR: 244169689Skan case LABEL_EXPR: 245169689Skan case SWITCH_EXPR: 246169689Skan case OMP_FOR: 247169689Skan case OMP_SECTIONS: 248169689Skan case OMP_SECTION: 249169689Skan case OMP_SINGLE: 250169689Skan case OMP_MASTER: 251169689Skan case OMP_ORDERED: 252169689Skan case OMP_CRITICAL: 253169689Skan case OMP_RETURN: 254169689Skan case OMP_CONTINUE: 255169689Skan break; 256169689Skan 257169689Skan case MODIFY_EXPR: 258169689Skan if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) 259169689Skan stmt = TREE_OPERAND (stmt, 1); 260169689Skan else 261169689Skan break; 262169689Skan /* FALLTHRU */ 263169689Skan 264169689Skan case CALL_EXPR: 265169689Skan { 266169689Skan tree decl = get_callee_fndecl (stmt); 267169689Skan if (decl 268169689Skan && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL 269169689Skan && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP) 270169689Skan { 271169689Skan data->calls_builtin_setjmp = true; 272169689Skan lower_builtin_setjmp (tsi); 273169689Skan return; 274169689Skan } 275169689Skan } 276169689Skan break; 277169689Skan 278169689Skan case OMP_PARALLEL: 279169689Skan lower_omp_directive (tsi, data); 280169689Skan return; 281169689Skan 282169689Skan default: 283169689Skan gcc_unreachable (); 284169689Skan } 285169689Skan 286169689Skan tsi_next (tsi); 287169689Skan} 288169689Skan 289169689Skan/* Lower a bind_expr TSI. DATA is passed through the recursion. */ 290169689Skan 291169689Skanstatic void 292169689Skanlower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) 293169689Skan{ 294169689Skan tree old_block = data->block; 295169689Skan tree stmt = tsi_stmt (*tsi); 296169689Skan tree new_block = BIND_EXPR_BLOCK (stmt); 297169689Skan 298169689Skan if (new_block) 299169689Skan { 300169689Skan if (new_block == old_block) 301169689Skan { 302169689Skan /* The outermost block of the original function may not be the 303169689Skan outermost statement chain of the gimplified function. So we 304169689Skan may see the outermost block just inside the function. */ 305169689Skan gcc_assert (new_block == DECL_INITIAL (current_function_decl)); 306169689Skan new_block = NULL; 307169689Skan } 308169689Skan else 309169689Skan { 310169689Skan /* We do not expect to handle duplicate blocks. */ 311169689Skan gcc_assert (!TREE_ASM_WRITTEN (new_block)); 312169689Skan TREE_ASM_WRITTEN (new_block) = 1; 313169689Skan 314169689Skan /* Block tree may get clobbered by inlining. Normally this would 315169689Skan be fixed in rest_of_decl_compilation using block notes, but 316169689Skan since we are not going to emit them, it is up to us. */ 317169689Skan BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block); 318169689Skan BLOCK_SUBBLOCKS (old_block) = new_block; 319169689Skan BLOCK_SUBBLOCKS (new_block) = NULL_TREE; 320169689Skan BLOCK_SUPERCONTEXT (new_block) = old_block; 321169689Skan 322169689Skan data->block = new_block; 323169689Skan } 324169689Skan } 325169689Skan 326169689Skan record_vars (BIND_EXPR_VARS (stmt)); 327169689Skan lower_stmt_body (BIND_EXPR_BODY (stmt), data); 328169689Skan 329169689Skan if (new_block) 330169689Skan { 331169689Skan gcc_assert (data->block == new_block); 332169689Skan 333169689Skan BLOCK_SUBBLOCKS (new_block) 334169689Skan = blocks_nreverse (BLOCK_SUBBLOCKS (new_block)); 335169689Skan data->block = old_block; 336169689Skan } 337169689Skan 338169689Skan /* The BIND_EXPR no longer carries any useful information -- kill it. */ 339169689Skan tsi_link_before (tsi, BIND_EXPR_BODY (stmt), TSI_SAME_STMT); 340169689Skan tsi_delink (tsi); 341169689Skan} 342169689Skan 343169689Skan/* Try to determine whether a TRY_CATCH expression can fall through. 344169689Skan This is a subroutine of block_may_fallthru. */ 345169689Skan 346169689Skanstatic bool 347169689Skantry_catch_may_fallthru (tree stmt) 348169689Skan{ 349169689Skan tree_stmt_iterator i; 350169689Skan 351169689Skan /* If the TRY block can fall through, the whole TRY_CATCH can 352169689Skan fall through. */ 353169689Skan if (block_may_fallthru (TREE_OPERAND (stmt, 0))) 354169689Skan return true; 355169689Skan 356169689Skan i = tsi_start (TREE_OPERAND (stmt, 1)); 357169689Skan switch (TREE_CODE (tsi_stmt (i))) 358169689Skan { 359169689Skan case CATCH_EXPR: 360169689Skan /* We expect to see a sequence of CATCH_EXPR trees, each with a 361169689Skan catch expression and a body. The whole TRY_CATCH may fall 362169689Skan through iff any of the catch bodies falls through. */ 363169689Skan for (; !tsi_end_p (i); tsi_next (&i)) 364169689Skan { 365169689Skan if (block_may_fallthru (CATCH_BODY (tsi_stmt (i)))) 366169689Skan return true; 367169689Skan } 368169689Skan return false; 369169689Skan 370169689Skan case EH_FILTER_EXPR: 371169689Skan /* The exception filter expression only matters if there is an 372169689Skan exception. If the exception does not match EH_FILTER_TYPES, 373169689Skan we will execute EH_FILTER_FAILURE, and we will fall through 374169689Skan if that falls through. If the exception does match 375169689Skan EH_FILTER_TYPES, the stack unwinder will continue up the 376169689Skan stack, so we will not fall through. We don't know whether we 377169689Skan will throw an exception which matches EH_FILTER_TYPES or not, 378169689Skan so we just ignore EH_FILTER_TYPES and assume that we might 379169689Skan throw an exception which doesn't match. */ 380169689Skan return block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i))); 381169689Skan 382169689Skan default: 383169689Skan /* This case represents statements to be executed when an 384169689Skan exception occurs. Those statements are implicitly followed 385169689Skan by a RESX_EXPR to resume execution after the exception. So 386169689Skan in this case the TRY_CATCH never falls through. */ 387169689Skan return false; 388169689Skan } 389169689Skan} 390169689Skan 391169689Skan/* Try to determine if we can fall out of the bottom of BLOCK. This guess 392169689Skan need not be 100% accurate; simply be conservative and return true if we 393169689Skan don't know. This is used only to avoid stupidly generating extra code. 394169689Skan If we're wrong, we'll just delete the extra code later. */ 395169689Skan 396169689Skanbool 397169689Skanblock_may_fallthru (tree block) 398169689Skan{ 399169689Skan tree stmt = expr_last (block); 400169689Skan 401169689Skan switch (stmt ? TREE_CODE (stmt) : ERROR_MARK) 402169689Skan { 403169689Skan case GOTO_EXPR: 404169689Skan case RETURN_EXPR: 405169689Skan case RESX_EXPR: 406169689Skan /* Easy cases. If the last statement of the block implies 407169689Skan control transfer, then we can't fall through. */ 408169689Skan return false; 409169689Skan 410169689Skan case SWITCH_EXPR: 411169689Skan /* If SWITCH_LABELS is set, this is lowered, and represents a 412169689Skan branch to a selected label and hence can not fall through. 413169689Skan Otherwise SWITCH_BODY is set, and the switch can fall 414169689Skan through. */ 415169689Skan return SWITCH_LABELS (stmt) == NULL_TREE; 416169689Skan 417169689Skan case COND_EXPR: 418169689Skan if (block_may_fallthru (COND_EXPR_THEN (stmt))) 419169689Skan return true; 420169689Skan return block_may_fallthru (COND_EXPR_ELSE (stmt)); 421169689Skan 422169689Skan case BIND_EXPR: 423169689Skan return block_may_fallthru (BIND_EXPR_BODY (stmt)); 424169689Skan 425169689Skan case TRY_CATCH_EXPR: 426169689Skan return try_catch_may_fallthru (stmt); 427169689Skan 428169689Skan case TRY_FINALLY_EXPR: 429169689Skan /* The finally clause is always executed after the try clause, 430169689Skan so if it does not fall through, then the try-finally will not 431169689Skan fall through. Otherwise, if the try clause does not fall 432169689Skan through, then when the finally clause falls through it will 433169689Skan resume execution wherever the try clause was going. So the 434169689Skan whole try-finally will only fall through if both the try 435169689Skan clause and the finally clause fall through. */ 436169689Skan return (block_may_fallthru (TREE_OPERAND (stmt, 0)) 437169689Skan && block_may_fallthru (TREE_OPERAND (stmt, 1))); 438169689Skan 439169689Skan case MODIFY_EXPR: 440169689Skan if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) 441169689Skan stmt = TREE_OPERAND (stmt, 1); 442169689Skan else 443169689Skan return true; 444169689Skan /* FALLTHRU */ 445169689Skan 446169689Skan case CALL_EXPR: 447169689Skan /* Functions that do not return do not fall through. */ 448169689Skan return (call_expr_flags (stmt) & ECF_NORETURN) == 0; 449169689Skan 450169689Skan case CLEANUP_POINT_EXPR: 451169689Skan return block_may_fallthru (TREE_OPERAND (stmt, 0)); 452169689Skan 453169689Skan default: 454169689Skan return true; 455169689Skan } 456169689Skan} 457169689Skan 458169689Skan/* Lower a cond_expr TSI. DATA is passed through the recursion. */ 459169689Skan 460169689Skanstatic void 461169689Skanlower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) 462169689Skan{ 463169689Skan tree stmt = tsi_stmt (*tsi); 464169689Skan bool then_is_goto, else_is_goto; 465169689Skan tree then_branch, else_branch; 466169689Skan tree then_goto, else_goto; 467169689Skan 468169689Skan then_branch = COND_EXPR_THEN (stmt); 469169689Skan else_branch = COND_EXPR_ELSE (stmt); 470169689Skan 471169689Skan lower_stmt_body (then_branch, data); 472169689Skan lower_stmt_body (else_branch, data); 473169689Skan 474169689Skan then_goto = expr_only (then_branch); 475169689Skan then_is_goto = then_goto && simple_goto_p (then_goto); 476169689Skan 477169689Skan else_goto = expr_only (else_branch); 478169689Skan else_is_goto = else_goto && simple_goto_p (else_goto); 479169689Skan 480169689Skan if (!then_is_goto || !else_is_goto) 481169689Skan { 482169689Skan tree then_label, else_label, end_label, t; 483169689Skan 484169689Skan then_label = NULL_TREE; 485169689Skan else_label = NULL_TREE; 486169689Skan end_label = NULL_TREE; 487169689Skan 488169689Skan /* Replace the cond_expr with explicit gotos. */ 489169689Skan if (!then_is_goto) 490169689Skan { 491169689Skan t = build1 (LABEL_EXPR, void_type_node, NULL_TREE); 492169689Skan if (TREE_SIDE_EFFECTS (then_branch)) 493169689Skan then_label = t; 494169689Skan else 495169689Skan end_label = t; 496169689Skan then_goto = build_and_jump (&LABEL_EXPR_LABEL (t)); 497169689Skan } 498169689Skan 499169689Skan if (!else_is_goto) 500169689Skan { 501169689Skan t = build1 (LABEL_EXPR, void_type_node, NULL_TREE); 502169689Skan if (TREE_SIDE_EFFECTS (else_branch)) 503169689Skan else_label = t; 504169689Skan else 505169689Skan { 506169689Skan /* Both THEN and ELSE can be no-ops if one or both contained an 507169689Skan empty BIND_EXPR that was associated with the toplevel block 508169689Skan of an inlined function. In that case remove_useless_stmts 509169689Skan can't have cleaned things up for us; kill the whole 510169689Skan conditional now. */ 511169689Skan if (end_label) 512169689Skan { 513169689Skan tsi_delink (tsi); 514169689Skan return; 515169689Skan } 516169689Skan else 517169689Skan end_label = t; 518169689Skan } 519169689Skan else_goto = build_and_jump (&LABEL_EXPR_LABEL (t)); 520169689Skan } 521169689Skan 522169689Skan if (then_label) 523169689Skan { 524169689Skan bool may_fallthru = block_may_fallthru (then_branch); 525169689Skan 526169689Skan tsi_link_after (tsi, then_label, TSI_CONTINUE_LINKING); 527169689Skan tsi_link_after (tsi, then_branch, TSI_CONTINUE_LINKING); 528169689Skan 529169689Skan if (else_label && may_fallthru) 530169689Skan { 531169689Skan end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE); 532169689Skan t = build_and_jump (&LABEL_EXPR_LABEL (end_label)); 533169689Skan tsi_link_after (tsi, t, TSI_CONTINUE_LINKING); 534169689Skan } 535169689Skan } 536169689Skan 537169689Skan if (else_label) 538169689Skan { 539169689Skan tsi_link_after (tsi, else_label, TSI_CONTINUE_LINKING); 540169689Skan tsi_link_after (tsi, else_branch, TSI_CONTINUE_LINKING); 541169689Skan } 542169689Skan 543169689Skan if (end_label) 544169689Skan tsi_link_after (tsi, end_label, TSI_CONTINUE_LINKING); 545169689Skan } 546169689Skan 547169689Skan COND_EXPR_THEN (stmt) = then_goto; 548169689Skan COND_EXPR_ELSE (stmt) = else_goto; 549169689Skan 550169689Skan tsi_next (tsi); 551169689Skan} 552169689Skan 553169689Skan/* Lower a return_expr TSI. DATA is passed through the recursion. */ 554169689Skan 555169689Skanstatic void 556169689Skanlower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) 557169689Skan{ 558169689Skan tree stmt = tsi_stmt (*tsi); 559169689Skan tree value, t, label; 560169689Skan 561169689Skan /* Extract the value being returned. */ 562169689Skan value = TREE_OPERAND (stmt, 0); 563169689Skan if (value && TREE_CODE (value) == MODIFY_EXPR) 564169689Skan value = TREE_OPERAND (value, 1); 565169689Skan 566169689Skan /* Match this up with an existing return statement that's been created. */ 567169689Skan for (t = data->return_statements; t ; t = TREE_CHAIN (t)) 568169689Skan { 569169689Skan tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0); 570169689Skan if (tvalue && TREE_CODE (tvalue) == MODIFY_EXPR) 571169689Skan tvalue = TREE_OPERAND (tvalue, 1); 572169689Skan 573169689Skan if (value == tvalue) 574169689Skan { 575169689Skan label = TREE_PURPOSE (t); 576169689Skan goto found; 577169689Skan } 578169689Skan } 579169689Skan 580169689Skan /* Not found. Create a new label and record the return statement. */ 581169689Skan label = create_artificial_label (); 582169689Skan data->return_statements = tree_cons (label, stmt, data->return_statements); 583169689Skan 584169689Skan /* Generate a goto statement and remove the return statement. */ 585169689Skan found: 586169689Skan t = build1 (GOTO_EXPR, void_type_node, label); 587169689Skan SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); 588169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 589169689Skan tsi_delink (tsi); 590169689Skan} 591169689Skan 592169689Skan/* Lower a __builtin_setjmp TSI. 593169689Skan 594169689Skan __builtin_setjmp is passed a pointer to an array of five words (not 595169689Skan all will be used on all machines). It operates similarly to the C 596169689Skan library function of the same name, but is more efficient. 597169689Skan 598169689Skan It is lowered into 3 other builtins, namely __builtin_setjmp_setup, 599169689Skan __builtin_setjmp_dispatcher and __builtin_setjmp_receiver, but with 600169689Skan __builtin_setjmp_dispatcher shared among all the instances; that's 601169689Skan why it is only emitted at the end by lower_function_body. 602169689Skan 603169689Skan After full lowering, the body of the function should look like: 604169689Skan 605169689Skan { 606169689Skan void * setjmpvar.0; 607169689Skan int D.1844; 608169689Skan int D.2844; 609169689Skan 610169689Skan [...] 611169689Skan 612169689Skan __builtin_setjmp_setup (&buf, &<D1847>); 613169689Skan D.1844 = 0; 614169689Skan goto <D1846>; 615169689Skan <D1847>:; 616169689Skan __builtin_setjmp_receiver (&<D1847>); 617169689Skan D.1844 = 1; 618169689Skan <D1846>:; 619169689Skan if (D.1844 == 0) goto <D1848>; else goto <D1849>; 620169689Skan 621169689Skan [...] 622169689Skan 623169689Skan __builtin_setjmp_setup (&buf, &<D2847>); 624169689Skan D.2844 = 0; 625169689Skan goto <D2846>; 626169689Skan <D2847>:; 627169689Skan __builtin_setjmp_receiver (&<D2847>); 628169689Skan D.2844 = 1; 629169689Skan <D2846>:; 630169689Skan if (D.2844 == 0) goto <D2848>; else goto <D2849>; 631169689Skan 632169689Skan [...] 633169689Skan 634169689Skan <D3850>:; 635169689Skan return; 636169689Skan <D3853>: [non-local]; 637169689Skan setjmpvar.0 = __builtin_setjmp_dispatcher (&<D3853>); 638169689Skan goto setjmpvar.0; 639169689Skan } 640169689Skan 641169689Skan The dispatcher block will be both the unique destination of all the 642169689Skan abnormal call edges and the unique source of all the abnormal edges 643169689Skan to the receivers, thus keeping the complexity explosion localized. */ 644169689Skan 645169689Skanstatic void 646169689Skanlower_builtin_setjmp (tree_stmt_iterator *tsi) 647169689Skan{ 648169689Skan tree stmt = tsi_stmt (*tsi); 649169689Skan tree cont_label = create_artificial_label (); 650169689Skan tree next_label = create_artificial_label (); 651169689Skan tree dest, t, arg; 652169689Skan 653169689Skan /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is 654169689Skan passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */ 655169689Skan FORCED_LABEL (next_label) = 1; 656169689Skan 657169689Skan if (TREE_CODE (stmt) == MODIFY_EXPR) 658169689Skan { 659169689Skan dest = TREE_OPERAND (stmt, 0); 660169689Skan stmt = TREE_OPERAND (stmt, 1); 661169689Skan } 662169689Skan else 663169689Skan dest = NULL_TREE; 664169689Skan 665169689Skan /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ 666169689Skan t = build_addr (next_label, current_function_decl); 667169689Skan arg = tree_cons (NULL, t, NULL); 668169689Skan t = TREE_VALUE (TREE_OPERAND (stmt, 1)); 669169689Skan arg = tree_cons (NULL, t, arg); 670169689Skan t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP]; 671169689Skan t = build_function_call_expr (t, arg); 672169689Skan SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); 673169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 674169689Skan 675169689Skan /* Build 'DEST = 0' and insert. */ 676169689Skan if (dest) 677169689Skan { 678169689Skan t = build2 (MODIFY_EXPR, void_type_node, dest, integer_zero_node); 679169689Skan SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); 680169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 681169689Skan } 682169689Skan 683169689Skan /* Build 'goto CONT_LABEL' and insert. */ 684169689Skan t = build1 (GOTO_EXPR, void_type_node, cont_label); 685169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 686169689Skan 687169689Skan /* Build 'NEXT_LABEL:' and insert. */ 688169689Skan t = build1 (LABEL_EXPR, void_type_node, next_label); 689169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 690169689Skan 691169689Skan /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ 692169689Skan t = build_addr (next_label, current_function_decl); 693169689Skan arg = tree_cons (NULL, t, NULL); 694169689Skan t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER]; 695169689Skan t = build_function_call_expr (t, arg); 696169689Skan SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); 697169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 698169689Skan 699169689Skan /* Build 'DEST = 1' and insert. */ 700169689Skan if (dest) 701169689Skan { 702169689Skan t = build2 (MODIFY_EXPR, void_type_node, dest, integer_one_node); 703169689Skan SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); 704169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 705169689Skan } 706169689Skan 707169689Skan /* Build 'CONT_LABEL:' and insert. */ 708169689Skan t = build1 (LABEL_EXPR, void_type_node, cont_label); 709169689Skan tsi_link_before (tsi, t, TSI_SAME_STMT); 710169689Skan 711169689Skan /* Remove the call to __builtin_setjmp. */ 712169689Skan tsi_delink (tsi); 713169689Skan} 714169689Skan 715169689Skan 716169689Skan/* Record the variables in VARS into function FN. */ 717169689Skan 718169689Skanvoid 719169689Skanrecord_vars_into (tree vars, tree fn) 720169689Skan{ 721169689Skan struct function *saved_cfun = cfun; 722169689Skan 723169689Skan if (fn != current_function_decl) 724169689Skan cfun = DECL_STRUCT_FUNCTION (fn); 725169689Skan 726169689Skan for (; vars; vars = TREE_CHAIN (vars)) 727169689Skan { 728169689Skan tree var = vars; 729169689Skan 730169689Skan /* BIND_EXPRs contains also function/type/constant declarations 731169689Skan we don't need to care about. */ 732169689Skan if (TREE_CODE (var) != VAR_DECL) 733169689Skan continue; 734169689Skan 735169689Skan /* Nothing to do in this case. */ 736169689Skan if (DECL_EXTERNAL (var)) 737169689Skan continue; 738169689Skan 739169689Skan /* Record the variable. */ 740169689Skan cfun->unexpanded_var_list = tree_cons (NULL_TREE, var, 741169689Skan cfun->unexpanded_var_list); 742169689Skan } 743169689Skan 744169689Skan if (fn != current_function_decl) 745169689Skan cfun = saved_cfun; 746169689Skan} 747169689Skan 748169689Skan 749169689Skan/* Record the variables in VARS into current_function_decl. */ 750169689Skan 751169689Skanvoid 752169689Skanrecord_vars (tree vars) 753169689Skan{ 754169689Skan record_vars_into (vars, current_function_decl); 755169689Skan} 756169689Skan 757169689Skan 758169689Skan/* Mark BLOCK used if it has a used variable in it, then recurse over its 759169689Skan subblocks. */ 760169689Skan 761169689Skanstatic void 762169689Skanmark_blocks_with_used_vars (tree block) 763169689Skan{ 764169689Skan tree var; 765169689Skan tree subblock; 766169689Skan 767169689Skan if (!TREE_USED (block)) 768169689Skan { 769169689Skan for (var = BLOCK_VARS (block); 770169689Skan var; 771169689Skan var = TREE_CHAIN (var)) 772169689Skan { 773169689Skan if (TREE_USED (var)) 774169689Skan { 775169689Skan TREE_USED (block) = true; 776169689Skan break; 777169689Skan } 778169689Skan } 779169689Skan } 780169689Skan for (subblock = BLOCK_SUBBLOCKS (block); 781169689Skan subblock; 782169689Skan subblock = BLOCK_CHAIN (subblock)) 783169689Skan mark_blocks_with_used_vars (subblock); 784169689Skan} 785169689Skan 786169689Skan/* Mark the used attribute on blocks correctly. */ 787169689Skan 788169689Skanstatic unsigned int 789169689Skanmark_used_blocks (void) 790169689Skan{ 791169689Skan mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl)); 792169689Skan return 0; 793169689Skan} 794169689Skan 795169689Skan 796169689Skanstruct tree_opt_pass pass_mark_used_blocks = 797169689Skan{ 798169689Skan "blocks", /* name */ 799169689Skan NULL, /* gate */ 800169689Skan mark_used_blocks, /* execute */ 801169689Skan NULL, /* sub */ 802169689Skan NULL, /* next */ 803169689Skan 0, /* static_pass_number */ 804169689Skan 0, /* tv_id */ 805169689Skan 0, /* properties_required */ 806169689Skan 0, /* properties_provided */ 807169689Skan 0, /* properties_destroyed */ 808169689Skan 0, /* todo_flags_start */ 809169689Skan TODO_dump_func, /* todo_flags_finish */ 810169689Skan 0 /* letter */ 811169689Skan}; 812