poly_int: DWARF locations
authorRichard Sandiford <richard.sandiford@linaro.org>
Wed, 20 Dec 2017 12:52:30 +0000 (12:52 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 20 Dec 2017 12:52:30 +0000 (12:52 +0000)
This patch adds support for DWARF location expressions
that involve polynomial offsets.  It adds a target hook that
says how the runtime invariants used in the offsets should be
represented in DWARF.  SVE vectors have to be a multiple of
128 bits in size, so the GCC port uses the number of 128-bit
blocks minus one as the runtime invariant.  However, in DWARF,
the vector length is exposed via a pseudo "VG" register that
holds the number of 64-bit elements in a vector.  Thus:

  indeterminate 1 == (VG / 2) - 1

The hook needs to be general enough to express this.
Note that in most cases the division and subtraction fold
away into surrounding expressions.

2017-12-20  Richard Sandiford  <richard.sandiford@linaro.org>
    Alan Hayward  <alan.hayward@arm.com>
    David Sherwood  <david.sherwood@arm.com>

gcc/
* target.def (dwarf_poly_indeterminate_value): New hook.
* targhooks.h (default_dwarf_poly_indeterminate_value): Declare.
* targhooks.c (default_dwarf_poly_indeterminate_value): New function.
* doc/tm.texi.in (TARGET_DWARF_POLY_INDETERMINATE_VALUE): Document.
* doc/tm.texi: Regenerate.
* dwarf2out.h (build_cfa_loc, build_cfa_aligned_loc): Take the
offset as a poly_int64.
* dwarf2out.c (new_reg_loc_descr): Move later in file.  Take the
offset as a poly_int64.
(loc_descr_plus_const, loc_list_plus_const, build_cfa_aligned_loc):
Take the offset as a poly_int64.
(build_cfa_loc): Likewise.  Use loc_descr_plus_const.
(frame_pointer_fb_offset): Change to a poly_int64.
(int_loc_descriptor): Take the offset as a poly_int64.  Use
targetm.dwarf_poly_indeterminate_value for polynomial offsets.
(based_loc_descr): Take the offset as a poly_int64.
Use strip_offset_and_add to handle (plus X (const)).
Use new_reg_loc_descr instead of an open-coded version of the
previous implementation.
(mem_loc_descriptor): Handle CONST_POLY_INT.
(compute_frame_pointer_to_fb_displacement): Take the offset as a
poly_int64.  Use strip_offset_and_add to handle (plus X (const)).

Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>
From-SVN: r255868

gcc/ChangeLog
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/dwarf2out.c
gcc/dwarf2out.h
gcc/target.def
gcc/targhooks.c
gcc/targhooks.h

index 78cd21e955622669aeca85c7f457b33d122302c5..2ba9e08dfef433ab8c182c708fc5370ce6d722c5 100644 (file)
@@ -1,3 +1,30 @@
+2017-12-20  Richard Sandiford  <richard.sandiford@linaro.org>
+           Alan Hayward  <alan.hayward@arm.com>
+           David Sherwood  <david.sherwood@arm.com>
+
+       * target.def (dwarf_poly_indeterminate_value): New hook.
+       * targhooks.h (default_dwarf_poly_indeterminate_value): Declare.
+       * targhooks.c (default_dwarf_poly_indeterminate_value): New function.
+       * doc/tm.texi.in (TARGET_DWARF_POLY_INDETERMINATE_VALUE): Document.
+       * doc/tm.texi: Regenerate.
+       * dwarf2out.h (build_cfa_loc, build_cfa_aligned_loc): Take the
+       offset as a poly_int64.
+       * dwarf2out.c (new_reg_loc_descr): Move later in file.  Take the
+       offset as a poly_int64.
+       (loc_descr_plus_const, loc_list_plus_const, build_cfa_aligned_loc):
+       Take the offset as a poly_int64.
+       (build_cfa_loc): Likewise.  Use loc_descr_plus_const.
+       (frame_pointer_fb_offset): Change to a poly_int64.
+       (int_loc_descriptor): Take the offset as a poly_int64.  Use
+       targetm.dwarf_poly_indeterminate_value for polynomial offsets.
+       (based_loc_descr): Take the offset as a poly_int64.
+       Use strip_offset_and_add to handle (plus X (const)).
+       Use new_reg_loc_descr instead of an open-coded version of the
+       previous implementation.
+       (mem_loc_descriptor): Handle CONST_POLY_INT.
+       (compute_frame_pointer_to_fb_displacement): Take the offset as a
+       poly_int64.  Use strip_offset_and_add to handle (plus X (const)).
+
 2017-12-20  Richard Sandiford  <richard.sandiford@linaro.org>
             Alan Hayward  <alan.hayward@arm.com>
            David Sherwood  <david.sherwood@arm.com>
index fc73bb25d5ec989e0cd11657ec4a704a77edcfec..434c42a4ca944794bb63d8dd6a79f24215cfa9cb 100644 (file)
@@ -3130,6 +3130,19 @@ the CFI label attached to the insn, @var{pattern} is the pattern of
 the insn and @var{index} is @code{UNSPEC_INDEX} or @code{UNSPECV_INDEX}.
 @end deftypefn
 
+@deftypefn {Target Hook} {unsigned int} TARGET_DWARF_POLY_INDETERMINATE_VALUE (unsigned int @var{i}, unsigned int *@var{factor}, int *@var{offset})
+Express the value of @code{poly_int} indeterminate @var{i} as a DWARF
+expression, with @var{i} counting from 1.  Return the number of a DWARF
+register @var{R} and set @samp{*@var{factor}} and @samp{*@var{offset}} such
+that the value of the indeterminate is:
+@smallexample
+value_of(@var{R}) / @var{factor} - @var{offset}
+@end smallexample
+
+A target only needs to define this hook if it sets
+@samp{NUM_POLY_INT_COEFFS} to a value greater than 1.
+@end deftypefn
+
 @defmac INCOMING_FRAME_SP_OFFSET
 A C expression whose value is an integer giving the offset, in bytes,
 from the value of the stack pointer register to the top of the stack
index ff0067360cdfc295f12494f6b15ecc378aa61ff8..c1d2a8cdc1e032de0a80ed4d7e3215943fd63351 100644 (file)
@@ -2544,6 +2544,8 @@ terminate the stack backtrace.  New ports should avoid this.
 
 @hook TARGET_DWARF_HANDLE_FRAME_UNSPEC
 
+@hook TARGET_DWARF_POLY_INDETERMINATE_VALUE
+
 @defmac INCOMING_FRAME_SP_OFFSET
 A C expression whose value is an integer giving the offset, in bytes,
 from the value of the stack pointer register to the top of the stack
index dc1a2f0fa1798976cb8202700847ae6f31a2c9d9..6e94ad32a3361cbd57b5409a207582caf60dc555 100644 (file)
@@ -1319,7 +1319,7 @@ typedef struct GTY(()) dw_loc_list_struct {
   bool force;
 } dw_loc_list_node;
 
-static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
+static dw_loc_descr_ref int_loc_descriptor (poly_int64);
 static dw_loc_descr_ref uint_loc_descriptor (unsigned HOST_WIDE_INT);
 
 /* Convert a DWARF stack opcode into its string name.  */
@@ -1356,19 +1356,6 @@ new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1,
   return descr;
 }
 
-/* Return a pointer to a newly allocated location description for
-   REG and OFFSET.  */
-
-static inline dw_loc_descr_ref
-new_reg_loc_descr (unsigned int reg,  unsigned HOST_WIDE_INT offset)
-{
-  if (reg <= 31)
-    return new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + reg),
-                         offset, 0);
-  else
-    return new_loc_descr (DW_OP_bregx, reg, offset);
-}
-
 /* Add a location description term to a location description expression.  */
 
 static inline void
@@ -1501,23 +1488,31 @@ loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b)
 }
 
 
-/* Add a constant OFFSET to a location expression.  */
+/* Add a constant POLY_OFFSET to a location expression.  */
 
 static void
-loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset)
+loc_descr_plus_const (dw_loc_descr_ref *list_head, poly_int64 poly_offset)
 {
   dw_loc_descr_ref loc;
   HOST_WIDE_INT *p;
 
   gcc_assert (*list_head != NULL);
 
-  if (!offset)
+  if (known_eq (poly_offset, 0))
     return;
 
   /* Find the end of the chain.  */
   for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
     ;
 
+  HOST_WIDE_INT offset;
+  if (!poly_offset.is_constant (&offset))
+    {
+      loc->dw_loc_next = int_loc_descriptor (poly_offset);
+      add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_plus, 0, 0));
+      return;
+    }
+
   p = NULL;
   if (loc->dw_loc_opc == DW_OP_fbreg
       || (loc->dw_loc_opc >= DW_OP_breg0 && loc->dw_loc_opc <= DW_OP_breg31))
@@ -1543,10 +1538,33 @@ loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset)
     }
 }
 
+/* Return a pointer to a newly allocated location description for
+   REG and OFFSET.  */
+
+static inline dw_loc_descr_ref
+new_reg_loc_descr (unsigned int reg, poly_int64 offset)
+{
+  HOST_WIDE_INT const_offset;
+  if (offset.is_constant (&const_offset))
+    {
+      if (reg <= 31)
+       return new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + reg),
+                             const_offset, 0);
+      else
+       return new_loc_descr (DW_OP_bregx, reg, const_offset);
+    }
+  else
+    {
+      dw_loc_descr_ref ret = new_reg_loc_descr (reg, 0);
+      loc_descr_plus_const (&ret, offset);
+      return ret;
+    }
+}
+
 /* Add a constant OFFSET to a location list.  */
 
 static void
-loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
+loc_list_plus_const (dw_loc_list_ref list_head, poly_int64 offset)
 {
   dw_loc_list_ref d;
   for (d = list_head; d != NULL; d = d->dw_loc_next)
@@ -2626,7 +2644,7 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
    expression.  */
 
 struct dw_loc_descr_node *
-build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
+build_cfa_loc (dw_cfa_location *cfa, poly_int64 offset)
 {
   struct dw_loc_descr_node *head, *tmp;
 
@@ -2639,11 +2657,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
       head->dw_loc_oprnd1.val_entry = NULL;
       tmp = new_loc_descr (DW_OP_deref, 0, 0);
       add_loc_descr (&head, tmp);
-      if (offset != 0)
-       {
-         tmp = new_loc_descr (DW_OP_plus_uconst, offset, 0);
-         add_loc_descr (&head, tmp);
-       }
+      loc_descr_plus_const (&head, offset);
     }
   else
     head = new_reg_loc_descr (cfa->reg, offset);
@@ -2657,7 +2671,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
 
 struct dw_loc_descr_node *
 build_cfa_aligned_loc (dw_cfa_location *cfa,
-                      HOST_WIDE_INT offset, HOST_WIDE_INT alignment)
+                      poly_int64 offset, HOST_WIDE_INT alignment)
 {
   struct dw_loc_descr_node *head;
   unsigned int dwarf_fp
@@ -3345,7 +3359,7 @@ static GTY(()) vec<tree, va_gc> *generic_type_instances;
 
 /* Offset from the "steady-state frame pointer" to the frame base,
    within the current function.  */
-static HOST_WIDE_INT frame_pointer_fb_offset;
+static poly_int64 frame_pointer_fb_offset;
 static bool frame_pointer_fb_offset_valid;
 
 static vec<dw_die_ref> base_types;
@@ -3519,7 +3533,7 @@ static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int,
                                                enum var_init_status);
 static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
                                                     enum var_init_status);
-static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
+static dw_loc_descr_ref based_loc_descr (rtx, poly_int64,
                                         enum var_init_status);
 static int is_based_loc (const_rtx);
 static bool resolve_one_addr (rtx *);
@@ -13222,13 +13236,58 @@ int_shift_loc_descriptor (HOST_WIDE_INT i, int shift)
   return ret;
 }
 
-/* Return a location descriptor that designates a constant.  */
+/* Return a location descriptor that designates constant POLY_I.  */
 
 static dw_loc_descr_ref
-int_loc_descriptor (HOST_WIDE_INT i)
+int_loc_descriptor (poly_int64 poly_i)
 {
   enum dwarf_location_atom op;
 
+  HOST_WIDE_INT i;
+  if (!poly_i.is_constant (&i))
+    {
+      /* Create location descriptions for the non-constant part and
+        add any constant offset at the end.  */
+      dw_loc_descr_ref ret = NULL;
+      HOST_WIDE_INT constant = poly_i.coeffs[0];
+      for (unsigned int j = 1; j < NUM_POLY_INT_COEFFS; ++j)
+       {
+         HOST_WIDE_INT coeff = poly_i.coeffs[j];
+         if (coeff != 0)
+           {
+             dw_loc_descr_ref start = ret;
+             unsigned int factor;
+             int bias;
+             unsigned int regno = targetm.dwarf_poly_indeterminate_value
+               (j, &factor, &bias);
+
+             /* Add COEFF * ((REGNO / FACTOR) - BIAS) to the value:
+                add COEFF * (REGNO / FACTOR) now and subtract
+                COEFF * BIAS from the final constant part.  */
+             constant -= coeff * bias;
+             add_loc_descr (&ret, new_reg_loc_descr (regno, 0));
+             if (coeff % factor == 0)
+               coeff /= factor;
+             else
+               {
+                 int amount = exact_log2 (factor);
+                 gcc_assert (amount >= 0);
+                 add_loc_descr (&ret, int_loc_descriptor (amount));
+                 add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
+               }
+             if (coeff != 1)
+               {
+                 add_loc_descr (&ret, int_loc_descriptor (coeff));
+                 add_loc_descr (&ret, new_loc_descr (DW_OP_mul, 0, 0));
+               }
+             if (start)
+               add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
+           }
+       }
+      loc_descr_plus_const (&ret, constant);
+      return ret;
+    }
+
   /* Pick the smallest representation of a constant, rather than just
      defaulting to the LEB encoding.  */
   if (i >= 0)
@@ -13594,7 +13653,7 @@ address_of_int_loc_descriptor (int size, HOST_WIDE_INT i)
 /* Return a location descriptor that designates a base+offset location.  */
 
 static dw_loc_descr_ref
-based_loc_descr (rtx reg, HOST_WIDE_INT offset,
+based_loc_descr (rtx reg, poly_int64 offset,
                 enum var_init_status initialized)
 {
   unsigned int regno;
@@ -13613,11 +13672,7 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
 
       if (elim != reg)
        {
-         if (GET_CODE (elim) == PLUS)
-           {
-             offset += INTVAL (XEXP (elim, 1));
-             elim = XEXP (elim, 0);
-           }
+         elim = strip_offset_and_add (elim, &offset);
          gcc_assert ((SUPPORTS_STACK_ALIGNMENT
                       && (elim == hard_frame_pointer_rtx
                           || elim == stack_pointer_rtx))
@@ -13641,7 +13696,15 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
 
          gcc_assert (frame_pointer_fb_offset_valid);
          offset += frame_pointer_fb_offset;
-         return new_loc_descr (DW_OP_fbreg, offset, 0);
+         HOST_WIDE_INT const_offset;
+         if (offset.is_constant (&const_offset))
+           return new_loc_descr (DW_OP_fbreg, const_offset, 0);
+         else
+           {
+             dw_loc_descr_ref ret = new_loc_descr (DW_OP_fbreg, 0, 0);
+             loc_descr_plus_const (&ret, offset);
+             return ret;
+           }
        }
     }
 
@@ -13656,8 +13719,10 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
 #endif
   regno = DWARF_FRAME_REGNUM (regno);
 
+  HOST_WIDE_INT const_offset;
   if (!optimize && fde
-      && (fde->drap_reg == regno || fde->vdrap_reg == regno))
+      && (fde->drap_reg == regno || fde->vdrap_reg == regno)
+      && offset.is_constant (&const_offset))
     {
       /* Use cfa+offset to represent the location of arguments passed
         on the stack when drap is used to align stack.
@@ -13665,14 +13730,10 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
         is supposed to track where the arguments live and the register
         used as vdrap or drap in some spot might be used for something
         else in other part of the routine.  */
-      return new_loc_descr (DW_OP_fbreg, offset, 0);
+      return new_loc_descr (DW_OP_fbreg, const_offset, 0);
     }
 
-  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);
+  result = new_reg_loc_descr (regno, offset);
 
   if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
     add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
@@ -14680,6 +14741,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
   enum dwarf_location_atom op;
   dw_loc_descr_ref op0, op1;
   rtx inner = NULL_RTX;
+  poly_int64 offset;
 
   if (mode == VOIDmode)
     mode = GET_MODE (rtl);
@@ -15384,6 +15446,10 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
        }
       break;
 
+    case CONST_POLY_INT:
+      mem_loc_result = int_loc_descriptor (rtx_to_poly_int64 (rtl));
+      break;
+
     case EQ:
       mem_loc_result = scompare_loc_descriptor (DW_OP_eq, rtl, mem_mode);
       break;
@@ -19709,7 +19775,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
    before the latter is negated.  */
 
 static void
-compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
+compute_frame_pointer_to_fb_displacement (poly_int64 offset)
 {
   rtx reg, elim;
 
@@ -19724,11 +19790,7 @@ compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
   elim = (ira_use_lra_p
          ? lra_eliminate_regs (reg, VOIDmode, NULL_RTX)
          : eliminate_regs (reg, VOIDmode, NULL_RTX));
-  if (GET_CODE (elim) == PLUS)
-    {
-      offset += INTVAL (XEXP (elim, 1));
-      elim = XEXP (elim, 0);
-    }
+  elim = strip_offset_and_add (elim, &offset);
 
   frame_pointer_fb_offset = -offset;
 
index 940247316d39242189cc9deb2b1819bb3d9f9c99..140724c8e8c48dc55f889059b85db44a22ad1ffc 100644 (file)
@@ -267,9 +267,9 @@ struct GTY(()) dw_discr_list_node {
 
 /* Interface from dwarf2out.c to dwarf2cfi.c.  */
 extern struct dw_loc_descr_node *build_cfa_loc
-  (dw_cfa_location *, HOST_WIDE_INT);
+  (dw_cfa_location *, poly_int64);
 extern struct dw_loc_descr_node *build_cfa_aligned_loc
-  (dw_cfa_location *, HOST_WIDE_INT offset, HOST_WIDE_INT alignment);
+  (dw_cfa_location *, poly_int64, HOST_WIDE_INT);
 extern struct dw_loc_descr_node *mem_loc_descriptor
   (rtx, machine_mode mode, machine_mode mem_mode,
    enum var_init_status);
index b1178ca2635ccb02b5244e6e75f9f715cb12812e..5296b25f25c507b4bbf36e6fd7d8cbb15280ec9a 100644 (file)
@@ -4136,6 +4136,21 @@ the CFI label attached to the insn, @var{pattern} is the pattern of\n\
 the insn and @var{index} is @code{UNSPEC_INDEX} or @code{UNSPECV_INDEX}.",
  void, (const char *label, rtx pattern, int index), NULL)
 
+DEFHOOK
+(dwarf_poly_indeterminate_value,
+ "Express the value of @code{poly_int} indeterminate @var{i} as a DWARF\n\
+expression, with @var{i} counting from 1.  Return the number of a DWARF\n\
+register @var{R} and set @samp{*@var{factor}} and @samp{*@var{offset}} such\n\
+that the value of the indeterminate is:\n\
+@smallexample\n\
+value_of(@var{R}) / @var{factor} - @var{offset}\n\
+@end smallexample\n\
+\n\
+A target only needs to define this hook if it sets\n\
+@samp{NUM_POLY_INT_COEFFS} to a value greater than 1.",
+ unsigned int, (unsigned int i, unsigned int *factor, int *offset),
+ default_dwarf_poly_indeterminate_value)
+
 /* ??? Documenting this hook requires a GFDL license grant.  */
 DEFHOOK_UNDOC
 (stdarg_optimize_hook,
index 4a90e81ebe40ee4203e1767ae31ccbf61d815319..d02fca9949793f17e2b542c274f9c1fd5cb6686e 100644 (file)
@@ -1874,6 +1874,15 @@ default_debug_unwind_info (void)
   return UI_NONE;
 }
 
+/* Targets that set NUM_POLY_INT_COEFFS to something greater than 1
+   must define this hook.  */
+
+unsigned int
+default_dwarf_poly_indeterminate_value (unsigned int, unsigned int *, int *)
+{
+  gcc_unreachable ();
+}
+
 /* Determine the correct mode for a Dwarf frame register that represents
    register REGNO.  */
 
index 4c6c65cd312892cbba611054d4b39fefb9620e06..05635975ddaf1afe081b0ab649107cdc44751490 100644 (file)
@@ -238,6 +238,9 @@ extern int default_label_align_max_skip (rtx_insn *);
 extern int default_jump_align_max_skip (rtx_insn *);
 extern section * default_function_section(tree decl, enum node_frequency freq,
                                          bool startup, bool exit);
+extern unsigned int default_dwarf_poly_indeterminate_value (unsigned int,
+                                                           unsigned int *,
+                                                           int *);
 extern machine_mode default_dwarf_frame_reg_mode (int);
 extern fixed_size_mode default_get_reg_raw_mode (int);
 extern bool default_keep_leaf_when_profiled ();