public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Andrew Stubbs <ams@codesourcery.com>
To: "gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] dwarf: Multi-register CFI address support
Date: Thu, 3 Sep 2020 16:29:41 +0100	[thread overview]
Message-ID: <4b1263f2-ae04-bf9a-4f2b-3da192c0daed@codesourcery.com> (raw)
In-Reply-To: <363f6c4b-4c7f-9244-9bf1-dee7e7a42f8c@codesourcery.com>

[-- Attachment #1: Type: text/plain, Size: 1628 bytes --]

On 28/08/2020 13:04, Andrew Stubbs wrote:
> Hi all,
> 
> This patch introduces DWARF CFI support for architectures that require 
> multiple registers to hold pointers, such as the stack pointer, frame 
> pointer, and return address. The motivating case is the AMD GCN 
> architecture which has 64-bit address pointers, but 32-bit registers.
> 
> The current implementation permits program variables to span as many 
> registers as they need, but assumes that CFI expressions will only need 
> a single register for each frame value.
> 
> To be fair, the DWARF standard makes a similar assumption; the engineers 
> working on LLVM and GDB, at AMD, have therefore invented some new DWARF 
> operators that they plan to propose for a future standard. Only one is 
> relevant here, however: DW_OP_LLVM_piece_end. (Unfortunately this 
> clashes with an AArch64 extension, but I think we can cope using an 
> alias -- only GCC dumps will be confusing.)
> 
> My approach is to change the type representing a DWARF register 
> throughout the CFI code. This permits the register span information to 
> propagate to where it is needed.
> 
> I've taken advantage of C++ struct copies and operator== to minimize the 
> amount of refactoring required. I'm not sure this meets the GCC 
> guidelines exactly, but if not I can change that once the basic form is 
> agreed. (I also considered an operator= to make assigning single dwreg 
> values transparent, but that hid too many invalid assumptions.)
> 
> OK to commit? (Although, I'll hold off until AMD release the compatible 
> GDB.)

Minor patch update, following Tom's feedback.

Andrew

[-- Attachment #2: 200903-dwarf-reg-spans.patch --]
[-- Type: text/x-patch, Size: 29948 bytes --]

dwarf: Multi-register CFI address support

Add support for architectures such as AMD GCN, in which the pointer size is
larger than the register size.  This allows the CFI information to include
multi-register locations for the stack pointer, frame pointer, and return
address.

Note that this uses a newly proposed DWARF operator DW_OP_LLVM_piece_end,
which is currently only recognized by the ROCGDB debugger from AMD.  The exact
name and encoding for this operator is subject to change if and when the DWARF
standard accepts it.

gcc/ChangeLog:

	* dwarf2cfi.c (dw_stack_pointer_regnum): Change type to struct cfa_reg.
	(dw_frame_pointer_regnum): Likewise.
	(new_cfi_row): Use set_by_dwreg.
	(get_cfa_from_loc_descr): Use set_by_dwreg.  Support register spans
	with DW_OP_piece and DW_OP_LLVM_piece_end.  Support DW_OP_lit*,
	DW_OP_const*, DW_OP_minus, and DW_OP_plus.
	(lookup_cfa_1): Use set_by_dwreg.
	(def_cfa_0): Update for cfa_reg and support register spans.
	(reg_save): Change sreg parameter to struct cfa_reg.  Support register
	spans.
	(dwf_cfa_reg): New function.
	(dwarf2out_flush_queued_reg_saves): Use dwf_cfa_reg instead of
	dwf_regno.
	(dwarf2out_frame_debug_def_cfa): Likewise.
	(dwarf2out_frame_debug_adjust_cfa): Likewise.
	(dwarf2out_frame_debug_cfa_offset): Likewise.  Update reg_save usage.
	(dwarf2out_frame_debug_cfa_register): Likewise.
	(dwarf2out_frame_debug_expr): Likewise.
	(create_pseudo_cfg): Use set_by_dwreg.
	(initial_return_save): Use set_by_dwreg and dwf_cfa_reg,
	(create_cie_data): Use dwf_cfa_reg.
	(execute_dwarf2_frame): Use dwf_cfa_reg.
	(dump_cfi_row): Use set_by_dwreg.
	* dwarf2out.c (build_span_loc): New function.
	(build_cfa_loc): Support register spans.
	(build_cfa_aligned_loc): Update cfa_reg usage.
	(convert_cfa_to_fb_loc_list): Use set_by_dwreg.
	* dwarf2out.h (struct cfa_reg): New type.
	(struct dw_cfa_location): Use struct cfa_reg.
	(build_span_loc): New prototype.
	* gengtype.c (main): Accept poly_uint16_pod type.

include/ChangeLog:

	* dwarf2.def (DW_OP_LLVM_piece_end): New extension operator.

diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index 0d179b388e4..63cb6de5c4f 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -229,8 +229,8 @@ static vec<queued_reg_save> queued_reg_saves;
 static bool any_cfis_emitted;
 
 /* Short-hand for commonly used register numbers.  */
-static unsigned dw_stack_pointer_regnum;
-static unsigned dw_frame_pointer_regnum;
+static struct cfa_reg dw_stack_pointer_regnum;
+static struct cfa_reg dw_frame_pointer_regnum;
 \f
 /* Hook used by __throw.  */
 
@@ -430,7 +430,7 @@ new_cfi_row (void)
 {
   dw_cfi_row *row = ggc_cleared_alloc<dw_cfi_row> ();
 
-  row->cfa.reg = INVALID_REGNUM;
+  row->cfa.reg.set_by_dwreg (INVALID_REGNUM);
 
   return row;
 }
@@ -538,7 +538,11 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_node *loc)
   cfa->offset = 0;
   cfa->base_offset = 0;
   cfa->indirect = 0;
-  cfa->reg = -1;
+  cfa->reg.set_by_dwreg (-1);
+
+  /* Record previous register pieces here.  */
+  struct cfa_reg span;
+  span.set_by_dwreg (INVALID_REGNUM);
 
   for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next)
     {
@@ -578,10 +582,10 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_node *loc)
 	case DW_OP_reg29:
 	case DW_OP_reg30:
 	case DW_OP_reg31:
-	  cfa->reg = op - DW_OP_reg0;
+	  cfa->reg.set_by_dwreg (op - DW_OP_reg0);
 	  break;
 	case DW_OP_regx:
-	  cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
+	  cfa->reg.set_by_dwreg (ptr->dw_loc_oprnd1.v.val_int);
 	  break;
 	case DW_OP_breg0:
 	case DW_OP_breg1:
@@ -615,17 +619,89 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_node *loc)
 	case DW_OP_breg29:
 	case DW_OP_breg30:
 	case DW_OP_breg31:
-	  cfa->reg = op - DW_OP_breg0;
+	  cfa->reg.set_by_dwreg (op - DW_OP_breg0);
 	  cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int;
 	  break;
 	case DW_OP_bregx:
-	  cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
+	  cfa->reg.set_by_dwreg (ptr->dw_loc_oprnd1.v.val_int);
 	  cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int;
 	  break;
+	case DW_OP_piece:
+	  if (span.reg != INVALID_REGNUM)
+	    {
+	      /* We only support contiguous pieces, for now.  */
+	      gcc_assert (cfa->reg.reg == span.reg + span.span);
+	      gcc_assert (known_eq (ptr->dw_loc_oprnd1.v.val_int,
+				    span.span_width));
+	      span.span++;
+	      cfa->reg = span;
+	    }
+	  else
+	    {
+	      cfa->reg.span_width = ptr->dw_loc_oprnd1.v.val_int;
+	      span = cfa->reg;
+	    }
+	  break;
+	case DW_OP_LLVM_piece_end:
+	  break;
 	case DW_OP_deref:
 	  cfa->indirect = 1;
 	  break;
+	case DW_OP_lit0:
+	case DW_OP_lit1:
+	case DW_OP_lit2:
+	case DW_OP_lit3:
+	case DW_OP_lit4:
+	case DW_OP_lit5:
+	case DW_OP_lit6:
+	case DW_OP_lit7:
+	case DW_OP_lit8:
+	case DW_OP_lit9:
+	case DW_OP_lit10:
+	case DW_OP_lit11:
+	case DW_OP_lit12:
+	case DW_OP_lit13:
+	case DW_OP_lit14:
+	case DW_OP_lit15:
+	case DW_OP_lit16:
+	case DW_OP_lit17:
+	case DW_OP_lit18:
+	case DW_OP_lit19:
+	case DW_OP_lit20:
+	case DW_OP_lit21:
+	case DW_OP_lit22:
+	case DW_OP_lit23:
+	case DW_OP_lit24:
+	case DW_OP_lit25:
+	case DW_OP_lit26:
+	case DW_OP_lit27:
+	case DW_OP_lit28:
+	case DW_OP_lit29:
+	case DW_OP_lit30:
+	case DW_OP_lit31:
+	  /* Stacked operands are not yet supported.  */
+	  gcc_assert (known_eq (cfa->offset, 0));
+	  cfa->offset = op - DW_OP_lit0;
+	  break;
+	case DW_OP_const1u:
+	case DW_OP_const1s:
+	case DW_OP_const2u:
+	case DW_OP_const2s:
+	case DW_OP_const4s:
+	case DW_OP_const8s:
+	case DW_OP_constu:
+	case DW_OP_consts:
+	  gcc_assert (known_eq (cfa->offset, 0));
+	  cfa->offset = ptr->dw_loc_oprnd1.v.val_int;
+	  break;
+	case DW_OP_minus:
+	  cfa->offset = -cfa->offset;
+	  break;
+	case DW_OP_plus:
+	  /* The offset is already in place.  */
+	  break;
 	case DW_OP_plus_uconst:
+	  gcc_assert (known_eq (cfa->offset, 0));
 	  cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
 	  break;
 	default:
@@ -648,11 +724,11 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember)
       loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
       break;
     case DW_CFA_def_cfa_register:
-      loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+      loc->reg.set_by_dwreg (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
       break;
     case DW_CFA_def_cfa:
     case DW_CFA_def_cfa_sf:
-      loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+      loc->reg.set_by_dwreg (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
       loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
       break;
     case DW_CFA_def_cfa_expression:
@@ -798,6 +874,7 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
 
   HOST_WIDE_INT const_offset;
   if (new_cfa->reg == old_cfa->reg
+      && new_cfa->reg.span == 1
       && !new_cfa->indirect
       && !old_cfa->indirect
       && new_cfa->offset.is_constant (&const_offset))
@@ -814,7 +891,8 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
     }
   else if (new_cfa->offset.is_constant ()
 	   && known_eq (new_cfa->offset, old_cfa->offset)
-	   && old_cfa->reg != INVALID_REGNUM
+	   && old_cfa->reg.reg != INVALID_REGNUM
+	   && new_cfa->reg.span == 1
 	   && !new_cfa->indirect
 	   && !old_cfa->indirect)
     {
@@ -824,10 +902,11 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
 	 been set as a register plus offset rather than a general
 	 DW_CFA_def_cfa_expression.  */
       cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg.reg;
     }
   else if (new_cfa->indirect == 0
-	   && new_cfa->offset.is_constant (&const_offset))
+	   && new_cfa->offset.is_constant (&const_offset)
+	   && new_cfa->reg.span == 1)
     {
       /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
 	 indicating the CFA register has changed to <register> with
@@ -838,7 +917,7 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
 	cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
       else
 	cfi->dw_cfi_opc = DW_CFA_def_cfa;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg.reg;
       cfi->dw_cfi_oprnd2.dw_cfi_offset = const_offset;
     }
   else
@@ -885,18 +964,18 @@ def_cfa_1 (dw_cfa_location *new_cfa)
 }
 
 /* Add the CFI for saving a register.  REG is the CFA column number.
-   If SREG is -1, the register is saved at OFFSET from the CFA;
+   If SREG is INVALID_REGISTER, the register is saved at OFFSET from the CFA;
    otherwise it is saved in SREG.  */
 
 static void
-reg_save (unsigned int reg, unsigned int sreg, poly_int64 offset)
+reg_save (unsigned int reg, struct cfa_reg sreg, poly_int64 offset)
 {
   dw_fde_ref fde = cfun ? cfun->fde : NULL;
   dw_cfi_ref cfi = new_cfi ();
 
   cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
 
-  if (sreg == INVALID_REGNUM)
+  if (sreg.reg == INVALID_REGNUM)
     {
       HOST_WIDE_INT const_offset;
       /* When stack is aligned, store REG using DW_CFA_expression with FP.  */
@@ -926,7 +1005,7 @@ reg_save (unsigned int reg, unsigned int sreg, poly_int64 offset)
 	    = build_cfa_loc (&cur_row->cfa, offset);
 	}
     }
-  else if (sreg == reg)
+  else if (sreg.reg == reg)
     {
       /* While we could emit something like DW_CFA_same_value or
 	 DW_CFA_restore, we never expect to see something like that
@@ -934,10 +1013,16 @@ reg_save (unsigned int reg, unsigned int sreg, poly_int64 offset)
 	 can always bypass this by using REG_CFA_RESTORE directly.  */
       gcc_unreachable ();
     }
+  else if (sreg.span > 1)
+    {
+      cfi->dw_cfi_opc = DW_CFA_expression;
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+      cfi->dw_cfi_oprnd2.dw_cfi_loc = build_span_loc (sreg);
+    }
   else
     {
       cfi->dw_cfi_opc = DW_CFA_register;
-      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
+      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg.reg;
     }
 
   add_cfi (cfi);
@@ -1018,6 +1103,43 @@ dwf_regno (const_rtx reg)
   return DWARF_FRAME_REGNUM (REGNO (reg));
 }
 
+/* Like dwf_regno, but when the value can span multiple registers.  */
+
+static struct cfa_reg
+dwf_cfa_reg (rtx reg)
+{
+  struct cfa_reg result;
+
+  gcc_assert (REGNO (reg) < FIRST_PSEUDO_REGISTER);
+
+  result.reg = dwf_regno (reg);
+  result.span = 1;
+  result.span_width = GET_MODE_SIZE (GET_MODE (reg));
+
+  rtx span = targetm.dwarf_register_span (reg);
+  if (span)
+    {
+      /* We only support the simple case of consecutive registers all with the
+	 same size.  */
+      result.span = XVECLEN (span, 0);
+      result.span_width = GET_MODE_SIZE (GET_MODE (XVECEXP (span, 0, 0)));
+
+#if CHECKING_P
+      /* Ensure that the above assumption is accurate.  */
+      for (unsigned int i = 0; i < result.span; i++)
+	{
+	  gcc_assert (known_eq (GET_MODE_SIZE (GET_MODE (XVECEXP (span,
+								  0, i))),
+				result.span_width));
+	  gcc_assert (REG_P (XVECEXP (span, 0, i)));
+	  gcc_assert (dwf_regno (XVECEXP (span, 0, i)) == result.reg + i);
+	}
+#endif
+    }
+
+  return result;
+}
+
 /* Compare X and Y for equivalence.  The inputs may be REGs or PC_RTX.  */
 
 static bool
@@ -1086,7 +1208,8 @@ dwarf2out_flush_queued_reg_saves (void)
 
   FOR_EACH_VEC_ELT (queued_reg_saves, i, q)
     {
-      unsigned int reg, sreg;
+      unsigned int reg;
+      struct cfa_reg sreg;
 
       record_reg_saved_in_reg (q->saved_reg, q->reg);
 
@@ -1095,9 +1218,9 @@ dwarf2out_flush_queued_reg_saves (void)
       else
         reg = dwf_regno (q->reg);
       if (q->saved_reg)
-	sreg = dwf_regno (q->saved_reg);
+	sreg = dwf_cfa_reg (q->saved_reg);
       else
-	sreg = INVALID_REGNUM;
+	sreg.set_by_dwreg (INVALID_REGNUM);
       reg_save (reg, sreg, q->cfa_offset);
     }
 
@@ -1169,7 +1292,7 @@ dwarf2out_frame_debug_def_cfa (rtx pat)
   /* ??? If this fails, we could be calling into the _loc functions to
      define a full expression.  So far no port does that.  */
   gcc_assert (REG_P (pat));
-  cur_cfa->reg = dwf_regno (pat);
+  cur_cfa->reg = dwf_cfa_reg (pat);
 }
 
 /* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note.  */
@@ -1186,7 +1309,7 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat)
   switch (GET_CODE (src))
     {
     case PLUS:
-      gcc_assert (dwf_regno (XEXP (src, 0)) == cur_cfa->reg);
+      gcc_assert (dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg);
       cur_cfa->offset -= rtx_to_poly_int64 (XEXP (src, 1));
       break;
 
@@ -1197,7 +1320,7 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat)
       gcc_unreachable ();
     }
 
-  cur_cfa->reg = dwf_regno (dest);
+  cur_cfa->reg = dwf_cfa_reg (dest);
   gcc_assert (cur_cfa->indirect == 0);
 }
 
@@ -1219,11 +1342,11 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
   switch (GET_CODE (addr))
     {
     case REG:
-      gcc_assert (dwf_regno (addr) == cur_cfa->reg);
+      gcc_assert (dwf_cfa_reg (addr) == cur_cfa->reg);
       offset = -cur_cfa->offset;
       break;
     case PLUS:
-      gcc_assert (dwf_regno (XEXP (addr, 0)) == cur_cfa->reg);
+      gcc_assert (dwf_cfa_reg (XEXP (addr, 0)) == cur_cfa->reg);
       offset = rtx_to_poly_int64 (XEXP (addr, 1)) - cur_cfa->offset;
       break;
     default:
@@ -1243,8 +1366,10 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
 
   /* ??? We'd like to use queue_reg_save, but we need to come up with
      a different flushing heuristic for epilogues.  */
+  struct cfa_reg invalid;
+  invalid.set_by_dwreg (INVALID_REGNUM);
   if (!span)
-    reg_save (sregno, INVALID_REGNUM, offset);
+    reg_save (sregno, invalid, offset);
   else
     {
       /* We have a PARALLEL describing where the contents of SRC live.
@@ -1258,7 +1383,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
 	{
 	  rtx elem = XVECEXP (span, 0, par_index);
 	  sregno = dwf_regno (src);
-	  reg_save (sregno, INVALID_REGNUM, span_offset);
+	  reg_save (sregno, invalid, span_offset);
 	  span_offset += GET_MODE_SIZE (GET_MODE (elem));
 	}
     }
@@ -1270,7 +1395,8 @@ static void
 dwarf2out_frame_debug_cfa_register (rtx set)
 {
   rtx src, dest;
-  unsigned sregno, dregno;
+  unsigned sregno;
+  struct cfa_reg dregno;
 
   src = XEXP (set, 1);
   dest = XEXP (set, 0);
@@ -1281,7 +1407,7 @@ dwarf2out_frame_debug_cfa_register (rtx set)
   else
     sregno = dwf_regno (src);
 
-  dregno = dwf_regno (dest);
+  dregno = dwf_cfa_reg (dest);
 
   /* ??? We'd like to use queue_reg_save, but we need to come up with
      a different flushing heuristic for epilogues.  */
@@ -1667,7 +1793,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 	{
 	  /* Setting FP from SP.  */
 	case REG:
-	  if (cur_cfa->reg == dwf_regno (src))
+	  if (cur_cfa->reg == dwf_cfa_reg (src))
 	    {
 	      /* Rule 1 */
 	      /* Update the CFA rule wrt SP or FP.  Make sure src is
@@ -1677,7 +1803,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 		 ARM copies SP to a temporary register, and from there to
 		 FP.  So we just rely on the backends to only set
 		 RTX_FRAME_RELATED_P on appropriate insns.  */
-	      cur_cfa->reg = dwf_regno (dest);
+	      cur_cfa->reg = dwf_cfa_reg (dest);
 	      cur_trace->cfa_temp.reg = cur_cfa->reg;
 	      cur_trace->cfa_temp.offset = cur_cfa->offset;
 	    }
@@ -1697,7 +1823,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 		  && REGNO (src) == STACK_POINTER_REGNUM)
 		gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM
 			    && fde->drap_reg != INVALID_REGNUM
-			    && cur_cfa->reg != dwf_regno (src));
+			    && cur_cfa->reg != dwf_cfa_reg (src));
 	      else
 		queue_reg_save (src, dest, 0);
 	    }
@@ -1712,7 +1838,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 	      /* Adjusting SP.  */
 	      if (REG_P (XEXP (src, 1)))
 		{
-		  gcc_assert (dwf_regno (XEXP (src, 1))
+		  gcc_assert (dwf_cfa_reg (XEXP (src, 1))
 			      == cur_trace->cfa_temp.reg);
 		  offset = cur_trace->cfa_temp.offset;
 		}
@@ -1746,7 +1872,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 	      gcc_assert (frame_pointer_needed);
 
 	      gcc_assert (REG_P (XEXP (src, 0))
-			  && dwf_regno (XEXP (src, 0)) == cur_cfa->reg);
+			  && dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg);
 	      offset = rtx_to_poly_int64 (XEXP (src, 1));
 	      if (GET_CODE (src) != MINUS)
 		offset = -offset;
@@ -1759,14 +1885,14 @@ dwarf2out_frame_debug_expr (rtx expr)
 
 	      /* Rule 4 */
 	      if (REG_P (XEXP (src, 0))
-		  && dwf_regno (XEXP (src, 0)) == cur_cfa->reg
+		  && dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg
 		  && poly_int_rtx_p (XEXP (src, 1), &offset))
 		{
 		  /* Setting a temporary CFA register that will be copied
 		     into the FP later on.  */
 		  offset = -offset;
 		  cur_cfa->offset += offset;
-		  cur_cfa->reg = dwf_regno (dest);
+		  cur_cfa->reg = dwf_cfa_reg (dest);
 		  /* Or used to save regs to the stack.  */
 		  cur_trace->cfa_temp.reg = cur_cfa->reg;
 		  cur_trace->cfa_temp.offset = cur_cfa->offset;
@@ -1774,13 +1900,13 @@ dwarf2out_frame_debug_expr (rtx expr)
 
 	      /* Rule 5 */
 	      else if (REG_P (XEXP (src, 0))
-		       && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
+		       && dwf_cfa_reg (XEXP (src, 0)) == cur_trace->cfa_temp.reg
 		       && XEXP (src, 1) == stack_pointer_rtx)
 		{
 		  /* Setting a scratch register that we will use instead
 		     of SP for saving registers to the stack.  */
 		  gcc_assert (cur_cfa->reg == dw_stack_pointer_regnum);
-		  cur_trace->cfa_store.reg = dwf_regno (dest);
+		  cur_trace->cfa_store.reg = dwf_cfa_reg (dest);
 		  cur_trace->cfa_store.offset
 		    = cur_cfa->offset - cur_trace->cfa_temp.offset;
 		}
@@ -1789,7 +1915,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 	      else if (GET_CODE (src) == LO_SUM
 		       && poly_int_rtx_p (XEXP (src, 1),
 					  &cur_trace->cfa_temp.offset))
-		cur_trace->cfa_temp.reg = dwf_regno (dest);
+		cur_trace->cfa_temp.reg = dwf_cfa_reg (dest);
 	      else
 		gcc_unreachable ();
 	    }
@@ -1798,17 +1924,17 @@ dwarf2out_frame_debug_expr (rtx expr)
 	  /* Rule 6 */
 	case CONST_INT:
 	case CONST_POLY_INT:
-	  cur_trace->cfa_temp.reg = dwf_regno (dest);
+	  cur_trace->cfa_temp.reg = dwf_cfa_reg (dest);
 	  cur_trace->cfa_temp.offset = rtx_to_poly_int64 (src);
 	  break;
 
 	  /* Rule 7 */
 	case IOR:
 	  gcc_assert (REG_P (XEXP (src, 0))
-		      && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
+		      && dwf_cfa_reg (XEXP (src, 0)) == cur_trace->cfa_temp.reg
 		      && CONST_INT_P (XEXP (src, 1)));
 
