bool gimple_stmt_may_fallthru (gimple stmt) { if (!stmt) return true; switch (gimple_code (stmt)) { case GIMPLE_GOTO: case GIMPLE_RETURN: case GIMPLE_RESX: /* Easy cases. If the last statement of the seq implies control transfer, then we can't fall through. */ return false; case GIMPLE_SWITCH: /* Switch has already been lowered and represents a branch to a selected label and hence can't fall through. */ return false; case GIMPLE_COND: /* GIMPLE_COND's are already lowered into a two-way branch. They can't fall through. */ return false; case GIMPLE_BIND: return gimple_seq_may_fallthru (gimple_bind_body (stmt)); case GIMPLE_TRY: if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH) return gimple_try_catch_may_fallthru (stmt); /* It must be a GIMPLE_TRY_FINALLY. */ /* The finally clause is always executed after the try clause, so if it does not fall through, then the try-finally will not fall through. Otherwise, if the try clause does not fall through, then when the finally clause falls through it will resume execution wherever the try clause was going. So the whole try-finally will only fall through if both the try clause and the finally clause fall through. */ return (gimple_seq_may_fallthru (gimple_try_eval (stmt)) && gimple_seq_may_fallthru (gimple_try_cleanup (stmt))); case GIMPLE_EH_ELSE: return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt)) || gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt))); case GIMPLE_CALL: /* Functions that do not return do not fall through. */ return (gimple_call_flags (stmt) & ECF_NORETURN) == 0; default: return true; } }
static void lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data) { tree old_block = data->block; gimple stmt = gsi_stmt (*gsi); tree new_block = gimple_bind_block (stmt); if (new_block) { if (new_block == old_block) { /* The outermost block of the original function may not be the outermost statement chain of the gimplified function. So we may see the outermost block just inside the function. */ gcc_assert (new_block == DECL_INITIAL (current_function_decl)); new_block = NULL; } else { /* We do not expect to handle duplicate blocks. */ gcc_assert (!TREE_ASM_WRITTEN (new_block)); TREE_ASM_WRITTEN (new_block) = 1; /* Block tree may get clobbered by inlining. Normally this would be fixed in rest_of_decl_compilation using block notes, but since we are not going to emit them, it is up to us. */ BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block); BLOCK_SUBBLOCKS (old_block) = new_block; BLOCK_SUBBLOCKS (new_block) = NULL_TREE; BLOCK_SUPERCONTEXT (new_block) = old_block; data->block = new_block; } } record_vars (gimple_bind_vars (stmt)); lower_sequence (gimple_bind_body_ptr (stmt), data); if (new_block) { gcc_assert (data->block == new_block); BLOCK_SUBBLOCKS (new_block) = blocks_nreverse (BLOCK_SUBBLOCKS (new_block)); data->block = old_block; } /* The GIMPLE_BIND no longer carries any useful information -- kill it. */ gsi_insert_seq_before (gsi, gimple_bind_body (stmt), GSI_SAME_STMT); gsi_remove (gsi, false); }
static void test_gimplification () { tree fndecl = build_trivial_generic_function (); /* Convert to gimple: */ gimplify_function_tree (fndecl); /* Verify that we got gimple out of it. */ /* The function is now in GIMPLE form but the CFG has not been built yet. */ /* We should have a struct function for the decl. */ function *fun = DECL_STRUCT_FUNCTION (fndecl); ASSERT_TRUE (fun != NULL); ASSERT_EQ (fndecl, fun->decl); /* We expect a GIMPLE_BIND, with two gimple statements within it: tmp = 42; return tmp; */ gimple_seq seq_fn_body = gimple_body (fndecl); ASSERT_TRUE (seq_fn_body != NULL); gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body); ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt)); ASSERT_EQ (NULL, bind_stmt->next); gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt)); /* Verify that we have the 2 statements we expect. */ ASSERT_TRUE (seq_bind_body != NULL); gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body); ASSERT_TRUE (stmt1 != NULL); ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1)); gimple *stmt2 = stmt1->next; ASSERT_TRUE (stmt2 != NULL); ASSERT_EQ (stmt1, stmt2->prev); ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2)); }
static unsigned int execute_trace () { gimple_seq body, body_bind_body, inner_cleanup, outer_cleanup; gimple inner_try, outer_try; tree record_type, func_start_decl, func_end_decl, var_decl, function_name_decl, constructor_clobber; gimple call_func_start; gimple_stmt_iterator gsi; // build record type record_type = build_type (); // build start & end function decl func_start_decl = build_function_decl ("__start_ctrace__", record_type); func_end_decl = build_function_decl ("__end_ctrace__", record_type); // init variables of current body body = gimple_body (current_function_decl); var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier ("__ctrace_var__"), record_type); DECL_CONTEXT (var_decl) = current_function_decl; TREE_ADDRESSABLE (var_decl) = 1; declare_vars (var_decl, body, false); TREE_USED (var_decl) = 1; // mimic __FUNCTION__ builtin. function_name_decl = make_fname_decl (); declare_vars (function_name_decl, body, false); // construct inner try // init calls call_func_start = gimple_build_call ( func_start_decl, 2, build1 (ADDR_EXPR, build_pointer_type (record_type), var_decl), build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (function_name_decl)), function_name_decl)); // make inner clean up inner_cleanup = gimple_build_call ( func_end_decl, 2, build1 (ADDR_EXPR, build_pointer_type (record_type), var_decl), build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (function_name_decl)), function_name_decl)); // update inner try body_bind_body = gimple_bind_body (body); inner_try = gimple_build_try (body_bind_body, inner_cleanup, GIMPLE_TRY_FINALLY); gsi = gsi_start (inner_try); gsi_insert_before (&gsi, call_func_start, GSI_NEW_STMT); // construct outer try constructor_clobber = make_node (CONSTRUCTOR); TREE_THIS_VOLATILE (constructor_clobber) = 1; TREE_TYPE (constructor_clobber) = TREE_TYPE (var_decl); outer_cleanup = gimple_build_assign (var_decl, constructor_clobber); // update outer try outer_try = gimple_build_try (call_func_start, outer_cleanup, GIMPLE_TRY_FINALLY); // update body bind body gimple_bind_set_body (body, outer_try); if (dump_file) { dump_function_to_file (current_function_decl, dump_file, TDF_TREE | TDF_BLOCKS | TDF_VERBOSE); } // exit (0); return 0; }
static void lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data) { tree old_block = data->block; gbind *stmt = as_a <gbind *> (gsi_stmt (*gsi)); tree new_block = gimple_bind_block (stmt); if (new_block) { if (new_block == old_block) { /* The outermost block of the original function may not be the outermost statement chain of the gimplified function. So we may see the outermost block just inside the function. */ gcc_assert (new_block == DECL_INITIAL (current_function_decl)); new_block = NULL; } else { /* We do not expect to handle duplicate blocks. */ gcc_assert (!TREE_ASM_WRITTEN (new_block)); TREE_ASM_WRITTEN (new_block) = 1; /* Block tree may get clobbered by inlining. Normally this would be fixed in rest_of_decl_compilation using block notes, but since we are not going to emit them, it is up to us. */ BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block); BLOCK_SUBBLOCKS (old_block) = new_block; BLOCK_SUBBLOCKS (new_block) = NULL_TREE; BLOCK_SUPERCONTEXT (new_block) = old_block; data->block = new_block; } } record_vars (gimple_bind_vars (stmt)); /* Scrap DECL_CHAIN up to BLOCK_VARS to ease GC after we no longer need gimple_bind_vars. */ tree next; /* BLOCK_VARS and gimple_bind_vars share a common sub-chain. Find it by marking all BLOCK_VARS. */ if (gimple_bind_block (stmt)) for (tree t = BLOCK_VARS (gimple_bind_block (stmt)); t; t = DECL_CHAIN (t)) TREE_VISITED (t) = 1; for (tree var = gimple_bind_vars (stmt); var && ! TREE_VISITED (var); var = next) { next = DECL_CHAIN (var); DECL_CHAIN (var) = NULL_TREE; } /* Unmark BLOCK_VARS. */ if (gimple_bind_block (stmt)) for (tree t = BLOCK_VARS (gimple_bind_block (stmt)); t; t = DECL_CHAIN (t)) TREE_VISITED (t) = 0; lower_sequence (gimple_bind_body_ptr (stmt), data); if (new_block) { gcc_assert (data->block == new_block); BLOCK_SUBBLOCKS (new_block) = blocks_nreverse (BLOCK_SUBBLOCKS (new_block)); data->block = old_block; } /* The GIMPLE_BIND no longer carries any useful information -- kill it. */ gsi_insert_seq_before (gsi, gimple_bind_body (stmt), GSI_SAME_STMT); gsi_remove (gsi, false); }