static tree vxworks_emutls_var_init (tree var, tree decl, tree tmpl_addr) { VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 3); constructor_elt *elt; tree type = TREE_TYPE (var); tree field = TYPE_FIELDS (type); elt = VEC_quick_push (constructor_elt, v, NULL); elt->index = field; elt->value = fold_convert (TREE_TYPE (field), tmpl_addr); elt = VEC_quick_push (constructor_elt, v, NULL); field = DECL_CHAIN (field); elt->index = field; elt->value = build_int_cst (TREE_TYPE (field), 0); elt = VEC_quick_push (constructor_elt, v, NULL); field = DECL_CHAIN (field); elt->index = field; elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl)); return build_constructor (type, v); }
static void lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, tree expr) { DECL_SIZE (expr) = stream_read_tree (ib, data_in); DECL_SIZE_UNIT (expr) = stream_read_tree (ib, data_in); DECL_ATTRIBUTES (expr) = stream_read_tree (ib, data_in); /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information for early inlining so drop it on the floor instead of ICEing in dwarf2out.c. */ if (TREE_CODE (expr) == PARM_DECL) TREE_CHAIN (expr) = streamer_read_chain (ib, data_in); if ((TREE_CODE (expr) == VAR_DECL || TREE_CODE (expr) == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (expr)) SET_DECL_VALUE_EXPR (expr, stream_read_tree (ib, data_in)); if (TREE_CODE (expr) == VAR_DECL) { tree dexpr = stream_read_tree (ib, data_in); if (dexpr) SET_DECL_DEBUG_EXPR (expr, dexpr); } }
static void add_stack_var (tree decl) { if (stack_vars_num >= stack_vars_alloc) { if (stack_vars_alloc) stack_vars_alloc = stack_vars_alloc * 3 / 2; else stack_vars_alloc = 32; stack_vars = XRESIZEVEC (struct stack_var, stack_vars, stack_vars_alloc); } stack_vars[stack_vars_num].decl = decl; stack_vars[stack_vars_num].offset = 0; stack_vars[stack_vars_num].size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); stack_vars[stack_vars_num].alignb = get_decl_align_unit (decl); /* All variables are initially in their own partition. */ stack_vars[stack_vars_num].representative = stack_vars_num; stack_vars[stack_vars_num].next = EOC; /* Ensure that this decl doesn't get put onto the list twice. */ SET_DECL_RTL (decl, pc_rtx); stack_vars_num++; }
unsigned int compute_unsafe_stack_layout() { unsigned int i, total = 0; tree var; FOR_EACH_LOCAL_DECL(cfun, i, var) { total += tree_to_uhwi (DECL_SIZE_UNIT(var)); /* size in bytes */ }
static void write_ts_decl_common_tree_pointers (struct output_block *ob, tree expr, bool ref_p) { stream_write_tree (ob, DECL_SIZE (expr), ref_p); stream_write_tree (ob, DECL_SIZE_UNIT (expr), ref_p); /* Note, DECL_INITIAL is not handled here. Since DECL_INITIAL needs special handling in LTO, it must be handled by streamer hooks. */ stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p); /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information for early inlining so drop it on the floor instead of ICEing in dwarf2out.c. */ if (TREE_CODE (expr) == PARM_DECL) streamer_write_chain (ob, TREE_CHAIN (expr), ref_p); if ((TREE_CODE (expr) == VAR_DECL || TREE_CODE (expr) == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (expr)) stream_write_tree (ob, DECL_VALUE_EXPR (expr), ref_p); if (TREE_CODE (expr) == VAR_DECL) stream_write_tree (ob, DECL_DEBUG_EXPR (expr), ref_p); }
static void build_field (segment_info *h, tree union_type, record_layout_info rli) { tree field; tree name; HOST_WIDE_INT offset = h->offset; unsigned HOST_WIDE_INT desired_align, known_align; name = get_identifier (h->sym->name); field = build_decl (FIELD_DECL, name, h->field); gfc_set_decl_location (field, &h->sym->declared_at); known_align = (offset & -offset) * BITS_PER_UNIT; if (known_align == 0 || known_align > BIGGEST_ALIGNMENT) known_align = BIGGEST_ALIGNMENT; desired_align = update_alignment_for_field (rli, field, known_align); if (desired_align > known_align) DECL_PACKED (field) = 1; DECL_FIELD_CONTEXT (field) = union_type; DECL_FIELD_OFFSET (field) = size_int (offset); DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; SET_DECL_OFFSET_ALIGN (field, known_align); rli->offset = size_binop (MAX_EXPR, rli->offset, size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field), DECL_SIZE_UNIT (field))); h->field = field; }
static void build_field (segment_info *h, tree union_type, record_layout_info rli) { tree field; tree name; HOST_WIDE_INT offset = h->offset; unsigned HOST_WIDE_INT desired_align, known_align; name = get_identifier (h->sym->name); field = build_decl (h->sym->declared_at.lb->location, FIELD_DECL, name, h->field); known_align = (offset & -offset) * BITS_PER_UNIT; if (known_align == 0 || known_align > BIGGEST_ALIGNMENT) known_align = BIGGEST_ALIGNMENT; desired_align = update_alignment_for_field (rli, field, known_align); if (desired_align > known_align) DECL_PACKED (field) = 1; DECL_FIELD_CONTEXT (field) = union_type; DECL_FIELD_OFFSET (field) = size_int (offset); DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; SET_DECL_OFFSET_ALIGN (field, known_align); rli->offset = size_binop (MAX_EXPR, rli->offset, size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field), DECL_SIZE_UNIT (field))); /* If this field is assigned to a label, we create another two variables. One will hold the address of target label or format label. The other will hold the length of format label string. */ if (h->sym->attr.assign) { tree len; tree addr; gfc_allocate_lang_decl (field); GFC_DECL_ASSIGN (field) = 1; len = gfc_create_var_np (gfc_charlen_type_node,h->sym->name); addr = gfc_create_var_np (pvoid_type_node, h->sym->name); TREE_STATIC (len) = 1; TREE_STATIC (addr) = 1; DECL_INITIAL (len) = build_int_cst (NULL_TREE, -2); gfc_set_decl_location (len, &h->sym->declared_at); gfc_set_decl_location (addr, &h->sym->declared_at); GFC_DECL_STRING_LEN (field) = pushdecl_top_level (len); GFC_DECL_ASSIGN_ADDR (field) = pushdecl_top_level (addr); } /* If this field is volatile, mark it. */ if (h->sym->attr.volatile_) { tree new_type; TREE_THIS_VOLATILE (field) = 1; new_type = build_qualified_type (TREE_TYPE (field), TYPE_QUAL_VOLATILE); TREE_TYPE (field) = new_type; } h->field = field; }
static tree build_equiv_decl (tree union_type, bool is_init) { tree decl; char name[15]; static int serial = 0; if (is_init) { decl = gfc_create_var (union_type, "equiv"); TREE_STATIC (decl) = 1; return decl; } snprintf (name, sizeof (name), "equiv.%d", serial++); decl = build_decl (VAR_DECL, get_identifier (name), union_type); DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; if (!gfc_can_put_var_on_stack (DECL_SIZE_UNIT (decl))) TREE_STATIC (decl) = 1; TREE_ADDRESSABLE (decl) = 1; TREE_USED (decl) = 1; /* The source location has been lost, and doesn't really matter. We need to set it to something though. */ gfc_set_decl_location (decl, &gfc_current_locus); gfc_add_decl_to_function (decl); return decl; }
static void expand_one_stack_var (tree var) { HOST_WIDE_INT size, offset, align; size = tree_low_cst (DECL_SIZE_UNIT (var), 1); align = get_decl_align_unit (var); offset = alloc_stack_frame_space (size, align); expand_one_stack_var_at (var, offset); }
static tree ubsan_walk_array_refs_r (tree *tp, int *walk_subtrees, void *data) { hash_set<tree> *pset = (hash_set<tree> *) data; if (TREE_CODE (*tp) == BIND_EXPR) { /* Since walk_tree doesn't call the callback function on the decls in BIND_EXPR_VARS, we have to walk them manually, so we can avoid instrumenting DECL_INITIAL of TREE_STATIC vars. */ *walk_subtrees = 0; for (tree decl = BIND_EXPR_VARS (*tp); decl; decl = DECL_CHAIN (decl)) { if (TREE_STATIC (decl)) continue; walk_tree (&DECL_INITIAL (decl), ubsan_walk_array_refs_r, pset, pset); walk_tree (&DECL_SIZE (decl), ubsan_walk_array_refs_r, pset, pset); walk_tree (&DECL_SIZE_UNIT (decl), ubsan_walk_array_refs_r, pset, pset); } walk_tree (&BIND_EXPR_BODY (*tp), ubsan_walk_array_refs_r, pset, pset); } else if (TREE_CODE (*tp) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (*tp, 0)) == ARRAY_REF) { ubsan_maybe_instrument_array_ref (&TREE_OPERAND (*tp, 0), true); /* Make sure ubsan_maybe_instrument_array_ref is not called again on the ARRAY_REF, the above call might not instrument anything as the index might be constant or masked, so ensure it is not walked again and walk its subtrees manually. */ tree aref = TREE_OPERAND (*tp, 0); pset->add (aref); *walk_subtrees = 0; walk_tree (&TREE_OPERAND (aref, 0), ubsan_walk_array_refs_r, pset, pset); walk_tree (&TREE_OPERAND (aref, 1), ubsan_walk_array_refs_r, pset, pset); walk_tree (&TREE_OPERAND (aref, 2), ubsan_walk_array_refs_r, pset, pset); walk_tree (&TREE_OPERAND (aref, 3), ubsan_walk_array_refs_r, pset, pset); } else if (TREE_CODE (*tp) == ARRAY_REF) ubsan_maybe_instrument_array_ref (tp, false); return NULL_TREE; }
static bool defer_stack_allocation (tree var, bool toplevel) { /* Variables in the outermost scope automatically conflict with every other variable. The only reason to want to defer them at all is that, after sorting, we can more efficiently pack small variables in the stack frame. Continue to defer at -O2. */ if (toplevel && optimize < 2) return false; /* Without optimization, *most* variables are allocated from the stack, which makes the quadratic problem large exactly when we want compilation to proceed as quickly as possible. On the other hand, we don't want the function's stack frame size to get completely out of hand. So we avoid adding scalars and "small" aggregates to the list at all. */ if (optimize == 0 && tree_low_cst (DECL_SIZE_UNIT (var), 1) < 32) return false; return true; }
static tree vxworks_emutls_var_init (tree var, tree decl, tree tmpl_addr) { vec<constructor_elt, va_gc> *v; vec_alloc (v, 3); tree type = TREE_TYPE (var); tree field = TYPE_FIELDS (type); constructor_elt elt = {field, fold_convert (TREE_TYPE (field), tmpl_addr)}; v->quick_push (elt); field = DECL_CHAIN (field); elt.index = field; elt.value = build_int_cst (TREE_TYPE (field), 0); v->quick_push (elt); field = DECL_CHAIN (field); elt.index = field; elt.value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl)); v->quick_push (elt); return build_constructor (type, v); }
static void mf_xform_derefs_1 (gimple_stmt_iterator *iter, tree *tp, location_t location, tree dirflag) { tree type, base, limit, addr, size, t; /* Don't instrument read operations. */ if (dirflag == integer_zero_node && flag_mudflap_ignore_reads) return; /* Don't instrument marked nodes. */ if (mf_marked_p (*tp)) return; t = *tp; type = TREE_TYPE (t); if (type == error_mark_node) return; size = TYPE_SIZE_UNIT (type); switch (TREE_CODE (t)) { case ARRAY_REF: case COMPONENT_REF: { /* This is trickier than it may first appear. The reason is that we are looking at expressions from the "inside out" at this point. We may have a complex nested aggregate/array expression (e.g. "a.b[i].c"), maybe with an indirection as the leftmost operator ("p->a.b.d"), where instrumentation is necessary. Or we may have an innocent "a.b.c" expression that must not be instrumented. We need to recurse all the way down the nesting structure to figure it out: looking just at the outer node is not enough. */ tree var; int component_ref_only = (TREE_CODE (t) == COMPONENT_REF); /* If we have a bitfield component reference, we must note the innermost addressable object in ELT, from which we will construct the byte-addressable bounds of the bitfield. */ tree elt = NULL_TREE; int bitfield_ref_p = (TREE_CODE (t) == COMPONENT_REF && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1))); /* Iterate to the top of the ARRAY_REF/COMPONENT_REF containment hierarchy to find the outermost VAR_DECL. */ var = TREE_OPERAND (t, 0); while (1) { if (bitfield_ref_p && elt == NULL_TREE && (TREE_CODE (var) == ARRAY_REF || TREE_CODE (var) == COMPONENT_REF)) elt = var; if (TREE_CODE (var) == ARRAY_REF) { component_ref_only = 0; var = TREE_OPERAND (var, 0); } else if (TREE_CODE (var) == COMPONENT_REF) var = TREE_OPERAND (var, 0); else if (INDIRECT_REF_P (var) || TREE_CODE (var) == MEM_REF) { base = TREE_OPERAND (var, 0); break; } else if (TREE_CODE (var) == VIEW_CONVERT_EXPR) { var = TREE_OPERAND (var, 0); if (CONSTANT_CLASS_P (var) && TREE_CODE (var) != STRING_CST) return; } else { gcc_assert (TREE_CODE (var) == VAR_DECL || TREE_CODE (var) == PARM_DECL || TREE_CODE (var) == RESULT_DECL || TREE_CODE (var) == STRING_CST); /* Don't instrument this access if the underlying variable is not "eligible". This test matches those arrays that have only known-valid indexes, and thus are not labeled TREE_ADDRESSABLE. */ if (! mf_decl_eligible_p (var) || component_ref_only) return; else { base = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (var)), var); break; } } } /* Handle the case of ordinary non-indirection structure accesses. These have only nested COMPONENT_REF nodes (no INDIRECT_REF), but pass through the above filter loop. Note that it's possible for such a struct variable to match the eligible_p test because someone else might take its address sometime. */ /* We need special processing for bitfield components, because their addresses cannot be taken. */ if (bitfield_ref_p) { tree field = TREE_OPERAND (t, 1); if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) size = DECL_SIZE_UNIT (field); if (elt) elt = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (elt)), elt); addr = fold_convert_loc (location, ptr_type_node, elt ? elt : base); addr = fold_build_pointer_plus_loc (location, addr, byte_position (field)); } else addr = build1 (ADDR_EXPR, build_pointer_type (type), t); limit = fold_build2_loc (location, MINUS_EXPR, mf_uintptr_type, fold_build2_loc (location, PLUS_EXPR, mf_uintptr_type, fold_convert (mf_uintptr_type, addr), size), integer_one_node); } break; case INDIRECT_REF: addr = TREE_OPERAND (t, 0); base = addr; limit = fold_build_pointer_plus_hwi_loc (location, fold_build_pointer_plus_loc (location, base, size), -1); break; case MEM_REF: if (addr_expr_of_non_mem_decl_p (TREE_OPERAND (t, 0))) return; addr = fold_build_pointer_plus_loc (location, TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)); base = addr; limit = fold_build_pointer_plus_hwi_loc (location, fold_build_pointer_plus_loc (location, base, size), -1); break; case TARGET_MEM_REF: if (addr_expr_of_non_mem_decl_p (TMR_BASE (t))) return; addr = tree_mem_ref_addr (ptr_type_node, t); base = addr; limit = fold_build_pointer_plus_hwi_loc (location, fold_build_pointer_plus_loc (location, base, size), -1); break; case ARRAY_RANGE_REF: warning (OPT_Wmudflap, "mudflap checking not yet implemented for ARRAY_RANGE_REF"); return; case BIT_FIELD_REF: /* ??? merge with COMPONENT_REF code above? */ { tree ofs, rem, bpu; /* If we're not dereferencing something, then the access must be ok. */ if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF) return; bpu = bitsize_int (BITS_PER_UNIT); ofs = fold_convert (bitsizetype, TREE_OPERAND (t, 2)); rem = size_binop_loc (location, TRUNC_MOD_EXPR, ofs, bpu); ofs = size_binop_loc (location, TRUNC_DIV_EXPR, ofs, bpu); size = fold_convert (bitsizetype, TREE_OPERAND (t, 1)); size = size_binop_loc (location, PLUS_EXPR, size, rem); size = size_binop_loc (location, CEIL_DIV_EXPR, size, bpu); size = fold_convert (sizetype, size); addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0); addr = fold_convert (ptr_type_node, addr); addr = fold_build_pointer_plus_loc (location, addr, ofs); base = addr; limit = fold_build_pointer_plus_hwi_loc (location, fold_build_pointer_plus_loc (location, base, size), -1); } break; default: return; } mf_build_check_statement_for (base, limit, iter, location, dirflag); }
void print_node (FILE *file, const char *prefix, tree node, int indent) { int hash; struct bucket *b; machine_mode mode; enum tree_code_class tclass; int len; int i; expanded_location xloc; enum tree_code code; if (node == 0) return; code = TREE_CODE (node); tclass = TREE_CODE_CLASS (code); /* Don't get too deep in nesting. If the user wants to see deeper, it is easy to use the address of a lowest-level node as an argument in another call to debug_tree. */ if (indent > 24) { print_node_brief (file, prefix, node, indent); return; } if (indent > 8 && (tclass == tcc_type || tclass == tcc_declaration)) { print_node_brief (file, prefix, node, indent); return; } /* It is unsafe to look at any other fields of an ERROR_MARK node. */ if (code == ERROR_MARK) { print_node_brief (file, prefix, node, indent); return; } /* Allow this function to be called if the table is not there. */ if (table) { hash = ((uintptr_t) node) % HASH_SIZE; /* If node is in the table, just mention its address. */ for (b = table[hash]; b; b = b->next) if (b->node == node) { print_node_brief (file, prefix, node, indent); return; } /* Add this node to the table. */ b = XNEW (struct bucket); b->node = node; b->next = table[hash]; table[hash] = b; } /* Indent to the specified column, since this is the long form. */ indent_to (file, indent); /* Print the slot this node is in, and its code, and address. */ fprintf (file, "%s <%s", prefix, get_tree_code_name (code)); dump_addr (file, " ", node); /* Print the name, if any. */ if (tclass == tcc_declaration) { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); else if (code == LABEL_DECL && LABEL_DECL_UID (node) != -1) { if (dump_flags & TDF_NOUID) fprintf (file, " L.xxxx"); else fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); } else { if (dump_flags & TDF_NOUID) fprintf (file, " %c.xxxx", code == CONST_DECL ? 'C' : 'D'); else fprintf (file, " %c.%u", code == CONST_DECL ? 'C' : 'D', DECL_UID (node)); } } else if (tclass == tcc_type) { if (TYPE_NAME (node)) { if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL && DECL_NAME (TYPE_NAME (node))) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); } } if (code == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (node)); if (code == INTEGER_CST) { if (indent <= 4) print_node_brief (file, "type", TREE_TYPE (node), indent + 4); } else if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) { print_node (file, "type", TREE_TYPE (node), indent + 4); if (TREE_TYPE (node)) indent_to (file, indent + 3); } if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node)) fputs (" side-effects", file); if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node)) fputs (" readonly", file); if (TYPE_P (node) && TYPE_ATOMIC (node)) fputs (" atomic", file); if (!TYPE_P (node) && TREE_CONSTANT (node)) fputs (" constant", file); else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) fputs (" sizes-gimplified", file); if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); if (TREE_ADDRESSABLE (node)) fputs (" addressable", file); if (TREE_THIS_VOLATILE (node)) fputs (" volatile", file); if (TREE_ASM_WRITTEN (node)) fputs (" asm_written", file); if (TREE_USED (node)) fputs (" used", file); if (TREE_NOTHROW (node)) fputs (" nothrow", file); if (TREE_PUBLIC (node)) fputs (" public", file); if (TREE_PRIVATE (node)) fputs (" private", file); if (TREE_PROTECTED (node)) fputs (" protected", file); if (TREE_STATIC (node)) fputs (code == CALL_EXPR ? " must-tail-call" : " static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); if (TREE_VISITED (node)) fputs (" visited", file); if (code != TREE_VEC && code != INTEGER_CST && code != SSA_NAME) { if (TREE_LANG_FLAG_0 (node)) fputs (" tree_0", file); if (TREE_LANG_FLAG_1 (node)) fputs (" tree_1", file); if (TREE_LANG_FLAG_2 (node)) fputs (" tree_2", file); if (TREE_LANG_FLAG_3 (node)) fputs (" tree_3", file); if (TREE_LANG_FLAG_4 (node)) fputs (" tree_4", file); if (TREE_LANG_FLAG_5 (node)) fputs (" tree_5", file); if (TREE_LANG_FLAG_6 (node)) fputs (" tree_6", file); } /* DECL_ nodes have additional attributes. */ switch (TREE_CODE_CLASS (code)) { case tcc_declaration: if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_UNSIGNED (node)) fputs (" unsigned", file); if (DECL_IGNORED_P (node)) fputs (" ignored", file); if (DECL_ABSTRACT_P (node)) fputs (" abstract", file); if (DECL_EXTERNAL (node)) fputs (" external", file); if (DECL_NONLOCAL (node)) fputs (" nonlocal", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) { if (DECL_WEAK (node)) fputs (" weak", file); if (DECL_IN_SYSTEM_HEADER (node)) fputs (" in_system_header", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL) && code != LABEL_DECL && code != FUNCTION_DECL && DECL_REGISTER (node)) fputs (" regdecl", file); if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node)) fputs (" suppress-debug", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_TARGET (node)) fputs (" function-specific-target", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node)) fputs (" function-specific-opt", file); if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node)) fputs (" autoinline", file); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) fputs (" built-in", file); if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node)) fputs (" static-chain", file); if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node)) fputs (" tm-clone", file); if (code == FIELD_DECL && DECL_PACKED (node)) fputs (" packed", file); if (code == FIELD_DECL && DECL_BIT_FIELD (node)) fputs (" bit-field", file); if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (node)) fputs (" nonaddressable", file); if (code == LABEL_DECL && EH_LANDING_PAD_NR (node)) fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node)); if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node)) fputs (" in-text-section", file); if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (node)) fputs (" in-constant-pool", file); if (code == VAR_DECL && DECL_COMMON (node)) fputs (" common", file); if (code == VAR_DECL && DECL_THREAD_LOCAL_P (node)) { fputs (" ", file); fputs (tls_model_names[DECL_TLS_MODEL (node)], file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_VIRTUAL_P (node)) fputs (" virtual", file); if (DECL_PRESERVE_P (node)) fputs (" preserve", file); if (DECL_LANG_FLAG_0 (node)) fputs (" decl_0", file); if (DECL_LANG_FLAG_1 (node)) fputs (" decl_1", file); if (DECL_LANG_FLAG_2 (node)) fputs (" decl_2", file); if (DECL_LANG_FLAG_3 (node)) fputs (" decl_3", file); if (DECL_LANG_FLAG_4 (node)) fputs (" decl_4", file); if (DECL_LANG_FLAG_5 (node)) fputs (" decl_5", file); if (DECL_LANG_FLAG_6 (node)) fputs (" decl_6", file); if (DECL_LANG_FLAG_7 (node)) fputs (" decl_7", file); mode = DECL_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); } if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL) && DECL_BY_REFERENCE (node)) fputs (" passed-by-reference", file); if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS) && DECL_DEFER_OUTPUT (node)) fputs (" defer-output", file); xloc = expand_location (DECL_SOURCE_LOCATION (node)); fprintf (file, " file %s line %d col %d", xloc.file, xloc.line, xloc.column); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node (file, "size", DECL_SIZE (node), indent + 4); print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4); if (code != FUNCTION_DECL || DECL_BUILT_IN (node)) indent_to (file, indent + 3); if (DECL_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d", DECL_ALIGN (node)); if (code == FIELD_DECL) fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, DECL_OFFSET_ALIGN (node)); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) { if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node)); else fprintf (file, " built-in %s:%s", built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], built_in_names[(int) DECL_FUNCTION_CODE (node)]); } } if (code == FIELD_DECL) { print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node), indent + 4); if (DECL_BIT_FIELD_TYPE (node)) print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), indent + 4); } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node_brief (file, "attributes", DECL_ATTRIBUTES (node), indent + 4); if (code != PARM_DECL) print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) { print_node_brief (file, "abstract_origin", DECL_ABSTRACT_ORIGIN (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) { print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); } lang_hooks.print_decl (file, node, indent); if (DECL_RTL_SET_P (node)) { indent_to (file, indent + 4); print_rtl (file, DECL_RTL (node)); } if (code == PARM_DECL) { print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4); if (DECL_INCOMING_RTL (node) != 0) { indent_to (file, indent + 4); fprintf (file, "incoming-rtl "); print_rtl (file, DECL_INCOMING_RTL (node)); } } else if (code == FUNCTION_DECL && DECL_STRUCT_FUNCTION (node) != 0) { print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4); indent_to (file, indent + 4); dump_addr (file, "struct-function ", DECL_STRUCT_FUNCTION (node)); } if ((code == VAR_DECL || code == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (node)) print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); /* Print the decl chain only if decl is at second level. */ if (indent == 4) print_node (file, "chain", TREE_CHAIN (node), indent + 4); else print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_type: if (TYPE_UNSIGNED (node)) fputs (" unsigned", file); if (TYPE_NO_FORCE_BLK (node)) fputs (" no-force-blk", file); if (TYPE_STRING_FLAG (node)) fputs (" string-flag", file); if (TYPE_NEEDS_CONSTRUCTING (node)) fputs (" needs-constructing", file); if ((code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE || code == ARRAY_TYPE) && TYPE_REVERSE_STORAGE_ORDER (node)) fputs (" reverse-storage-order", file); /* The transparent-union flag is used for different things in different nodes. */ if ((code == UNION_TYPE || code == RECORD_TYPE) && TYPE_TRANSPARENT_AGGR (node)) fputs (" transparent-aggr", file); else if (code == ARRAY_TYPE && TYPE_NONALIASED_COMPONENT (node)) fputs (" nonaliased-component", file); if (TYPE_PACKED (node)) fputs (" packed", file); if (TYPE_RESTRICT (node)) fputs (" restrict", file); if (TYPE_LANG_FLAG_0 (node)) fputs (" type_0", file); if (TYPE_LANG_FLAG_1 (node)) fputs (" type_1", file); if (TYPE_LANG_FLAG_2 (node)) fputs (" type_2", file); if (TYPE_LANG_FLAG_3 (node)) fputs (" type_3", file); if (TYPE_LANG_FLAG_4 (node)) fputs (" type_4", file); if (TYPE_LANG_FLAG_5 (node)) fputs (" type_5", file); if (TYPE_LANG_FLAG_6 (node)) fputs (" type_6", file); if (TYPE_LANG_FLAG_7 (node)) fputs (" type_7", file); mode = TYPE_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); print_node (file, "size", TYPE_SIZE (node), indent + 4); print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4); indent_to (file, indent + 3); if (TYPE_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d symtab %d alias set " HOST_WIDE_INT_PRINT_DEC, TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node), (HOST_WIDE_INT) TYPE_ALIAS_SET (node)); if (TYPE_STRUCTURAL_EQUALITY_P (node)) fprintf (file, " structural equality"); else dump_addr (file, " canonical type ", TYPE_CANONICAL (node)); print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4); if (INTEGRAL_TYPE_P (node) || code == REAL_TYPE || code == FIXED_POINT_TYPE) { fprintf (file, " precision %d", TYPE_PRECISION (node)); print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4); print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4); } if (code == ENUMERAL_TYPE) print_node (file, "values", TYPE_VALUES (node), indent + 4); else if (code == ARRAY_TYPE) print_node (file, "domain", TYPE_DOMAIN (node), indent + 4); else if (code == VECTOR_TYPE) fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node)); else if (code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE) print_node (file, "fields", TYPE_FIELDS (node), indent + 4); else if (code == FUNCTION_TYPE || code == METHOD_TYPE) { if (TYPE_METHOD_BASETYPE (node)) print_node_brief (file, "method basetype", TYPE_METHOD_BASETYPE (node), indent + 4); print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4); } else if (code == OFFSET_TYPE) print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node), indent + 4); if (TYPE_CONTEXT (node)) print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4); lang_hooks.print_type (file, node, indent); if (TYPE_POINTER_TO (node) || TREE_CHAIN (node)) indent_to (file, indent + 3); print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), indent + 4); print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), indent + 4); print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_expression: case tcc_comparison: case tcc_unary: case tcc_binary: case tcc_reference: case tcc_statement: case tcc_vl_exp: if (code == BIND_EXPR) { print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4); print_node (file, "body", TREE_OPERAND (node, 1), indent + 4); print_node (file, "block", TREE_OPERAND (node, 2), indent + 4); break; } if (code == CALL_EXPR) { call_expr_arg_iterator iter; tree arg; print_node (file, "fn", CALL_EXPR_FN (node), indent + 4); print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node), indent + 4); i = 0; FOR_EACH_CALL_EXPR_ARG (arg, iter, node) { char temp[10]; sprintf (temp, "arg %d", i); print_node (file, temp, arg, indent + 4); i++; } }
static tree build_common_decl (gfc_common_head *com, tree union_type, bool is_init) { gfc_symbol *common_sym; tree decl; /* Create a namespace to store symbols for common blocks. */ if (gfc_common_ns == NULL) gfc_common_ns = gfc_get_namespace (NULL); gfc_get_symbol (com->name, gfc_common_ns, &common_sym); decl = common_sym->backend_decl; /* Update the size of this common block as needed. */ if (decl != NULL_TREE) { tree size = TYPE_SIZE_UNIT (union_type); if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size)) { /* Named common blocks of the same name shall be of the same size in all scoping units of a program in which they appear, but blank common blocks may be of different sizes. */ if (strcmp (com->name, BLANK_COMMON_NAME)) gfc_warning ("Named COMMON block '%s' at %L shall be of the " "same size", com->name, &com->where); DECL_SIZE_UNIT (decl) = size; } } /* If this common block has been declared in a previous program unit, and either it is already initialized or there is no new initialization for it, just return. */ if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl))) return decl; /* If there is no backend_decl for the common block, build it. */ if (decl == NULL_TREE) { decl = build_decl (VAR_DECL, get_identifier (com->name), union_type); SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_common_id (com->name)); TREE_PUBLIC (decl) = 1; TREE_STATIC (decl) = 1; DECL_ALIGN (decl) = BIGGEST_ALIGNMENT; DECL_USER_ALIGN (decl) = 0; gfc_set_decl_location (decl, &com->where); /* Place the back end declaration for this common block in GLOBAL_BINDING_LEVEL. */ common_sym->backend_decl = pushdecl_top_level (decl); } /* Has no initial values. */ if (!is_init) { DECL_INITIAL (decl) = NULL_TREE; DECL_COMMON (decl) = 1; DECL_DEFER_OUTPUT (decl) = 1; } else { DECL_INITIAL (decl) = error_mark_node; DECL_COMMON (decl) = 0; DECL_DEFER_OUTPUT (decl) = 0; } return decl; }
/* The method walks the node hierarchy to the topmost node. This is exactly how its done in mudflap and has been borrowed. */ static tree mf_walk_comp_ref(tree *tp, tree type, location_t location, \ tree *addr_store, tree *base_store) { tree var, t, addr, base, size; t = *tp; int component_ref_only = (TREE_CODE (t) == COMPONENT_REF); /* If we have a bitfield component reference, we must note the innermost addressable object in ELT, from which we will construct the byte-addressable bounds of the bitfield. */ tree elt = NULL_TREE; int bitfield_ref_p = (TREE_CODE (t) == COMPONENT_REF && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1))); /* Iterate to the top of the ARRAY_REF/COMPONENT_REF containment hierarchy to find the outermost VAR_DECL. */ var = TREE_OPERAND (t, 0); while (1) { if (bitfield_ref_p && elt == NULL_TREE && (TREE_CODE (var) == ARRAY_REF || TREE_CODE (var) == COMPONENT_REF)) elt = var; if (TREE_CODE (var) == ARRAY_REF) { component_ref_only = 0; var = TREE_OPERAND (var, 0); } else if (TREE_CODE (var) == COMPONENT_REF) var = TREE_OPERAND (var, 0); else if (INDIRECT_REF_P (var) || TREE_CODE (var) == MEM_REF) { base = TREE_OPERAND (var, 0); break; } else if (TREE_CODE (var) == VIEW_CONVERT_EXPR) { var = TREE_OPERAND (var, 0); if (CONSTANT_CLASS_P (var) && TREE_CODE (var) != STRING_CST) return NULL_TREE; } else { DEBUGLOG("TREE_CODE(temp) : %s comp_ref_only = %d eligigle = %d\n", \ tree_code_name[(int)TREE_CODE(var)], component_ref_only, \ mf_decl_eligible_p(var)); gcc_assert (TREE_CODE (var) == VAR_DECL || TREE_CODE (var) == SSA_NAME /* TODO: Check this */ || TREE_CODE (var) == PARM_DECL || TREE_CODE (var) == RESULT_DECL || TREE_CODE (var) == STRING_CST); /* Don't instrument this access if the underlying variable is not "eligible". This test matches those arrays that have only known-valid indexes, and thus are not labeled TREE_ADDRESSABLE. */ if (! mf_decl_eligible_p (var)) //TODO is this needed? || component_ref_only) return NULL_TREE; else { base = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (var)), var); break; } } } /* Handle the case of ordinary non-indirection structure accesses. These have only nested COMPONENT_REF nodes (no INDIRECT_REF), but pass through the above filter loop. Note that it's possible for such a struct variable to match the eligible_p test because someone else might take its address sometime. */ /* We need special processing for bitfield components, because their addresses cannot be taken. */ if (bitfield_ref_p) { tree field = TREE_OPERAND (t, 1); if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) size = DECL_SIZE_UNIT (field); if (elt) elt = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (elt)), elt); addr = fold_convert_loc (location, ptr_type_node, elt ? elt : base); addr = fold_build2_loc (location, POINTER_PLUS_EXPR, ptr_type_node, addr, fold_convert_loc (location, sizetype, byte_position (field))); } else addr = build1 (ADDR_EXPR, build_pointer_type (type), t); if (addr_store) *addr_store = addr; if (base_store) *base_store = addr; return var; }
static unsigned HOST_WIDE_INT addr_object_size (struct object_size_info *osi, const_tree ptr, int object_size_type) { tree pt_var, pt_var_size = NULL_TREE, var_size, bytes; gcc_assert (TREE_CODE (ptr) == ADDR_EXPR); pt_var = TREE_OPERAND (ptr, 0); while (handled_component_p (pt_var)) pt_var = TREE_OPERAND (pt_var, 0); if (pt_var && TREE_CODE (pt_var) == MEM_REF) { unsigned HOST_WIDE_INT sz; if (!osi || (object_size_type & 1) != 0 || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME) { sz = compute_builtin_object_size (TREE_OPERAND (pt_var, 0), object_size_type & ~1); } else { tree var = TREE_OPERAND (pt_var, 0); if (osi->pass == 0) collect_object_sizes_for (osi, var); if (bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (var))) sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)]; else sz = unknown[object_size_type]; } if (sz != unknown[object_size_type]) { double_int dsz = double_int::from_uhwi (sz) - mem_ref_offset (pt_var); if (dsz.is_negative ()) sz = 0; else if (dsz.fits_uhwi ()) sz = dsz.to_uhwi (); else sz = unknown[object_size_type]; } if (sz != unknown[object_size_type] && sz < offset_limit) pt_var_size = size_int (sz); } else if (pt_var && DECL_P (pt_var) && host_integerp (DECL_SIZE_UNIT (pt_var), 1) && (unsigned HOST_WIDE_INT) tree_low_cst (DECL_SIZE_UNIT (pt_var), 1) < offset_limit) pt_var_size = DECL_SIZE_UNIT (pt_var); else if (pt_var && TREE_CODE (pt_var) == STRING_CST && TYPE_SIZE_UNIT (TREE_TYPE (pt_var)) && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1) && (unsigned HOST_WIDE_INT) tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1) < offset_limit) pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var)); else return unknown[object_size_type]; if (pt_var != TREE_OPERAND (ptr, 0)) { tree var; if (object_size_type & 1) { var = TREE_OPERAND (ptr, 0); while (var != pt_var && TREE_CODE (var) != BIT_FIELD_REF && TREE_CODE (var) != COMPONENT_REF && TREE_CODE (var) != ARRAY_REF && TREE_CODE (var) != ARRAY_RANGE_REF && TREE_CODE (var) != REALPART_EXPR && TREE_CODE (var) != IMAGPART_EXPR) var = TREE_OPERAND (var, 0); if (var != pt_var && TREE_CODE (var) == ARRAY_REF) var = TREE_OPERAND (var, 0); if (! TYPE_SIZE_UNIT (TREE_TYPE (var)) || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1) || (pt_var_size && tree_int_cst_lt (pt_var_size, TYPE_SIZE_UNIT (TREE_TYPE (var))))) var = pt_var; else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF) { tree v = var; /* For &X->fld, compute object size only if fld isn't the last field, as struct { int i; char c[1]; } is often used instead of flexible array member. */ while (v && v != pt_var) switch (TREE_CODE (v)) { case ARRAY_REF: if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0))) && TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST) { tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0))); if (domain && TYPE_MAX_VALUE (domain) && TREE_CODE (TYPE_MAX_VALUE (domain)) == INTEGER_CST && tree_int_cst_lt (TREE_OPERAND (v, 1), TYPE_MAX_VALUE (domain))) { v = NULL_TREE; break; } } v = TREE_OPERAND (v, 0); break; case REALPART_EXPR: case IMAGPART_EXPR: v = NULL_TREE; break; case COMPONENT_REF: if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE) { v = NULL_TREE; break; } while (v != pt_var && TREE_CODE (v) == COMPONENT_REF) if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) != UNION_TYPE && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) != QUAL_UNION_TYPE) break; else v = TREE_OPERAND (v, 0); if (TREE_CODE (v) == COMPONENT_REF && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) == RECORD_TYPE) { tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1)); for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain)) if (TREE_CODE (fld_chain) == FIELD_DECL) break; if (fld_chain) { v = NULL_TREE; break; } v = TREE_OPERAND (v, 0); } while (v != pt_var && TREE_CODE (v) == COMPONENT_REF) if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) != UNION_TYPE && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) != QUAL_UNION_TYPE) break; else v = TREE_OPERAND (v, 0); if (v != pt_var) v = NULL_TREE; else v = pt_var; break; default: v = pt_var; break; } if (v == pt_var) var = pt_var; } } else var = pt_var; if (var != pt_var) var_size = TYPE_SIZE_UNIT (TREE_TYPE (var)); else if (!pt_var_size) return unknown[object_size_type]; else var_size = pt_var_size; bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var); if (bytes != error_mark_node) { if (TREE_CODE (bytes) == INTEGER_CST && tree_int_cst_lt (var_size, bytes)) bytes = size_zero_node; else bytes = size_binop (MINUS_EXPR, var_size, bytes); } if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF && bytes != error_mark_node) { tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var); if (bytes2 != error_mark_node) { if (TREE_CODE (bytes2) == INTEGER_CST && tree_int_cst_lt (pt_var_size, bytes2)) bytes2 = size_zero_node; else bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2); bytes = size_binop (MIN_EXPR, bytes, bytes2); } } } else if (!pt_var_size) return unknown[object_size_type]; else bytes = pt_var_size; if (host_integerp (bytes, 1)) return tree_low_cst (bytes, 1); return unknown[object_size_type]; }
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 tree build_common_decl (gfc_common_head *com, tree union_type, bool is_init) { gfc_symbol *common_sym; tree decl; /* Create a namespace to store symbols for common blocks. */ if (gfc_common_ns == NULL) gfc_common_ns = gfc_get_namespace (NULL, 0); gfc_get_symbol (com->name, gfc_common_ns, &common_sym); decl = common_sym->backend_decl; /* Update the size of this common block as needed. */ if (decl != NULL_TREE) { tree size = TYPE_SIZE_UNIT (union_type); /* Named common blocks of the same name shall be of the same size in all scoping units of a program in which they appear, but blank common blocks may be of different sizes. */ if (!tree_int_cst_equal (DECL_SIZE_UNIT (decl), size) && strcmp (com->name, BLANK_COMMON_NAME)) gfc_warning ("Named COMMON block '%s' at %L shall be of the " "same size as elsewhere (%lu vs %lu bytes)", com->name, &com->where, (unsigned long) TREE_INT_CST_LOW (size), (unsigned long) TREE_INT_CST_LOW (DECL_SIZE_UNIT (decl))); if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size)) { DECL_SIZE (decl) = TYPE_SIZE (union_type); DECL_SIZE_UNIT (decl) = size; DECL_MODE (decl) = TYPE_MODE (union_type); TREE_TYPE (decl) = union_type; layout_decl (decl, 0); } } /* If this common block has been declared in a previous program unit, and either it is already initialized or there is no new initialization for it, just return. */ if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl))) return decl; /* If there is no backend_decl for the common block, build it. */ if (decl == NULL_TREE) { decl = build_decl (input_location, VAR_DECL, get_identifier (com->name), union_type); gfc_set_decl_assembler_name (decl, gfc_sym_mangled_common_id (com)); TREE_PUBLIC (decl) = 1; TREE_STATIC (decl) = 1; DECL_IGNORED_P (decl) = 1; if (!com->is_bind_c) DECL_ALIGN (decl) = BIGGEST_ALIGNMENT; else { /* Do not set the alignment for bind(c) common blocks to BIGGEST_ALIGNMENT because that won't match what C does. Also, for common blocks with one element, the alignment must be that of the field within the common block in order to match what C will do. */ tree field = NULL_TREE; field = TYPE_FIELDS (TREE_TYPE (decl)); if (DECL_CHAIN (field) == NULL_TREE) DECL_ALIGN (decl) = TYPE_ALIGN (TREE_TYPE (field)); } DECL_USER_ALIGN (decl) = 0; GFC_DECL_COMMON_OR_EQUIV (decl) = 1; gfc_set_decl_location (decl, &com->where); if (com->threadprivate) DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); /* Place the back end declaration for this common block in GLOBAL_BINDING_LEVEL. */ common_sym->backend_decl = pushdecl_top_level (decl); } /* Has no initial values. */ if (!is_init) { DECL_INITIAL (decl) = NULL_TREE; DECL_COMMON (decl) = 1; DECL_DEFER_OUTPUT (decl) = 1; } else { DECL_INITIAL (decl) = error_mark_node; DECL_COMMON (decl) = 0; DECL_DEFER_OUTPUT (decl) = 0; } return decl; }
static tree get_init_field (segment_info *head, tree union_type, tree *field_init, record_layout_info rli) { segment_info *s; HOST_WIDE_INT length = 0; HOST_WIDE_INT offset = 0; unsigned HOST_WIDE_INT known_align, desired_align; bool overlap = false; tree tmp, field; tree init; unsigned char *data, *chk; VEC(constructor_elt,gc) *v = NULL; tree type = unsigned_char_type_node; int i; /* Obtain the size of the union and check if there are any overlapping initializers. */ for (s = head; s; s = s->next) { HOST_WIDE_INT slen = s->offset + s->length; if (s->sym->value) { if (s->offset < offset) overlap = true; offset = slen; } length = length < slen ? slen : length; } if (!overlap) return NULL_TREE; /* Now absorb all the initializer data into a single vector, whilst checking for overlapping, unequal values. */ data = XCNEWVEC (unsigned char, (size_t)length); chk = XCNEWVEC (unsigned char, (size_t)length); /* TODO - change this when default initialization is implemented. */ memset (data, '\0', (size_t)length); memset (chk, '\0', (size_t)length); for (s = head; s; s = s->next) if (s->sym->value) gfc_merge_initializers (s->sym->ts, s->sym->value, &data[s->offset], &chk[s->offset], (size_t)s->length); for (i = 0; i < length; i++) CONSTRUCTOR_APPEND_ELT (v, NULL, build_int_cst (type, data[i])); free (data); free (chk); /* Build a char[length] array to hold the initializers. Much of what follows is borrowed from build_field, above. */ tmp = build_int_cst (gfc_array_index_type, length - 1); tmp = build_range_type (gfc_array_index_type, gfc_index_zero_node, tmp); tmp = build_array_type (type, tmp); field = build_decl (gfc_current_locus.lb->location, FIELD_DECL, NULL_TREE, tmp); known_align = BIGGEST_ALIGNMENT; desired_align = update_alignment_for_field (rli, field, known_align); if (desired_align > known_align) DECL_PACKED (field) = 1; DECL_FIELD_CONTEXT (field) = union_type; DECL_FIELD_OFFSET (field) = size_int (0); DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; SET_DECL_OFFSET_ALIGN (field, known_align); rli->offset = size_binop (MAX_EXPR, rli->offset, size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field), DECL_SIZE_UNIT (field))); init = build_constructor (TREE_TYPE (field), v); TREE_CONSTANT (init) = 1; *field_init = init; for (s = head; s; s = s->next) { if (s->sym->value == NULL) continue; gfc_free_expr (s->sym->value); s->sym->value = NULL; } return field; }
/* Return 1 if check CI against BOUNDS always pass, -1 if check CI against BOUNDS always fails and 0 if we cannot compute check result. */ static int chkp_get_check_result (struct check_info *ci, tree bounds) { gimple *bnd_def; address_t bound_val; int sign, res = 0; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Trying to compute result of the check\n"); fprintf (dump_file, " check: "); print_gimple_stmt (dump_file, ci->stmt, 0, 0); fprintf (dump_file, " address: "); chkp_print_addr (ci->addr); fprintf (dump_file, "\n bounds: "); print_generic_expr (dump_file, bounds, 0); fprintf (dump_file, "\n"); } if (TREE_CODE (bounds) != SSA_NAME) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: bounds tree code is not ssa_name\n"); return 0; } bnd_def = SSA_NAME_DEF_STMT (bounds); /* Currently we handle cases when bounds are result of bndmk or loaded static bounds var. */ if (gimple_code (bnd_def) == GIMPLE_CALL && gimple_call_fndecl (bnd_def) == chkp_bndmk_fndecl) { bound_val.pol.create (0); chkp_collect_value (gimple_call_arg (bnd_def, 0), bound_val); if (ci->type == CHECK_UPPER_BOUND) { address_t size_val; size_val.pol.create (0); chkp_collect_value (gimple_call_arg (bnd_def, 1), size_val); chkp_add_addr_addr (bound_val, size_val); size_val.pol.release (); chkp_add_addr_item (bound_val, integer_minus_one_node, NULL); } } else if (gimple_code (bnd_def) == GIMPLE_ASSIGN && gimple_assign_rhs1 (bnd_def) == chkp_get_zero_bounds_var ()) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: always pass with zero bounds\n"); return 1; } else if (gimple_code (bnd_def) == GIMPLE_ASSIGN && gimple_assign_rhs1 (bnd_def) == chkp_get_none_bounds_var ()) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: always fails with none bounds\n"); return -1; } else if (gimple_code (bnd_def) == GIMPLE_ASSIGN && TREE_CODE (gimple_assign_rhs1 (bnd_def)) == VAR_DECL) { tree bnd_var = gimple_assign_rhs1 (bnd_def); tree var; tree size; if (!DECL_INITIAL (bnd_var) || DECL_INITIAL (bnd_var) == error_mark_node) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: cannot compute bounds\n"); return 0; } gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var)) == ADDR_EXPR); var = TREE_OPERAND (DECL_INITIAL (bnd_var), 0); bound_val.pol.create (0); chkp_collect_value (DECL_INITIAL (bnd_var), bound_val); if (ci->type == CHECK_UPPER_BOUND) { if (TREE_CODE (var) == VAR_DECL) { if (DECL_SIZE (var) && !chkp_variable_size_type (TREE_TYPE (var))) size = DECL_SIZE_UNIT (var); else { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: cannot compute bounds\n"); return 0; } } else { gcc_assert (TREE_CODE (var) == STRING_CST); size = build_int_cst (size_type_node, TREE_STRING_LENGTH (var)); } address_t size_val; size_val.pol.create (0); chkp_collect_value (size, size_val); chkp_add_addr_addr (bound_val, size_val); size_val.pol.release (); chkp_add_addr_item (bound_val, integer_minus_one_node, NULL); } } else { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: cannot compute bounds\n"); return 0; } if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, " bound value: "); chkp_print_addr (bound_val); fprintf (dump_file, "\n"); } chkp_sub_addr_addr (bound_val, ci->addr); if (!chkp_is_constant_addr (bound_val, &sign)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: cannot compute result\n"); res = 0; } else if (sign == 0 || (ci->type == CHECK_UPPER_BOUND && sign > 0) || (ci->type == CHECK_LOWER_BOUND && sign < 0)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: always pass\n"); res = 1; } else { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " result: always fail\n"); res = -1; } bound_val.pol.release (); return res; }