Commit 770ca8c6 by Jeffrey Oldham Committed by Jeffrey D. Oldham

dwarf2out.c: Added explanation of abbreviations.

2001-02-01  Jeffrey Oldham  <oldham@codesourcery.com>

	* dwarf2out.c: Added explanation of abbreviations.
	(def_cfa_1): Added comments listing DWARF2 instructions.
	(cfa_temp_reg): Removed in favor of cfa_temp.
	(cfa_temp_value): Removed in favor of cfa_temp.
	(cfa_temp): New global variable.
	(dwarf2out_frame_debug_expr): Added extensive introductory
	comments explaining the function's transformations.  Revised to
	use cfa_temp.  Added some rtx checking.  Generalize IOR case.
	(dwarf2out_frame_debug): Revised to use cfa_temp.
	(output_aranges): Cast as "unsigned" to avoid warning.
	* rtl.texi (RTX_FRAME_RELATED_P): Revise entry to emphasize better
	explain which instructions must be marked.

From-SVN: r39405
parent cad33336
2001-02-01 Jeffrey Oldham <oldham@codesourcery.com>
* dwarf2out.c: Added explanation of abbreviations.
(def_cfa_1): Added comments listing DWARF2 instructions.
(cfa_temp_reg): Removed in favor of cfa_temp.
(cfa_temp_value): Removed in favor of cfa_temp.
(cfa_temp): New global variable.
(dwarf2out_frame_debug_expr): Added extensive introductory
comments explaining the function's transformations. Revised to
use cfa_temp. Added some rtx checking. Generalize IOR case.
(dwarf2out_frame_debug): Revised to use cfa_temp.
(output_aranges): Cast as "unsigned" to avoid warning.
* rtl.texi (RTX_FRAME_RELATED_P): Revise entry to emphasize better
explain which instructions must be marked.
2001-02-01 Richard Henderson <rth@redhat.com> 2001-02-01 Richard Henderson <rth@redhat.com>
* local-alloc.c (update_equiv_regs): Copy INSN_CODE to the * local-alloc.c (update_equiv_regs): Copy INSN_CODE to the
......
...@@ -55,6 +55,24 @@ Boston, MA 02111-1307, USA. */ ...@@ -55,6 +55,24 @@ Boston, MA 02111-1307, USA. */
#include "md5.h" #include "md5.h"
#include "tm_p.h" #include "tm_p.h"
/* DWARF2 Abbreviation Glossary:
CFA = Canonical Frame Address
stack address identifying a stack call frame; its value is
the value of the stack pointer just before the call to the
current function
CFI = Canonical Frame Instruction
information describing entries in a stack call frame, e.g.,
CIE and FDE
CIE = Common Information Entry
information describing information common to one or more FDEs
DIE = Debugging Information Entry
FDE = Frame Description Entry
information describing the stack call frame, in particular,
how to restore registers
DW_CFA_... = DWARF2 CFA call frame instruction
DW_TAG_... = DWARF2 DIE tag */
/* Decide whether we want to emit frame unwind information for the current /* Decide whether we want to emit frame unwind information for the current
translation unit. */ translation unit. */
...@@ -855,7 +873,7 @@ dwarf2out_def_cfa (label, reg, offset) ...@@ -855,7 +873,7 @@ dwarf2out_def_cfa (label, reg, offset)
def_cfa_1 (label, &loc); def_cfa_1 (label, &loc);
} }
/* This routine does the actual work. The CFA is now calculated from /* This routine does the actual work. The CFA is now calculated from
the dw_cfa_location structure. */ the dw_cfa_location structure. */
static void static void
def_cfa_1 (label, loc_p) def_cfa_1 (label, loc_p)
...@@ -879,6 +897,8 @@ def_cfa_1 (label, loc_p) ...@@ -879,6 +897,8 @@ def_cfa_1 (label, loc_p)
{ {
if (loc.indirect == 0 if (loc.indirect == 0
|| loc.base_offset == old_cfa.base_offset) || loc.base_offset == old_cfa.base_offset)
/* Nothing changed so no need to issue any call frame
instructions. */
return; return;
} }
...@@ -886,6 +906,9 @@ def_cfa_1 (label, loc_p) ...@@ -886,6 +906,9 @@ def_cfa_1 (label, loc_p)
if (loc.reg == old_cfa.reg && !loc.indirect) if (loc.reg == old_cfa.reg && !loc.indirect)
{ {
/* Construct a "DW_CFA_def_cfa_offset <offset>" instruction,
indicating the CFA register did not change but the offset
did. */
cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset; cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
} }
...@@ -894,6 +917,9 @@ def_cfa_1 (label, loc_p) ...@@ -894,6 +917,9 @@ def_cfa_1 (label, loc_p)
else if (loc.offset == old_cfa.offset && old_cfa.reg != (unsigned long) -1 else if (loc.offset == old_cfa.offset && old_cfa.reg != (unsigned long) -1
&& !loc.indirect) && !loc.indirect)
{ {
/* Construct a "DW_CFA_def_cfa_register <register>" instruction,
indicating the CFA register has changed to <register> but the
offset has not changed. */
cfi->dw_cfi_opc = DW_CFA_def_cfa_register; cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
} }
...@@ -901,12 +927,18 @@ def_cfa_1 (label, loc_p) ...@@ -901,12 +927,18 @@ def_cfa_1 (label, loc_p)
else if (loc.indirect == 0) else if (loc.indirect == 0)
{ {
/* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
indicating the CFA register has changed to <register> with
the specified offset. */
cfi->dw_cfi_opc = DW_CFA_def_cfa; cfi->dw_cfi_opc = DW_CFA_def_cfa;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset; cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
} }
else else
{ {
/* Construct a DW_CFA_def_cfa_expression instruction to
calculate the CFA using a full location expression since no
register-offset pair is available. */
struct dw_loc_descr_struct *loc_list; struct dw_loc_descr_struct *loc_list;
cfi->dw_cfi_opc = DW_CFA_def_cfa_expression; cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
loc_list = build_cfa_loc (&loc); loc_list = build_cfa_loc (&loc);
...@@ -1237,15 +1269,132 @@ dwarf2out_stack_adjust (insn) ...@@ -1237,15 +1269,132 @@ dwarf2out_stack_adjust (insn)
dwarf2out_args_size (label, args_size); dwarf2out_args_size (label, args_size);
} }
/* A temporary register used in adjusting SP or setting up the store_reg. */ /* A temporary register holding an integral value used in adjusting SP
static unsigned cfa_temp_reg; or setting up the store_reg. The "offset" field holds the integer
value, not an offset. */
/* A temporary value used in adjusting SP or setting up the store_reg. */ dw_cfa_location cfa_temp;
static long cfa_temp_value;
/* Record call frame debugging information for an expression EXPR,
/* Record call frame debugging information for an expression, which either which either sets SP or FP (adjusting how we calculate the frame
sets SP or FP (adjusting how we calculate the frame address) or saves a address) or saves a register to the stack. LABEL indicates the
register to the stack. */ address of EXPR.
This function encodes a state machine mapping rtxes to actions on
cfa, cfa_store, and cfa_temp.reg. We describe these rules so
users need not read the source code.
Invariants / Summaries of Rules
cfa current register used to calculate the DWARF2 canonical
frame address register and offset
cfa_store register used by prologue code to save things to the stack
cfa_store.offset is the offset from the value of
cfa_store.reg to the actual CFA
cfa_temp register holding an integral value. cfa_temp.offset
stores the value, which will be used to adjust the
stack pointer.
Rules 1- 4: Setting a register's value to cfa.reg or an expression
with cfa.reg as the first operand changes the cfa.reg and its
cfa.offset.
(For an unknown reason, Rule 4 does not fully obey the
invariant.)
Rules 6- 9: Set a non-cfa.reg register value to a constant or an
expression yielding a constant. This sets cfa_temp.reg
and cfa_temp.offset.
Rule 5: Create a new register cfa_store used to save items to the
stack.
Rules 10-13: Save a register to the stack. Record the location in
cfa_store.offset. Define offset as the difference of
the original location and cfa_store's location.
The Rules
"{a,b}" indicates a choice of a xor b.
"<reg>:cfa.reg" indicates that <reg> must equal cfa.reg.
Rule 1:
(set <reg1> <reg2>:cfa.reg)
effects: cfa.reg = <REG1>
cfa.offset unchanged
Rule 2:
(set sp ({minus,plus} {sp,fp}:cfa.reg {<const_int>,<reg>:cfa_temp.reg}))
effects: cfa.reg = sp if fp used
cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
cfa_store.offset += {+/- <const_int>, cfa_temp.offset}
if cfa_store.reg==sp
Rule 3:
(set fp ({minus,plus} <reg>:cfa.reg <const_int>))
effects: cfa.reg = fp
cfa_offset += +/- <const_int>
Rule 4:
(set <reg1> (plus <reg2>:cfa.reg <const_int>))
constraints: <reg1> != fp
<reg1> != sp
effects: cfa.reg = <reg1>
questions: Where is <const_int> used?
Should cfa.offset be changed?
Rule 5:
(set <reg1> (plus <reg2>:cfa_temp.reg sp:cfa.reg))
constraints: <reg1> != fp
<reg1> != sp
effects: cfa_store.reg = <reg1>
cfa_store.offset = cfa.offset - cfa_temp.offset
Rule 6:
(set <reg> <const_int>)
effects: cfa_temp.reg = <reg>
cfa_temp.offset = <const_int>
Rule 7:
(set <reg1>:cfa_temp.reg (ior <reg2>:cfa_temp.reg <const_int>))
effects: cfa_temp.reg = <reg1>
cfa_temp.offset |= <const_int>
Rule 8:
(set <reg> (high <exp>))
effects: none
Rule 9:
(set <reg> (lo_sum <exp> <const_int>))
effects: cfa_temp.reg = <reg>
cfa_temp.offset = <const_int>
Rule 10:
(set (mem (pre_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
effects: cfa_store.offset -= <const_int>
cfa.offset = cfa_store.offset if cfa.reg == sp
offset = -cfa_store.offset
cfa.reg = sp
cfa.base_offset = offset
Rule 11:
(set (mem ({pre_inc,pre_dec} sp:cfa_store.reg)) <reg>)
effects: cfa_store.offset += -/+ mode_size(mem)
cfa.offset = cfa_store.offset if cfa.reg == sp
offset = -cfa_store.offset
cfa.reg = sp
cfa.base_offset = offset
Rule 12:
(set (mem ({minus,plus} <reg1>:cfa_store <const_int>)) <reg2>)
effects: cfa_store.offset += -/+ <const_int>
offset = -cfa_store.offset
cfa.reg = <reg1
cfa.base_offset = offset
Rule 13:
(set (mem <reg1>:cfa_store) <reg2>)
effects: offset = -cfa_store.offset
cfa.reg = <reg1>
cfa.base_offset = offset */
static void static void
dwarf2out_frame_debug_expr (expr, label) dwarf2out_frame_debug_expr (expr, label)
...@@ -1257,7 +1406,7 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1257,7 +1406,7 @@ dwarf2out_frame_debug_expr (expr, label)
/* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
the PARALLEL independently. The first element is always processed if the PARALLEL independently. The first element is always processed if
it is a SET. This is for backward compatability. Other elements it is a SET. This is for backward compatibility. Other elements
are processed only if they are SETs and the RTX_FRAME_RELATED_P are processed only if they are SETs and the RTX_FRAME_RELATED_P
flag is set in them. */ flag is set in them. */
...@@ -1287,6 +1436,7 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1287,6 +1436,7 @@ dwarf2out_frame_debug_expr (expr, label)
switch (GET_CODE (dest)) switch (GET_CODE (dest))
{ {
case REG: case REG:
/* Rule 1 */
/* Update the CFA rule wrt SP or FP. Make sure src is /* Update the CFA rule wrt SP or FP. Make sure src is
relative to the current CFA register. */ relative to the current CFA register. */
switch (GET_CODE (src)) switch (GET_CODE (src))
...@@ -1310,6 +1460,7 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1310,6 +1460,7 @@ dwarf2out_frame_debug_expr (expr, label)
case MINUS: case MINUS:
if (dest == stack_pointer_rtx) if (dest == stack_pointer_rtx)
{ {
/* Rule 2 */
/* Adjusting SP. */ /* Adjusting SP. */
switch (GET_CODE (XEXP (src, 1))) switch (GET_CODE (XEXP (src, 1)))
{ {
...@@ -1317,9 +1468,9 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1317,9 +1468,9 @@ dwarf2out_frame_debug_expr (expr, label)
offset = INTVAL (XEXP (src, 1)); offset = INTVAL (XEXP (src, 1));
break; break;
case REG: case REG:
if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp_reg) if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp.reg)
abort (); abort ();
offset = cfa_temp_value; offset = cfa_temp.offset;
break; break;
default: default:
abort (); abort ();
...@@ -1344,6 +1495,7 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1344,6 +1495,7 @@ dwarf2out_frame_debug_expr (expr, label)
} }
else if (dest == hard_frame_pointer_rtx) else if (dest == hard_frame_pointer_rtx)
{ {
/* Rule 3 */
/* Either setting the FP from an offset of the SP, /* Either setting the FP from an offset of the SP,
or adjusting the FP */ or adjusting the FP */
if (! frame_pointer_needed) if (! frame_pointer_needed)
...@@ -1367,39 +1519,44 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1367,39 +1519,44 @@ dwarf2out_frame_debug_expr (expr, label)
if (GET_CODE (src) != PLUS) if (GET_CODE (src) != PLUS)
abort (); abort ();
/* Rule 4 */
if (GET_CODE (XEXP (src, 0)) == REG if (GET_CODE (XEXP (src, 0)) == REG
&& REGNO (XEXP (src, 0)) == cfa.reg && REGNO (XEXP (src, 0)) == cfa.reg
&& GET_CODE (XEXP (src, 1)) == CONST_INT) && GET_CODE (XEXP (src, 1)) == CONST_INT)
/* Setting the FP (or a scratch that will be copied into the FP /* Setting the FP (or a scratch that will be copied into the FP
later on) from SP + const. */ later on) from SP + const. */
cfa.reg = REGNO (dest); cfa.reg = REGNO (dest);
/* Rule 5 */
else else
{ {
if (XEXP (src, 1) != stack_pointer_rtx) if (XEXP (src, 1) != stack_pointer_rtx)
abort (); abort ();
if (GET_CODE (XEXP (src, 0)) != REG if (GET_CODE (XEXP (src, 0)) != REG
|| (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg) || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp.reg)
abort (); abort ();
if (cfa.reg != STACK_POINTER_REGNUM) if (cfa.reg != STACK_POINTER_REGNUM)
abort (); abort ();
cfa_store.reg = REGNO (dest); cfa_store.reg = REGNO (dest);
cfa_store.offset = cfa.offset - cfa_temp_value; cfa_store.offset = cfa.offset - cfa_temp.offset;
} }
} }
break; break;
/* Rule 6 */
case CONST_INT: case CONST_INT:
cfa_temp_reg = REGNO (dest); cfa_temp.reg = REGNO (dest);
cfa_temp_value = INTVAL (src); cfa_temp.offset = INTVAL (src);
break; break;
/* Rule 7 */
case IOR: case IOR:
if (GET_CODE (XEXP (src, 0)) != REG if (GET_CODE (XEXP (src, 0)) != REG
|| (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp.reg
|| (unsigned) REGNO (dest) != cfa_temp_reg
|| GET_CODE (XEXP (src, 1)) != CONST_INT) || GET_CODE (XEXP (src, 1)) != CONST_INT)
abort (); abort ();
cfa_temp_value |= INTVAL (XEXP (src, 1)); if ((unsigned) REGNO (dest) != cfa_temp.reg)
cfa_temp.reg = REGNO (dest);
cfa_temp.offset |= INTVAL (XEXP (src, 1));
break; break;
default: default:
...@@ -1410,12 +1567,16 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1410,12 +1567,16 @@ dwarf2out_frame_debug_expr (expr, label)
/* Skip over HIGH, assuming it will be followed by a LO_SUM, which /* Skip over HIGH, assuming it will be followed by a LO_SUM, which
will fill in all of the bits. */ will fill in all of the bits. */
/* Rule 8 */
case HIGH: case HIGH:
break; break;
/* Rule 9 */
case LO_SUM: case LO_SUM:
cfa_temp_reg = REGNO (dest); if (GET_CODE (XEXP (src, 1)) != CONST_INT)
cfa_temp_value = INTVAL (XEXP (src, 1)); abort ();
cfa_temp.reg = REGNO (dest);
cfa_temp.offset = INTVAL (XEXP (src, 1));
break; break;
case MEM: case MEM:
...@@ -1426,6 +1587,7 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1426,6 +1587,7 @@ dwarf2out_frame_debug_expr (expr, label)
CFA register. */ CFA register. */
switch (GET_CODE (XEXP (dest, 0))) switch (GET_CODE (XEXP (dest, 0)))
{ {
/* Rule 10 */
/* With a push. */ /* With a push. */
case PRE_MODIFY: case PRE_MODIFY:
/* We can't handle variable size modifications. */ /* We can't handle variable size modifications. */
...@@ -1442,6 +1604,7 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1442,6 +1604,7 @@ dwarf2out_frame_debug_expr (expr, label)
offset = -cfa_store.offset; offset = -cfa_store.offset;
break; break;
/* Rule 11 */
case PRE_INC: case PRE_INC:
case PRE_DEC: case PRE_DEC:
offset = GET_MODE_SIZE (GET_MODE (dest)); offset = GET_MODE_SIZE (GET_MODE (dest));
...@@ -1458,9 +1621,12 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1458,9 +1621,12 @@ dwarf2out_frame_debug_expr (expr, label)
offset = -cfa_store.offset; offset = -cfa_store.offset;
break; break;
/* Rule 12 */
/* With an offset. */ /* With an offset. */
case PLUS: case PLUS:
case MINUS: case MINUS:
if (GET_CODE (XEXP (XEXP (dest, 0), 1)) != CONST_INT)
abort ();
offset = INTVAL (XEXP (XEXP (dest, 0), 1)); offset = INTVAL (XEXP (XEXP (dest, 0), 1));
if (GET_CODE (XEXP (dest, 0)) == MINUS) if (GET_CODE (XEXP (dest, 0)) == MINUS)
offset = -offset; offset = -offset;
...@@ -1470,6 +1636,7 @@ dwarf2out_frame_debug_expr (expr, label) ...@@ -1470,6 +1636,7 @@ dwarf2out_frame_debug_expr (expr, label)
offset -= cfa_store.offset; offset -= cfa_store.offset;
break; break;
/* Rule 13 */
/* Without an offset. */ /* Without an offset. */
case REG: case REG:
if (cfa_store.reg != (unsigned) REGNO (XEXP (dest, 0))) if (cfa_store.reg != (unsigned) REGNO (XEXP (dest, 0)))
...@@ -1543,8 +1710,8 @@ dwarf2out_frame_debug (insn) ...@@ -1543,8 +1710,8 @@ dwarf2out_frame_debug (insn)
abort (); abort ();
cfa.reg = STACK_POINTER_REGNUM; cfa.reg = STACK_POINTER_REGNUM;
cfa_store = cfa; cfa_store = cfa;
cfa_temp_reg = -1; cfa_temp.reg = -1;
cfa_temp_value = 0; cfa_temp.offset = 0;
return; return;
} }
...@@ -6356,7 +6523,7 @@ output_aranges () ...@@ -6356,7 +6523,7 @@ output_aranges ()
/* Pad using a 2 bytes word so that padding is correct /* Pad using a 2 bytes word so that padding is correct
for any pointer size. */ for any pointer size. */
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0); ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0);
for (i = 2; i < DWARF_ARANGES_PAD_SIZE; i += 2) for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
fprintf (asm_out_file, ",0"); fprintf (asm_out_file, ",0");
if (flag_debug_asm) if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Pad to %d byte boundary", fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
......
...@@ -458,10 +458,29 @@ Stored in the @code{integrated} field and printed as @samp{/i}. ...@@ -458,10 +458,29 @@ Stored in the @code{integrated} field and printed as @samp{/i}.
@findex RTX_FRAME_RELATED_P @findex RTX_FRAME_RELATED_P
@item RTX_FRAME_RELATED_P (@var{x}) @item RTX_FRAME_RELATED_P (@var{x})
Nonzero in an insn or expression which is part of a function Nonzero in an insn or expression which is part of a function prologue
prologue and sets the stack pointer, sets the frame pointer, or saves a and sets the stack pointer, sets the frame pointer, or saves a register.
register. This flag is required for exception handling support This flag should also be set on an instruction that sets up a temporary
on targets with RTL prologues. register to use in place of the frame pointer.
In particular, on RISC targets where there are limits on the sizes of
immediate constants, it is sometimes impossible to reach the register
save area directly from the stack pointer. In that case, a temporary
register is used that is near enough to the register save area, and the
Canonical Frame Address, i.e., DWARF2's logical frame pointer, register
must (temporarily) be changed to be this temporary register. So, the
instruction that sets this temporary register must be marked as
@code{RTX_FRAME_RELATED_P}.
If the marked instruction is overly complex (defined in terms of what
@code{dwarf2out_frame_debug_expr} can handle), you will also have to
create a @code{REG_FRAME_RELATED_EXPR} note and attach it to the
instruction. This note should contain a simple expression of the
computation performed by this instruction, i.e., one that
@code{dwarf2out_frame_debug_expr} can handle.
This flag is required for exception handling support on targets with RTL
prologues.
@findex SYMBOL_REF_USED @findex SYMBOL_REF_USED
@cindex @code{used}, in @code{symbol_ref} @cindex @code{used}, in @code{symbol_ref}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment