/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004 Free Software Foundation, Inc.
+ 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Gary Funck (gary@intrepid.com).
Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
Extensively modified by Jason Merrill (jason@cygnus.com).
/* Various versions of targetm.eh_frame_section. Note these must appear
outside the DWARF2_DEBUGGING_INFO || DWARF2_UNWIND_INFO macro guards. */
-/* Version of targetm.eh_frame_section for systems with named sections. */
+/* Version of targetm.eh_frame_section for systems with named sections. */
void
named_section_eh_frame_section (void)
{
#ifdef EH_FRAME_SECTION_NAME
-#ifdef HAVE_LD_RO_RW_SECTION_MIXING
- int fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
- int per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
- int lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
int flags;
- flags = (! flag_pic
- || ((fde_encoding & 0x70) != DW_EH_PE_absptr
- && (fde_encoding & 0x70) != DW_EH_PE_aligned
- && (per_encoding & 0x70) != DW_EH_PE_absptr
- && (per_encoding & 0x70) != DW_EH_PE_aligned
- && (lsda_encoding & 0x70) != DW_EH_PE_absptr
- && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
- ? 0 : SECTION_WRITE;
+ if (EH_TABLES_CAN_BE_READ_ONLY)
+ {
+ int fde_encoding;
+ int per_encoding;
+ int lsda_encoding;
+
+ fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
+ per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
+ lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
+ flags = (! flag_pic
+ || ((fde_encoding & 0x70) != DW_EH_PE_absptr
+ && (fde_encoding & 0x70) != DW_EH_PE_aligned
+ && (per_encoding & 0x70) != DW_EH_PE_absptr
+ && (per_encoding & 0x70) != DW_EH_PE_aligned
+ && (lsda_encoding & 0x70) != DW_EH_PE_absptr
+ && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
+ ? 0 : SECTION_WRITE;
+ }
+ else
+ flags = SECTION_WRITE;
named_section_flags (EH_FRAME_SECTION_NAME, flags);
-#else
- named_section_flags (EH_FRAME_SECTION_NAME, SECTION_WRITE);
-#endif
#endif
}
-/* Version of targetm.eh_frame_section for systems using collect2. */
+/* Version of targetm.eh_frame_section for systems using collect2. */
void
collect2_eh_frame_section (void)
{
static GTY(()) varray_type used_rtx_varray;
/* A pointer to the base of a list of incomplete types which might be
- completed at some later time. incomplete_types_list needs to be a VARRAY
- because we want to tell the garbage collector about it. */
-static GTY(()) varray_type incomplete_types;
+ completed at some later time. incomplete_types_list needs to be a
+ VEC(tree,gc) because we want to tell the garbage collector about
+ it. */
+static GTY(()) VEC(tree,gc) *incomplete_types;
/* A pointer to the base of a table of references to declaration
scopes. This table is a display which tracks the nesting
of declaration scopes at the current scope and containing
scopes. This table is used to find the proper place to
define type declaration DIE's. */
-static GTY(()) varray_type decl_scope_table;
+static GTY(()) VEC(tree,gc) *decl_scope_table;
/* How to start an assembler comment. */
#ifndef ASM_COMMENT_START
const char *dw_fde_begin;
const char *dw_fde_current_label;
const char *dw_fde_end;
+ const char *dw_fde_hot_section_label;
+ const char *dw_fde_hot_section_end_label;
+ const char *dw_fde_unlikely_section_label;
+ const char *dw_fde_unlikely_section_end_label;
+ bool dw_fde_switched_sections;
dw_cfi_ref dw_fde_cfi;
unsigned funcdef_number;
unsigned all_throwers_are_sibcalls : 1;
static HOST_WIDE_INT stack_adjust_offset (rtx);
static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
static void output_call_frame_info (int);
-static void dwarf2out_stack_adjust (rtx);
+static void dwarf2out_stack_adjust (rtx, bool);
static void flush_queued_reg_saves (void);
static bool clobbers_queued_reg_save (rtx);
static void dwarf2out_frame_debug_expr (rtx, const char *);
much extra space it needs to pop off the stack. */
static void
-dwarf2out_stack_adjust (rtx insn)
+dwarf2out_stack_adjust (rtx insn, bool after_p)
{
HOST_WIDE_INT offset;
const char *label;
if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn))
return;
- if (!flag_asynchronous_unwind_tables && CALL_P (insn))
+ /* If only calls can throw, and we have a frame pointer,
+ save up adjustments until we see the CALL_INSN. */
+ if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
{
- /* Extract the size of the args from the CALL rtx itself. */
- insn = PATTERN (insn);
- if (GET_CODE (insn) == PARALLEL)
- insn = XVECEXP (insn, 0, 0);
- if (GET_CODE (insn) == SET)
- insn = SET_SRC (insn);
- gcc_assert (GET_CODE (insn) == CALL);
-
- dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
+ if (CALL_P (insn) && !after_p)
+ {
+ /* Extract the size of the args from the CALL rtx itself. */
+ insn = PATTERN (insn);
+ if (GET_CODE (insn) == PARALLEL)
+ insn = XVECEXP (insn, 0, 0);
+ if (GET_CODE (insn) == SET)
+ insn = SET_SRC (insn);
+ gcc_assert (GET_CODE (insn) == CALL);
+ dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
+ }
return;
}
- /* If only calls can throw, and we have a frame pointer,
- save up adjustments until we see the CALL_INSN. */
- else if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
- return;
-
- if (BARRIER_P (insn))
+ if (CALL_P (insn) && !after_p)
+ {
+ if (!flag_asynchronous_unwind_tables)
+ dwarf2out_args_size ("", args_size);
+ return;
+ }
+ else if (BARRIER_P (insn))
{
/* When we see a BARRIER, we know to reset args_size to 0. Usually
the compiler will have already emitted a stack adjustment, but
label = dwarf2out_cfi_label ();
def_cfa_1 (label, &cfa);
- dwarf2out_args_size (label, args_size);
+ if (flag_asynchronous_unwind_tables)
+ dwarf2out_args_size (label, args_size);
}
#endif
more efficient data structure. */
static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4];
static GTY(()) size_t num_regs_saved_in_regs;
-
+
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
static const char *last_reg_save_label;
unsigned int regn = REGNO (reg);
size_t i;
struct queued_reg_save *q;
-
+
for (q = queued_reg_saves; q; q = q->next)
if (q->saved_reg && regn == REGNO (q->saved_reg))
return q->reg;
the intent is to save the value of SP from the previous frame.
In addition, if a register has previously been saved to a different
- register,
+ register,
Invariants / Summaries of Rules
(set (mem (postinc <reg1>:cfa_temp <const_int>)) <reg2>)
effects: cfa.reg = <reg1>
cfa.base_offset = -cfa_temp.offset
- cfa_temp.offset -= mode_size(mem) */
+ cfa_temp.offset -= mode_size(mem)
+
+ Rule 15:
+ (set <reg> {unspec, unspec_volatile})
+ effects: target-dependent */
static void
dwarf2out_frame_debug_expr (rtx expr, const char *label)
src = SET_SRC (expr);
dest = SET_DEST (expr);
- if (GET_CODE (src) == REG)
+ if (REG_P (src))
{
rtx rsi = reg_saved_in (src);
if (rsi)
{
/* Rule 1 */
/* Update the CFA rule wrt SP or FP. Make sure src is
- relative to the current CFA register.
+ relative to the current CFA register.
We used to require that dest be either SP or FP, but the
ARM copies SP to a temporary register, and from there to
{
/* Saving a register in a register. */
gcc_assert (call_used_regs [REGNO (dest)]
- && !fixed_regs [REGNO (dest)]);
+ && (!fixed_regs [REGNO (dest)]
+ /* For the SPARC and its register window. */
+ || DWARF_FRAME_REGNUM (REGNO (src))
+ == DWARF_FRAME_RETURN_COLUMN));
queue_reg_save (label, src, dest, 0);
}
break;
case HIGH:
break;
+ /* Rule 15 */
+ case UNSPEC:
+ case UNSPEC_VOLATILE:
+ gcc_assert (targetm.dwarf_handle_frame_unspec);
+ targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
+ break;
+
default:
gcc_unreachable ();
}
case LO_SUM:
{
int regno;
-
+
gcc_assert (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT);
offset = INTVAL (XEXP (XEXP (dest, 0), 1));
if (GET_CODE (XEXP (dest, 0)) == MINUS)
offset = -offset;
regno = REGNO (XEXP (XEXP (dest, 0), 0));
-
+
if (cfa_store.reg == (unsigned) regno)
offset -= cfa_store.offset;
else
case REG:
{
int regno = REGNO (XEXP (dest, 0));
-
+
if (cfa_store.reg == (unsigned) regno)
offset = -cfa_store.offset;
else
/* Record call frame debugging information for INSN, which either
sets SP or FP (adjusting how we calculate the frame address) or saves a
- register to the stack. If INSN is NULL_RTX, initialize our state. */
+ register to the stack. If INSN is NULL_RTX, initialize our state.
+
+ If AFTER_P is false, we're being called before the insn is emitted,
+ otherwise after. Call instructions get invoked twice. */
void
-dwarf2out_frame_debug (rtx insn)
+dwarf2out_frame_debug (rtx insn, bool after_p)
{
const char *label;
rtx src;
if (insn == NULL_RTX)
{
size_t i;
-
+
/* Flush any queued register saves. */
flush_queued_reg_saves ();
cfa_store = cfa;
cfa_temp.reg = -1;
cfa_temp.offset = 0;
-
+
for (i = 0; i < num_regs_saved_in_regs; i++)
{
regs_saved_in_regs[i].orig_reg = NULL_RTX;
if (! RTX_FRAME_RELATED_P (insn))
{
if (!ACCUMULATE_OUTGOING_ARGS)
- dwarf2out_stack_adjust (insn);
-
+ dwarf2out_stack_adjust (insn, after_p);
return;
}
/* If we make FDEs linkonce, we may have to emit an empty label for
an FDE that wouldn't otherwise be emitted. We want to avoid
having an FDE kept around when the function it refers to is
- discarded. (Example where this matters: a primary function
+ discarded. Example where this matters: a primary function
template in C++ requires EH information, but an explicit
specialization doesn't. */
if (TARGET_USES_WEAK_UNWIND_INFO
for (i = 0; i < fde_table_in_use; i++)
if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
&& !fde_table[i].uses_eh_lsda
- && ! DECL_ONE_ONLY (fde_table[i].decl))
+ && ! DECL_WEAK (fde_table[i].decl))
targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
for_eh, /* empty */ 1);
for (i = 0; i < fde_table_in_use; i++)
if (fde_table[i].uses_eh_lsda)
any_eh_needed = any_lsda_needed = true;
- else if (TARGET_USES_WEAK_UNWIND_INFO
- && DECL_ONE_ONLY (fde_table[i].decl))
+ else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
any_eh_needed = true;
else if (! fde_table[i].nothrow
&& ! fde_table[i].all_throwers_are_sibcalls)
/* Don't emit EH unwind info for leaf functions that don't need it. */
if (for_eh && !flag_asynchronous_unwind_tables && flag_exceptions
&& (fde->nothrow || fde->all_throwers_are_sibcalls)
- && (! TARGET_USES_WEAK_UNWIND_INFO || ! DECL_ONE_ONLY (fde->decl))
+ && ! (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
&& !fde->uses_eh_lsda)
continue;
dw2_asm_output_encoded_addr_rtx (fde_encoding,
sym_ref,
"FDE initial location");
- dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
- fde->dw_fde_end, fde->dw_fde_begin,
- "FDE address range");
+ if (fde->dw_fde_switched_sections)
+ {
+ rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
+ fde->dw_fde_unlikely_section_label);
+ rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
+ fde->dw_fde_hot_section_label);
+ SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
+ SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3,
+ "FDE initial location");
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_hot_section_end_label,
+ fde->dw_fde_hot_section_label,
+ "FDE address range");
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2,
+ "FDE initial location");
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_unlikely_section_end_label,
+ fde->dw_fde_unlikely_section_label,
+ "FDE address range");
+ }
+ else
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
"FDE initial location");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE,
- fde->dw_fde_end, fde->dw_fde_begin,
- "FDE address range");
+ if (fde->dw_fde_switched_sections)
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ fde->dw_fde_hot_section_label,
+ "FDE initial location");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_hot_section_end_label,
+ fde->dw_fde_hot_section_label,
+ "FDE address range");
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ fde->dw_fde_unlikely_section_label,
+ "FDE initial location");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_unlikely_section_end_label,
+ fde->dw_fde_unlikely_section_label,
+ "FDE address range");
+ }
+ else
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
}
if (augmentation[0])
fde->decl = current_function_decl;
fde->dw_fde_begin = dup_label;
fde->dw_fde_current_label = NULL;
+ fde->dw_fde_hot_section_label = NULL;
+ fde->dw_fde_hot_section_end_label = NULL;
+ fde->dw_fde_unlikely_section_label = NULL;
+ fde->dw_fde_unlikely_section_end_label = NULL;
+ fde->dw_fde_switched_sections = false;
fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
fde->funcdef_number = current_function_funcdef_no;
dwarf2out_frame_finish (void)
{
/* Output call frame information. */
- if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+ if (write_symbols == DWARF2_DEBUG
+ || write_symbols == VMS_AND_DWARF2_DEBUG
+#ifdef DWARF2_FRAME_INFO
+ || DWARF2_FRAME_INFO
+#endif
+ )
output_call_frame_info (0);
#ifndef TARGET_UNWIND_INFO
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx);
static void dwarf2out_begin_function (tree);
+static void dwarf2out_switch_text_section (void);
/* The debug hooks structure. */
dwarf2out_abstract_function, /* outlining_inline_function */
debug_nothing_rtx, /* label */
debug_nothing_int, /* handle_pch */
- dwarf2out_var_location
+ dwarf2out_var_location,
+ dwarf2out_switch_text_section,
+ 1 /* start_end_main_source_file */
};
#endif
\f
{
rtx GTY (()) var_loc_note;
const char * GTY (()) label;
+ const char * GTY (()) section_label;
struct var_loc_node * GTY (()) next;
};
static const char *dwarf_tag_name (unsigned);
static const char *dwarf_attr_name (unsigned);
static const char *dwarf_form_name (unsigned);
-#if 0
-static const char *dwarf_type_encoding_name (unsigned);
-#endif
static tree decl_ultimate_origin (tree);
static tree block_ultimate_origin (tree);
static tree decl_class_context (tree);
static inline int local_scope_p (dw_die_ref);
static inline int class_or_namespace_scope_p (dw_die_ref);
static void add_type_attribute (dw_die_ref, tree, int, int, dw_die_ref);
+static void add_calling_convention_attribute (dw_die_ref, tree);
static const char *type_tag (tree);
static tree member_declared_type (tree);
#if 0
static const char *decl_start_label (tree);
#endif
static void gen_array_type_die (tree, dw_die_ref);
-static void gen_set_type_die (tree, dw_die_ref);
#if 0
static void gen_entry_point_die (tree, dw_die_ref);
#endif
#ifndef TEXT_SECTION_LABEL
#define TEXT_SECTION_LABEL "Ltext"
#endif
+#ifndef COLD_TEXT_SECTION_LABEL
+#define COLD_TEXT_SECTION_LABEL "Ltext_cold"
+#endif
#ifndef DEBUG_LINE_SECTION_LABEL
#define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
#endif
static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char cold_text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
#ifndef TEXT_END_LABEL
#define TEXT_END_LABEL "Letext"
#endif
+#ifndef COLD_END_LABEL
+#define COLD_END_LABEL "Letext_cold"
+#endif
#ifndef BLOCK_BEGIN_LABEL
#define BLOCK_BEGIN_LABEL "LBB"
#endif
#endif
\f
/* We allow a language front-end to designate a function that is to be
- called to "demangle" any name before it it put into a DIE. */
+ called to "demangle" any name before it is put into a DIE. */
static const char *(*demangle_name_func) (const char *);
return "DW_FORM_<unknown>";
}
}
-
-/* Convert a DWARF type code into its string name. */
-
-#if 0
-static const char *
-dwarf_type_encoding_name (unsigned enc)
-{
- switch (enc)
- {
- case DW_ATE_address:
- return "DW_ATE_address";
- case DW_ATE_boolean:
- return "DW_ATE_boolean";
- case DW_ATE_complex_float:
- return "DW_ATE_complex_float";
- case DW_ATE_float:
- return "DW_ATE_float";
- case DW_ATE_signed:
- return "DW_ATE_signed";
- case DW_ATE_signed_char:
- return "DW_ATE_signed_char";
- case DW_ATE_unsigned:
- return "DW_ATE_unsigned";
- case DW_ATE_unsigned_char:
- return "DW_ATE_unsigned_char";
- default:
- return "DW_ATE_<unknown>";
- }
-}
-#endif
\f
/* Determine the "ultimate origin" of a decl. The decl may be an inlined
instance of an inlined instance of a decl which is local to an inline
? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
}
while (lookahead != NULL && lookahead != ret_val);
+
+ /* The block's abstract origin chain may not be the *ultimate* origin of
+ the block. It could lead to a DECL that has an abstract origin set.
+ If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
+ will give us if it has one). Note that DECL's abstract origins are
+ supposed to be the most distant ancestor (or so decl_ultimate_origin
+ claims), so we don't need to loop following the DECL origins. */
+ if (DECL_P (ret_val))
+ return DECL_ORIGIN (ret_val);
return ret_val;
}
char label[32];
gcc_assert (a && AT_class (a) == dw_val_class_str);
-
+
node = a->dw_attr_val.v.val_str;
if (node->form)
return node->form;
-
+
len = strlen (node->str) + 1;
/* If the string is shorter or equal to the size of the reference, it is
*d = new_loc_list (descr, begin, end, section, 0);
}
+static void
+dwarf2out_switch_text_section (void)
+{
+ dw_fde_ref fde;
+
+ if (!cfun)
+ internal_error ("Attempt to switch text sections without any code.");
+
+ fde = &fde_table[fde_table_in_use - 1];
+ fde->dw_fde_switched_sections = true;
+ fde->dw_fde_hot_section_label = cfun->hot_section_label;
+ fde->dw_fde_hot_section_end_label = cfun->hot_section_end_label;
+ fde->dw_fde_unlikely_section_label = cfun->cold_section_label;
+ fde->dw_fde_unlikely_section_end_label = cfun->cold_section_end_label;
+ separate_line_info_table_in_use++;
+}
+
/* Output the location list given to us. */
static void
dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
text_section_label, "Length");
+ if (flag_reorder_blocks_and_partition)
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
+ "Address");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
+ cold_text_section_label, "Length");
+ }
for (i = 0; i < arange_table_in_use; i++)
{
a series of state machine operations. */
current_file = 1;
current_line = 1;
- strcpy (prev_line_label, text_section_label);
+
+ if (cfun
+ && (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name == cfun->unlikely_text_section_name)))
+ strcpy (prev_line_label, cfun->cold_section_label);
+ else
+ strcpy (prev_line_label, text_section_label);
for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
{
dw_line_info_ref line_info = &line_info_table[lt_index];
case CHAR_TYPE:
return 1;
- case SET_TYPE:
case ARRAY_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
case METHOD_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
- case FILE_TYPE:
case OFFSET_TYPE:
case LANG_TYPE:
case VECTOR_TYPE:
case ASHIFT:
op = DW_OP_shl;
goto do_binop;
-
+
case ASHIFTRT:
op = DW_OP_shra;
goto do_binop;
concat_loc_descriptor (rtx x0, rtx x1)
{
dw_loc_descr_ref cc_loc_result = NULL;
- dw_loc_descr_ref x0_ref = loc_descriptor (x0, true);
- dw_loc_descr_ref x1_ref = loc_descriptor (x1, true);
+ dw_loc_descr_ref x0_ref = loc_descriptor (x0, false);
+ dw_loc_descr_ref x1_ref = loc_descriptor (x1, false);
if (x0_ref == 0 || x1_ref == 0)
return 0;
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
- return loc_descriptor (rtl, true);
+ return loc_descriptor (rtl, false);
mode = GET_MODE (rtl);
if (MEM_P (rtl))
rtl = XEXP (rtl, 0);
have_address = 1;
}
- ret = mem_loc_descriptor (rtl, mode, true);
+ ret = mem_loc_descriptor (rtl, mode, false);
}
}
break;
int volatilep;
obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
- &unsignedp, &volatilep);
+ &unsignedp, &volatilep, false);
if (obj == loc)
return 0;
return 0;
mode = GET_MODE (rtl);
rtl = XEXP (rtl, 0);
- ret = mem_loc_descriptor (rtl, mode, true);
+ ret = mem_loc_descriptor (rtl, mode, false);
have_address = 1;
break;
}
}
break;
+ case FIX_TRUNC_EXPR:
+ case FIX_CEIL_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ return 0;
+
default:
/* Leave front-end specific codes as simply unknown. This comes
up, for instance, with the C STMT_EXPR. */
#ifdef ENABLE_CHECKING
/* Otherwise this is a generic code; we should just lists all of
- these explicitly. Aborting means we forgot one. */
+ these explicitly. We forgot one. */
gcc_unreachable ();
#else
/* In a release build, we want to degrade gracefully: better to
if (TREE_CODE (decl) == ERROR_MARK)
return 0;
-
+
gcc_assert (TREE_CODE (decl) == FIELD_DECL);
type = field_type (decl);
if (val < 0)
add_AT_int (die, DW_AT_const_value, val);
- else
+ else
add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
}
break;
{
rtx elt = CONST_VECTOR_ELT (rtl, i);
HOST_WIDE_INT lo, hi;
-
+
switch (GET_CODE (elt))
{
case CONST_INT:
lo = INTVAL (elt);
hi = -(lo < 0);
break;
-
+
case CONST_DOUBLE:
lo = CONST_DOUBLE_LOW (elt);
hi = CONST_DOUBLE_HIGH (elt);
break;
-
+
default:
gcc_unreachable ();
}
-
+
if (elt_size <= sizeof (HOST_WIDE_INT))
insert_int (lo, elt_size, p);
else
{
unsigned char *p0 = p;
unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
-
+
gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
if (WORDS_BIG_ENDIAN)
{
}
+/* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
+ for use in a later add_const_value_attribute call. */
+
+static rtx
+rtl_for_decl_init (tree init, tree type)
+{
+ rtx rtl = NULL_RTX;
+
+ /* If a variable is initialized with a string constant without embedded
+ zeros, build CONST_STRING. */
+ if (TREE_CODE (init) == STRING_CST && TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree enttype = TREE_TYPE (type);
+ tree domain = TYPE_DOMAIN (type);
+ enum machine_mode mode = TYPE_MODE (enttype);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
+ && domain
+ && integer_zerop (TYPE_MIN_VALUE (domain))
+ && compare_tree_int (TYPE_MAX_VALUE (domain),
+ TREE_STRING_LENGTH (init) - 1) == 0
+ && ((size_t) TREE_STRING_LENGTH (init)
+ == strlen (TREE_STRING_POINTER (init)) + 1))
+ rtl = gen_rtx_CONST_STRING (VOIDmode,
+ ggc_strdup (TREE_STRING_POINTER (init)));
+ }
+ /* If the initializer is something that we know will expand into an
+ immediate RTL constant, expand it now. Expanding anything else
+ tends to produce unresolved symbols; see debug/5770 and c++/6381. */
+ /* Aggregate, vector, and complex types may contain constructors that may
+ result in code being generated when expand_expr is called, so we can't
+ handle them here. Integer and float are useful and safe types to handle
+ here. */
+ else if ((INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
+ && initializer_constant_valid_p (init, type) == null_pointer_node)
+ {
+ rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+
+ /* If expand_expr returns a MEM, it wasn't immediate. */
+ gcc_assert (!rtl || !MEM_P (rtl));
+ }
+
+ return rtl;
+}
+
+/* Generate RTL for the variable DECL to represent its location. */
+
static rtx
rtl_for_decl_location (tree decl)
{
{
if (rtl == NULL_RTX || is_pseudo_reg (rtl))
{
- tree declared_type = type_main_variant (TREE_TYPE (decl));
- tree passed_type = type_main_variant (DECL_ARG_TYPE (decl));
+ tree declared_type = TREE_TYPE (decl);
+ tree passed_type = DECL_ARG_TYPE (decl);
+ enum machine_mode dmode = TYPE_MODE (declared_type);
+ enum machine_mode pmode = TYPE_MODE (passed_type);
/* This decl represents a formal parameter which was optimized out.
Note that DECL_INCOMING_RTL may be NULL in here, but we handle
all cases where (rtl == NULL_RTX) just below. */
- if (declared_type == passed_type)
- rtl = DECL_INCOMING_RTL (decl);
- else if (! BYTES_BIG_ENDIAN
- && TREE_CODE (declared_type) == INTEGER_TYPE
- && (GET_MODE_SIZE (TYPE_MODE (declared_type))
- <= GET_MODE_SIZE (TYPE_MODE (passed_type))))
+ if (dmode == pmode)
rtl = DECL_INCOMING_RTL (decl);
+ else if (SCALAR_INT_MODE_P (dmode)
+ && GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode)
+ && DECL_INCOMING_RTL (decl))
+ {
+ rtx inc = DECL_INCOMING_RTL (decl);
+ if (REG_P (inc))
+ rtl = inc;
+ else if (MEM_P (inc))
+ {
+ if (BYTES_BIG_ENDIAN)
+ rtl = adjust_address_nv (inc, dmode,
+ GET_MODE_SIZE (pmode)
+ - GET_MODE_SIZE (dmode));
+ else
+ rtl = inc;
+ }
+ }
}
/* If the parm was passed in registers, but lives on the stack, then
and will have been substituted directly into all expressions that use it.
C does not have such a concept, but C++ and other languages do. */
else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
- {
- /* If a variable is initialized with a string constant without embedded
- zeros, build CONST_STRING. */
- if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
- && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
- {
- tree arrtype = TREE_TYPE (decl);
- tree enttype = TREE_TYPE (arrtype);
- tree domain = TYPE_DOMAIN (arrtype);
- tree init = DECL_INITIAL (decl);
- enum machine_mode mode = TYPE_MODE (enttype);
-
- if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
- && domain
- && integer_zerop (TYPE_MIN_VALUE (domain))
- && compare_tree_int (TYPE_MAX_VALUE (domain),
- TREE_STRING_LENGTH (init) - 1) == 0
- && ((size_t) TREE_STRING_LENGTH (init)
- == strlen (TREE_STRING_POINTER (init)) + 1))
- rtl = gen_rtx_CONST_STRING (VOIDmode,
- ggc_strdup (TREE_STRING_POINTER (init)));
- }
- /* If the initializer is something that we know will expand into an
- immediate RTL constant, expand it now. Expanding anything else
- tends to produce unresolved symbols; see debug/5770 and c++/6381. */
- else if (TREE_CODE (DECL_INITIAL (decl)) == INTEGER_CST
- || TREE_CODE (DECL_INITIAL (decl)) == REAL_CST)
- {
- rtl = expand_expr (DECL_INITIAL (decl), NULL_RTX, VOIDmode,
- EXPAND_INITIALIZER);
- /* If expand_expr returns a MEM, it wasn't immediate. */
- gcc_assert (!rtl || !MEM_P (rtl));
- }
- }
+ rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
if (rtl)
rtl = targetm.delegitimize_address (rtl);
return rtl;
}
+/* Return true if DECL's containing function has a frame base attribute.
+ Return false otherwise. */
+
+static bool
+containing_function_has_frame_base (tree decl)
+{
+ tree declcontext = decl_function_context (decl);
+ dw_die_ref context;
+ dw_attr_ref attr;
+
+ if (!declcontext)
+ return false;
+
+ context = lookup_decl_die (declcontext);
+ if (!context)
+ return false;
+
+ for (attr = context->die_attr; attr; attr = attr->dw_attr_next)
+ if (attr->dw_attr == DW_AT_frame_base)
+ return true;
+ return false;
+}
+
/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
data attribute for a variable or a parameter. We generate the
DW_AT_const_value attribute only in those cases where the given variable
rtx rtl;
dw_loc_descr_ref descr;
var_loc_list *loc_list;
-
+ bool can_use_fb;
+ struct var_loc_node *node;
if (TREE_CODE (decl) == ERROR_MARK)
return;
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL);
+
+ can_use_fb = containing_function_has_frame_base (decl);
/* See if we possibly have multiple locations for this variable. */
loc_list = lookup_decl_loc (decl);
const char *endname;
dw_loc_list_ref list;
rtx varloc;
- struct var_loc_node *node;
/* We need to figure out what section we should use as the base
for the address ranges where a given location is valid.
tree sectree = DECL_SECTION_NAME (current_function_decl);
secname = TREE_STRING_POINTER (sectree);
}
+ else if (cfun
+ && (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name ==
+ cfun->unlikely_text_section_name)))
+ secname = cfun->cold_section_label;
else
secname = text_section_label;
node = loc_list->first;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- list = new_loc_list (loc_descriptor (varloc, attr != DW_AT_frame_base),
+ list = new_loc_list (loc_descriptor (varloc, can_use_fb),
node->label, node->next->label, secname, 1);
node = node->next;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
add_loc_descr_to_loc_list (&list,
loc_descriptor (varloc,
- attr != DW_AT_frame_base),
+ can_use_fb),
node->label, node->next->label, secname);
}
}
add_loc_descr_to_loc_list (&list,
loc_descriptor (varloc,
- attr != DW_AT_frame_base),
+ can_use_fb),
node->label, endname, secname);
}
return;
}
+ /* Try to get some constant RTL for this decl, and use that as the value of
+ the location. */
+
rtl = rtl_for_decl_location (decl);
if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
{
add_const_value_attribute (die, rtl);
return;
}
-
+
+ /* We couldn't get any rtl, and we had no >1 element location list, so try
+ directly generating the location description from the tree. */
descr = loc_descriptor_from_tree (decl);
if (descr)
- add_AT_location_description (die, attr, descr);
+ {
+ add_AT_location_description (die, attr, descr);
+ return;
+ }
+
+ /* Lastly, if we have tried to generate the location otherwise, and it
+ didn't work out (we wouldn't be here if we did), and we have a one entry
+ location list, try generating a location from that. */
+ if (loc_list && loc_list->first)
+ {
+ node = loc_list->first;
+ descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note),
+ can_use_fb);
+ if (descr)
+ add_AT_location_description (die, attr, descr);
+ }
}
/* If we don't have a copy of this variable in memory for some reason (such
{
tree init = DECL_INITIAL (decl);
tree type = TREE_TYPE (decl);
+ rtx rtl;
- if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init
- && initializer_constant_valid_p (init, type) == null_pointer_node)
+ if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init)
/* OK */;
else
return;
- switch (TREE_CODE (type))
- {
- case INTEGER_TYPE:
- if (host_integerp (init, 0))
- add_AT_unsigned (var_die, DW_AT_const_value,
- tree_low_cst (init, 0));
- else
- add_AT_long_long (var_die, DW_AT_const_value,
- TREE_INT_CST_HIGH (init),
- TREE_INT_CST_LOW (init));
- break;
-
- default:;
- }
+ rtl = rtl_for_decl_init (init, type);
+ if (rtl)
+ add_const_value_attribute (var_die, rtl);
}
/* Generate a DW_AT_name attribute given some string value to be included as
if (TYPE_P (fn))
fn = TYPE_STUB_DECL (fn);
-
+
fn = decl_function_context (fn);
if (fn)
dwarf2out_abstract_function (fn);
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
- gcc_assert (origin_die);
+ /* XXX: Functions that are never lowered don't always have correct block
+ trees (in the case of java, they simply have no block tree, in some other
+ languages). For these functions, there is nothing we can really do to
+ output correct debug info for inlined functions in all cases. Rather
+ than die, we'll just produce deficient debug info now, in that we will
+ have variables without a proper abstract origin. In the future, when all
+ functions are lowered, we should re-add a gcc_assert (origin_die)
+ here. */
- add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
+ if (origin_die)
+ add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
}
/* We do not currently support the pure_virtual attribute. */
static void
push_decl_scope (tree scope)
{
- VARRAY_PUSH_TREE (decl_scope_table, scope);
+ VEC_safe_push (tree, gc, decl_scope_table, scope);
}
/* Pop a declaration scope. */
static inline void
pop_decl_scope (void)
{
- gcc_assert (VARRAY_ACTIVE_SIZE (decl_scope_table) > 0);
-
- VARRAY_POP (decl_scope_table);
+ VEC_pop (tree, decl_scope_table);
}
/* Return the DIE for the scope that immediately contains this type.
/* For types, we can just look up the appropriate DIE. But
first we check to see if we're in the middle of emitting it
so we know where the new DIE should go. */
- for (i = VARRAY_ACTIVE_SIZE (decl_scope_table) - 1; i >= 0; --i)
- if (VARRAY_TREE (decl_scope_table, i) == containing_scope)
+ for (i = VEC_length (tree, decl_scope_table) - 1; i >= 0; --i)
+ if (VEC_index (tree, decl_scope_table, i) == containing_scope)
break;
if (i < 0)
add_AT_die_ref (object_die, DW_AT_type, type_die);
}
+/* Given an object die, add the calling convention attribute for the
+ function call type. */
+static void
+add_calling_convention_attribute (dw_die_ref subr_die, tree type)
+{
+ enum dwarf_calling_convention value = DW_CC_normal;
+
+ value = targetm.dwarf_calling_convention (type);
+
+ /* Only add the attribute if the backend requests it, and
+ is not DW_CC_normal. */
+ if (value && (value != DW_CC_normal))
+ add_AT_unsigned (subr_die, DW_AT_calling_convention, value);
+}
+
/* Given a tree pointer to a struct, class, union, or enum type node, return
a pointer to the (string) tag name for the given type, or zero if the type
was declared without a tag. */
add_type_attribute (array_die, element_type, 0, 0, context_die);
}
-static void
-gen_set_type_die (tree type, dw_die_ref context_die)
-{
- dw_die_ref type_die
- = new_die (DW_TAG_set_type, scope_die_for (type, context_die), type);
-
- equate_type_number_to_die (type, type_die);
- add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die);
-}
-
#if 0
static void
gen_entry_point_die (tree decl, dw_die_ref context_die)
{
int i;
- for (i = VARRAY_ACTIVE_SIZE (incomplete_types) - 1; i >= 0; i--)
- gen_type_die (VARRAY_TREE (incomplete_types, i), comp_unit_die);
+ for (i = VEC_length (tree, incomplete_types) - 1; i >= 0; i--)
+ gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
}
/* Generate a DIE to represent an inlined instance of an enumeration type. */
if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
&& ! lookup_decl_die (member))
{
+ dw_die_ref type_die;
gcc_assert (!decl_ultimate_origin (member));
push_decl_scope (type);
+ type_die = lookup_type_die (type);
if (TREE_CODE (member) == FUNCTION_DECL)
- gen_subprogram_die (member, lookup_type_die (type));
+ gen_subprogram_die (member, type_die);
+ else if (TREE_CODE (member) == FIELD_DECL)
+ {
+ /* Ignore the nameless fields that are used to skip bits but handle
+ C++ anonymous unions and structs. */
+ if (DECL_NAME (member) != NULL_TREE
+ || TREE_CODE (TREE_TYPE (member)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)
+ {
+ gen_type_die (member_declared_type (member), type_die);
+ gen_field_die (member, type_die);
+ }
+ }
else
- gen_variable_die (member, lookup_type_die (type));
+ gen_variable_die (member, type_die);
pop_decl_scope ();
}
It seems reasonable to use AT_specification in this case. */
&& !get_AT (old_die, DW_AT_inline))
{
- /* ??? This can happen if there is a bug in the program, for
- instance, if it has duplicate function definitions. Ideally,
- we should detect this case and ignore it. For now, if we have
- already reported an error, any error at all, then assume that
- we got here because of an input error, not a dwarf2 bug. */
- gcc_assert (errorcount);
+ /* Detect and ignore this case, where we are trying to output
+ something we have already output. */
return;
}
subr_die = old_die;
/* Clear out the declaration attribute and the formal parameters.
- Do not remove all children, because it is possible that this
+ Do not remove all children, because it is possible that this
declaration die was forced using force_decl_die(). In such
cases die that forced declaration die (e.g. TAG_imported_module)
is one of the children that we do not want to remove. */
/* The first time we see a member function, it is in the context of
the class to which it belongs. We make sure of this by emitting
the class first. The next time is the definition, which is
- handled above. The two may come from the same source text.
+ handled above. The two may come from the same source text.
Note that force_decl_die() forces function declaration die. It is
later reused to represent definition. */
if (!old_die || !get_AT (old_die, DW_AT_inline))
equate_decl_number_to_die (decl, subr_die);
- ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
- current_function_funcdef_no);
- add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
- ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
- current_function_funcdef_no);
- add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
-
- add_pubname (decl, subr_die);
- add_arange (decl, subr_die);
+ if (!flag_reorder_blocks_and_partition)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
+ current_function_funcdef_no);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
+
+ add_pubname (decl, subr_die);
+ add_arange (decl, subr_die);
+ }
+ else
+ { /* Do nothing for now; maybe need to duplicate die, one for
+ hot section and ond for cold section, then use the hot/cold
+ section begin/end labels to generate the aranges... */
+ /*
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, hot_section_label);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, hot_section_end_label);
+ add_AT_lbl_id (subr_die, DW_AT_lo_user, unlikely_section_label);
+ add_AT_lbl_id (subr_die, DW_AT_hi_user, cold_section_end_label);
+
+ add_pubname (decl, subr_die);
+ add_arange (decl, subr_die);
+ add_arange (decl, subr_die);
+ */
+ }
#ifdef MIPS_DEBUGGING_INFO
/* Add a reference to the FDE for this routine. */
}
#endif
}
+ /* Add the calling convention attribute if requested. */
+ add_calling_convention_attribute (subr_die, TREE_TYPE (decl));
+
}
/* Generate a DIE to represent a declared data object. */
copy decls and set the DECL_ABSTRACT flag on them instead of
sharing them.
- ??? Duplicated blocks have been rewritten to use .debug_ranges. */
- else if (old_die && TREE_STATIC (decl)
+ ??? Duplicated blocks have been rewritten to use .debug_ranges.
+
+ ??? The declare_in_namespace support causes us to get two DIEs for one
+ variable, both of which are declarations. We want to avoid considering
+ one to be a specification, so we must test that this DIE is not a
+ declaration. */
+ else if (old_die && TREE_STATIC (decl) && ! declaration
&& get_AT_flag (old_die, DW_AT_declaration) == 1)
{
/* This is a definition of a C++ class level static. */
}
}
-/* Generate a DIE for a lexical block. */
+/* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
+ Add low_pc and high_pc attributes to the DIE for a block STMT. */
-static void
-gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
+static inline void
+add_high_low_attributes (tree stmt, dw_die_ref die)
{
- dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (! BLOCK_ABSTRACT (stmt))
+ if (BLOCK_FRAGMENT_CHAIN (stmt))
{
- if (BLOCK_FRAGMENT_CHAIN (stmt))
- {
- tree chain;
+ tree chain;
- add_AT_range_list (stmt_die, DW_AT_ranges, add_ranges (stmt));
+ add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
- chain = BLOCK_FRAGMENT_CHAIN (stmt);
- do
- {
- add_ranges (chain);
- chain = BLOCK_FRAGMENT_CHAIN (chain);
- }
- while (chain);
- add_ranges (NULL);
- }
- else
+ chain = BLOCK_FRAGMENT_CHAIN (stmt);
+ do
{
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
+ add_ranges (chain);
+ chain = BLOCK_FRAGMENT_CHAIN (chain);
}
+ while (chain);
+ add_ranges (NULL);
+ }
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+ BLOCK_NUMBER (stmt));
+ add_AT_lbl_id (die, DW_AT_low_pc, label);
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
+ BLOCK_NUMBER (stmt));
+ add_AT_lbl_id (die, DW_AT_high_pc, label);
}
+}
+
+/* Generate a DIE for a lexical block. */
+
+static void
+gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
+{
+ dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+
+ if (! BLOCK_ABSTRACT (stmt))
+ add_high_low_attributes (stmt, stmt_die);
decls_for_scope (stmt, stmt_die, depth);
}
{
dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
add_abstract_origin_attribute (subr_die, decl);
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (subr_die, DW_AT_low_pc, label);
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (subr_die, DW_AT_high_pc, label);
+ add_high_low_attributes (stmt, subr_die);
+
decls_for_scope (stmt, subr_die, depth);
current_function_has_inlines = 1;
}
/* First output info about the base classes. */
if (binfo)
{
- VEC (tree) *accesses = BINFO_BASE_ACCESSES (binfo);
+ VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo);
int i;
tree base;
/* We don't need to do this for function-local types. */
if (TYPE_STUB_DECL (type)
&& ! decl_function_context (TYPE_STUB_DECL (type)))
- VARRAY_PUSH_TREE (incomplete_types, type);
+ VEC_safe_push (tree, gc, incomplete_types, type);
}
}
gen_ptr_to_mbr_type_die (type, context_die);
break;
- case SET_TYPE:
- gen_type_die (TYPE_DOMAIN (type), context_die);
- gen_set_type_die (type, context_die);
- break;
-
- case FILE_TYPE:
- gen_type_die (TREE_TYPE (type), context_die);
- /* No way to represent these in Dwarf yet! */
- gcc_unreachable ();
- break;
-
case FUNCTION_TYPE:
/* Force out return type (in case it wasn't forced out already). */
gen_type_die (TREE_TYPE (type), context_die);
tree decl;
enum tree_code origin_code;
- /* Ignore blocks never really used to make RTL. */
- if (stmt == NULL_TREE || !TREE_USED (stmt)
- || (!TREE_ASM_WRITTEN (stmt) && !BLOCK_ABSTRACT (stmt)))
+ /* Ignore blocks that are NULL. */
+ if (stmt == NULL_TREE)
return;
/* If the block is one fragment of a non-contiguous block, do not
if (debug_info_level > DINFO_LEVEL_TERSE)
/* We are not in terse mode so *any* local declaration counts
as being a "significant" one. */
- must_output_die = (BLOCK_VARS (stmt) != NULL);
+ must_output_die = (BLOCK_VARS (stmt) != NULL
+ && (TREE_USED (stmt)
+ || TREE_ASM_WRITTEN (stmt)
+ || BLOCK_ABSTRACT (stmt)));
else
/* We are in terse mode, so only local (nested) function
definitions count as "significant" local declarations. */
tree decl;
tree subblocks;
- /* Ignore blocks never really used to make RTL. */
- if (stmt == NULL_TREE || ! TREE_USED (stmt))
+ /* Ignore NULL blocks. */
+ if (stmt == NULL_TREE)
return;
- /* Output the DIEs to represent all of the data objects and typedefs
- declared directly within this block but not within any nested
- sub-blocks. Also, nested function and tag DIEs have been
- generated with a parent of NULL; fix that up now. */
- for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
+ if (TREE_USED (stmt))
{
- dw_die_ref die;
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- die = lookup_decl_die (decl);
- else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
- die = lookup_type_die (TREE_TYPE (decl));
- else
- die = NULL;
-
- if (die != NULL && die->die_parent == NULL)
- add_child_die (context_die, die);
- else
- gen_decl_die (decl, context_die);
+ /* Output the DIEs to represent all of the data objects and typedefs
+ declared directly within this block but not within any nested
+ sub-blocks. Also, nested function and tag DIEs have been
+ generated with a parent of NULL; fix that up now. */
+ for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
+ {
+ dw_die_ref die;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ die = lookup_decl_die (decl);
+ else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
+ die = lookup_type_die (TREE_TYPE (decl));
+ else
+ die = NULL;
+
+ if (die != NULL && die->die_parent == NULL)
+ add_child_die (context_die, die);
+ else
+ gen_decl_die (decl, context_die);
+ }
}
/* If we're at -g1, we're not interested in subblocks. */
return 0;
}
-/* Returns the DIE for decl or aborts. */
+/* Returns the DIE for decl. A DIE will always be returned. */
static dw_die_ref
force_decl_die (tree decl)
save_fn = current_function_decl;
current_function_decl = NULL_TREE;
gen_subprogram_die (decl, context_die);
- current_function_decl = save_fn;
+ current_function_decl = save_fn;
break;
case VAR_DECL:
default:
gcc_unreachable ();
}
-
- /* See if we can find the die for this deci now.
- If not then abort. */
+
+ /* We should be able to find the DIE now. */
if (!decl_die)
decl_die = lookup_decl_die (decl);
gcc_assert (decl_die);
}
-
+
return decl_die;
}
-/* Returns the DIE for decl or aborts. */
+/* Returns the DIE for TYPE. A DIE is always returned. */
static dw_die_ref
force_type_die (tree type)
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
+ /* If this decl is from an inlined function, then don't try to emit it in its
+ namespace, as we will get confused. It would have already been emitted
+ when the abstract instance of the inline function was emitted anyways. */
+ if (DECL_P (thing) && DECL_ABSTRACT_ORIGIN (thing))
+ return;
+
ns_context = setup_namespace_context (thing, context_die);
if (ns_context != context_die)
dwarf2out_decl (decl);
}
-/* Output debug information for imported module or decl. */
-
+/* Output debug information for imported module or decl. */
+
static void
dwarf2out_imported_module_or_decl (tree decl, tree context)
{
dw_die_ref scope_die;
unsigned file_index;
expanded_location xloc;
-
+
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
gcc_assert (decl);
/* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
- We need decl DIE for reference and scope die. First, get DIE for the decl
+ We need decl DIE for reference and scope die. First, get DIE for the decl
itself. */
/* Get the scope die for decl context. Use comp_unit_die for global module
if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
at_import_die = force_type_die (TREE_TYPE (decl));
else
- at_import_die = force_decl_die (decl);
-
- /* OK, now we have DIEs for decl as well as scope. Emit imported die. */
+ {
+ at_import_die = lookup_decl_die (decl);
+ if (!at_import_die)
+ {
+ /* If we're trying to avoid duplicate debug info, we may not have
+ emitted the member decl for this field. Emit it now. */
+ if (TREE_CODE (decl) == FIELD_DECL)
+ {
+ tree type = DECL_CONTEXT (decl);
+ dw_die_ref type_context_die;
+
+ if (TYPE_CONTEXT (type))
+ if (TYPE_P (TYPE_CONTEXT (type)))
+ type_context_die = force_type_die (TYPE_CONTEXT (type));
+ else
+ type_context_die = force_decl_die (TYPE_CONTEXT (type));
+ else
+ type_context_die = comp_unit_die;
+ gen_type_die_for_member (type, decl, type_context_die);
+ }
+ at_import_die = force_decl_die (decl);
+ }
+ }
+
+ /* OK, now we have DIEs for decl as well as scope. Emit imported die. */
if (TREE_CODE (decl) == NAMESPACE_DECL)
imported_die = new_die (DW_TAG_imported_module, scope_die, context);
else
dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
unsigned int blocknum)
{
- function_section (current_function_decl);
+ current_function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
}
static void
dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
- function_section (current_function_decl);
+ current_function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
}
VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
VARRAY_PUSH_UINT (file_table_emitted, 0);
+ /* If the assembler is emitting the file table, and we aren't eliminating
+ unused debug types, then we must emit .file here. If we are eliminating
+ unused debug types, then this will be done by the maybe_emit_file call in
+ prune_unused_types_walk_attribs. */
+
+ if (DWARF2_ASM_LINE_DEBUG_INFO && ! flag_eliminate_unused_debug_types)
+ maybe_emit_file (i);
+
return i;
}
rtx prev_insn;
static rtx last_insn;
static const char *last_label;
+ tree decl;
if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
return;
newloc->var_loc_note = loc_note;
newloc->next = NULL;
+ if (cfun
+ && (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name == cfun->unlikely_text_section_name)))
+ newloc->section_label = cfun->cold_section_label;
+ else
+ newloc->section_label = text_section_label;
+
last_insn = loc_note;
last_label = newloc->label;
-
- add_var_loc_to_decl (NOTE_VAR_LOCATION_DECL (loc_note), newloc);
+ decl = NOTE_VAR_LOCATION_DECL (loc_note);
+ if (DECL_DEBUG_EXPR (decl) && DECL_DEBUG_EXPR_IS_FROM (decl)
+ && DECL_P (DECL_DEBUG_EXPR (decl)))
+ decl = DECL_DEBUG_EXPR (decl);
+ add_var_loc_to_decl (decl, newloc);
}
/* We need to reset the locations at the beginning of each
if (debug_info_level >= DINFO_LEVEL_NORMAL
&& line != 0)
{
- function_section (current_function_decl);
+ current_function_section (current_function_decl);
/* If requested, emit something human-readable. */
if (flag_debug_asm)
decl_loc_table_eq, NULL);
/* Allocate the initial hunk of the decl_scope_table. */
- VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table");
+ decl_scope_table = VEC_alloc (tree, gc, 256);
/* Allocate the initial hunk of the abbrev_die_table. */
abbrev_die_table = ggc_alloc_cleared (ABBREV_DIE_TABLE_INCREMENT
in this value in dwarf2out_finish. */
comp_unit_die = gen_compile_unit_die (NULL);
- VARRAY_TREE_INIT (incomplete_types, 64, "incomplete_types");
+ incomplete_types = VEC_alloc (tree, gc, 64);
VARRAY_RTX_INIT (used_rtx_varray, 32, "used_rtx_varray");
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
DEBUG_ABBREV_SECTION_LABEL, 0);
- if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
- ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
- else
- strcpy (text_section_label, stripattributes (TEXT_SECTION_NAME));
+ ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
+ COLD_TEXT_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
DEBUG_INFO_SECTION_LABEL, 0);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
}
- if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
+ text_section ();
+ ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
+ if (flag_reorder_blocks_and_partition)
{
- text_section ();
- ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
+ unlikely_text_section ();
+ ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
}
}
prune_unused_types_prune (dw_die_ref die)
{
dw_die_ref c, p, n;
-
+
gcc_assert (die->die_mark);
p = NULL;
context = DECL_CONTEXT (node->created_for);
else if (TYPE_P (node->created_for))
context = TYPE_CONTEXT (node->created_for);
-
+
gcc_assert (context && TREE_CODE (context) == FUNCTION_DECL);
-
+
origin = lookup_decl_die (context);
if (origin)
add_child_die (origin, die);
+ else
+ add_child_die (comp_unit_die, die);
}
}
}
/* Output a terminator label for the .text section. */
text_section ();
targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
+ if (flag_reorder_blocks_and_partition)
+ {
+ unlikely_text_section ();
+ targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
+ }
/* Output the source line correspondence table. We must do this
even if there is no line information. Otherwise, on an empty
output_ranges ();
}
- /* Have to end the primary source file. */
+ /* Have to end the macro section. */
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
- dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
dw2_asm_output_data (1, 0, "End compilation unit");
}