/* 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).
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* TODO: Emit .debug_line header even when there are no functions, since
the file numbers are used by .debug_info. Alternately, leave
/* 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)
{
#endif
}
+DEF_VEC_P(rtx);
+DEF_VEC_ALLOC_P(rtx,gc);
+
/* Array of RTXes referenced by the debugging information, which therefore
must be kept around forever. */
-static GTY(()) varray_type used_rtx_varray;
+static GTY(()) VEC(rtx,gc) *used_rtx_array;
/* 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
of this structure. */
typedef struct cfa_loc GTY(())
{
- unsigned long reg;
HOST_WIDE_INT offset;
HOST_WIDE_INT base_offset;
+ unsigned int reg;
int indirect; /* 1 if CFA is accessed via a dereference. */
} dw_cfa_location;
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 *);
#ifndef DWARF_FRAME_REGNUM
#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
#endif
-
-/* The offset from the incoming value of %sp to the top of the stack frame
- for the current function. */
-#ifndef INCOMING_FRAME_SP_OFFSET
-#define INCOMING_FRAME_SP_OFFSET 0
-#endif
\f
/* Hook used by __throw. */
if (offset < 0)
continue;
- emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
+ emit_move_insn (adjust_address (mem, mode, offset),
+ gen_int_mode (size, mode));
}
#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
- if (! wrote_return_column)
- abort ();
+ gcc_assert (wrote_return_column);
i = DWARF_ALT_FRAME_RETURN_COLUMN;
wrote_return_column = false;
#else
/* Subroutine of lookup_cfa. */
-static inline void
+static void
lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc)
{
switch (cfi->dw_cfi_opc)
{
dw_cfi_ref cfi;
- loc->reg = (unsigned long) -1;
+ loc->reg = INVALID_REGNUM;
loc->offset = 0;
loc->indirect = 0;
loc->base_offset = 0;
def_cfa_1 (label, &loc);
}
+/* Determine if two dw_cfa_location structures define the same data. */
+
+static bool
+cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
+{
+ return (loc1->reg == loc2->reg
+ && loc1->offset == loc2->offset
+ && loc1->indirect == loc2->indirect
+ && (loc1->indirect == 0
+ || loc1->base_offset == loc2->base_offset));
+}
+
/* This routine does the actual work. The CFA is now calculated from
the dw_cfa_location structure. */
lookup_cfa (&old_cfa);
/* If nothing changed, no need to issue any call frame instructions. */
- if (loc.reg == old_cfa.reg && loc.offset == old_cfa.offset
- && loc.indirect == old_cfa.indirect
- && (loc.indirect == 0 || loc.base_offset == old_cfa.base_offset))
+ if (cfa_equal_p (&loc, &old_cfa))
return;
cfi = new_cfi ();
}
#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */
- else if (loc.offset == old_cfa.offset && old_cfa.reg != (unsigned long) -1
+ else if (loc.offset == old_cfa.offset
+ && old_cfa.reg != INVALID_REGNUM
&& !loc.indirect)
{
/* Construct a "DW_CFA_def_cfa_register <register>" instruction,
description. */
HOST_WIDE_INT check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
- if (check_offset * DWARF_CIE_DATA_ALIGNMENT != offset)
- abort ();
+ gcc_assert (check_offset * DWARF_CIE_DATA_ALIGNMENT == offset);
}
#endif
offset /= DWARF_CIE_DATA_ALIGNMENT;
switch (GET_CODE (rtl))
{
case REG:
- if (REGNO (rtl) != STACK_POINTER_REGNUM)
- abort ();
+ gcc_assert (REGNO (rtl) == STACK_POINTER_REGNUM);
offset = 0;
break;
case PLUS:
- if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
- abort ();
+ gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
offset = INTVAL (XEXP (rtl, 1));
break;
case MINUS:
- if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
- abort ();
+ gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
offset = -INTVAL (XEXP (rtl, 1));
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
/* The return address is at some offset from any value we can
actually load. For instance, on the SPARC it is in %i7+8. Just
ignore the offset for now; it doesn't matter for unwinding frames. */
- if (GET_CODE (XEXP (rtl, 1)) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XEXP (rtl, 1)) == CONST_INT);
initial_return_save (XEXP (rtl, 0));
return;
default:
- abort ();
+ gcc_unreachable ();
}
if (reg != DWARF_FRAME_RETURN_COLUMN)
{
rtx val = XEXP (XEXP (src, 1), 1);
/* We handle only adjustments by constant amount. */
- if (GET_CODE (XEXP (src, 1)) != PLUS ||
- GET_CODE (val) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS
+ && GET_CODE (val) == CONST_INT);
offset = -INTVAL (val);
break;
}
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);
- if (GET_CODE (insn) != CALL)
- abort ();
-
- 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;
break;
if (q->saved_reg && i == num_regs_saved_in_regs)
{
- if (i == ARRAY_SIZE (regs_saved_in_regs))
- abort ();
+ gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
num_regs_saved_in_regs++;
}
if (i != num_regs_saved_in_regs)
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)
return;
}
- if (GET_CODE (expr) != SET)
- abort ();
+ gcc_assert (GET_CODE (expr) == SET);
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
cfa_temp.reg = cfa.reg;
cfa_temp.offset = cfa.offset;
}
- else if (call_used_regs [REGNO (dest)]
- && ! fixed_regs [REGNO (dest)])
+ else
{
/* Saving a register in a register. */
+ gcc_assert (call_used_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);
}
- else
- abort ();
break;
case PLUS:
offset = INTVAL (XEXP (src, 1));
break;
case REG:
- if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp.reg)
- abort ();
+ gcc_assert ((unsigned) REGNO (XEXP (src, 1))
+ == cfa_temp.reg);
offset = cfa_temp.offset;
break;
default:
- abort ();
+ gcc_unreachable ();
}
if (XEXP (src, 0) == hard_frame_pointer_rtx)
{
/* Restoring SP from FP in the epilogue. */
- if (cfa.reg != (unsigned) HARD_FRAME_POINTER_REGNUM)
- abort ();
+ gcc_assert (cfa.reg == (unsigned) HARD_FRAME_POINTER_REGNUM);
cfa.reg = STACK_POINTER_REGNUM;
}
else if (GET_CODE (src) == LO_SUM)
/* Assume we've set the source reg of the LO_SUM from sp. */
;
- else if (XEXP (src, 0) != stack_pointer_rtx)
- abort ();
+ else
+ gcc_assert (XEXP (src, 0) == stack_pointer_rtx);
if (GET_CODE (src) != MINUS)
offset = -offset;
/* Rule 3 */
/* Either setting the FP from an offset of the SP,
or adjusting the FP */
- if (! frame_pointer_needed)
- abort ();
+ gcc_assert (frame_pointer_needed);
- if (REG_P (XEXP (src, 0))
- && (unsigned) REGNO (XEXP (src, 0)) == cfa.reg
- && GET_CODE (XEXP (src, 1)) == CONST_INT)
- {
- offset = INTVAL (XEXP (src, 1));
- if (GET_CODE (src) != MINUS)
- offset = -offset;
- cfa.offset += offset;
- cfa.reg = HARD_FRAME_POINTER_REGNUM;
- }
- else
- abort ();
+ gcc_assert (REG_P (XEXP (src, 0))
+ && (unsigned) REGNO (XEXP (src, 0)) == cfa.reg
+ && GET_CODE (XEXP (src, 1)) == CONST_INT);
+ offset = INTVAL (XEXP (src, 1));
+ if (GET_CODE (src) != MINUS)
+ offset = -offset;
+ cfa.offset += offset;
+ cfa.reg = HARD_FRAME_POINTER_REGNUM;
}
else
{
- if (GET_CODE (src) == MINUS)
- abort ();
+ gcc_assert (GET_CODE (src) != MINUS);
/* Rule 4 */
if (REG_P (XEXP (src, 0))
{
/* Setting a scratch register that we will use instead
of SP for saving registers to the stack. */
- if (cfa.reg != STACK_POINTER_REGNUM)
- abort ();
+ gcc_assert (cfa.reg == STACK_POINTER_REGNUM);
cfa_store.reg = REGNO (dest);
cfa_store.offset = cfa.offset - cfa_temp.offset;
}
cfa_temp.offset = INTVAL (XEXP (src, 1));
}
else
- abort ();
+ gcc_unreachable ();
}
break;
/* Rule 7 */
case IOR:
- if (!REG_P (XEXP (src, 0))
- || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp.reg
- || GET_CODE (XEXP (src, 1)) != CONST_INT)
- abort ();
+ gcc_assert (REG_P (XEXP (src, 0))
+ && (unsigned) REGNO (XEXP (src, 0)) == cfa_temp.reg
+ && GET_CODE (XEXP (src, 1)) == CONST_INT);
if ((unsigned) REGNO (dest) != cfa_temp.reg)
cfa_temp.reg = REGNO (dest);
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:
- abort ();
+ gcc_unreachable ();
}
def_cfa_1 (label, &cfa);
break;
case MEM:
- if (!REG_P (src))
- abort ();
+ gcc_assert (REG_P (src));
/* Saving a register to the stack. Make sure dest is relative to the
CFA register. */
/* With a push. */
case PRE_MODIFY:
/* We can't handle variable size modifications. */
- if (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1)) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
+ == CONST_INT);
offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
- if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM
- || cfa_store.reg != STACK_POINTER_REGNUM)
- abort ();
+ gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
+ && cfa_store.reg == STACK_POINTER_REGNUM);
cfa_store.offset += offset;
if (cfa.reg == STACK_POINTER_REGNUM)
if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
offset = -offset;
- if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM
- || cfa_store.reg != STACK_POINTER_REGNUM)
- abort ();
+ gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
+ && cfa_store.reg == STACK_POINTER_REGNUM);
cfa_store.offset += offset;
if (cfa.reg == STACK_POINTER_REGNUM)
case PLUS:
case MINUS:
case LO_SUM:
- if (GET_CODE (XEXP (XEXP (dest, 0), 1)) != CONST_INT)
- abort ();
- offset = INTVAL (XEXP (XEXP (dest, 0), 1));
- if (GET_CODE (XEXP (dest, 0)) == MINUS)
- offset = -offset;
+ {
+ int regno;
- if (cfa_store.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
- offset -= cfa_store.offset;
- else if (cfa_temp.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
- offset -= cfa_temp.offset;
- else
- abort ();
+ 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
+ {
+ gcc_assert (cfa_temp.reg == (unsigned) regno);
+ offset -= cfa_temp.offset;
+ }
+ }
break;
/* Rule 13 */
/* Without an offset. */
case REG:
- if (cfa_store.reg == (unsigned) REGNO (XEXP (dest, 0)))
- offset = -cfa_store.offset;
- else if (cfa_temp.reg == (unsigned) REGNO (XEXP (dest, 0)))
- offset = -cfa_temp.offset;
- else
- abort ();
+ {
+ int regno = REGNO (XEXP (dest, 0));
+
+ if (cfa_store.reg == (unsigned) regno)
+ offset = -cfa_store.offset;
+ else
+ {
+ gcc_assert (cfa_temp.reg == (unsigned) regno);
+ offset = -cfa_temp.offset;
+ }
+ }
break;
/* Rule 14 */
case POST_INC:
- if (cfa_temp.reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
- abort ();
+ gcc_assert (cfa_temp.reg
+ == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)));
offset = -cfa_temp.offset;
cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
break;
default:
- abort ();
+ gcc_unreachable ();
}
if (REGNO (src) != STACK_POINTER_REGNUM
if (!REG_P (x))
x = XEXP (x, 0);
- if (!REG_P (x))
- abort ();
+ gcc_assert (REG_P (x));
cfa.reg = REGNO (x);
cfa.base_offset = offset;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
/* 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 ();
/* Set up state for generating call frame debug info. */
lookup_cfa (&cfa);
- if (cfa.reg != (unsigned long) DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM))
- abort ();
+ gcc_assert (cfa.reg
+ == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
cfa.reg = STACK_POINTER_REGNUM;
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;
}
return dw_cfi_oprnd_loc;
default:
- abort ();
+ gcc_unreachable ();
}
}
case DW_CFA_GNU_negative_offset_extended:
/* Obsoleted by DW_CFA_offset_extended_sf. */
- abort ();
+ gcc_unreachable ();
default:
break;
int fde_encoding = DW_EH_PE_absptr;
int per_encoding = DW_EH_PE_absptr;
int lsda_encoding = DW_EH_PE_absptr;
+ int return_reg;
/* Don't emit a CIE if there won't be any FDEs. */
if (fde_table_in_use == 0)
/* 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))
- any_eh_needed = 1;
+ 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)
any_eh_needed = true;
P Indicates the presence of an encoding + language
personality routine in the CIE augmentation. */
- fde_encoding = TARGET_USES_WEAK_UNWIND_INFO
- ? ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1)
- : ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
+ 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);
/* Augmentations should be small, so there's scarce need to
iterate for a solution. Die if we exceed one uleb128 byte. */
- if (size_of_uleb128 (augmentation_size) != 1)
- abort ();
+ gcc_assert (size_of_uleb128 (augmentation_size) == 1);
}
}
dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
"CIE Data Alignment Factor");
+ return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
if (DW_CIE_VERSION == 1)
- dw2_asm_output_data (1, DWARF_FRAME_RETURN_COLUMN, "CIE RA Column");
+ dw2_asm_output_data (1, return_reg, "CIE RA Column");
else
- dw2_asm_output_data_uleb128 (DWARF_FRAME_RETURN_COLUMN, "CIE RA Column");
+ dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column");
if (augmentation[0])
{
/* 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;
if (for_eh)
{
- if (TARGET_USES_WEAK_UNWIND_INFO
- && DECL_ONE_ONLY (fde->decl))
- dw2_asm_output_encoded_addr_rtx (fde_encoding,
- gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER
- (DECL_ASSEMBLER_NAME (fde->decl))),
- "FDE initial location");
- else
+ rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin);
+ SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
+ dw2_asm_output_encoded_addr_rtx (fde_encoding,
+ sym_ref,
+ "FDE initial location");
+ if (fde->dw_fde_switched_sections)
{
- rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin);
- SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
- dw2_asm_output_encoded_addr_rtx (fde_encoding,
- sym_ref,
+ 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");
}
- 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_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])
int pad = -offset & (PTR_SIZE - 1);
size += pad;
- if (size_of_uleb128 (size) != 1)
- abort ();
+ gcc_assert (size_of_uleb128 (size) == 1);
}
dw2_asm_output_data_uleb128 (size, "Augmentation size");
const char *file ATTRIBUTE_UNUSED)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ char * dup_label;
dw_fde_ref fde;
- current_function_func_begin_label = 0;
+ current_function_func_begin_label = NULL;
#ifdef TARGET_UNWIND_INFO
/* ??? current_function_func_begin_label is also used by except.c
current_function_funcdef_no);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
- current_function_func_begin_label = get_identifier (label);
+ dup_label = xstrdup (label);
+ current_function_func_begin_label = dup_label;
#ifdef TARGET_UNWIND_INFO
/* We can elide the fde allocation if we're not emitting debug info. */
/* Add the new FDE at the end of the fde_table. */
fde = &fde_table[fde_table_in_use++];
fde->decl = current_function_decl;
- fde->dw_fde_begin = xstrdup (label);
+ 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
+ /* Output another copy for the unwinder. */
if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
output_call_frame_info (1);
+#endif
}
#endif
\f
return descr;
}
-
/* Add a location description term to a location description expression. */
static inline void
break;
case DW_OP_const8u:
case DW_OP_const8s:
- if (HOST_BITS_PER_LONG < 64)
- abort ();
+ gcc_assert (HOST_BITS_PER_LONG >= 64);
dw2_asm_output_data (8, val1->v.val_int, NULL);
break;
case DW_OP_skip:
{
int offset;
- if (val1->val_class == dw_val_class_loc)
- offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
- else
- abort ();
+ gcc_assert (val1->val_class == dw_val_class_loc);
+ offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
dw2_asm_output_data (2, offset, NULL);
}
aligned properly like we do for the main unwind info, so
don't support emitting things larger than a byte if we're
only doing unwinding. */
- abort ();
+ gcc_unreachable ();
#endif
case DW_OP_const1u:
case DW_OP_const1s:
break;
case INTERNAL_DW_OP_tls_addr:
-#ifdef ASM_OUTPUT_DWARF_DTPREL
- ASM_OUTPUT_DWARF_DTPREL (asm_out_file, DWARF2_ADDR_SIZE,
- val1->v.val_addr);
- fputc ('\n', asm_out_file);
-#else
- abort ();
-#endif
+ if (targetm.asm_out.output_dwarf_dtprel)
+ {
+ targetm.asm_out.output_dwarf_dtprel (asm_out_file,
+ DWARF2_ADDR_SIZE,
+ val1->v.val_addr);
+ fputc ('\n', asm_out_file);
+ }
+ else
+ gcc_unreachable ();
break;
default:
{
struct dw_loc_descr_struct *head, *tmp;
- if (cfa->indirect == 0)
- abort ();
-
- if (cfa->base_offset)
+ if (cfa->indirect)
{
- if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
+ if (cfa->base_offset)
+ {
+ if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
+ else
+ head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
+ }
+ else if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
else
- head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
+ head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
+
+ head->dw_loc_oprnd1.val_class = dw_val_class_const;
+ tmp = new_loc_descr (DW_OP_deref, 0, 0);
+ add_loc_descr (&head, tmp);
+ if (cfa->offset != 0)
+ {
+ tmp = new_loc_descr (DW_OP_plus_uconst, cfa->offset, 0);
+ add_loc_descr (&head, tmp);
+ }
}
- else if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
else
- head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
-
- head->dw_loc_oprnd1.val_class = dw_val_class_const;
- tmp = new_loc_descr (DW_OP_deref, 0, 0);
- add_loc_descr (&head, tmp);
- if (cfa->offset != 0)
{
- tmp = new_loc_descr (DW_OP_plus_uconst, cfa->offset, 0);
- add_loc_descr (&head, tmp);
+ if (cfa->offset == 0)
+ if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
+ else
+ head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
+ else if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->offset, 0);
+ else
+ head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->offset);
}
return head;
cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
break;
default:
- internal_error ("DW_LOC_OP %s not implemented\n",
+ internal_error ("DW_LOC_OP %s not implemented",
dwarf_stack_op_name (ptr->dw_loc_opc));
}
}
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;
};
/* Number of elements in line_info_table currently in use. */
static GTY(()) unsigned line_info_table_in_use;
+/* True if the compilation unit contains more than one .text section. */
+static GTY(()) bool have_switched_text_section = false;
+
/* A pointer to the base of a table that contains line information
for each source code line outside of .text in the compilation unit. */
static GTY ((length ("separate_line_info_table_allocated")))
#ifdef DWARF2_DEBUGGING_INFO
+/* Offset from the "steady-state frame pointer" to the CFA,
+ within the current function. */
+static HOST_WIDE_INT frame_pointer_cfa_offset;
+
/* Forward declarations for functions defined in this file. */
static int is_pseudo_reg (rtx);
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 dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
static int type_is_enum (tree);
static unsigned int dbx_reg_number (rtx);
+static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
static dw_loc_descr_ref reg_loc_descriptor (rtx);
static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int);
static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx);
static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
-static dw_loc_descr_ref based_loc_descr (unsigned, HOST_WIDE_INT, bool);
+static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT);
static int is_based_loc (rtx);
-static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode, bool);
+static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx);
-static dw_loc_descr_ref loc_descriptor (rtx, bool);
-static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
+static dw_loc_descr_ref loc_descriptor (rtx);
+static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree);
static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
static tree field_type (tree);
static unsigned int simple_type_align_in_bits (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
static tree
decl_ultimate_origin (tree decl)
{
+ if (!CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_COMMON))
+ return NULL_TREE;
+
/* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
nodes in the function to point to themselves; ignore that if
we're trying to output the abstract instance of this function. */
if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
return NULL_TREE;
-#ifdef ENABLE_CHECKING
- if (DECL_FROM_INLINE (DECL_ORIGIN (decl)))
- /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
- most distant ancestor, this should never happen. */
- abort ();
-#endif
+ /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
+ most distant ancestor, this should never happen. */
+ gcc_assert (!DECL_FROM_INLINE (DECL_ORIGIN (decl)));
return DECL_ABSTRACT_ORIGIN (decl);
}
? 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;
}
static inline unsigned
AT_flag (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_flag)
- return a->dw_attr_val.v.val_flag;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_flag);
+ return a->dw_attr_val.v.val_flag;
}
/* Add a signed integer attribute value to a DIE. */
static inline HOST_WIDE_INT
AT_int (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_const)
- return a->dw_attr_val.v.val_int;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_const);
+ return a->dw_attr_val.v.val_int;
}
/* Add an unsigned integer attribute value to a DIE. */
static inline unsigned HOST_WIDE_INT
AT_unsigned (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_unsigned_const)
- return a->dw_attr_val.v.val_unsigned;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
+ return a->dw_attr_val.v.val_unsigned;
}
/* Add an unsigned double integer attribute value to a DIE. */
static inline const char *
AT_string (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_str)
- return a->dw_attr_val.v.val_str->str;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_str);
+ return a->dw_attr_val.v.val_str->str;
}
/* Find out whether a string should be output inline in DIE
static int
AT_string_form (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_str)
- {
- struct indirect_string_node *node;
- unsigned int len;
- char label[32];
+ struct indirect_string_node *node;
+ unsigned int len;
+ char label[32];
- node = a->dw_attr_val.v.val_str;
- if (node->form)
- return node->form;
+ gcc_assert (a && AT_class (a) == dw_val_class_str);
- len = strlen (node->str) + 1;
+ node = a->dw_attr_val.v.val_str;
+ if (node->form)
+ return node->form;
- /* If the string is shorter or equal to the size of the reference, it is
- always better to put it inline. */
- if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
- return node->form = DW_FORM_string;
+ len = strlen (node->str) + 1;
- /* If we cannot expect the linker to merge strings in .debug_str
- section, only put it into .debug_str if it is worth even in this
- single module. */
- if ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0
- && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)
- return node->form = DW_FORM_string;
+ /* If the string is shorter or equal to the size of the reference, it is
+ always better to put it inline. */
+ if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
+ return node->form = DW_FORM_string;
- ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
- ++dw2_string_counter;
- node->label = xstrdup (label);
+ /* If we cannot expect the linker to merge strings in .debug_str
+ section, only put it into .debug_str if it is worth even in this
+ single module. */
+ if ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0
+ && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)
+ return node->form = DW_FORM_string;
- return node->form = DW_FORM_strp;
- }
+ ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+ ++dw2_string_counter;
+ node->label = xstrdup (label);
- abort ();
+ return node->form = DW_FORM_strp;
}
/* Add a DIE reference attribute value to a DIE. */
add_AT_specification (dw_die_ref die, dw_die_ref targ_die)
{
add_AT_die_ref (die, DW_AT_specification, targ_die);
- if (targ_die->die_definition)
- abort ();
+ gcc_assert (!targ_die->die_definition);
targ_die->die_definition = die;
}
static inline dw_die_ref
AT_ref (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_die_ref)
- return a->dw_attr_val.v.val_die_ref.die;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
+ return a->dw_attr_val.v.val_die_ref.die;
}
static inline int
static inline void
set_AT_ref_external (dw_attr_ref a, int i)
{
- if (a && AT_class (a) == dw_val_class_die_ref)
- a->dw_attr_val.v.val_die_ref.external = i;
- else
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
+ a->dw_attr_val.v.val_die_ref.external = i;
}
/* Add an FDE reference attribute value to a DIE. */
static inline dw_loc_descr_ref
AT_loc (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_loc)
- return a->dw_attr_val.v.val_loc;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_loc);
+ return a->dw_attr_val.v.val_loc;
}
static inline void
static inline dw_loc_list_ref
AT_loc_list (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_loc_list)
- return a->dw_attr_val.v.val_loc_list;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
+ return a->dw_attr_val.v.val_loc_list;
}
/* Add an address constant attribute value to a DIE. */
static inline rtx
AT_addr (dw_attr_ref a)
{
- if (a && AT_class (a) == dw_val_class_addr)
- return a->dw_attr_val.v.val_addr;
-
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_addr);
+ return a->dw_attr_val.v.val_addr;
}
/* Add a label identifier attribute value to a DIE. */
static inline const char *
AT_lbl (dw_attr_ref a)
{
- if (a && (AT_class (a) == dw_val_class_lbl_id
- || AT_class (a) == dw_val_class_lbl_offset))
- return a->dw_attr_val.v.val_lbl_id;
-
- abort ();
+ gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
+ || AT_class (a) == dw_val_class_lbl_offset));
+ return a->dw_attr_val.v.val_lbl_id;
}
/* Get the attribute of type attr_kind. */
{
if (die != NULL && child_die != NULL)
{
- if (die == child_die)
- abort ();
+ gcc_assert (die != child_die);
child_die->die_parent = die;
child_die->die_sib = die->die_child;
child = tmp;
}
- if (child->die_parent != parent
- && child->die_parent != get_AT_ref (parent, DW_AT_specification))
- abort ();
+ gcc_assert (child->die_parent == parent
+ || (child->die_parent
+ == get_AT_ref (parent, DW_AT_specification)));
for (p = &(child->die_parent->die_child); *p; p = &((*p)->die_sib))
if (*p == child)
case dw_val_class_addr:
r = AT_addr (at);
- switch (GET_CODE (r))
- {
- case SYMBOL_REF:
- CHECKSUM_STRING (XSTR (r, 0));
- break;
-
- default:
- abort ();
- }
+ gcc_assert (GET_CODE (r) == SYMBOL_REF);
+ CHECKSUM_STRING (XSTR (r, 0));
break;
case dw_val_class_offset:
r2 = v2->v.val_addr;
if (GET_CODE (r1) != GET_CODE (r2))
return 0;
- switch (GET_CODE (r1))
- {
- case SYMBOL_REF:
- return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
-
- default:
- abort ();
- }
+ gcc_assert (GET_CODE (r1) == SYMBOL_REF);
+ return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
case dw_val_class_offset:
return v1->v.val_offset == v2->v.val_offset;
#if 0
/* We can only use this in debugging, since the frontend doesn't check
to make sure that we leave every include file we enter. */
- if (unit != NULL)
- abort ();
+ gcc_assert (!unit);
#endif
assign_symbol_names (die);
if (AT_class (d_attr) == dw_val_class_die_ref
&& AT_ref (d_attr)->die_mark == 0)
{
- if (AT_ref (d_attr)->die_symbol == 0)
- abort ();
+ gcc_assert (AT_ref (d_attr)->die_symbol);
set_AT_ref_external (d_attr, 1);
}
size += strlen (a->dw_attr_val.v.val_str->str) + 1;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
{
dw_die_ref c;
- if (die->die_mark)
- abort ();
+ gcc_assert (!die->die_mark);
die->die_mark = 1;
for (c = die->die_child; c; c = c->die_sib)
{
dw_die_ref c;
- if (!die->die_mark)
- abort ();
+ gcc_assert (die->die_mark);
die->die_mark = 0;
for (c = die->die_child; c; c = c->die_sib)
return DW_FORM_addr;
case dw_val_class_range_list:
case dw_val_class_offset:
- if (DWARF_OFFSET_SIZE == 4)
- return DW_FORM_data4;
- if (DWARF_OFFSET_SIZE == 8)
- return DW_FORM_data8;
- abort ();
+ switch (DWARF_OFFSET_SIZE)
+ {
+ case 4:
+ return DW_FORM_data4;
+ case 8:
+ return DW_FORM_data8;
+ default:
+ gcc_unreachable ();
+ }
case dw_val_class_loc_list:
/* FIXME: Could be DW_FORM_data8, with a > 32 bit size
.debug_loc section */
case 2:
return DW_FORM_block2;
default:
- abort ();
+ gcc_unreachable ();
}
case dw_val_class_const:
return DW_FORM_sdata;
case 8:
return DW_FORM_data8;
default:
- abort ();
+ gcc_unreachable ();
}
case dw_val_class_long_long:
return DW_FORM_block1;
return AT_string_form (a);
default:
- abort ();
+ gcc_unreachable ();
}
}
*d = new_loc_list (descr, begin, end, section, 0);
}
+static void
+dwarf2out_switch_text_section (void)
+{
+ dw_fde_ref fde;
+
+ gcc_assert (cfun);
+
+ 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;
+ have_switched_text_section = true;
+}
+
/* Output the location list given to us. */
static void
for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
{
unsigned long size;
- if (separate_line_info_table_in_use == 0)
+ if (!separate_line_info_table_in_use && !have_switched_text_section)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
"Location list begin address (%s)",
size = size_of_locs (curr->expr);
/* Output the block length for this list of location operations. */
- if (size > 0xffff)
- abort ();
+ gcc_assert (size <= 0xffff);
dw2_asm_output_data (2, size, "%s", "Location expression size");
output_loc_sequence (curr->expr);
{
char *sym = AT_loc_list (a)->ll_symbol;
- if (sym == 0)
- abort ();
+ gcc_assert (sym);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, "%s", name);
}
break;
{
char *sym = AT_ref (a)->die_symbol;
- if (sym == 0)
- abort ();
+ gcc_assert (sym);
dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, "%s", name);
}
- else if (AT_ref (a)->die_offset == 0)
- abort ();
else
- dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
- "%s", name);
+ {
+ gcc_assert (AT_ref (a)->die_offset);
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
+ "%s", name);
+ }
break;
case dw_val_class_fde_ref:
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
pubname_ref pub = &pubname_table[i];
/* We shouldn't see pubnames for DIEs outside of the main CU. */
- if (pub->die->die_mark == 0)
- abort ();
+ gcc_assert (pub->die->die_mark);
dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
"DIE offset");
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++)
{
dw_die_ref die = arange_table[i];
/* We shouldn't see aranges for DIEs outside of the main CU. */
- if (die->die_mark == 0)
- abort ();
+ gcc_assert (die->die_mark);
if (die->die_tag == DW_TAG_subprogram)
{
dw_attr_ref a = get_AT (die, DW_AT_location);
dw_loc_descr_ref loc;
- if (! a || AT_class (a) != dw_val_class_loc)
- abort ();
+ gcc_assert (a && AT_class (a) == dw_val_class_loc);
loc = AT_loc (a);
- if (loc->dw_loc_opc != DW_OP_addr)
- abort ();
+ gcc_assert (loc->dw_loc_opc == DW_OP_addr);
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE,
loc->dw_loc_oprnd1.v.val_addr, "Address");
/* If all code is in the text section, then the compilation
unit base address defaults to DW_AT_low_pc, which is the
base of the text section. */
- if (separate_line_info_table_in_use == 0)
+ if (!separate_line_info_table_in_use && !have_switched_text_section)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
text_section_label,
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];
that contain spaces; other names might occur by coincidence in other
languages. */
if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
- && (type == char_type_node
+ && (TYPE_MAIN_VARIANT (type) == char_type_node
|| ! strcmp (type_name, "signed char")
|| ! strcmp (type_name, "unsigned char"))))
{
default:
/* No other TREE_CODEs are Dwarf fundamental types. */
- abort ();
+ gcc_unreachable ();
}
base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
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:
return 0;
default:
- abort ();
+ gcc_unreachable ();
}
return 0;
/* Vectors have the debugging information in the type,
not the main variant. */
mod_type_die = lookup_type_die (type);
- if (mod_type_die == NULL)
- abort ();
+ gcc_assert (mod_type_die);
}
/* We want to equate the qualified type to the die below. */
{
unsigned regno = REGNO (rtl);
- if (regno >= FIRST_PSEUDO_REGISTER)
- abort ();
+ /* We do not want to see registers that should have been eliminated. */
+ gcc_assert (HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM
+ || rtl != arg_pointer_rtx);
+ gcc_assert (HARD_FRAME_POINTER_REGNUM == FRAME_POINTER_REGNUM
+ || rtl != frame_pointer_rtx);
+
+ gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+
+#ifdef LEAF_REG_REMAP
+ regno = LEAF_REG_REMAP (regno);
+#endif
return DBX_REGISTER_NUMBER (regno);
}
+/* Optionally add a DW_OP_piece term to a location description expression.
+ DW_OP_piece is only added if the location description expression already
+ doesn't end with DW_OP_piece. */
+
+static void
+add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
+{
+ dw_loc_descr_ref loc;
+
+ if (*list_head != NULL)
+ {
+ /* Find the end of the chain. */
+ for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
+ ;
+
+ if (loc->dw_loc_opc != DW_OP_piece)
+ loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
+ }
+}
+
/* Return a location descriptor that designates a machine register or
zero if there is none. */
static dw_loc_descr_ref
reg_loc_descriptor (rtx rtl)
{
- unsigned reg;
rtx regs;
if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
return 0;
- reg = dbx_reg_number (rtl);
regs = targetm.dwarf_register_span (rtl);
- if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1
- || regs)
+ if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
return multiple_reg_loc_descriptor (rtl, regs);
else
- return one_reg_loc_descriptor (reg);
+ return one_reg_loc_descriptor (dbx_reg_number (rtl));
}
/* Return a location descriptor that designates a machine register for
t = one_reg_loc_descriptor (reg);
add_loc_descr (&loc_result, t);
- add_loc_descr (&loc_result, new_loc_descr (DW_OP_piece, size, 0));
+ add_loc_descr_op_piece (&loc_result, size);
++reg;
}
return loc_result;
/* Now onto stupid register sets in non contiguous locations. */
- if (GET_CODE (regs) != PARALLEL)
- abort ();
+ gcc_assert (GET_CODE (regs) == PARALLEL);
size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
loc_result = NULL;
t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)));
add_loc_descr (&loc_result, t);
size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
- add_loc_descr (&loc_result, new_loc_descr (DW_OP_piece, size, 0));
+ add_loc_descr_op_piece (&loc_result, size);
}
return loc_result;
}
return new_loc_descr (op, i, 0);
}
+/* Return an offset from an eliminable register to the post-prologue
+ frame pointer. */
+
+static HOST_WIDE_INT
+eliminate_reg_to_offset (rtx reg)
+{
+ HOST_WIDE_INT offset = 0;
+
+ reg = eliminate_regs (reg, VOIDmode, NULL_RTX);
+ if (GET_CODE (reg) == PLUS)
+ {
+ offset = INTVAL (XEXP (reg, 1));
+ reg = XEXP (reg, 0);
+ }
+ gcc_assert (reg == (frame_pointer_needed ? hard_frame_pointer_rtx
+ : stack_pointer_rtx));
+
+ return offset;
+}
+
/* Return a location descriptor that designates a base+offset location. */
static dw_loc_descr_ref
-based_loc_descr (unsigned int reg, HOST_WIDE_INT offset, bool can_use_fbreg)
+based_loc_descr (rtx reg, HOST_WIDE_INT offset)
{
dw_loc_descr_ref loc_result;
- /* For the "frame base", we use the frame pointer or stack pointer
- registers, since the RTL for local variables is relative to one of
- them. */
- unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed
- ? HARD_FRAME_POINTER_REGNUM
- : STACK_POINTER_REGNUM);
-
- if (reg == fp_reg && can_use_fbreg)
- loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
- else if (reg <= 31)
- loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0);
+
+ /* We only use "frame base" when we're sure we're talking about the
+ post-prologue local stack frame. We do this by *not* running
+ register elimination until this point, and recognizing the special
+ argument pointer and soft frame pointer rtx's. */
+ if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
+ {
+ offset += eliminate_reg_to_offset (reg);
+ offset += frame_pointer_cfa_offset;
+
+ loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
+ }
else
- loc_result = new_loc_descr (DW_OP_bregx, reg, offset);
+ {
+ unsigned int regno = dbx_reg_number (reg);
+
+ if (regno <= 31)
+ loc_result = new_loc_descr (DW_OP_breg0 + regno, offset, 0);
+ else
+ loc_result = new_loc_descr (DW_OP_bregx, regno, offset);
+ }
return loc_result;
}
MODE is the mode of the memory reference, needed to handle some
autoincrement addressing modes.
- CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the location
- list for RTL. We can't use it when we are emitting location list for
- virtual variable frame_base_decl (i.e. a location list for DW_AT_frame_base)
- which describes how frame base changes when !frame_pointer_needed.
+ CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
+ location list for RTL.
Return 0 if we can't represent the location. */
static dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode, bool can_use_fbreg)
+mem_loc_descriptor (rtx rtl, enum machine_mode mode)
{
dw_loc_descr_ref mem_loc_result = NULL;
enum dwarf_location_atom op;
up an entire register. For now, just assume that it is
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
- rtl = SUBREG_REG (rtl);
+ rtl = XEXP (rtl, 0);
/* ... fall through ... */
memory) so DWARF consumers need to be aware of the subtle
distinction between OP_REG and OP_BASEREG. */
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
- mem_loc_result = based_loc_descr (dbx_reg_number (rtl), 0,
- can_use_fbreg);
+ mem_loc_result = based_loc_descr (rtl, 0);
break;
case MEM:
- mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
- can_use_fbreg);
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
if (mem_loc_result != 0)
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
break;
mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
- VARRAY_PUSH_RTX (used_rtx_varray, rtl);
+ VEC_safe_push (rtx, gc, used_rtx_array, rtl);
break;
case PRE_MODIFY:
case PLUS:
plus:
if (is_based_loc (rtl))
- mem_loc_result = based_loc_descr (dbx_reg_number (XEXP (rtl, 0)),
- INTVAL (XEXP (rtl, 1)),
- can_use_fbreg);
+ mem_loc_result = based_loc_descr (XEXP (rtl, 0),
+ INTVAL (XEXP (rtl, 1)));
else
{
- mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
- can_use_fbreg);
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
if (mem_loc_result == 0)
break;
else
{
add_loc_descr (&mem_loc_result,
- mem_loc_descriptor (XEXP (rtl, 1), mode,
- can_use_fbreg));
+ mem_loc_descriptor (XEXP (rtl, 1), mode));
add_loc_descr (&mem_loc_result,
new_loc_descr (DW_OP_plus, 0, 0));
}
case ASHIFT:
op = DW_OP_shl;
goto do_binop;
-
+
case ASHIFTRT:
op = DW_OP_shra;
goto do_binop;
do_binop:
{
- dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
- can_use_fbreg);
- dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
- can_use_fbreg);
+ dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode);
+ dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode);
if (op0 == 0 || op1 == 0)
break;
break;
default:
- abort ();
+ gcc_unreachable ();
}
return mem_loc_result;
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);
+ dw_loc_descr_ref x1_ref = loc_descriptor (x1);
if (x0_ref == 0 || x1_ref == 0)
return 0;
cc_loc_result = x0_ref;
- add_loc_descr (&cc_loc_result,
- new_loc_descr (DW_OP_piece,
- GET_MODE_SIZE (GET_MODE (x0)), 0));
+ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
add_loc_descr (&cc_loc_result, x1_ref);
- add_loc_descr (&cc_loc_result,
- new_loc_descr (DW_OP_piece,
- GET_MODE_SIZE (GET_MODE (x1)), 0));
+ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
return cc_loc_result;
}
If we don't know how to describe it, return 0. */
static dw_loc_descr_ref
-loc_descriptor (rtx rtl, bool can_use_fbreg)
+loc_descriptor (rtx rtl)
{
dw_loc_descr_ref loc_result = NULL;
break;
case MEM:
- loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
- can_use_fbreg);
+ loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
break;
case CONCAT:
/* Single part. */
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
{
- loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), can_use_fbreg);
- }
- /* Multiple parts. */
- else
- {
- rtvec par_elems = XVEC (XEXP (rtl, 1), 0);
- int num_elem = GET_NUM_ELEM (par_elems);
- enum machine_mode mode;
- int i;
-
- /* Create the first one, so we have something to add to. */
- loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
- can_use_fbreg);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
- add_loc_descr (&loc_result,
- new_loc_descr (DW_OP_piece, GET_MODE_SIZE (mode), 0));
- for (i = 1; i < num_elem; i++)
- {
- dw_loc_descr_ref temp;
-
- temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
- can_use_fbreg);
- add_loc_descr (&loc_result, temp);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
- add_loc_descr (&loc_result,
- new_loc_descr (DW_OP_piece,
- GET_MODE_SIZE (mode), 0));
- }
+ loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0));
+ break;
}
+
+ rtl = XEXP (rtl, 1);
+ /* FALLTHRU */
+
+ case PARALLEL:
+ {
+ rtvec par_elems = XVEC (rtl, 0);
+ int num_elem = GET_NUM_ELEM (par_elems);
+ enum machine_mode mode;
+ int i;
+
+ /* Create the first one, so we have something to add to. */
+ loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0));
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
+ add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+ for (i = 1; i < num_elem; i++)
+ {
+ dw_loc_descr_ref temp;
+
+ temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0));
+ add_loc_descr (&loc_result, temp);
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
+ add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+ }
+ }
break;
default:
- abort ();
+ gcc_unreachable ();
}
return loc_result;
}
/* Similar, but generate the descriptor from trees instead of rtl. This comes
- up particularly with variable length arrays. If ADDRESSP is nonzero, we are
- looking for an address. Otherwise, we return a value. If we can't make a
- descriptor, return 0. */
+ up particularly with variable length arrays. WANT_ADDRESS is 2 if this is
+ a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a
+ top-level invocation, and we require the address of LOC; is 0 if we require
+ the value of LOC. */
static dw_loc_descr_ref
-loc_descriptor_from_tree (tree loc, int addressp)
+loc_descriptor_from_tree_1 (tree loc, int want_address)
{
dw_loc_descr_ref ret, ret1;
- int indirect_p = 0;
+ int have_address = 0;
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
enum dwarf_location_atom op;
return 0;
case ADDR_EXPR:
- /* We can support this only if we can look through conversions and
- find an INDIRECT_EXPR. */
- for (loc = TREE_OPERAND (loc, 0);
- TREE_CODE (loc) == CONVERT_EXPR || TREE_CODE (loc) == NOP_EXPR
- || TREE_CODE (loc) == NON_LVALUE_EXPR
- || TREE_CODE (loc) == VIEW_CONVERT_EXPR
- || TREE_CODE (loc) == SAVE_EXPR;
- loc = TREE_OPERAND (loc, 0))
- ;
+ /* If we already want an address, there's nothing we can do. */
+ if (want_address)
+ return 0;
- return (TREE_CODE (loc) == INDIRECT_REF
- ? loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp)
- : 0);
+ /* Otherwise, process the argument and look for the address. */
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1);
case VAR_DECL:
- if (DECL_THREAD_LOCAL (loc))
+ if (DECL_THREAD_LOCAL_P (loc))
{
rtx rtl;
-#ifndef ASM_OUTPUT_DWARF_DTPREL
/* If this is not defined, we have no way to emit the data. */
- return 0;
-#endif
+ if (!targetm.asm_out.output_dwarf_dtprel)
+ return 0;
/* The way DW_OP_GNU_push_tls_address is specified, we can only
look up addresses of objects in the current module. */
ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
add_loc_descr (&ret, ret1);
- indirect_p = 1;
+ have_address = 1;
break;
}
- /* Fall through. */
+ /* FALLTHRU */
case PARM_DECL:
+ if (DECL_HAS_VALUE_EXPR_P (loc))
+ return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc),
+ want_address);
+ /* FALLTHRU */
+
case RESULT_DECL:
{
rtx rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX)
return 0;
+ else if (GET_CODE (rtl) == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (rtl);
+ if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+ val &= GET_MODE_MASK (DECL_MODE (loc));
+ ret = int_loc_descriptor (val);
+ }
+ else if (GET_CODE (rtl) == CONST_STRING)
+ return 0;
else if (CONSTANT_P (rtl))
{
ret = new_loc_descr (DW_OP_addr, 0, 0);
ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
ret->dw_loc_oprnd1.v.val_addr = rtl;
- indirect_p = 1;
}
else
{
- enum machine_mode mode = GET_MODE (rtl);
+ enum machine_mode mode;
+
+ /* Certain constructs can only be represented at top-level. */
+ if (want_address == 2)
+ return loc_descriptor (rtl);
+ mode = GET_MODE (rtl);
if (MEM_P (rtl))
{
- indirect_p = 1;
rtl = XEXP (rtl, 0);
+ have_address = 1;
}
-
- ret = mem_loc_descriptor (rtl, mode, true);
+ ret = mem_loc_descriptor (rtl, mode);
}
}
break;
case INDIRECT_REF:
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
- indirect_p = 1;
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ have_address = 1;
break;
case COMPOUND_EXPR:
- return loc_descriptor_from_tree (TREE_OPERAND (loc, 1), addressp);
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address);
case NOP_EXPR:
case CONVERT_EXPR:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
case MODIFY_EXPR:
- return loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp);
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
case COMPONENT_REF:
case BIT_FIELD_REF:
int volatilep;
obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
- &unsignedp, &volatilep);
+ &unsignedp, &volatilep, false);
if (obj == loc)
return 0;
- ret = loc_descriptor_from_tree (obj, 1);
+ ret = loc_descriptor_from_tree_1 (obj, 1);
if (ret == 0
|| bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
return 0;
if (offset != NULL_TREE)
{
/* Variable offset. */
- add_loc_descr (&ret, loc_descriptor_from_tree (offset, 0));
+ add_loc_descr (&ret, loc_descriptor_from_tree_1 (offset, 0));
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
- if (!addressp)
- indirect_p = 1;
-
bytepos = bitpos / BITS_PER_UNIT;
if (bytepos > 0)
add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
add_loc_descr (&ret, int_loc_descriptor (bytepos));
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
+
+ have_address = 1;
break;
}
rtx rtl = lookup_constant_def (loc);
enum machine_mode mode;
- if (!MEM_P (rtl))
+ if (!rtl || !MEM_P (rtl))
return 0;
mode = GET_MODE (rtl);
rtl = XEXP (rtl, 0);
-
- rtl = targetm.delegitimize_address (rtl);
-
- indirect_p = 1;
- ret = mem_loc_descriptor (rtl, mode, true);
+ ret = mem_loc_descriptor (rtl, mode);
+ have_address = 1;
break;
}
if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
&& host_integerp (TREE_OPERAND (loc, 1), 0))
{
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0)
return 0;
goto do_binop;
do_binop:
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
- ret1 = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
if (ret == 0 || ret1 == 0)
return 0;
goto do_unop;
do_unop:
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0)
return 0;
loc = build3 (COND_EXPR, TREE_TYPE (loc),
build2 (code, integer_type_node,
TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
- TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+ TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
}
/* ... fall through ... */
case COND_EXPR:
{
dw_loc_descr_ref lhs
- = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+ = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
dw_loc_descr_ref rhs
- = loc_descriptor_from_tree (TREE_OPERAND (loc, 2), 0);
+ = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0);
dw_loc_descr_ref bra_node, jump_node, tmp;
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0 || lhs == 0 || rhs == 0)
return 0;
}
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. */
>= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
return 0;
+#ifdef ENABLE_CHECKING
/* Otherwise this is a generic code; we should just lists all of
- these explicitly. Aborting means we forgot one. */
- abort ();
+ these explicitly. We forgot one. */
+ gcc_unreachable ();
+#else
+ /* In a release build, we want to degrade gracefully: better to
+ generate incomplete debugging information than to crash. */
+ return NULL;
+#endif
}
/* Show if we can't fill the request for an address. */
- if (addressp && indirect_p == 0)
+ if (want_address && !have_address)
return 0;
/* If we've got an address and don't want one, dereference. */
- if (!addressp && indirect_p > 0)
+ if (!want_address && have_address)
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
return ret;
}
+static inline dw_loc_descr_ref
+loc_descriptor_from_tree (tree loc)
+{
+ return loc_descriptor_from_tree_1 (loc, 2);
+}
+
/* Given a value, round it up to the lowest multiple of `boundary'
which is not less than the value itself. */
if (TREE_CODE (decl) == ERROR_MARK)
return 0;
- else if (TREE_CODE (decl) != FIELD_DECL)
- abort ();
+
+ gcc_assert (TREE_CODE (decl) == FIELD_DECL);
type = field_type (decl);
field_size_tree = DECL_SIZE (decl);
/* Calculate the address of the offset. */
offset = tree_low_cst (BINFO_VPTR_FIELD (decl), 0);
- if (offset >= 0)
- abort ();
+ gcc_assert (offset < 0);
tmp = int_loc_descriptor (-offset);
add_loc_descr (&loc_descr, tmp);
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;
else
{
/* ??? We really should be using HOST_WIDE_INT throughout. */
- if (HOST_BITS_PER_LONG != HOST_BITS_PER_WIDE_INT)
- abort ();
+ gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
add_AT_long_long (die, DW_AT_const_value,
CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
unsigned int i;
unsigned char *p;
- if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
+ switch (GET_MODE_CLASS (mode))
{
+ case MODE_VECTOR_INT:
for (i = 0, p = array; i < length; i++, p += elt_size)
{
rtx elt = CONST_VECTOR_ELT (rtl, i);
HOST_WIDE_INT lo, hi;
- if (GET_CODE (elt) == CONST_INT)
+
+ switch (GET_CODE (elt))
{
+ case CONST_INT:
lo = INTVAL (elt);
hi = -(lo < 0);
- }
- else if (GET_CODE (elt) == CONST_DOUBLE)
- {
+ break;
+
+ case CONST_DOUBLE:
lo = CONST_DOUBLE_LOW (elt);
hi = CONST_DOUBLE_HIGH (elt);
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else
- abort ();
if (elt_size <= sizeof (HOST_WIDE_INT))
insert_int (lo, elt_size, p);
- else if (elt_size == 2 * sizeof (HOST_WIDE_INT))
+ 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)
{
p0 = p1;
insert_int (lo, sizeof (HOST_WIDE_INT), p0);
insert_int (hi, sizeof (HOST_WIDE_INT), p1);
}
- else
- abort ();
}
- }
- else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
- {
+ break;
+
+ case MODE_VECTOR_FLOAT:
for (i = 0, p = array; i < length; i++, p += elt_size)
{
rtx elt = CONST_VECTOR_ELT (rtl, i);
insert_float (elt, p);
}
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else
- abort ();
add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
}
case LABEL_REF:
case CONST:
add_AT_addr (die, DW_AT_const_value, rtl);
- VARRAY_PUSH_RTX (used_rtx_varray, rtl);
+ VEC_safe_push (rtx, gc, used_rtx_array, rtl);
break;
case PLUS:
default:
/* No other kinds of rtx should be possible here. */
- abort ();
+ gcc_unreachable ();
+ }
+
+}
+
+/* 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
plus_constant (XEXP (rtl, 0), rsize-dsize));
}
- if (rtl != NULL_RTX)
- {
- rtl = eliminate_regs (rtl, 0, NULL_RTX);
-#ifdef LEAF_REG_REMAP
- if (current_function_uses_only_leaf_regs)
- leaf_renumber_regs_insn (rtl);
-#endif
- }
-
/* A variable with no DECL_RTL but a DECL_INITIAL is a compile-time constant,
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, 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. */
- if (rtl && MEM_P (rtl))
- abort ();
- }
- }
+ if (!rtl && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
+ rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
if (rtl)
rtl = targetm.delegitimize_address (rtl);
return rtl;
}
+/* We need to figure out what section we should use as the base for the
+ address ranges where a given location is valid.
+ 1. If this particular DECL has a section associated with it, use that.
+ 2. If this function has a section associated with it, use that.
+ 3. Otherwise, use the text section.
+ XXX: If you split a variable across multiple sections, we won't notice. */
+
+static const char *
+secname_for_decl (tree decl)
+{
+ const char *secname;
+
+ if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
+ {
+ tree sectree = DECL_SECTION_NAME (decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
+ {
+ 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;
+
+ return secname;
+}
+
/* 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;
-
+ struct var_loc_node *node;
if (TREE_CODE (decl) == ERROR_MARK)
return;
- else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL
- && TREE_CODE (decl) != RESULT_DECL)
- abort ();
+ gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL);
+
/* See if we possibly have multiple locations for this variable. */
loc_list = lookup_decl_loc (decl);
differ. */
if (loc_list && loc_list->first != loc_list->last)
{
- const char *secname;
- const char *endname;
+ const char *endname, *secname;
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.
- 1. If this particular DECL has a section associated with it,
- use that.
- 2. If this function has a section associated with it, use
- that.
- 3. Otherwise, use the text section.
- XXX: If you split a variable across multiple sections, this
- won't notice. */
-
- if (DECL_SECTION_NAME (decl))
- {
- tree sectree = DECL_SECTION_NAME (decl);
- secname = TREE_STRING_POINTER (sectree);
- }
- else if (current_function_decl
- && DECL_SECTION_NAME (current_function_decl))
- {
- tree sectree = DECL_SECTION_NAME (current_function_decl);
- secname = TREE_STRING_POINTER (sectree);
- }
- else
- secname = text_section_label;
/* Now that we know what section we are using for a base,
actually construct the list of locations.
node = loc_list->first;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- list = new_loc_list (loc_descriptor (varloc, attr != DW_AT_frame_base),
+ secname = secname_for_decl (decl);
+
+ list = new_loc_list (loc_descriptor (varloc),
node->label, node->next->label, secname, 1);
node = node->next;
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- add_loc_descr_to_loc_list (&list,
- loc_descriptor (varloc,
- attr != DW_AT_frame_base),
+ add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
node->label, node->next->label, secname);
}
current_function_funcdef_no);
endname = ggc_strdup (label_id);
}
- add_loc_descr_to_loc_list (&list,
- loc_descriptor (varloc,
- attr != DW_AT_frame_base),
+ add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
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 == NULL_RTX)
- return;
-
- switch (GET_CODE (rtl))
+ if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
{
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- case CONST_STRING:
- case SYMBOL_REF:
- case LABEL_REF:
- case CONST:
- case PLUS:
- /* DECL_RTL could be (plus (reg ...) (const_int ...)) */
add_const_value_attribute (die, rtl);
- break;
-
- case MEM:
- if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
- {
- /* Need loc_descriptor_from_tree since that's where we know
- how to handle TLS variables. Want the object's address
- since the top-level DW_AT_location assumes such. See
- the confusion in loc_descriptor for reference. */
- descr = loc_descriptor_from_tree (decl, 1);
- }
- else
+ return;
+ }
+
+ /* 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));
+ if (descr)
{
- case REG:
- case SUBREG:
- case CONCAT:
- descr = loc_descriptor (rtl, true);
+ add_AT_location_description (die, attr, descr);
+ return;
}
- add_AT_location_description (die, attr, descr);
- break;
-
- case PARALLEL:
- {
- rtvec par_elems = XVEC (rtl, 0);
- int num_elem = GET_NUM_ELEM (par_elems);
- enum machine_mode mode;
- int i;
-
- /* Create the first one, so we have something to add to. */
- descr = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0), true);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
- add_loc_descr (&descr,
- new_loc_descr (DW_OP_piece, GET_MODE_SIZE (mode), 0));
- for (i = 1; i < num_elem; i++)
- {
- dw_loc_descr_ref temp;
-
- temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0), true);
- add_loc_descr (&descr, temp);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
- add_loc_descr (&descr,
- new_loc_descr (DW_OP_piece,
- GET_MODE_SIZE (mode), 0));
- }
- }
- add_AT_location_description (die, DW_AT_location, descr);
- break;
+ }
- default:
- abort ();
+ /* We couldn't get any rtl, 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);
+ return;
}
}
{
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;
+ rtl = rtl_for_decl_init (init, type);
+ if (rtl)
+ add_const_value_attribute (var_die, rtl);
+}
+
+#ifdef DWARF2_UNWIND_INFO
+/* Convert the CFI instructions for the current function into a location
+ list. This is used for DW_AT_frame_base when we targeting a dwarf2
+ consumer that does not support the dwarf3 DW_OP_call_frame_cfa. */
+
+static dw_loc_list_ref
+convert_cfa_to_loc_list (void)
+{
+ dw_fde_ref fde;
+ dw_loc_list_ref list, *list_tail;
+ dw_cfi_ref cfi;
+ dw_cfa_location last_cfa, next_cfa;
+ const char *start_label, *last_label, *section;
+
+ fde = &fde_table[fde_table_in_use - 1];
+
+ section = secname_for_decl (current_function_decl);
+ list_tail = &list;
+ list = NULL;
+
+ next_cfa.reg = INVALID_REGNUM;
+ next_cfa.offset = 0;
+ next_cfa.indirect = 0;
+ next_cfa.base_offset = 0;
- default:;
+ start_label = fde->dw_fde_begin;
+
+ /* ??? Bald assumption that the CIE opcode list does not contain
+ advance opcodes. */
+ for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+ lookup_cfa_1 (cfi, &next_cfa);
+
+ last_cfa = next_cfa;
+ last_label = start_label;
+
+ for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_advance_loc1:
+ case DW_CFA_advance_loc2:
+ case DW_CFA_advance_loc4:
+ if (!cfa_equal_p (&last_cfa, &next_cfa))
+ {
+ *list_tail = new_loc_list (build_cfa_loc (&last_cfa), start_label,
+ last_label, section, list == NULL);
+
+ list_tail = &(*list_tail)->dw_loc_next;
+ last_cfa = next_cfa;
+ start_label = last_label;
+ }
+ last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_advance_loc:
+ /* The encoding is complex enough that we should never emit this. */
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ /* We don't handle these two in this function. It would be possible
+ if it were to be required. */
+ gcc_unreachable ();
+
+ default:
+ lookup_cfa_1 (cfi, &next_cfa);
+ break;
+ }
+
+ if (!cfa_equal_p (&last_cfa, &next_cfa))
+ {
+ *list_tail = new_loc_list (build_cfa_loc (&last_cfa), start_label,
+ last_label, section, list == NULL);
+ list_tail = &(*list_tail)->dw_loc_next;
+ start_label = last_label;
}
+ *list_tail = new_loc_list (build_cfa_loc (&next_cfa), start_label,
+ fde->dw_fde_end, section, list == NULL);
+
+ return list;
}
+/* Compute a displacement from the "steady-state frame pointer" to
+ the CFA, and store it in frame_pointer_cfa_offset. */
+
+static void
+compute_frame_pointer_to_cfa_displacement (void)
+{
+ HOST_WIDE_INT offset;
+
+ offset = eliminate_reg_to_offset (arg_pointer_rtx);
+ offset += ARG_POINTER_CFA_OFFSET (current_function_decl);
+
+ frame_pointer_cfa_offset = -offset;
+}
+#endif
+
/* Generate a DW_AT_name attribute given some string value to be included as
the value of the attribute. */
dw_die_ref ctx, decl_die;
dw_loc_descr_ref loc;
- loc = loc_descriptor_from_tree (bound, 0);
+ loc = loc_descriptor_from_tree (bound);
if (loc == NULL)
break;
size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Note that `size' might be -1 when we get to this point. If it is, that
HOST_WIDE_INT unsigned bit_offset;
/* Must be a field and a bit field. */
- if (!type
- || TREE_CODE (decl) != FIELD_DECL)
- abort ();
+ gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
/* We can't yet handle bit-fields whose offsets are variable, so if we
encounter such things, just return without generating any attribute
add_bit_size_attribute (dw_die_ref die, tree decl)
{
/* Must be a field and a bit field. */
- if (TREE_CODE (decl) != FIELD_DECL
- || ! DECL_BIT_FIELD_TYPE (decl))
- abort ();
+ gcc_assert (TREE_CODE (decl) == FIELD_DECL
+ && DECL_BIT_FIELD_TYPE (decl));
if (host_integerp (DECL_SIZE (decl), 1))
add_AT_unsigned (die, DW_AT_bit_size, tree_low_cst (DECL_SIZE (decl), 1));
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);
- if (origin_die == NULL)
- abort ();
+ /* 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. */
{
add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
XEXP (DECL_RTL (decl), 0));
- VARRAY_PUSH_RTX (used_rtx_varray, XEXP (DECL_RTL (decl), 0));
+ VEC_safe_push (tree, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
}
#endif
}
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)
{
- if (VARRAY_ACTIVE_SIZE (decl_scope_table) <= 0)
- abort ();
-
- VARRAY_POP (decl_scope_table);
+ VEC_pop (tree, decl_scope_table);
}
/* Return the DIE for the scope that immediately contains this type.
int i;
/* Non-types always go in the current scope. */
- if (! TYPE_P (t))
- abort ();
+ gcc_assert (TYPE_P (t));
containing_scope = TYPE_CONTEXT (t);
/* 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)
{
- if (debug_info_level > DINFO_LEVEL_TERSE
- && !TREE_ASM_WRITTEN (containing_scope))
- abort ();
+ gcc_assert (debug_info_level <= DINFO_LEVEL_TERSE
+ || TREE_ASM_WRITTEN (containing_scope));
/* If none of the current dies are suitable, we get file scope. */
scope_die = comp_unit_die;
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. */
const char *fnname;
x = DECL_RTL (decl);
- if (!MEM_P (x))
- abort ();
+ gcc_assert (MEM_P (x));
x = XEXP (x, 0);
- if (GET_CODE (x) != SYMBOL_REF)
- abort ();
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
fnname = XSTR (x, 0);
return fnname;
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. */
switch (TREE_CODE_CLASS (TREE_CODE (node)))
{
- case 'd':
+ case tcc_declaration:
origin = decl_ultimate_origin (node);
if (origin != NULL)
add_abstract_origin_attribute (parm_die, origin);
break;
- case 't':
+ case tcc_type:
/* We were called with some kind of a ..._TYPE node. */
add_type_attribute (parm_die, node, 0, 0, context_die);
break;
default:
- abort ();
+ gcc_unreachable ();
}
return parm_die;
if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
&& ! lookup_decl_die (member))
{
- if (decl_ultimate_origin (member))
- abort ();
+ 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 ();
}
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
tree origin = decl_ultimate_origin (decl);
dw_die_ref subr_die;
- rtx fp_reg;
tree fn_arg_types;
tree outer_scope;
dw_die_ref old_die = lookup_decl_die (decl);
if (origin && declaration && class_or_namespace_scope_p (context_die))
{
origin = NULL;
- if (old_die)
- abort ();
+ gcc_assert (!old_die);
}
if (origin != NULL)
{
- if (declaration && ! local_scope_p (context_die))
- abort ();
+ gcc_assert (!declaration || local_scope_p (context_die));
/* Fixup die_parent for the abstract instance of a nested
inline function. */
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. */
- if (errorcount)
- return;
- abort ();
+ /* Detect and ignore this case, where we are trying to output
+ something we have already output. */
+ return;
}
/* If the definition comes from the same place as the declaration,
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. */
add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
#endif
- /* Define the "frame base" location for this routine. We use the
- frame pointer or stack pointer registers, since the RTL for local
- variables is relative to one of them. */
- if (frame_base_decl && lookup_decl_loc (frame_base_decl) != NULL)
- {
- add_location_or_const_value_attribute (subr_die, frame_base_decl,
- DW_AT_frame_base);
- }
- else
- {
- fp_reg
- = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
- add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
- }
+#ifdef DWARF2_UNWIND_INFO
+ /* We define the "frame base" as the function's CFA. This is more
+ convenient for several reasons: (1) It's stable across the prologue
+ and epilogue, which makes it better than just a frame pointer,
+ (2) With dwarf3, there exists a one-byte encoding that allows us
+ to reference the .debug_frame data by proxy, but failing that,
+ (3) We can at least reuse the code inspection and interpretation
+ code that determines the CFA position at various points in the
+ function. */
+ /* ??? Use some command-line or configury switch to enable the use
+ of dwarf3 DW_OP_call_frame_cfa. At present there are no dwarf
+ consumers that understand it; fall back to "pure" dwarf2 and
+ convert the CFA data into a location list. */
+ {
+ dw_loc_list_ref list = convert_cfa_to_loc_list ();
+ if (list->dw_loc_next)
+ add_AT_loc_list (subr_die, DW_AT_frame_base, list);
+ else
+ add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
+ }
+
+ /* Compute a displacement from the "steady-state frame pointer" to
+ the CFA. The former is what all stack slots and argument slots
+ will reference in the rtl; the later is what we've told the
+ debugger about. We'll need to adjust all frame_base references
+ by this displacement. */
+ compute_frame_pointer_to_cfa_displacement ();
+#else
+ /* For targets which support DWARF2, but not DWARF2 call-frame info,
+ we just use the stack pointer or frame pointer. */
+ /* ??? Should investigate getting better info via callbacks, or else
+ by interpreting the IA-64 unwind info. */
+ {
+ rtx fp_reg
+ = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
+ add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
+ }
+#endif
if (cfun->static_chain_decl)
add_AT_location_description (subr_die, DW_AT_static_link,
- loc_descriptor_from_tree (cfun->static_chain_decl, 0));
+ loc_descriptor_from_tree (cfun->static_chain_decl));
}
/* Now output descriptions of the arguments for this function. This gets
}
#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. */
dw_die_ref old_die = lookup_decl_die (decl);
int declaration = (DECL_EXTERNAL (decl)
+ /* If DECL is COMDAT and has not actually been
+ emitted, we cannot take its address; there
+ might end up being no definition anywhere in
+ the program. For example, consider the C++
+ test case:
+
+ template <class T>
+ struct S { static const int i = 7; };
+
+ template <class T>
+ const int S<T>::i;
+
+ int f() { return S<int>::i; }
+
+ Here, S<int>::i is not DECL_EXTERNAL, but no
+ definition is required, so the compiler will
+ not emit a definition. */
+ || (TREE_CODE (decl) == VAR_DECL
+ && DECL_COMDAT (decl) && !TREE_ASM_WRITTEN (decl))
|| class_or_namespace_scope_p (context_die));
if (origin != NULL)
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. */
represent source-level labels which were explicitly declared by
the user. This really shouldn't be happening though, so catch
it if it ever does happen. */
- if (INSN_DELETED_P (insn))
- abort ();
+ gcc_assert (!INSN_DELETED_P (insn));
ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
}
}
-/* Generate a DIE for a lexical block. */
+/* A helper function for gen_inlined_subroutine_die. Add source coordinate
+ attributes to the DIE for a block STMT, to describe where the inlined
+ function was called from. This is similar to add_src_coords_attributes. */
-static void
-gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
+static inline void
+add_call_src_coords_attributes (tree stmt, dw_die_ref die)
+{
+ expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
+ unsigned file_index = lookup_filename (s.file);
+
+ add_AT_unsigned (die, DW_AT_call_file, file_index);
+ add_AT_unsigned (die, DW_AT_call_line, s.line);
+}
+
+/* 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 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);
+ add_call_src_coords_attributes (stmt, subr_die);
+
decls_for_scope (stmt, subr_die, depth);
current_function_has_inlines = 1;
}
add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected);
else if (TREE_PRIVATE (decl))
add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private);
+
+ /* Equate decl number to die, so that we can look up this decl later on. */
+ equate_decl_number_to_die (decl, decl_die);
}
#if 0
/* First output info about the base classes. */
if (binfo)
{
- tree accesses = BINFO_BASE_ACCESSES (binfo);
+ VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo);
int i;
tree base;
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base); i++)
gen_inheritance_die (base,
- (accesses ? TREE_VEC_ELT (accesses, i)
+ (accesses ? VEC_index (tree, accesses, i)
: access_public_node), context_die);
}
/* 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);
}
}
{
type = DECL_ORIGINAL_TYPE (decl);
- if (type == TREE_TYPE (decl))
- abort ();
- else
- equate_type_number_to_die (TREE_TYPE (decl), type_die);
+ gcc_assert (type != TREE_TYPE (decl));
+ equate_type_number_to_die (TREE_TYPE (decl), type_die);
}
else
type = TREE_TYPE (decl);
return;
/* Prevent broken recursion; we can't hand off to the same type. */
- if (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) == type)
- abort ();
+ gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type);
TREE_ASM_WRITTEN (type) = 1;
gen_decl_die (TYPE_NAME (type), context_die);
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);
- abort (); /* No way to represent these in Dwarf yet! */
- break;
-
case FUNCTION_TYPE:
/* Force out return type (in case it wasn't forced out already). */
gen_type_die (TREE_TYPE (type), context_die);
break;
default:
- abort ();
+ gcc_unreachable ();
}
TREE_ASM_WRITTEN (type) = 1;
this type (i.e. without any const or volatile qualifiers) so make sure
that we have the main variant (i.e. the unqualified version) of this
type now. */
- if (type != type_main_variant (type))
- abort ();
+ gcc_assert (type == type_main_variant (type));
/* Do not check TREE_ASM_WRITTEN (type) as it may not be set if this is
an instance of an unresolved type. */
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
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);
+ /* Do not produce debug information for static variables since
+ these might be optimized out. We are called for these later
+ in cgraph_varpool_analyze_pending_decls. */
+ if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
+ ;
+ 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:
break;
default:
- abort ();
+ 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);
- if (!decl_die)
- abort ();
+ 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)
gen_type_die (type, context_die);
type_die = lookup_type_die (type);
- if (!type_die)
- abort();
+ gcc_assert (type_die);
}
return type_die;
}
static dw_die_ref
setup_namespace_context (tree thing, dw_die_ref context_die)
{
- tree context = DECL_P (thing) ? DECL_CONTEXT (thing) : TYPE_CONTEXT (thing);
+ tree context = (DECL_P (thing)
+ ? DECL_CONTEXT (thing) : TYPE_CONTEXT (thing));
if (context && TREE_CODE (context) == NAMESPACE_DECL)
/* Force out the namespace. */
context_die = force_decl_die (context);
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)
break;
default:
- if ((int)TREE_CODE (decl) > NUM_TREE_CODES)
- /* Probably some frontend-internal decl. Assume we don't care. */
- break;
- abort ();
+ /* Probably some frontend-internal decl. Assume we don't care. */
+ gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
+ break;
}
}
\f
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;
- if (!decl)
- abort ();
+ 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
declarations. We have to check DECL_INITIAL instead. That's because
the C front-end supports some weird semantics for "extern inline"
function definitions. These can get inlined within the current
- translation unit (an thus, we need to generate Dwarf info for their
+ translation unit (and thus, we need to generate Dwarf info for their
abstract instances so that the Dwarf info for the concrete inlined
instances can have something to refer to) but the compiler never
generates any out-of-lines instances of such things (despite the fact
if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
return;
+ /* For local statics lookup proper context die. */
+ if (TREE_STATIC (decl) && decl_function_context (decl))
+ context_die = lookup_decl_die (DECL_CONTEXT (decl));
+
/* If we are in terse mode, don't generate any DIEs to represent any
variable declarations or definitions. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
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);
}
return file_table_last_lookup_index;
}
- /* Didn't match the previous lookup, search the table */
+ /* Didn't match the previous lookup, search the table. */
n = VARRAY_ACTIVE_SIZE (file_table);
for (i = 1; i < n; i++)
if (strcmp (file_name, VARRAY_CHAR_PTR (file_table, i)) == 0)
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)
+ return maybe_emit_file (i);
+
return i;
}
+/* If the assembler will construct the file table, then translate the compiler
+ internal file table number into the assembler file table number, and emit
+ a .file directive if we haven't already emitted one yet. The file table
+ numbers are different because we prune debug info for unused variables and
+ types, which may include filenames. */
+
static int
maybe_emit_file (int fileno)
{
return fileno;
}
+/* Initialize the compiler internal file table. */
+
static void
init_file_table (void)
{
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_IS_FROM (decl) && DECL_DEBUG_EXPR (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)
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
+ int fileno;
+
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
lineno);
- maybe_emit_file (lookup_filename (filename));
- dw2_asm_output_data_uleb128 (lookup_filename (filename),
- "Filename we just started");
+
+ fileno = maybe_emit_file (lookup_filename (filename));
+ dw2_asm_output_data_uleb128 (fileno, "Filename we just started");
}
}
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
* sizeof (dw_die_ref));
abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
- /* Zero-th entry is allocated, but unused */
+ /* Zero-th entry is allocated, but unused. */
abbrev_die_table_in_use = 1;
/* Allocate the initial hunk of the line_info_table. */
* sizeof (dw_line_info_entry));
line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
- /* Zero-th entry is allocated, but unused */
+ /* Zero-th entry is allocated, but unused. */
line_info_table_in_use = 1;
/* Generate the initial DIE for the .debug section. Note that the (string)
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");
+ used_rtx_array = VEC_alloc (rtx, gc, 32);
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);
}
}
Make sure that it will get emitted. */
prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
}
- else if (a->dw_attr == DW_AT_decl_file)
+ else if (a->dw_attr == DW_AT_decl_file || a->dw_attr == DW_AT_call_file)
{
/* A reference to a file. Make sure the file name is emitted. */
a->dw_attr_val.v.val_unsigned =
prune_unused_types_prune (dw_die_ref die)
{
dw_die_ref c, p, n;
- if (!die->die_mark)
- abort();
+
+ gcc_assert (die->die_mark);
p = NULL;
for (c = die->die_child; c; c = n)
if (die->die_parent == NULL)
{
dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
- tree context;
if (origin)
add_child_die (origin->die_parent, die);
else if (errorcount > 0 || sorrycount > 0)
/* It's OK to be confused by errors in the input. */
add_child_die (comp_unit_die, die);
- else if (node->created_for
- && ((DECL_P (node->created_for)
- && (context = DECL_CONTEXT (node->created_for)))
- || (TYPE_P (node->created_for)
- && (context = TYPE_CONTEXT (node->created_for))))
- && TREE_CODE (context) == FUNCTION_DECL)
+ else
{
/* In certain situations, the lexical block containing a
nested function can be optimized away, which results
in the nested function die being orphaned. Likewise
with the return type of that nested function. Force
- this to be a child of the containing function. */
+ this to be a child of the containing function.
+
+ It may happen that even the containing function got fully
+ inlined and optimized out. In that case we are lost and
+ assign the empty child. This should not be big issue as
+ the function is likely unreachable too. */
+ tree context = NULL_TREE;
+
+ gcc_assert (node->created_for);
+
+ if (DECL_P (node->created_for))
+ 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)
- abort ();
- add_child_die (origin, die);
+ if (origin)
+ add_child_die (origin, die);
+ else
+ add_child_die (comp_unit_die, die);
}
- else
- abort ();
}
}
/* 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
/* We can only use the low/high_pc attributes if all of the code was
in .text. */
- if (separate_line_info_table_in_use == 0)
+ if (!separate_line_info_table_in_use && !have_switched_text_section)
{
add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
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");
}