-	  cur_trace->cfa_temp.reg = dwf_regno (dest);
+	  cur_trace->cfa_temp.reg = dwf_cfa_reg (dest);
 	  if (!can_ior_p (cur_trace->cfa_temp.offset, INTVAL (XEXP (src, 1)),
 			  &cur_trace->cfa_temp.offset))
 	    /* The target shouldn't generate this kind of CFI note if we
@@ -1841,14 +1967,17 @@ dwarf2out_frame_debug_expr (rtx expr)
 	      dwarf2out_flush_queued_reg_saves ();
 
               gcc_assert (cur_trace->cfa_store.reg
-			  == dwf_regno (XEXP (src, 0)));
+			  == dwf_cfa_reg (XEXP (src, 0)));
               fde->stack_realign = 1;
               fde->stack_realignment = INTVAL (XEXP (src, 1));
               cur_trace->cfa_store.offset = 0;
 
 	      if (cur_cfa->reg != dw_stack_pointer_regnum
 		  && cur_cfa->reg != dw_frame_pointer_regnum)
-		fde->drap_reg = cur_cfa->reg;
+		{
+		  gcc_assert (cur_cfa->reg.span == 1);
+		  fde->drap_reg = cur_cfa->reg.reg;
+		}
             }
           return;
 
@@ -1924,14 +2053,14 @@ dwarf2out_frame_debug_expr (rtx expr)
 	case MINUS:
 	case LO_SUM:
 	  {
-	    unsigned int regno;
+	    struct cfa_reg regno;
 
 	    gcc_assert (REG_P (XEXP (XEXP (dest, 0), 0)));
 	    offset = rtx_to_poly_int64 (XEXP (XEXP (dest, 0), 1));
 	    if (GET_CODE (XEXP (dest, 0)) == MINUS)
 	      offset = -offset;
 
-	    regno = dwf_regno (XEXP (XEXP (dest, 0), 0));
+	    regno = dwf_cfa_reg (XEXP (XEXP (dest, 0), 0));
 
 	    if (cur_cfa->reg == regno)
 	      offset -= cur_cfa->offset;
@@ -1949,7 +2078,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 	  /* Without an offset.  */
 	case REG:
 	  {
-	    unsigned int regno = dwf_regno (XEXP (dest, 0));
+	    struct cfa_reg regno = dwf_cfa_reg (XEXP (dest, 0));
 
 	    if (cur_cfa->reg == regno)
 	      offset = -cur_cfa->offset;
@@ -1966,7 +2095,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 	  /* Rule 14 */
 	case POST_INC:
 	  gcc_assert (cur_trace->cfa_temp.reg
-		      == dwf_regno (XEXP (XEXP (dest, 0), 0)));
+		      == dwf_cfa_reg (XEXP (XEXP (dest, 0), 0)));
 	  offset = -cur_trace->cfa_temp.offset;
 	  cur_trace->cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
 	  break;
@@ -1984,7 +2113,7 @@ dwarf2out_frame_debug_expr (rtx expr)
       if (REG_P (src)
 	  && REGNO (src) != STACK_POINTER_REGNUM
 	  && REGNO (src) != HARD_FRAME_POINTER_REGNUM
-	  && dwf_regno (src) == cur_cfa->reg)
+	  && dwf_cfa_reg (src) == cur_cfa->reg)
 	{
 	  /* We're storing the current CFA reg into the stack.  */
 
@@ -2001,7 +2130,7 @@ dwarf2out_frame_debug_expr (rtx expr)
                   && cur_cfa->indirect == 0
                   && cur_cfa->reg != dw_frame_pointer_regnum)
                 {
-		  gcc_assert (fde->drap_reg == cur_cfa->reg);
+		  gcc_assert (fde->drap_reg == cur_cfa->reg.reg);
 
 		  cur_cfa->indirect = 1;
 		  cur_cfa->reg = dw_frame_pointer_regnum;
@@ -2028,7 +2157,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 		x = XEXP (x, 0);
 	      gcc_assert (REG_P (x));
 
-	      cur_cfa->reg = dwf_regno (x);
+	      cur_cfa->reg = dwf_cfa_reg (x);
 	      cur_cfa->base_offset = offset;
 	      cur_cfa->indirect = 1;
 	      break;
@@ -2924,7 +3053,7 @@ create_pseudo_cfg (void)
   ti.head = get_insns ();
   ti.beg_row = cie_cfi_row;
   ti.cfa_store = cie_cfi_row->cfa;
-  ti.cfa_temp.reg = INVALID_REGNUM;
+  ti.cfa_temp.reg.set_by_dwreg (INVALID_REGNUM);
   trace_info.quick_push (ti);
 
   if (cie_return_save)
@@ -2987,14 +3116,15 @@ create_pseudo_cfg (void)
 static void
 initial_return_save (rtx rtl)
 {
-  unsigned int reg = INVALID_REGNUM;
+  struct cfa_reg reg;
+  reg.set_by_dwreg (INVALID_REGNUM);
   poly_int64 offset = 0;
 
   switch (GET_CODE (rtl))
     {
     case REG:
       /* RA is in a register.  */
-      reg = dwf_regno (rtl);
+      reg = dwf_cfa_reg (rtl);
       break;
 
     case MEM:
@@ -3035,9 +3165,9 @@ initial_return_save (rtx rtl)
       gcc_unreachable ();
     }
 
-  if (reg != DWARF_FRAME_RETURN_COLUMN)
+  if (reg.reg != DWARF_FRAME_RETURN_COLUMN)
     {
-      if (reg != INVALID_REGNUM)
+      if (reg.reg != INVALID_REGNUM)
         record_reg_saved_in_reg (rtl, pc_rtx);
       reg_save (DWARF_FRAME_RETURN_COLUMN, reg, offset - cur_row->cfa.offset);
     }
@@ -3049,7 +3179,8 @@ create_cie_data (void)
   dw_cfa_location loc;
   dw_trace_info cie_trace;
 
-  dw_stack_pointer_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
+  dw_stack_pointer_regnum =
+    dwf_cfa_reg (gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
 
   memset (&cie_trace, 0, sizeof (cie_trace));
   cur_trace = &cie_trace;
@@ -3108,7 +3239,8 @@ static unsigned int
 execute_dwarf2_frame (void)
 {
   /* Different HARD_FRAME_POINTER_REGNUM might coexist in the same file.  */
-  dw_frame_pointer_regnum = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
+  dw_frame_pointer_regnum =
+    dwf_cfa_reg (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM));
 
   /* The first time we're called, compute the incoming frame state.  */
   if (cie_cfi_vec == NULL)
@@ -3488,7 +3620,7 @@ dump_cfi_row (FILE *f, dw_cfi_row *row)
     {
       dw_cfa_location dummy;
       memset (&dummy, 0, sizeof (dummy));
-      dummy.reg = INVALID_REGNUM;
+      dummy.reg.set_by_dwreg (INVALID_REGNUM);
       cfi = def_cfa_0 (&dummy, &row->cfa);
     }
   output_cfi_directive (f, cfi);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 9deca031fc2..f779ac5d464 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2723,6 +2723,34 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
     }
 }
 
+/* Build a dwarf location for a cfa_reg spanning multiple
+   consecutive registers.  */
+
+struct dw_loc_descr_node *
+build_span_loc (struct cfa_reg reg)
+{
+  struct dw_loc_descr_node *head = NULL;
+
+  gcc_assert (known_gt (reg.span_width, 0));
+  for (unsigned int i = 0; i < reg.span; i++)
+    {
+      unsigned int regno = reg.reg + i;
+      if (regno <= 31)
+	add_loc_descr (&head,
+		       new_loc_descr ((enum dwarf_location_atom)
+				      (DW_OP_reg0 + regno),
+				      0, 0));
+      else
+	add_loc_descr (&head, new_loc_descr (DW_OP_regx, regno, 0));
+      add_loc_descr (&head,
+		     new_loc_descr (DW_OP_piece,
+				    reg.span_width.to_constant (),
+				    0));
+    }
+
+  return head;
+}
+
 /* This function builds a dwarf location descriptor sequence from a
    dw_cfa_location, adding the given OFFSET to the result of the
    expression.  */
@@ -2734,9 +2762,20 @@ build_cfa_loc (dw_cfa_location *cfa, poly_int64 offset)
 
   offset += cfa->offset;
 
-  if (cfa->indirect)
+  if (cfa->reg.span > 1)
+    {
+      head = build_span_loc (cfa->reg);
+
+      if (maybe_ne (offset, 0))
+	{
+	  add_loc_descr (&head, new_loc_descr (DW_OP_LLVM_piece_end, 0, 0));
+	  add_loc_descr (&head, new_loc_descr (DW_OP_deref, 0, 0));
+	  loc_descr_plus_const (&head, offset);
+	}
+    }
+  else if (cfa->indirect)
     {
-      head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
+      head = new_reg_loc_descr (cfa->reg.reg, cfa->base_offset);
       head->dw_loc_oprnd1.val_class = dw_val_class_const;
       head->dw_loc_oprnd1.val_entry = NULL;
       tmp = new_loc_descr (DW_OP_deref, 0, 0);
@@ -2744,7 +2783,7 @@ build_cfa_loc (dw_cfa_location *cfa, poly_int64 offset)
       loc_descr_plus_const (&head, offset);
     }
   else
-    head = new_reg_loc_descr (cfa->reg, offset);
+    head = new_reg_loc_descr (cfa->reg.reg, offset);
 
   return head;
 }
@@ -2762,7 +2801,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa,
     = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
 
   /* When CFA is defined as FP+OFFSET, emulate stack alignment.  */
-  if (cfa->reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0)
+  if (cfa->reg.reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0)
     {
       head = new_reg_loc_descr (dwarf_fp, 0);
       add_loc_descr (&head, int_loc_descriptor (alignment));
@@ -20374,7 +20413,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
   list = NULL;
 
   memset (&next_cfa, 0, sizeof (next_cfa));
-  next_cfa.reg = INVALID_REGNUM;
+  next_cfa.reg.set_by_dwreg (INVALID_REGNUM);
   remember = next_cfa;
 
   start_label = fde->dw_fde_begin;
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index 9571f8b4b10..5daf44ff6ba 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -111,6 +111,40 @@ struct GTY(()) dw_fde_node {
 };
 
 
+/* This represents a register, in DWARF_FRAME_REGNUM space, for use in CFA
+   definitions and expressions.
+   Most architectures only need a single register number, but some (amdgcn)
+   have pointers that span multiple registers.  DWARF permits arbitrary
+   register sets, using DW_OP_piece, but existing use-cases only require
+   contiguous register sets, as represented here.  */
+struct GTY(()) cfa_reg {
+  unsigned int reg;
+  unsigned int span;
+  poly_uint16_pod span_width;  /* A.K.A. register mode size.  */
+
+  cfa_reg& set_by_dwreg (unsigned int r)
+    {
+      reg = r;
+      span = 1;
+      span_width = 0;  /* Unknown size (permitted when span == 1).  */
+      return *this;
+    }
+
+  bool operator== (const cfa_reg other) const
+    {
+      return (reg == other.reg
+	      && span == other.span
+	      && (known_eq (span_width, other.span_width)
+		  || (span == 1
+		      && (known_eq (span_width, 0)
+			  || known_eq (other.span_width, 0)))));
+    }
+  bool operator!= (const cfa_reg other) const
+    {
+      return !(*this == other);
+    }
+};
+
 /* This is how we define the location of the CFA. We use to handle it
    as REG + OFFSET all the time,  but now it can be more complex.
    It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET.
@@ -120,7 +154,7 @@ struct GTY(()) dw_cfa_location {
   poly_int64_pod offset;
   poly_int64_pod base_offset;
   /* REG is in DWARF_FRAME_REGNUM space, *not* normal REGNO space.  */
-  unsigned int reg;
+  struct cfa_reg reg;
   BOOL_BITFIELD indirect : 1;  /* 1 if CFA is accessed via a dereference.  */
   BOOL_BITFIELD in_use : 1;    /* 1 if a saved cfa is stored here.  */
 };
@@ -277,6 +311,7 @@ extern struct dw_loc_descr_node *build_cfa_loc
   (dw_cfa_location *, poly_int64);
 extern struct dw_loc_descr_node *build_cfa_aligned_loc
   (dw_cfa_location *, poly_int64, HOST_WIDE_INT);
+extern struct dw_loc_descr_node *build_span_loc (struct cfa_reg);
 extern struct dw_loc_descr_node *mem_loc_descriptor
   (rtx, machine_mode mode, machine_mode mem_mode,
    enum var_init_status);
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 981577481af..7e99f37a998 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -5193,6 +5193,7 @@ main (int argc, char **argv)
       POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("double_int", &pos));
+      POS_HERE (do_scalar_typedef ("poly_uint16_pod", &pos));
       POS_HERE (do_scalar_typedef ("poly_int64_pod", &pos));
       POS_HERE (do_scalar_typedef ("offset_int", &pos));
       POS_HERE (do_scalar_typedef ("widest_int", &pos));
diff --git a/include/dwarf2.def b/include/dwarf2.def
index d8a8cce7947..eb9f1a09455 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -704,6 +704,12 @@ DW_OP (DW_OP_PGI_omp_thread_num, 0xf8)
    to 0 except explicitly documented for one action.  Please refer AArch64 DWARF
    ABI documentation for details.  */
 DW_OP (DW_OP_AARCH64_operation, 0xea)
+
+/* AMD GCN extensions (originally for LLVM).  See
+   http://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html  */
+// This clashes with DW_OP_AARCH64_operation, so use an alias instead
+// DW_OP (DW_OP_LLVM_piece_end, 0xea)
+#define DW_OP_LLVM_piece_end DW_OP_AARCH64_operation
 DW_END_OP
 
 DW_FIRST_ATE (DW_ATE_void, 0x0)

  parent reply	other threads:[~2020-09-03 15:29 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-28 12:04 Andrew Stubbs
2020-09-02 17:49 ` Tom Tromey
2020-09-02 19:35   ` Andrew Stubbs
2020-09-02 19:55     ` Tom Tromey
2020-09-03 15:29 ` Andrew Stubbs [this message]
2020-09-21 13:51   ` Andrew Stubbs
2020-10-05 10:07     ` Andrew Stubbs
2020-09-22 14:22   ` [committed, OG10] " Andrew Stubbs
2020-10-19  9:36 ` [PATCH] " Jakub Jelinek
2021-06-13 13:27 Hafiz Abid Qadeer
2021-07-22 10:58 ` Hafiz Abid Qadeer
2021-08-24 15:55   ` Hafiz Abid Qadeer
2021-11-02 15:02     ` Hafiz Abid Qadeer
2021-11-09 15:59 ` Jakub Jelinek
2021-11-11 18:12   ` Hafiz Abid Qadeer
2021-12-01 15:49     ` Jakub Jelinek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4b1263f2-ae04-bf9a-4f2b-3da192c0daed@codesourcery.com \
    --to=ams@codesourcery.com \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).