static void expand_used_vars_for_block (tree block, bool toplevel) { size_t i, j, old_sv_num, this_sv_num, new_sv_num; tree t; old_sv_num = toplevel ? 0 : stack_vars_num; /* Expand all variables at this level. */ for (t = BLOCK_VARS (block); t ; t = TREE_CHAIN (t)) if (TREE_USED (t)) expand_one_var (t, toplevel); this_sv_num = stack_vars_num; /* Expand all variables at containing levels. */ for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) expand_used_vars_for_block (t, false); /* Since we do not track exact variable lifetimes (which is not even possible for varibles whose address escapes), we mirror the block tree in the interference graph. Here we cause all variables at this level, and all sublevels, to conflict. Do make certain that a variable conflicts with itself. */ if (old_sv_num < this_sv_num) { new_sv_num = stack_vars_num; resize_stack_vars_conflict (new_sv_num); for (i = old_sv_num; i < new_sv_num; ++i) for (j = i < this_sv_num ? i+1 : this_sv_num; j-- > old_sv_num ;) add_stack_var_conflict (i, j); } }
static void set_block_origin_self (tree stmt) { if (BLOCK_ABSTRACT_ORIGIN (stmt) == NULL_TREE) { BLOCK_ABSTRACT_ORIGIN (stmt) = stmt; { tree local_decl; for (local_decl = BLOCK_VARS (stmt); local_decl != NULL_TREE; local_decl = DECL_CHAIN (local_decl)) if (! DECL_EXTERNAL (local_decl)) set_decl_origin_self (local_decl); /* Potential recursion. */ } { tree subblock; for (subblock = BLOCK_SUBBLOCKS (stmt); subblock != NULL_TREE; subblock = BLOCK_CHAIN (subblock)) set_block_origin_self (subblock); /* Recurse. */ } } }
static void set_block_abstract_flags (tree stmt, int setting) { tree local_decl; tree subblock; unsigned int i; BLOCK_ABSTRACT (stmt) = setting; for (local_decl = BLOCK_VARS (stmt); local_decl != NULL_TREE; local_decl = DECL_CHAIN (local_decl)) if (! DECL_EXTERNAL (local_decl)) set_decl_abstract_flags (local_decl, setting); for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++) { local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i); if ((TREE_CODE (local_decl) == VAR_DECL && !TREE_STATIC (local_decl)) || TREE_CODE (local_decl) == PARM_DECL) set_decl_abstract_flags (local_decl, setting); } for (subblock = BLOCK_SUBBLOCKS (stmt); subblock != NULL_TREE; subblock = BLOCK_CHAIN (subblock)) set_block_abstract_flags (subblock, setting); }
static void xcoffout_block (tree block, int depth, tree args) { while (block) { /* Ignore blocks never expanded or otherwise marked as real. */ if (TREE_USED (block)) { /* When we reach the specified block, output its symbols. */ if (BLOCK_NUMBER (block) == do_block) { /* Output the syms of the block. */ if (debug_info_level != DINFO_LEVEL_TERSE || depth == 0) dbxout_syms (BLOCK_VARS (block)); if (args) dbxout_reg_parms (args); /* We are now done with the block. Don't go to inner blocks. */ return; } /* If we are past the specified block, stop the scan. */ else if (BLOCK_NUMBER (block) >= do_block) return; /* Output the subblocks. */ xcoffout_block (BLOCK_SUBBLOCKS (block), depth + 1, NULL_TREE); } block = BLOCK_CHAIN (block); } }
static void set_block_levels (tree block, int level) { while (block) { BLOCK_NUMBER (block) = level; set_block_levels (BLOCK_SUBBLOCKS (block), level + 1); block = BLOCK_CHAIN (block); } }
static void clear_tree_used (tree block) { tree t; for (t = BLOCK_VARS (block); t ; t = TREE_CHAIN (t)) /* if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) */ TREE_USED (t) = 0; for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) clear_tree_used (t); }
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 lto_input_ts_block_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, tree expr) { /* Do not stream BLOCK_SOURCE_LOCATION. We cannot handle debug information for early inlining so drop it on the floor instead of ICEing in dwarf2out.c. */ BLOCK_VARS (expr) = streamer_read_chain (ib, data_in); /* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information for early inlining so drop it on the floor instead of ICEing in dwarf2out.c. */ BLOCK_SUPERCONTEXT (expr) = stream_read_tree (ib, data_in); /* Do not stream BLOCK_ABSTRACT_ORIGIN. We cannot handle debug information for early inlining so drop it on the floor instead of ICEing in dwarf2out.c. */ BLOCK_FRAGMENT_ORIGIN (expr) = stream_read_tree (ib, data_in); BLOCK_FRAGMENT_CHAIN (expr) = stream_read_tree (ib, data_in); /* We re-compute BLOCK_SUBBLOCKS of our parent here instead of streaming it. For non-BLOCK BLOCK_SUPERCONTEXTs we still stream the child relationship explicitly. */ if (BLOCK_SUPERCONTEXT (expr) && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == BLOCK) { BLOCK_CHAIN (expr) = BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)); BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)) = expr; } /* The global block is rooted at the TU decl. Hook it here to avoid the need to stream in this block during WPA time. */ else if (BLOCK_SUPERCONTEXT (expr) && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == TRANSLATION_UNIT_DECL) DECL_INITIAL (BLOCK_SUPERCONTEXT (expr)) = expr; /* The function-level block is connected at the time we read in function bodies for the same reason. */ }
static void sdbout_block (tree block) { while (block) { /* Ignore blocks never expanded or otherwise marked as real. */ if (TREE_USED (block)) { /* When we reach the specified block, output its symbols. */ if (BLOCK_NUMBER (block) == do_block) sdbout_syms (BLOCK_VARS (block)); /* If we are past the specified block, stop the scan. */ if (BLOCK_NUMBER (block) > do_block) return; /* Scan the blocks within this block. */ sdbout_block (BLOCK_SUBBLOCKS (block)); } block = BLOCK_CHAIN (block); } }
static void mark_blocks_with_used_vars (tree block) { tree var; tree subblock; if (!TREE_USED (block)) { for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var)) { if (TREE_USED (var)) { TREE_USED (block) = true; break; } } } for (subblock = BLOCK_SUBBLOCKS (block); subblock; subblock = BLOCK_CHAIN (subblock)) mark_blocks_with_used_vars (subblock); }
tree poplevel (int keep, int functionbody) { /* Points to a BLOCK tree node. This is the BLOCK node constructed for the binding level that we are about to exit and which is returned by this routine. */ tree block_node = NULL_TREE; tree decl_chain = current_binding_level->names; tree subblock_chain = current_binding_level->blocks; tree subblock_node; /* If there were any declarations in the current binding level, or if this binding level is a function body, or if there are any nested blocks then create a BLOCK node to record them for the life of this function. */ if (keep || functionbody) block_node = build_block (keep ? decl_chain : 0, subblock_chain, 0, 0); /* Record the BLOCK node just built as the subblock its enclosing scope. */ for (subblock_node = subblock_chain; subblock_node; subblock_node = BLOCK_CHAIN (subblock_node)) BLOCK_SUPERCONTEXT (subblock_node) = block_node; /* Clear out the meanings of the local variables of this level. */ for (subblock_node = decl_chain; subblock_node; subblock_node = DECL_CHAIN (subblock_node)) if (DECL_NAME (subblock_node) != 0) /* If the identifier was used or addressed via a local extern decl, don't forget that fact. */ if (DECL_EXTERNAL (subblock_node)) { if (TREE_USED (subblock_node)) TREE_USED (DECL_NAME (subblock_node)) = 1; if (TREE_ADDRESSABLE (subblock_node)) TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (subblock_node)) = 1; } /* Pop the current level. */ current_binding_level = current_binding_level->level_chain; if (functionbody) /* This is the top level block of a function. */ DECL_INITIAL (current_function_decl) = block_node; else if (current_binding_level == global_binding_level) /* When using gfc_start_block/gfc_finish_block from middle-end hooks, don't add newly created BLOCKs as subblocks of global_binding_level. */ ; else if (block_node) { current_binding_level->blocks = block_chainon (current_binding_level->blocks, block_node); } /* If we did not make a block for the level just exited, any blocks made for inner levels (since they cannot be recorded as subblocks in that level) must be carried forward so they will later become subblocks of something else. */ else if (subblock_chain) current_binding_level->blocks = block_chainon (current_binding_level->blocks, subblock_chain); if (block_node) TREE_USED (block_node) = 1; return block_node; }
static unsigned int lower_function_body (void) { struct lower_data data; gimple_seq body = gimple_body (current_function_decl); gimple_seq lowered_body; gimple_stmt_iterator i; gimple *bind; gimple *x; /* The gimplifier should've left a body of exactly one statement, namely a GIMPLE_BIND. */ gcc_assert (gimple_seq_first (body) == gimple_seq_last (body) && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND); memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements.create (8); bind = gimple_seq_first_stmt (body); lowered_body = NULL; gimple_seq_add_stmt (&lowered_body, bind); i = gsi_start (lowered_body); lower_gimple_bind (&i, &data); i = gsi_last (lowered_body); /* If we had begin stmt markers from e.g. PCH, but this compilation doesn't want them, lower_stmt will have cleaned them up; we can now clear the flag that indicates we had them. */ if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers) { /* This counter needs not be exact, but before lowering it will most certainly be. */ gcc_assert (cfun->debug_marker_count == 0); cfun->debug_nonbind_markers = false; } /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ bool may_fallthru = gimple_seq_may_fallthru (lowered_body); if (may_fallthru && (data.return_statements.is_empty () || (gimple_return_retval (data.return_statements.last().stmt) != NULL))) { x = gimple_build_return (NULL); gimple_set_location (x, cfun->function_end_locus); gimple_set_block (x, DECL_INITIAL (current_function_decl)); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); may_fallthru = false; } /* If we lowered any return statements, emit the representative at the end of the function. */ while (!data.return_statements.is_empty ()) { return_statements_t t = data.return_statements.pop (); x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); if (may_fallthru) { /* Remove the line number from the representative return statement. It now fills in for the fallthru too. Failure to remove this will result in incorrect results for coverage analysis. */ gimple_set_location (t.stmt, UNKNOWN_LOCATION); may_fallthru = false; } } /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); data.return_statements.release (); return 0; }
static unsigned int lower_function_body (void) { struct lower_data data; gimple_seq body = gimple_body (current_function_decl); gimple_seq lowered_body; gimple_stmt_iterator i; gimple bind; gimple x; /* The gimplifier should've left a body of exactly one statement, namely a GIMPLE_BIND. */ gcc_assert (gimple_seq_first (body) == gimple_seq_last (body) && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND); memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements.create (8); bind = gimple_seq_first_stmt (body); lowered_body = NULL; gimple_seq_add_stmt (&lowered_body, bind); i = gsi_start (lowered_body); lower_gimple_bind (&i, &data); i = gsi_last (lowered_body); /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ if (gimple_seq_may_fallthru (lowered_body) && (data.return_statements.is_empty () || (gimple_return_retval (data.return_statements.last().stmt) != NULL))) { x = gimple_build_return (NULL); gimple_set_location (x, cfun->function_end_locus); gimple_set_block (x, DECL_INITIAL (current_function_decl)); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* If we lowered any return statements, emit the representative at the end of the function. */ while (!data.return_statements.is_empty ()) { return_statements_t t = data.return_statements.pop (); x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); } /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); data.return_statements.release (); return 0; }
static void lower_function_body (void) { struct lower_data data; tree *body_p = &DECL_SAVED_TREE (current_function_decl); tree bind = *body_p; tree_stmt_iterator i; tree t, x; gcc_assert (TREE_CODE (bind) == BIND_EXPR); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements = NULL_TREE; *body_p = alloc_stmt_list (); i = tsi_start (*body_p); tsi_link_after (&i, bind, TSI_NEW_STMT); lower_bind_expr (&i, &data); i = tsi_last (*body_p); /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements list, we don't need to do anything special. Otherwise build one by hand. */ if (block_may_fallthru (*body_p) && (data.return_statements == NULL || TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL)) { x = build (RETURN_EXPR, void_type_node, NULL); SET_EXPR_LOCATION (x, cfun->function_end_locus); tsi_link_after (&i, x, TSI_CONTINUE_LINKING); } /* If we lowered any return statements, emit the representative at the end of the function. */ for (t = data.return_statements ; t ; t = TREE_CHAIN (t)) { x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t)); tsi_link_after (&i, x, TSI_CONTINUE_LINKING); /* Remove the line number from the representative return statement. It now fills in for many such returns. Failure to remove this will result in incorrect results for coverage analysis. */ x = TREE_VALUE (t); #ifdef USE_MAPPED_LOCATION SET_EXPR_LOCATION (x, UNKNOWN_LOCATION); #else SET_EXPR_LOCUS (x, NULL); #endif tsi_link_after (&i, x, TSI_CONTINUE_LINKING); } gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); }
static void push_binding (enum binding_kind kind) { struct binding_level *res; /* Get a binding level (old ones are recycled). */ if (old_binding_levels == NULL) res = ggc_alloc_binding_level (); else { res = old_binding_levels; old_binding_levels = res->prev; } /* Init. */ res->first_decl = NULL_TREE; res->last_decl = NULL_TREE; res->first_block = NULL_TREE; res->last_block = NULL_TREE; res->save_stack = 0; switch (kind) { case GLOBAL_BINDING: res->bind = NULL_TREE; res->block = NULL_TREE; res->prev = NULL; res->prev_stmts = NULL; break; case FUNCTION_BINDING: case LOCAL_BINDING: res->block = make_node (BLOCK); TREE_USED (res->block) = true; res->bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE, res->block); TREE_SIDE_EFFECTS (res->bind) = true; res->prev_stmts = cur_stmts; cur_stmts = alloc_stmt_list (); break; } switch (kind) { case GLOBAL_BINDING: /* No supercontext for the global binding. */ break; case FUNCTION_BINDING: /* No containing block. */ BLOCK_SUPERCONTEXT (res->block) = current_function_decl; break; case LOCAL_BINDING: /* Append the block created. */ if (cur_binding_level->first_block == NULL) cur_binding_level->first_block = res->block; else BLOCK_CHAIN (cur_binding_level->last_block) = res->block; cur_binding_level->last_block = res->block; BLOCK_SUPERCONTEXT (res->block) = cur_binding_level->block; break; } /* Chain previous binding, set current binding. */ res->prev = cur_binding_level; cur_binding_level = res; }
static unsigned int lower_function_body (void) { struct lower_data data; gimple_seq body = gimple_body (current_function_decl); gimple_seq lowered_body; gimple_stmt_iterator i; gimple bind; tree t; gimple x; /* The gimplifier should've left a body of exactly one statement, namely a GIMPLE_BIND. */ gcc_assert (gimple_seq_first (body) == gimple_seq_last (body) && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND); memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements.create (8); bind = gimple_seq_first_stmt (body); lowered_body = NULL; gimple_seq_add_stmt (&lowered_body, bind); i = gsi_start (lowered_body); lower_gimple_bind (&i, &data); i = gsi_last (lowered_body); /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ if (gimple_seq_may_fallthru (lowered_body) && (data.return_statements.is_empty () || gimple_return_retval (data.return_statements.last().stmt) != NULL)) { x = gimple_build_return (NULL); gimple_set_location (x, cfun->function_end_locus); gimple_set_block (x, DECL_INITIAL (current_function_decl)); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* If we lowered any return statements, emit the representative at the end of the function. */ while (!data.return_statements.is_empty ()) { return_statements_t t = data.return_statements.pop (); x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); } /* If the function calls __builtin_setjmp, we need to emit the computed goto that will serve as the unique dispatcher for all the receivers. */ if (data.calls_builtin_setjmp) { tree disp_label, disp_var, arg; /* Build 'DISP_LABEL:' and insert. */ disp_label = create_artificial_label (cfun->function_end_locus); /* This mark will create forward edges from every call site. */ DECL_NONLOCAL (disp_label) = 1; cfun->has_nonlocal_label = 1; x = gimple_build_label (disp_label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);' and insert. */ disp_var = create_tmp_var (ptr_type_node, "setjmpvar"); arg = build_addr (disp_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_DISPATCHER); x = gimple_build_call (t, 1, arg); gimple_call_set_lhs (x, disp_var); /* Build 'goto DISP_VAR;' and insert. */ gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); x = gimple_build_goto (disp_var); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); data.return_statements.release (); return 0; }
void browse_tree (tree begin) { tree head; TB_CODE tbc = TB_UNUSED_COMMAND; ssize_t rd; char *input = NULL; long input_size = 0; fprintf (TB_OUT_FILE, "\nTree Browser\n"); #define TB_SET_HEAD(N) do { \ vec_safe_push (TB_history_stack, N); \ head = N; \ if (TB_verbose) \ if (head) \ { \ print_generic_expr (TB_OUT_FILE, head, 0); \ fprintf (TB_OUT_FILE, "\n"); \ } \ } while (0) TB_SET_HEAD (begin); /* Store in a hashtable information about previous and upper statements. */ { TB_up_ht = new hash_table<tree_upper_hasher> (1023); TB_update_up (head); } while (24) { fprintf (TB_OUT_FILE, "TB> "); rd = TB_getline (&input, &input_size, TB_IN_FILE); if (rd == -1) /* EOF. */ goto ret; if (rd != 1) /* Get a new command. Otherwise the user just pressed enter, and thus she expects the last command to be reexecuted. */ tbc = TB_get_command (input); switch (tbc) { case TB_UPDATE_UP: TB_update_up (head); break; case TB_MAX: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE || TREE_CODE (head) == FIXED_POINT_TYPE)) TB_SET_HEAD (TYPE_MAX_VALUE (head)); else TB_WF; break; case TB_MIN: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE || TREE_CODE (head) == FIXED_POINT_TYPE)) TB_SET_HEAD (TYPE_MIN_VALUE (head)); else TB_WF; break; case TB_ELT: if (head && TREE_CODE (head) == TREE_VEC) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else if (head && TREE_CODE (head) == VECTOR_CST) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else TB_WF; break; case TB_VALUE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_VALUE (head)); else TB_WF; break; case TB_PURPOSE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_PURPOSE (head)); else TB_WF; break; case TB_IMAG: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_IMAGPART (head)); else TB_WF; break; case TB_REAL: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_REALPART (head)); else TB_WF; break; case TB_BLOCK: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_SUBBLOCKS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); else TB_WF; break; case TB_SUPERCONTEXT: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); else TB_WF; break; case TB_VARS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_VARS (head)); else if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_REFERENCE_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_REFERENCE_TO (head)); else TB_WF; break; case TB_POINTER_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_POINTER_TO (head)); else TB_WF; break; case TB_BASETYPE: if (head && TREE_CODE (head) == OFFSET_TYPE) TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); else TB_WF; break; case TB_ARG_TYPES: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE)) TB_SET_HEAD (TYPE_ARG_TYPES (head)); else TB_WF; break; case TB_METHOD_BASE_TYPE: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE) && TYPE_METHOD_BASETYPE (head)) TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); else TB_WF; break; case TB_FIELDS: if (head && (TREE_CODE (head) == RECORD_TYPE || TREE_CODE (head) == UNION_TYPE || TREE_CODE (head) == QUAL_UNION_TYPE)) TB_SET_HEAD (TYPE_FIELDS (head)); else TB_WF; break; case TB_DOMAIN: if (head && TREE_CODE (head) == ARRAY_TYPE) TB_SET_HEAD (TYPE_DOMAIN (head)); else TB_WF; break; case TB_VALUES: if (head && TREE_CODE (head) == ENUMERAL_TYPE) TB_SET_HEAD (TYPE_VALUES (head)); else TB_WF; break; case TB_ARG_TYPE: if (head && TREE_CODE (head) == PARM_DECL) TB_SET_HEAD (DECL_ARG_TYPE (head)); else TB_WF; break; case TB_INITIAL: if (head && DECL_P (head)) TB_SET_HEAD (DECL_INITIAL (head)); else TB_WF; break; case TB_RESULT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_RESULT_FLD (head)); else TB_WF; break; case TB_ARGUMENTS: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ARGUMENTS (head)); else TB_WF; break; case TB_ABSTRACT_ORIGIN: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); else if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); else TB_WF; break; case TB_ATTRIBUTES: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ATTRIBUTES (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_ATTRIBUTES (head)); else TB_WF; break; case TB_CONTEXT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_CONTEXT (head)); else if (head && TYPE_P (head) && TYPE_CONTEXT (head)) TB_SET_HEAD (TYPE_CONTEXT (head)); else TB_WF; break; case TB_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_OFFSET (head)); else TB_WF; break; case TB_BIT_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); else TB_WF; break; case TB_UNIT_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE_UNIT (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE_UNIT (head)); else TB_WF; break; case TB_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE (head)); else TB_WF; break; case TB_TYPE: if (head && TREE_TYPE (head)) TB_SET_HEAD (TREE_TYPE (head)); else TB_WF; break; case TB_DECL_SAVED_TREE: if (head && TREE_CODE (head) == FUNCTION_DECL && DECL_SAVED_TREE (head)) TB_SET_HEAD (DECL_SAVED_TREE (head)); else TB_WF; break; case TB_BODY: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_0: if (head && EXPR_P (head) && TREE_OPERAND (head, 0)) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_CHILD_1: if (head && EXPR_P (head) && TREE_OPERAND (head, 1)) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_2: if (head && EXPR_P (head) && TREE_OPERAND (head, 2)) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_CHILD_3: if (head && EXPR_P (head) && TREE_OPERAND (head, 3)) TB_SET_HEAD (TREE_OPERAND (head, 3)); else TB_WF; break; case TB_PRINT: if (head) debug_tree (head); else TB_WF; break; case TB_PRETTY_PRINT: if (head) { print_generic_stmt (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } else TB_WF; break; case TB_SEARCH_NAME: break; case TB_SEARCH_CODE: { enum tree_code code; char *arg_text; arg_text = strchr (input, ' '); if (arg_text == NULL) { fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); break; } code = TB_get_tree_code (arg_text + 1); /* Search in the subtree a node with the given code. */ { tree res; res = walk_tree (&head, find_node_with_code, &code, NULL); if (res == NULL_TREE) { fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); } else { fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); TB_SET_HEAD (res); } } break; } #define TB_MOVE_HEAD(FCT) do { \ if (head) \ { \ tree t; \ t = FCT (head); \ if (t) \ TB_SET_HEAD (t); \ else \ TB_WF; \ } \ else \ TB_WF; \ } while (0) case TB_FIRST: TB_MOVE_HEAD (TB_first_in_bind); break; case TB_LAST: TB_MOVE_HEAD (TB_last_in_bind); break; case TB_UP: TB_MOVE_HEAD (TB_up_expr); break; case TB_PREV: TB_MOVE_HEAD (TB_prev_expr); break; case TB_NEXT: TB_MOVE_HEAD (TB_next_expr); break; case TB_HPREV: /* This command is a little bit special, since it deals with history stack. For this reason it should keep the "head = ..." statement and not use TB_MOVE_HEAD. */ if (head) { tree t; t = TB_history_prev (); if (t) { head = t; if (TB_verbose) { print_generic_expr (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } } else TB_WF; } else TB_WF; break; case TB_CHAIN: /* Don't go further if it's the last node in this chain. */ if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_CHAIN (head)); else if (head && TREE_CHAIN (head)) TB_SET_HEAD (TREE_CHAIN (head)); else TB_WF; break; case TB_FUN: /* Go up to the current function declaration. */ TB_SET_HEAD (current_function_decl); fprintf (TB_OUT_FILE, "Current function declaration.\n"); break; case TB_HELP: /* Display a help message. */ { int i; fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); for (i = 0; i < TB_UNUSED_COMMAND; i++) { fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); } } break; case TB_VERBOSE: if (TB_verbose == 0) { TB_verbose = 1; fprintf (TB_OUT_FILE, "Verbose on.\n"); } else { TB_verbose = 0; fprintf (TB_OUT_FILE, "Verbose off.\n"); } break; case TB_EXIT: case TB_QUIT: /* Just exit from this function. */ goto ret; default: TB_NIY; } } ret:; delete TB_up_ht; TB_up_ht = NULL; return; }
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); }