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 tree get_function_decl_from_block (tree block) { tree decl; if (LOCATION_LOCUS (BLOCK_SOURCE_LOCATION (block) == UNKNOWN_LOCATION)) return NULL_TREE; for (decl = BLOCK_ABSTRACT_ORIGIN (block); decl && (TREE_CODE (decl) == BLOCK); decl = BLOCK_ABSTRACT_ORIGIN (decl)) if (TREE_CODE (decl) == FUNCTION_DECL) break; return decl; }
static void write_ts_block_tree_pointers (struct output_block *ob, tree expr, bool ref_p) { streamer_write_chain (ob, BLOCK_VARS (expr), ref_p); stream_write_tree (ob, BLOCK_SUPERCONTEXT (expr), ref_p); /* Stream BLOCK_ABSTRACT_ORIGIN for the limited cases we can handle - those that represent inlined function scopes. For the rest them on the floor instead of ICEing in dwarf2out.c, but keep the notion of whether the block is an inlined block by refering to itself for the sake of tree_nonartificial_location. */ if (inlined_function_outer_scope_p (expr)) { tree ultimate_origin = block_ultimate_origin (expr); stream_write_tree (ob, ultimate_origin, ref_p); } else stream_write_tree (ob, (BLOCK_ABSTRACT_ORIGIN (expr) ? expr : NULL_TREE), ref_p); /* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information for early inlined BLOCKs so drop it on the floor instead of ICEing in dwarf2out.c. */ /* BLOCK_FRAGMENT_ORIGIN and BLOCK_FRAGMENT_CHAIN is not live at LTO streaming time. */ /* Do not output BLOCK_SUBBLOCKS. Instead on streaming-in this list is re-constructed from BLOCK_SUPERCONTEXT. */ }
static tree get_function_decl_from_block (tree block) { if (!inlined_function_outer_scope_p (block)) return NULL_TREE; return BLOCK_ABSTRACT_ORIGIN (block); }
static void lto_input_ts_block_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, tree expr) { BLOCK_VARS (expr) = streamer_read_chain (ib, data_in); BLOCK_SUPERCONTEXT (expr) = stream_read_tree (ib, data_in); /* Stream BLOCK_ABSTRACT_ORIGIN and BLOCK_SOURCE_LOCATION for the limited cases we can handle - those that represent inlined function scopes. For the rest them on the floor instead of ICEing in dwarf2out.c. */ BLOCK_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in); /* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information for early inlined BLOCKs so drop it on the floor instead of ICEing in dwarf2out.c. */ /* BLOCK_FRAGMENT_ORIGIN and BLOCK_FRAGMENT_CHAIN is not live at LTO streaming time. */ /* 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. */ }
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; }
bool maybe_clone_body (tree fn) { tree clone; bool first = true; /* APPLE LOCAL begin ARM structor thunks */ tree clone_to_call; struct clone_info info; /* APPLE LOCAL end ARM structor thunks */ /* We only clone constructors and destructors. */ if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) return 0; /* Emit the DWARF1 abstract instance. */ (*debug_hooks->deferred_inline_function) (fn); /* APPLE LOCAL begin ARM structor thunks */ /* Figure out whether we can use the 'thunk' implementation, and if so on which clones. */ info.next_clone = 0; info.which_thunks_ok = compute_use_thunks (fn); /* APPLE LOCAL end ARM structor thunks */ /* We know that any clones immediately follow FN in the TYPE_METHODS list. */ push_to_top_level (); FOR_EACH_CLONE (clone, fn) { tree parm; tree clone_parm; int parmno; splay_tree decl_map; /* Update CLONE's source position information to match FN's. */ DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn); DECL_INLINE (clone) = DECL_INLINE (fn); DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn); /* LLVM LOCAL begin inlinehint attribute */ DECL_EXPLICIT_INLINE_P (clone) = DECL_EXPLICIT_INLINE_P (fn); /* LLVM LOCAL end inlinehint attribute */ DECL_COMDAT (clone) = DECL_COMDAT (fn); DECL_WEAK (clone) = DECL_WEAK (fn); DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn); DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn); DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn); DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn); DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn); DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn); TREE_PUBLIC (clone) = TREE_PUBLIC (fn); DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn); DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn); /* Adjust the parameter names and locations. */ parm = DECL_ARGUMENTS (fn); clone_parm = DECL_ARGUMENTS (clone); /* Update the `this' parameter, which is always first. */ update_cloned_parm (parm, clone_parm, first); parm = TREE_CHAIN (parm); clone_parm = TREE_CHAIN (clone_parm); if (DECL_HAS_IN_CHARGE_PARM_P (fn)) parm = TREE_CHAIN (parm); if (DECL_HAS_VTT_PARM_P (fn)) parm = TREE_CHAIN (parm); if (DECL_HAS_VTT_PARM_P (clone)) clone_parm = TREE_CHAIN (clone_parm); for (; parm; parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm)) /* Update this parameter. */ update_cloned_parm (parm, clone_parm, first); /* Start processing the function. */ start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); /* Remap the parameters. */ decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); for (parmno = 0, parm = DECL_ARGUMENTS (fn), clone_parm = DECL_ARGUMENTS (clone); parm; ++parmno, parm = TREE_CHAIN (parm)) { /* Map the in-charge parameter to an appropriate constant. */ if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1) { tree in_charge; in_charge = in_charge_arg_for_name (DECL_NAME (clone)); splay_tree_insert (decl_map, (splay_tree_key) parm, (splay_tree_value) in_charge); /* APPLE LOCAL ARM structor thunks */ info.in_charge_value [info.next_clone] = in_charge; } else if (DECL_ARTIFICIAL (parm) && DECL_NAME (parm) == vtt_parm_identifier) { /* For a subobject constructor or destructor, the next argument is the VTT parameter. Remap the VTT_PARM from the CLONE to this parameter. */ if (DECL_HAS_VTT_PARM_P (clone)) { DECL_ABSTRACT_ORIGIN (clone_parm) = parm; splay_tree_insert (decl_map, (splay_tree_key) parm, (splay_tree_value) clone_parm); clone_parm = TREE_CHAIN (clone_parm); } /* Otherwise, map the VTT parameter to `NULL'. */ else { splay_tree_insert (decl_map, (splay_tree_key) parm, (splay_tree_value) null_pointer_node); } } /* Map other parameters to their equivalents in the cloned function. */ else { splay_tree_insert (decl_map, (splay_tree_key) parm, (splay_tree_value) clone_parm); clone_parm = TREE_CHAIN (clone_parm); } } if (targetm.cxx.cdtor_returns_this ()) { parm = DECL_RESULT (fn); clone_parm = DECL_RESULT (clone); splay_tree_insert (decl_map, (splay_tree_key) parm, (splay_tree_value) clone_parm); } /* APPLE LOCAL begin ARM structor thunks */ clone_to_call = find_earlier_clone (&info); if (clone_to_call) /* Bodies are identical; replace later one with call to an earlier one. */ thunk_body (clone, fn, clone_to_call); else /* Clone the body. */ clone_body (clone, fn, decl_map); /* APPLE LOCAL end ARM structor thunks */ /* The clone can throw iff the original function can throw. */ cp_function_chain->can_throw = !TREE_NOTHROW (fn); /* Now, expand this function into RTL, if appropriate. */ finish_function (0); BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); expand_or_defer_fn (clone); first = false; /* APPLE LOCAL begin ARM structor thunks */ info.clones [info.next_clone] = clone; info.next_clone++; /* APPLE LOCAL end ARM structor thunks */ }