diff mbox

Emitting correct DWARF location descriptor for multi-reg frame pointer

Message ID 20121204072906.GA5086@atmel.com
State New
Headers show

Commit Message

Senthil Kumar Selvaraj Dec. 4, 2012, 7:29 a.m. UTC
As a follow-up to this discussion
(http://gcc.gnu.org/ml/gcc/2012-11/msg00307.html), I have a patch that
makes dwarf2out.c emit correct location information for a FP register spanning
multiple hard regs.

Before the patch, the DW_AT_location for a local variable on the AVR
target (whose FP spans registers R29 and R28) looks like this
<4f>   DW_AT_location    : 2 byte block: 8c 1   (DW_OP_breg28 (r28): 1)

After the patch, it looks like this
<4f>   DW_AT_location    : 11 byte block: 6c 93 1 6d 93 1 11 1 22 94 2
(DW_OP_reg28 (r28); DW_OP_piece: 1; DW_OP_reg29 (r29); DW_OP_piece: 1;
DW_OP_consts: 1; DW_OP_plus; DW_OP_deref_size: 2)

What do you guys think?

Regards
Senthil

Comments

Jakub Jelinek Dec. 4, 2012, 7:59 a.m. UTC | #1
On Tue, Dec 04, 2012 at 12:59:11PM +0530, Senthil Kumar Selvaraj wrote:
> As a follow-up to this discussion
> (http://gcc.gnu.org/ml/gcc/2012-11/msg00307.html), I have a patch that
> makes dwarf2out.c emit correct location information for a FP register spanning
> multiple hard regs.
> 
> Before the patch, the DW_AT_location for a local variable on the AVR
> target (whose FP spans registers R29 and R28) looks like this
> <4f>   DW_AT_location    : 2 byte block: 8c 1   (DW_OP_breg28 (r28): 1)
> 
> After the patch, it looks like this
> <4f>   DW_AT_location    : 11 byte block: 6c 93 1 6d 93 1 11 1 22 94 2
> (DW_OP_reg28 (r28); DW_OP_piece: 1; DW_OP_reg29 (r29); DW_OP_piece: 1;
> DW_OP_consts: 1; DW_OP_plus; DW_OP_deref_size: 2)
> 
> What do you guys think?

That is invalid DWARF.
Most DW_OP_* opcodes are usable in DWARF expressions, but not all of them,
and DW_OP_reg0..DW_OP_reg31/DW_OP_regx/DW_OP_piece/DW_OP_bit_piece
/DW_OP_implicit_value/DW_OP_stack_value/DW_OP_GNU_implicit_pointer
are the exceptions that can't be used in DWARF expressions.
Then there are DWARF location descriptions, which can be:
1) memory location descriptions (a sequence of DWARF expression opcodes)
2) register location descriptions (one of DW_OP_reg0..DW_OP_reg31 or DW_OP_regx)
3) implicit location descriptions, either DW_OP_implicit_value alone, or
   DWARF expression opcodes followed by DW_OP_stack_value
4) implicit pointer, DW_OP_GNU_implicit_pointer
5) composite location description (a series of 1), 2), 3) or 4) followed
   by DW_OP_piece or DW_OP_bit_piece
So, you can't put any DWARF expression opcodes after DW_OP_reg* or
DW_OP_piece.  If your registers are 8-bit, but pointers 16-bit, the question
is what the consumers actually push into the DWARF stack on say DW_OP_bregx,
if they push just one 8-bit register (and, is it zero or sign extending?),
then perhaps you could emit for say based_loc_register register 4 with
offset 16 if register 4 is 8-bit something like (assuming little endian):
DW_OP_breg5 <0> DW_OP_lit8 DW_OP_shl DW_OP_breg4 <0> DW_OP_const1u <0xff>
DW_OP_and DW_OP_plus DW_OP_plus_uconst <offset> (for positive offset, for
negative offset you'd want int_loc_descriptor (offset) followed by DW_OP_plus.
That will put there (reg5<<8)+(reg4&0xff)+offset.
DW_OP_deref* shouldn't be used, DWARF expression is simply a memory location
description ( 1) above) by default.

	Jakub
diff mbox

Patch

diff --git gcc/dwarf2out.c gcc/dwarf2out.c
index f0256ae..53a4e56 100644
--- gcc/dwarf2out.c
+++ gcc/dwarf2out.c
@@ -10875,11 +10875,25 @@  based_loc_descr (rtx reg, HOST_WIDE_INT offset,
       return new_loc_descr (DW_OP_fbreg, offset, 0);
     }
 
-  if (regno <= 31)
-    result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
-			    offset, 0);
+  rtx regs = targetm.dwarf_register_span (reg);
+
+  if (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] > 1 || regs)
+    {
+      result = multiple_reg_loc_descriptor (reg, regs, initialized);
+      add_loc_descr (&result, new_loc_descr (DW_OP_consts, offset, 0));
+      add_loc_descr (&result, new_loc_descr (DW_OP_plus, 0, 0));
+      add_loc_descr (&result, new_loc_descr (DW_OP_deref_size, 
+                  GET_MODE_SIZE (GET_MODE (reg)),
+                  0));
+    }
   else
-    result = new_loc_descr (DW_OP_bregx, regno, offset);
+    {
+      if (regno <= 31)
+          result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
+			    offset, 0);
+      else
+          result = new_loc_descr (DW_OP_bregx, regno, offset);
+    }
 
   if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
     add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));