public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Further libgcc unwinder improvements
@ 2022-11-08 18:05 Florian Weimer
  2022-11-08 18:05 ` [PATCH 1/3] Compute a table of DWARF register sizes at compile Florian Weimer
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Florian Weimer @ 2022-11-08 18:05 UTC (permalink / raw)
  To: gcc-patches

This series makes some further unwinder improvements.  Unfortunately,
not many targets define __LIBGCC_DWARF_REG_SIZES_CONSTANT__; x86-64
does, and it makes uw_install_context_1 quite a bit faster because GCC
no longer has to emit generic memcpy code for it.  In general, it may be
worthwhile to replace this code with target-specific implementations.

Tested on powerpc64le-linux-gnu, x86_64-linux-gnu; I didn't see any test
result differences.  Built GCC for msp430-elf, too.

The revision for the patch I posted earlier (using SWAR techniques for
get_cie_encoding) is not ready yet and probably won't make GCC 13.  It
requires some header cleanups first.

Thanks,
Florian

Florian Weimer (3):
  Compute a table of DWARF register sizes at compile
  Define __LIBGCC_DWARF_REG_SIZES_CONSTANT__ if DWARF register size is
    constant
  libgcc: Specialize execute_cfa_program in DWARF unwinder for
    alignments

 gcc/c-family/c-cppbuiltin.cc    |   8 +
 gcc/config/msp430/msp430.cc     |  11 +-
 gcc/config/rs6000/rs6000.cc     |  14 +-
 gcc/debug.h                     |   2 +
 gcc/doc/tm.texi                 |   7 +-
 gcc/dwarf2cfi.cc                | 116 +++++-----
 gcc/target.def                  |   8 +-
 libgcc/unwind-dw2-execute_cfa.h | 322 ++++++++++++++++++++++++++++
 libgcc/unwind-dw2.c             | 360 ++++++--------------------------
 9 files changed, 472 insertions(+), 376 deletions(-)
 create mode 100644 libgcc/unwind-dw2-execute_cfa.h


base-commit: 5d060d8b0477ff4911f41c816281daaa24b41a13
-- 
2.38.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] Compute a table of DWARF register sizes at compile
  2022-11-08 18:05 [PATCH 0/3] Further libgcc unwinder improvements Florian Weimer
@ 2022-11-08 18:05 ` Florian Weimer
  2022-11-20 15:23   ` Jeff Law
  2022-11-08 18:05 ` [PATCH 2/3] Define __LIBGCC_DWARF_REG_SIZES_CONSTANT__ if DWARF register size is constant Florian Weimer
  2022-11-08 18:05 ` [PATCH 3/3] libgcc: Specialize execute_cfa_program in DWARF unwinder for alignments Florian Weimer
  2 siblings, 1 reply; 6+ messages in thread
From: Florian Weimer @ 2022-11-08 18:05 UTC (permalink / raw)
  To: gcc-patches

The sizes are compile-time constants.  Create a vector with them,
so that they can be inspected at compile time.

	* gcc/dwarf2cfi.cc (init_return_column_size): Remove.
	(init_one_dwarf_reg_size): Adjust.
	(generate_dwarf_reg_sizes): New function.  Extracted
	from expand_builtin_init_dwarf_reg_sizes.
	(expand_builtin_init_dwarf_reg_sizes): Call
	generate_dwarf_reg_sizes.
	* gcc/target.def (init_dwarf_reg_sizes_extra): Adjust
	hook signature.
	* gcc/config/msp430/msp430.cc
	(msp430_init_dwarf_reg_sizes_extra): Adjust.
	* gcc/config/rs6000.cc (rs6000_init_dwarf_reg_sizes_extra):
	Likewise.
	* gcc/doc/tm.texi: Update.
---
 gcc/config/msp430/msp430.cc | 11 +----
 gcc/config/rs6000/rs6000.cc | 14 +-----
 gcc/doc/tm.texi             |  7 +--
 gcc/dwarf2cfi.cc            | 93 ++++++++++++++++++-------------------
 gcc/target.def              |  8 ++--
 5 files changed, 58 insertions(+), 75 deletions(-)

diff --git a/gcc/config/msp430/msp430.cc b/gcc/config/msp430/msp430.cc
index 6c15780a2b6..dbea8d7f50f 100644
--- a/gcc/config/msp430/msp430.cc
+++ b/gcc/config/msp430/msp430.cc
@@ -3202,11 +3202,9 @@ msp430_expand_eh_return (rtx eh_handler)
 #undef  TARGET_INIT_DWARF_REG_SIZES_EXTRA
 #define TARGET_INIT_DWARF_REG_SIZES_EXTRA msp430_init_dwarf_reg_sizes_extra
 void
-msp430_init_dwarf_reg_sizes_extra (tree address)
+msp430_init_dwarf_reg_sizes_extra (poly_uint16 *sizes)
 {
   int i;
-  rtx addr = expand_normal (address);
-  rtx mem = gen_rtx_MEM (BLKmode, addr);
 
   /* This needs to match msp430_unwind_word_mode (above).  */
   if (!msp430x)
@@ -3218,12 +3216,7 @@ msp430_init_dwarf_reg_sizes_extra (tree address)
       unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
 
       if (rnum < DWARF_FRAME_REGISTERS)
-	{
-	  HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (QImode);
-
-	  emit_move_insn (adjust_address (mem, QImode, offset),
-			  gen_int_mode (4, QImode));
-	}
+	sizes[rnum] = 4;
     }
 }
 
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index a85d7630b41..fddb6a8a0f7 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -23783,27 +23783,17 @@ rs6000_initial_elimination_offset (int from, int to)
 /* Fill in sizes of registers used by unwinder.  */
 
 static void
-rs6000_init_dwarf_reg_sizes_extra (tree address)
+rs6000_init_dwarf_reg_sizes_extra (poly_uint16 *sizes)
 {
   if (TARGET_MACHO && ! TARGET_ALTIVEC)
     {
       int i;
-      machine_mode mode = TYPE_MODE (char_type_node);
-      rtx addr = expand_expr (address, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-      rtx mem = gen_rtx_MEM (BLKmode, addr);
-      rtx value = gen_int_mode (16, mode);
 
       /* On Darwin, libgcc may be built to run on both G3 and G4/5.
 	 The unwinder still needs to know the size of Altivec registers.  */
 
       for (i = FIRST_ALTIVEC_REGNO; i < LAST_ALTIVEC_REGNO+1; i++)
-	{
-	  int column = DWARF_REG_TO_UNWIND_COLUMN
-		(DWARF2_FRAME_REG_OUT (DWARF_FRAME_REGNUM (i), true));
-	  HOST_WIDE_INT offset = column * GET_MODE_SIZE (mode);
-
-	  emit_move_insn (adjust_address (mem, mode, offset), value);
-	}
+	sizes[i] = 16;
     }
 }
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 8572313b308..09a3ab3e55c 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9824,13 +9824,14 @@ used to return a smaller mode than the raw mode to prevent call
 clobbered parts of a register altering the frame register size
 @end deftypefn
 
-@deftypefn {Target Hook} void TARGET_INIT_DWARF_REG_SIZES_EXTRA (tree @var{address})
+@deftypefn {Target Hook} void TARGET_INIT_DWARF_REG_SIZES_EXTRA (poly_uint16 *@var{sizes})
 If some registers are represented in Dwarf-2 unwind information in
 multiple pieces, define this hook to fill in information about the
 sizes of those pieces in the table used by the unwinder at runtime.
-It will be called by @code{expand_builtin_init_dwarf_reg_sizes} after
+It will be called by @code{generate_dwarf_reg_sizes} after
 filling in a single size corresponding to each hard register;
-@var{address} is the address of the table.
+@var{sizes} is the address of the table.  It will contain
+@code{DWARF_FRAME_REGISTERS} elements when this hook is called.
 @end deftypefn
 
 @deftypefn {Target Hook} bool TARGET_ASM_TTYPE (rtx @var{sym})
diff --git a/gcc/dwarf2cfi.cc b/gcc/dwarf2cfi.cc
index bef3165e691..b29173b2156 100644
--- a/gcc/dwarf2cfi.cc
+++ b/gcc/dwarf2cfi.cc
@@ -36,7 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "except.h"		/* expand_builtin_dwarf_sp_column */
 #include "profile-count.h"	/* For expr.h */
-#include "expr.h"		/* init_return_column_size */
+#include "expr.h"		/* expand_normal, emit_move_insn */
 #include "output.h"		/* asm_out_file */
 #include "debug.h"		/* dwarf2out_do_frame, dwarf2out_do_cfi_asm */
 #include "flags.h"		/* dwarf_debuginfo_p */
@@ -241,18 +241,6 @@ expand_builtin_dwarf_sp_column (void)
   return GEN_INT (DWARF2_FRAME_REG_OUT (dwarf_regnum, 1));
 }
 
-/* MEM is a memory reference for the register size table, each element of
-   which has mode MODE.  Initialize column C as a return address column.  */
-
-static void
-init_return_column_size (scalar_int_mode mode, rtx mem, unsigned int c)
-{
-  HOST_WIDE_INT offset = c * GET_MODE_SIZE (mode);
-  HOST_WIDE_INT size = GET_MODE_SIZE (Pmode);
-  emit_move_insn (adjust_address (mem, mode, offset),
-		  gen_int_mode (size, mode));
-}
-
 /* Datastructure used by expand_builtin_init_dwarf_reg_sizes and
    init_one_dwarf_reg_size to communicate on what has been done by the
    latter.  */
@@ -274,17 +262,14 @@ struct init_one_dwarf_reg_state
    use for the size entry to initialize, and INIT_STATE is the communication
    datastructure conveying what we're doing to our caller.  */
 
-static
-void init_one_dwarf_reg_size (int regno, machine_mode regmode,
-			      rtx table, machine_mode slotmode,
-			      init_one_dwarf_reg_state *init_state)
+static void
+init_one_dwarf_reg_size (int regno, machine_mode regmode,
+			 poly_uint16 *table,
+			 init_one_dwarf_reg_state *init_state)
 {
   const unsigned int dnum = DWARF_FRAME_REGNUM (regno);
   const unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
   const unsigned int dcol = DWARF_REG_TO_UNWIND_COLUMN (rnum);
-  
-  poly_int64 slotoffset = dcol * GET_MODE_SIZE (slotmode);
-  poly_int64 regsize = GET_MODE_SIZE (regmode);
 
   init_state->processed_regno[regno] = true;
 
@@ -298,34 +283,22 @@ void init_one_dwarf_reg_size (int regno, machine_mode regmode,
       init_state->wrote_return_column = true;
     }
 
-  /* ??? When is this true?  Should it be a test based on DCOL instead?  */
-  if (maybe_lt (slotoffset, 0))
-    return;
-
-  emit_move_insn (adjust_address (table, slotmode, slotoffset),
-		  gen_int_mode (regsize, slotmode));
+  table[dcol] = GET_MODE_SIZE (regmode);
 }
 
-/* Generate code to initialize the dwarf register size table located
-   at the provided ADDRESS.  */
+/* Fill SIZES with size information for each DWARF register. */
 
-void
-expand_builtin_init_dwarf_reg_sizes (tree address)
+static void
+generate_dwarf_reg_sizes (poly_uint16 *sizes)
 {
-  unsigned int i;
-  scalar_int_mode mode = SCALAR_INT_TYPE_MODE (char_type_node);
-  rtx addr = expand_normal (address);
-  rtx mem = gen_rtx_MEM (BLKmode, addr);
-
-  init_one_dwarf_reg_state init_state;
+  for (unsigned int i = 0; i < DWARF_FRAME_REGISTERS; i++)
+    sizes[i] = poly_uint16{};
 
+  init_one_dwarf_reg_state init_state{};
   memset ((char *)&init_state, 0, sizeof (init_state));
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  for (unsigned int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      machine_mode save_mode;
-      rtx span;
-
       /* No point in processing a register multiple times.  This could happen
 	 with register spans, e.g. when a reg is first processed as a piece of
 	 a span, then as a register on its own later on.  */
@@ -333,11 +306,11 @@ expand_builtin_init_dwarf_reg_sizes (tree address)
       if (init_state.processed_regno[i])
 	continue;
 
-      save_mode = targetm.dwarf_frame_reg_mode (i);
-      span = targetm.dwarf_register_span (gen_rtx_REG (save_mode, i));
+      machine_mode save_mode = targetm.dwarf_frame_reg_mode (i);
+      rtx span = targetm.dwarf_register_span (gen_rtx_REG (save_mode, i));
 
       if (!span)
-	init_one_dwarf_reg_size (i, save_mode, mem, mode, &init_state);
+	init_one_dwarf_reg_size (i, save_mode, sizes, &init_state);
       else
 	{
 	  for (int si = 0; si < XVECLEN (span, 0); si++)
@@ -345,19 +318,45 @@ expand_builtin_init_dwarf_reg_sizes (tree address)
 	      rtx reg = XVECEXP (span, 0, si);
 
 	      init_one_dwarf_reg_size
-		(REGNO (reg), GET_MODE (reg), mem, mode, &init_state);
+		(REGNO (reg), GET_MODE (reg), sizes, &init_state);
 	    }
 	}
     }
 
   if (!init_state.wrote_return_column)
-    init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN);
+    sizes[DWARF_FRAME_RETURN_COLUMN] = GET_MODE_SIZE (Pmode);
 
 #ifdef DWARF_ALT_FRAME_RETURN_COLUMN
-  init_return_column_size (mode, mem, DWARF_ALT_FRAME_RETURN_COLUMN);
+  sizes[DWARF_ALT_FRAME_RETURN_COLUMN] = GET_MODE_SIZE (Pmode);
 #endif
 
-  targetm.init_dwarf_reg_sizes_extra (address);
+  if (targetm.init_dwarf_reg_sizes_extra != nullptr)
+    targetm.init_dwarf_reg_sizes_extra (sizes);
+}
+
+/* Generate code to initialize the dwarf register size table located
+   at the provided ADDRESS.  */
+
+void
+expand_builtin_init_dwarf_reg_sizes (tree address)
+{
+  poly_uint16 *sizes = XALLOCAVEC (poly_uint16, DWARF_FRAME_REGISTERS);
+  generate_dwarf_reg_sizes (sizes);
+
+  scalar_int_mode mode = SCALAR_INT_TYPE_MODE (char_type_node);
+  rtx addr = expand_normal (address);
+  rtx mem = gen_rtx_MEM (BLKmode, addr);
+  for (unsigned int i = 0; i < DWARF_FRAME_REGISTERS; ++i)
+    {
+      unsigned short value;
+      if (sizes[i].is_constant (&value) && value == 0)
+	/* No need to set the value to zero again.  */
+	continue;
+
+      HOST_WIDE_INT offset = i * GET_MODE_SIZE (mode);
+      emit_move_insn (adjust_address (mem, mode, offset),
+		      gen_int_mode (sizes[i], mode));
+    }
 }
 
 \f
diff --git a/gcc/target.def b/gcc/target.def
index 25f94c19fa7..e2c080d42a6 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4020,11 +4020,11 @@ DEFHOOK
  "If some registers are represented in Dwarf-2 unwind information in\n\
 multiple pieces, define this hook to fill in information about the\n\
 sizes of those pieces in the table used by the unwinder at runtime.\n\
-It will be called by @code{expand_builtin_init_dwarf_reg_sizes} after\n\
+It will be called by @code{generate_dwarf_reg_sizes} after\n\
 filling in a single size corresponding to each hard register;\n\
-@var{address} is the address of the table.",
- void, (tree address),
- hook_void_tree)
+@var{sizes} is the address of the table.  It will contain\n\
+@code{DWARF_FRAME_REGISTERS} elements when this hook is called.",
+ void, (poly_uint16 *sizes), nullptr)
 
 /* Fetch the fixed register(s) which hold condition codes, for
    targets where it makes sense to look for duplicate assignments to
-- 
2.38.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/3] Define __LIBGCC_DWARF_REG_SIZES_CONSTANT__ if DWARF register size is constant
  2022-11-08 18:05 [PATCH 0/3] Further libgcc unwinder improvements Florian Weimer
  2022-11-08 18:05 ` [PATCH 1/3] Compute a table of DWARF register sizes at compile Florian Weimer
@ 2022-11-08 18:05 ` Florian Weimer
  2022-11-08 18:05 ` [PATCH 3/3] libgcc: Specialize execute_cfa_program in DWARF unwinder for alignments Florian Weimer
  2 siblings, 0 replies; 6+ messages in thread
From: Florian Weimer @ 2022-11-08 18:05 UTC (permalink / raw)
  To: gcc-patches

And use that to speed up the libgcc unwinder.

	* gcc/debug.h (dwarf_reg_sizes_constant): Declare.
	* gcc/dwarf2cfi.cc (dwarf_reg_sizes_constant): New function.
	* gcc/c-family/c-cppbuiltin.c
	(__LIBGCC_DWARF_REG_SIZES_CONSTANT__): Define if constant is
	known.

libgcc/

	* unwind-dw2.c (dwarf_reg_size): New function.
	(_Unwind_GetGR, _Unwind_SetGR, _Unwind_SetGRPtr)
	(_Unwind_SetSpColumn, uw_install_context_1): Use it.
	(uw_init_context_1): Do not initialize dwarf_reg_size_table
	if not in use.
---
 gcc/c-family/c-cppbuiltin.cc |  6 ++++++
 gcc/debug.h                  |  2 ++
 gcc/dwarf2cfi.cc             | 23 ++++++++++++++++++++
 libgcc/unwind-dw2.c          | 41 +++++++++++++++++++++++++-----------
 4 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index cdb658f6ac9..ab98bf3b059 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -1515,6 +1515,12 @@ c_cpp_builtins (cpp_reader *pfile)
 #endif
       builtin_define_with_int_value ("__LIBGCC_DWARF_FRAME_REGISTERS__",
 				     DWARF_FRAME_REGISTERS);
+      {
+	int value = dwarf_reg_sizes_constant ();
+	if (value > 0)
+	  builtin_define_with_int_value ("__LIBGCC_DWARF_REG_SIZES_CONSTANT__",
+					 value);
+      }
 #ifdef EH_RETURN_STACKADJ_RTX
       cpp_define (pfile, "__LIBGCC_EH_RETURN_STACKADJ_RTX__");
 #endif
diff --git a/gcc/debug.h b/gcc/debug.h
index fe85115d5f3..6bcc8da1f76 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -245,6 +245,8 @@ extern const struct gcc_debug_hooks vmsdbg_debug_hooks;
 
 /* Dwarf2 frame information.  */
 
+extern int dwarf_reg_sizes_constant ();
+
 extern void dwarf2out_begin_prologue (unsigned int, unsigned int,
 				      const char *);
 extern void dwarf2out_vms_end_prologue (unsigned int, const char *);
diff --git a/gcc/dwarf2cfi.cc b/gcc/dwarf2cfi.cc
index b29173b2156..d45d20478b4 100644
--- a/gcc/dwarf2cfi.cc
+++ b/gcc/dwarf2cfi.cc
@@ -334,6 +334,29 @@ generate_dwarf_reg_sizes (poly_uint16 *sizes)
     targetm.init_dwarf_reg_sizes_extra (sizes);
 }
 
+/* Return 0 if the DWARF register sizes are not constant, otherwise
+   return the size constant.  */
+
+int
+dwarf_reg_sizes_constant ()
+{
+  poly_uint16 *sizes = XALLOCAVEC (poly_uint16, DWARF_FRAME_REGISTERS);
+  generate_dwarf_reg_sizes (sizes);
+
+  int result;
+  for (unsigned int i = 0; i < DWARF_FRAME_REGISTERS; i++)
+    {
+      unsigned short value;
+      if (!sizes[i].is_constant (&value))
+	return 0;
+      if (i == 0)
+	result = value;
+      else if (result != value)
+	return 0;
+    }
+  return result;
+}
+
 /* Generate code to initialize the dwarf register size table located
    at the provided ADDRESS.  */
 
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
index eaceace2029..c370121bb29 100644
--- a/libgcc/unwind-dw2.c
+++ b/libgcc/unwind-dw2.c
@@ -148,9 +148,25 @@ struct _Unwind_Context
   char by_value[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
 };
 
+#ifdef __LIBGCC_DWARF_REG_SIZES_CONSTANT__
+static inline unsigned char
+dwarf_reg_size (int index __attribute__ ((__unused__)))
+{
+  return __LIBGCC_DWARF_REG_SIZES_CONSTANT__;
+}
+#else
 /* Byte size of every register managed by these routines.  */
 static unsigned char dwarf_reg_size_table[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
 
+
+static inline unsigned char
+dwarf_reg_size (unsigned index)
+{
+  gcc_assert (index < sizeof (dwarf_reg_size_table));
+  return dwarf_reg_size_table[index];
+}
+#endif
+
 \f
 /* Read unaligned data from the instruction buffer.  */
 
@@ -232,8 +248,7 @@ _Unwind_GetGR (struct _Unwind_Context *context, int regno)
 #endif
 
   index = DWARF_REG_TO_UNWIND_COLUMN (regno);
-  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
-  size = dwarf_reg_size_table[index];
+  size = dwarf_reg_size (index);
   val = context->reg[index];
 
   if (_Unwind_IsExtendedContext (context) && context->by_value[index])
@@ -280,8 +295,7 @@ _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
   void *ptr;
 
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
-  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
-  size = dwarf_reg_size_table[index];
+  size = dwarf_reg_size (index);
 
   if (_Unwind_IsExtendedContext (context) && context->by_value[index])
     {
@@ -329,9 +343,8 @@ _Unwind_SetGRValue (struct _Unwind_Context *context, int index,
 		    _Unwind_Word val)
 {
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
-  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
   /* Return column size may be smaller than _Unwind_Context_Reg_Val.  */
-  gcc_assert (dwarf_reg_size_table[index] <= sizeof (_Unwind_Context_Reg_Val));
+  gcc_assert (dwarf_reg_size (index) <= sizeof (_Unwind_Context_Reg_Val));
 
   context->by_value[index] = 1;
   context->reg[index] = _Unwind_Get_Unwind_Context_Reg_Val (val);
@@ -1387,7 +1400,7 @@ static inline void
 _Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa,
 		     _Unwind_SpTmp *tmp_sp)
 {
-  int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()];
+  int size = dwarf_reg_size (__builtin_dwarf_sp_column ());
 
   if (size == sizeof(_Unwind_Ptr))
     tmp_sp->ptr = (_Unwind_Ptr) cfa;
@@ -1573,11 +1586,13 @@ uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     }									   \
   while (0)
 
+#ifndef __LIBGCC_DWARF_REG_SIZES_CONSTANT__
 static inline void
 init_dwarf_reg_size_table (void)
 {
   __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
 }
+#endif
 
 static void __attribute__((noinline))
 uw_init_context_1 (struct _Unwind_Context *context,
@@ -1596,16 +1611,18 @@ uw_init_context_1 (struct _Unwind_Context *context,
   code = uw_frame_state_for (context, &fs);
   gcc_assert (code == _URC_NO_REASON);
 
-#if __GTHREADS
+#ifndef __LIBGCC_DWARF_REG_SIZES_CONSTANT__
+# if __GTHREADS
   {
     static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
     if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0
 	&& dwarf_reg_size_table[0] == 0)
       init_dwarf_reg_size_table ();
   }
-#else
+# else
   if (dwarf_reg_size_table[0] == 0)
     init_dwarf_reg_size_table ();
+# endif
 #endif
 
   /* Force the frame state to use the known cfa value.  */
@@ -1682,20 +1699,20 @@ uw_install_context_1 (struct _Unwind_Context *current,
 	{
 	  _Unwind_Word w;
 	  _Unwind_Ptr p;
-	  if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word))
+	  if (dwarf_reg_size (i) == sizeof (_Unwind_Word))
 	    {
 	      w = (_Unwind_Internal_Ptr) t;
 	      memcpy (c, &w, sizeof (_Unwind_Word));
 	    }
 	  else
 	    {
-	      gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr));
+	      gcc_assert (dwarf_reg_size (i) == sizeof (_Unwind_Ptr));
 	      p = (_Unwind_Internal_Ptr) t;
 	      memcpy (c, &p, sizeof (_Unwind_Ptr));
 	    }
 	}
       else if (t && c && t != c)
-	memcpy (c, t, dwarf_reg_size_table[i]);
+	memcpy (c, t, dwarf_reg_size (i));
     }
 
   /* If the current frame doesn't have a saved stack pointer, then we
-- 
2.38.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/3] libgcc: Specialize execute_cfa_program in DWARF unwinder for alignments
  2022-11-08 18:05 [PATCH 0/3] Further libgcc unwinder improvements Florian Weimer
  2022-11-08 18:05 ` [PATCH 1/3] Compute a table of DWARF register sizes at compile Florian Weimer
  2022-11-08 18:05 ` [PATCH 2/3] Define __LIBGCC_DWARF_REG_SIZES_CONSTANT__ if DWARF register size is constant Florian Weimer
@ 2022-11-08 18:05 ` Florian Weimer
  2 siblings, 0 replies; 6+ messages in thread
From: Florian Weimer @ 2022-11-08 18:05 UTC (permalink / raw)
  To: gcc-patches

The parameters fs->data_align and fs->code_align always have fixed
values for a particular target in GCC-generated code.  Specialize
execute_cfa_program for these values, to avoid multiplications.

gcc/

	* c-family/c-cppbuiltin.c (c_cpp_builtins): Define
	__LIBGCC_DWARF_CIE_DATA_ALIGNMENT__.

libgcc/

	* unwind-dw2-execute_cfa.h: New file.  Extracted from
	the execute_cfa_program function in unwind-dw2.c.
	* unwind-dw2.c (execute_cfa_program_generic): New function.
	(execute_cfa_program_specialized): Likewise.
	(execute_cfa_program): Call execute_cfa_program_specialized
	or execute_cfa_program_generic, as appropriate.
---
 gcc/c-family/c-cppbuiltin.cc    |   2 +
 libgcc/unwind-dw2-execute_cfa.h | 322 ++++++++++++++++++++++++++++++++
 libgcc/unwind-dw2.c             | 319 +++----------------------------
 3 files changed, 354 insertions(+), 289 deletions(-)
 create mode 100644 libgcc/unwind-dw2-execute_cfa.h

diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index ab98bf3b059..c8c327b3b2e 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -1521,6 +1521,8 @@ c_cpp_builtins (cpp_reader *pfile)
 	  builtin_define_with_int_value ("__LIBGCC_DWARF_REG_SIZES_CONSTANT__",
 					 value);
       }
+      builtin_define_with_int_value ("__LIBGCC_DWARF_CIE_DATA_ALIGNMENT__",
+				     DWARF_CIE_DATA_ALIGNMENT);
 #ifdef EH_RETURN_STACKADJ_RTX
       cpp_define (pfile, "__LIBGCC_EH_RETURN_STACKADJ_RTX__");
 #endif
diff --git a/libgcc/unwind-dw2-execute_cfa.h b/libgcc/unwind-dw2-execute_cfa.h
new file mode 100644
index 00000000000..dd97b786668
--- /dev/null
+++ b/libgcc/unwind-dw2-execute_cfa.h
@@ -0,0 +1,322 @@
+/* DWARF2 exception handling CFA execution engine.
+   Copyright (C) 1997-2022 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file is included from unwind-dw2.c to specialize the code for certain
+   values of DATA_ALIGN and CODE_ALIGN.  These macros must be defined prior to
+   including this file.  */
+
+{
+  struct frame_state_reg_info *unused_rs = NULL;
+
+  /* Don't allow remember/restore between CIE and FDE programs.  */
+  fs->regs.prev = NULL;
+
+  /* The comparison with the return address uses < rather than <= because
+     we are only interested in the effects of code before the call; for a
+     noreturn function, the return address may point to unrelated code with
+     a different stack configuration that we are not interested in.  We
+     assume that the call itself is unwind info-neutral; if not, or if
+     there are delay instructions that adjust the stack, these must be
+     reflected at the point immediately before the call insn.
+     In signal frames, return address is after last completed instruction,
+     so we add 1 to return address to make the comparison <=.  */
+  while (insn_ptr < insn_end
+	 && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
+    {
+      unsigned char insn = *insn_ptr++;
+      _uleb128_t reg, utmp;
+      _sleb128_t offset, stmp;
+
+      if ((insn & 0xc0) == DW_CFA_advance_loc)
+	fs->pc += (insn & 0x3f) * CODE_ALIGN;
+      else if ((insn & 0xc0) == DW_CFA_offset)
+	{
+	  reg = insn & 0x3f;
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  offset = (_Unwind_Sword) utmp * DATA_ALIGN;
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_OFFSET;
+	      fs->regs.reg[reg].loc.offset = offset;
+	    }
+	}
+      else if ((insn & 0xc0) == DW_CFA_restore)
+	{
+	  reg = insn & 0x3f;
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    fs->regs.how[reg] = REG_UNSAVED;
+	}
+      else switch (insn)
+	{
+	case DW_CFA_set_loc:
+	  {
+	    _Unwind_Ptr pc;
+
+	    insn_ptr = read_encoded_value (context, fs->fde_encoding,
+					   insn_ptr, &pc);
+	    fs->pc = (void *) pc;
+	  }
+	  break;
+
+	case DW_CFA_advance_loc1:
+	  fs->pc += read_1u (insn_ptr) * CODE_ALIGN;
+	  insn_ptr += 1;
+	  break;
+	case DW_CFA_advance_loc2:
+	  fs->pc += read_2u (insn_ptr) * CODE_ALIGN;
+	  insn_ptr += 2;
+	  break;
+	case DW_CFA_advance_loc4:
+	  fs->pc += read_4u (insn_ptr) * CODE_ALIGN;
+	  insn_ptr += 4;
+	  break;
+
+	case DW_CFA_offset_extended:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  offset = (_Unwind_Sword) utmp * DATA_ALIGN;
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_OFFSET;
+	      fs->regs.reg[reg].loc.offset = offset;
+	    }
+	  break;
+
+	case DW_CFA_restore_extended:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  /* FIXME, this is wrong; the CIE might have said that the
+	     register was saved somewhere.  */
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    fs->regs.how[reg] = REG_UNSAVED;
+	  break;
+
+	case DW_CFA_same_value:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    fs->regs.how[reg] = REG_UNSAVED;
+	  break;
+
+	case DW_CFA_undefined:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    fs->regs.how[reg] = REG_UNDEFINED;
+	  break;
+
+	case DW_CFA_nop:
+	  break;
+
+	case DW_CFA_register:
+	  {
+	    _uleb128_t reg2;
+	    insn_ptr = read_uleb128 (insn_ptr, &reg);
+	    insn_ptr = read_uleb128 (insn_ptr, &reg2);
+	    reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	    if (UNWIND_COLUMN_IN_RANGE (reg))
+	      {
+		fs->regs.how[reg] = REG_SAVED_REG;
+	        fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
+	      }
+	  }
+	  break;
+
+	case DW_CFA_remember_state:
+	  {
+	    struct frame_state_reg_info *new_rs;
+	    if (unused_rs)
+	      {
+		new_rs = unused_rs;
+		unused_rs = unused_rs->prev;
+	      }
+	    else
+	      new_rs = alloca (sizeof (struct frame_state_reg_info));
+
+	    *new_rs = fs->regs;
+	    fs->regs.prev = new_rs;
+	  }
+	  break;
+
+	case DW_CFA_restore_state:
+	  {
+	    struct frame_state_reg_info *old_rs = fs->regs.prev;
+	    fs->regs = *old_rs;
+	    old_rs->prev = unused_rs;
+	    unused_rs = old_rs;
+	  }
+	  break;
+
+	case DW_CFA_def_cfa:
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  fs->regs.cfa_offset = (_Unwind_Word)utmp;
+	  fs->regs.cfa_how = CFA_REG_OFFSET;
+	  break;
+
+	case DW_CFA_def_cfa_register:
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
+	  fs->regs.cfa_how = CFA_REG_OFFSET;
+	  break;
+
+	case DW_CFA_def_cfa_offset:
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  fs->regs.cfa_offset = utmp;
+	  /* cfa_how deliberately not set.  */
+	  break;
+
+	case DW_CFA_def_cfa_expression:
+	  fs->regs.cfa_exp = insn_ptr;
+	  fs->regs.cfa_how = CFA_EXP;
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  insn_ptr += utmp;
+	  break;
+
+	case DW_CFA_expression:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_EXP;
+	      fs->regs.reg[reg].loc.exp = insn_ptr;
+	    }
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  insn_ptr += utmp;
+	  break;
+
+	  /* Dwarf3.  */
+	case DW_CFA_offset_extended_sf:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
+	  offset = stmp * DATA_ALIGN;
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_OFFSET;
+	      fs->regs.reg[reg].loc.offset = offset;
+	    }
+	  break;
+
+	case DW_CFA_def_cfa_sf:
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
+	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
+	  fs->regs.cfa_offset = (_Unwind_Sword)stmp;
+	  fs->regs.cfa_how = CFA_REG_OFFSET;
+	  fs->regs.cfa_offset *= DATA_ALIGN;
+	  break;
+
+	case DW_CFA_def_cfa_offset_sf:
+	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
+	  fs->regs.cfa_offset = (_Unwind_Sword)stmp;
+	  fs->regs.cfa_offset *= DATA_ALIGN;
+	  /* cfa_how deliberately not set.  */
+	  break;
+
+	case DW_CFA_val_offset:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  offset = (_Unwind_Sword) utmp * DATA_ALIGN;
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
+	      fs->regs.reg[reg].loc.offset = offset;
+	    }
+	  break;
+
+	case DW_CFA_val_offset_sf:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
+	  offset = stmp * DATA_ALIGN;
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
+	      fs->regs.reg[reg].loc.offset = offset;
+	    }
+	  break;
+
+	case DW_CFA_val_expression:
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_VAL_EXP;
+	      fs->regs.reg[reg].loc.exp = insn_ptr;
+	    }
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  insn_ptr += utmp;
+	  break;
+
+	case DW_CFA_GNU_window_save:
+#if defined (__aarch64__) && !defined (__ILP32__)
+	  /* This CFA is multiplexed with Sparc.  On AArch64 it's used to toggle
+	     return address signing status.  */
+	  reg = DWARF_REGNUM_AARCH64_RA_STATE;
+	  gcc_assert (fs->regs.how[reg] == REG_UNSAVED);
+	  fs->regs.reg[reg].loc.offset ^= 1;
+#else
+	  /* ??? Hardcoded for SPARC register window configuration.  */
+	  if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
+	    for (reg = 16; reg < 32; ++reg)
+	      {
+		fs->regs.how[reg] = REG_SAVED_OFFSET;
+		fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
+	      }
+#endif
+	  break;
+
+	case DW_CFA_GNU_args_size:
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  context->args_size = (_Unwind_Word)utmp;
+	  break;
+
+	case DW_CFA_GNU_negative_offset_extended:
+	  /* Obsoleted by DW_CFA_offset_extended_sf, but used by
+	     older PowerPC code.  */
+	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
+	  offset = (_Unwind_Word) utmp * DATA_ALIGN;
+	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+	  if (UNWIND_COLUMN_IN_RANGE (reg))
+	    {
+	      fs->regs.how[reg] = REG_SAVED_OFFSET;
+	      fs->regs.reg[reg].loc.offset = -offset;
+	    }
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+}
+
+#undef DATA_ALIGN
+#undef CODE_ALIGN
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
index c370121bb29..792338c1e38 100644
--- a/libgcc/unwind-dw2.c
+++ b/libgcc/unwind-dw2.c
@@ -960,302 +960,43 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
    instruction sequence to decode, current register information and
    CIE info, and the PC range to evaluate.  */
 
+static void  __attribute__ ((__noinline__))
+execute_cfa_program_generic (const unsigned char *insn_ptr,
+			     const unsigned char *insn_end,
+			     struct _Unwind_Context *context,
+			     _Unwind_FrameState *fs)
+{
+#define DATA_ALIGN fs->data_align
+#define CODE_ALIGN fs->code_align
+#include "unwind-dw2-execute_cfa.h"
+}
+
+static inline void
+execute_cfa_program_specialized (const unsigned char *insn_ptr,
+				 const unsigned char *insn_end,
+				 struct _Unwind_Context *context,
+				 _Unwind_FrameState *fs)
+{
+#define DATA_ALIGN __LIBGCC_DWARF_CIE_DATA_ALIGNMENT__
+  /* GCC always uses 1 even on architectures with a fixed instruction
+     width.  */
+#define CODE_ALIGN 1
+#include "unwind-dw2-execute_cfa.h"
+}
+
 static void
 execute_cfa_program (const unsigned char *insn_ptr,
 		     const unsigned char *insn_end,
 		     struct _Unwind_Context *context,
 		     _Unwind_FrameState *fs)
 {
-  struct frame_state_reg_info *unused_rs = NULL;
-
-  /* Don't allow remember/restore between CIE and FDE programs.  */
-  fs->regs.prev = NULL;
-
-  /* The comparison with the return address uses < rather than <= because
-     we are only interested in the effects of code before the call; for a
-     noreturn function, the return address may point to unrelated code with
-     a different stack configuration that we are not interested in.  We
-     assume that the call itself is unwind info-neutral; if not, or if
-     there are delay instructions that adjust the stack, these must be
-     reflected at the point immediately before the call insn.
-     In signal frames, return address is after last completed instruction,
-     so we add 1 to return address to make the comparison <=.  */
-  while (insn_ptr < insn_end
-	 && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
-    {
-      unsigned char insn = *insn_ptr++;
-      _uleb128_t reg, utmp;
-      _sleb128_t offset, stmp;
-
-      if ((insn & 0xc0) == DW_CFA_advance_loc)
-	fs->pc += (insn & 0x3f) * fs->code_align;
-      else if ((insn & 0xc0) == DW_CFA_offset)
-	{
-	  reg = insn & 0x3f;
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  offset = (_Unwind_Sword) utmp * fs->data_align;
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_OFFSET;
-	      fs->regs.reg[reg].loc.offset = offset;
-	    }
-	}
-      else if ((insn & 0xc0) == DW_CFA_restore)
-	{
-	  reg = insn & 0x3f;
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    fs->regs.how[reg] = REG_UNSAVED;
-	}
-      else switch (insn)
-	{
-	case DW_CFA_set_loc:
-	  {
-	    _Unwind_Ptr pc;
-
-	    insn_ptr = read_encoded_value (context, fs->fde_encoding,
-					   insn_ptr, &pc);
-	    fs->pc = (void *) pc;
-	  }
-	  break;
-
-	case DW_CFA_advance_loc1:
-	  fs->pc += read_1u (insn_ptr) * fs->code_align;
-	  insn_ptr += 1;
-	  break;
-	case DW_CFA_advance_loc2:
-	  fs->pc += read_2u (insn_ptr) * fs->code_align;
-	  insn_ptr += 2;
-	  break;
-	case DW_CFA_advance_loc4:
-	  fs->pc += read_4u (insn_ptr) * fs->code_align;
-	  insn_ptr += 4;
-	  break;
-
-	case DW_CFA_offset_extended:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  offset = (_Unwind_Sword) utmp * fs->data_align;
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_OFFSET;
-	      fs->regs.reg[reg].loc.offset = offset;
-	    }
-	  break;
-
-	case DW_CFA_restore_extended:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  /* FIXME, this is wrong; the CIE might have said that the
-	     register was saved somewhere.  */
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    fs->regs.how[reg] = REG_UNSAVED;
-	  break;
-
-	case DW_CFA_same_value:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    fs->regs.how[reg] = REG_UNSAVED;
-	  break;
-
-	case DW_CFA_undefined:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    fs->regs.how[reg] = REG_UNDEFINED;
-	  break;
-
-	case DW_CFA_nop:
-	  break;
-
-	case DW_CFA_register:
-	  {
-	    _uleb128_t reg2;
-	    insn_ptr = read_uleb128 (insn_ptr, &reg);
-	    insn_ptr = read_uleb128 (insn_ptr, &reg2);
-	    reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	    if (UNWIND_COLUMN_IN_RANGE (reg))
-	      {
-		fs->regs.how[reg] = REG_SAVED_REG;
-	        fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
-	      }
-	  }
-	  break;
-
-	case DW_CFA_remember_state:
-	  {
-	    struct frame_state_reg_info *new_rs;
-	    if (unused_rs)
-	      {
-		new_rs = unused_rs;
-		unused_rs = unused_rs->prev;
-	      }
-	    else
-	      new_rs = alloca (sizeof (struct frame_state_reg_info));
-
-	    *new_rs = fs->regs;
-	    fs->regs.prev = new_rs;
-	  }
-	  break;
-
-	case DW_CFA_restore_state:
-	  {
-	    struct frame_state_reg_info *old_rs = fs->regs.prev;
-	    fs->regs = *old_rs;
-	    old_rs->prev = unused_rs;
-	    unused_rs = old_rs;
-	  }
-	  break;
-
-	case DW_CFA_def_cfa:
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  fs->regs.cfa_offset = (_Unwind_Word)utmp;
-	  fs->regs.cfa_how = CFA_REG_OFFSET;
-	  break;
-
-	case DW_CFA_def_cfa_register:
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
-	  fs->regs.cfa_how = CFA_REG_OFFSET;
-	  break;
-
-	case DW_CFA_def_cfa_offset:
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  fs->regs.cfa_offset = utmp;
-	  /* cfa_how deliberately not set.  */
-	  break;
-
-	case DW_CFA_def_cfa_expression:
-	  fs->regs.cfa_exp = insn_ptr;
-	  fs->regs.cfa_how = CFA_EXP;
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  insn_ptr += utmp;
-	  break;
-
-	case DW_CFA_expression:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_EXP;
-	      fs->regs.reg[reg].loc.exp = insn_ptr;
-	    }
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  insn_ptr += utmp;
-	  break;
-
-	  /* Dwarf3.  */
-	case DW_CFA_offset_extended_sf:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
-	  offset = stmp * fs->data_align;
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_OFFSET;
-	      fs->regs.reg[reg].loc.offset = offset;
-	    }
-	  break;
-
-	case DW_CFA_def_cfa_sf:
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
-	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
-	  fs->regs.cfa_offset = (_Unwind_Sword)stmp;
-	  fs->regs.cfa_how = CFA_REG_OFFSET;
-	  fs->regs.cfa_offset *= fs->data_align;
-	  break;
-
-	case DW_CFA_def_cfa_offset_sf:
-	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
-	  fs->regs.cfa_offset = (_Unwind_Sword)stmp;
-	  fs->regs.cfa_offset *= fs->data_align;
-	  /* cfa_how deliberately not set.  */
-	  break;
-
-	case DW_CFA_val_offset:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  offset = (_Unwind_Sword) utmp * fs->data_align;
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
-	      fs->regs.reg[reg].loc.offset = offset;
-	    }
-	  break;
-
-	case DW_CFA_val_offset_sf:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
-	  offset = stmp * fs->data_align;
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
-	      fs->regs.reg[reg].loc.offset = offset;
-	    }
-	  break;
-
-	case DW_CFA_val_expression:
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_VAL_EXP;
-	      fs->regs.reg[reg].loc.exp = insn_ptr;
-	    }
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  insn_ptr += utmp;
-	  break;
-
-	case DW_CFA_GNU_window_save:
-#if defined (__aarch64__) && !defined (__ILP32__)
-	  /* This CFA is multiplexed with Sparc.  On AArch64 it's used to toggle
-	     return address signing status.  */
-	  reg = DWARF_REGNUM_AARCH64_RA_STATE;
-	  gcc_assert (fs->regs.how[reg] == REG_UNSAVED);
-	  fs->regs.reg[reg].loc.offset ^= 1;
-#else
-	  /* ??? Hardcoded for SPARC register window configuration.  */
-	  if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
-	    for (reg = 16; reg < 32; ++reg)
-	      {
-		fs->regs.how[reg] = REG_SAVED_OFFSET;
-		fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
-	      }
-#endif
-	  break;
-
-	case DW_CFA_GNU_args_size:
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  context->args_size = (_Unwind_Word)utmp;
-	  break;
-
-	case DW_CFA_GNU_negative_offset_extended:
-	  /* Obsoleted by DW_CFA_offset_extended_sf, but used by
-	     older PowerPC code.  */
-	  insn_ptr = read_uleb128 (insn_ptr, &reg);
-	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
-	  offset = (_Unwind_Word) utmp * fs->data_align;
-	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
-	  if (UNWIND_COLUMN_IN_RANGE (reg))
-	    {
-	      fs->regs.how[reg] = REG_SAVED_OFFSET;
-	      fs->regs.reg[reg].loc.offset = -offset;
-	    }
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
-    }
+  if (fs->data_align == __LIBGCC_DWARF_CIE_DATA_ALIGNMENT__
+      && fs->code_align == 1)
+    execute_cfa_program_specialized (insn_ptr, insn_end, context, fs);
+  else
+    execute_cfa_program_generic (insn_ptr, insn_end, context, fs);
 }
+
 \f
 /* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
    its caller and decode it into FS.  This function also sets the
-- 
2.38.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] Compute a table of DWARF register sizes at compile
  2022-11-08 18:05 ` [PATCH 1/3] Compute a table of DWARF register sizes at compile Florian Weimer
@ 2022-11-20 15:23   ` Jeff Law
  2023-01-02 15:20     ` Florian Weimer
  0 siblings, 1 reply; 6+ messages in thread
From: Jeff Law @ 2022-11-20 15:23 UTC (permalink / raw)
  To: Florian Weimer, gcc-patches


On 11/8/22 11:05, Florian Weimer via Gcc-patches wrote:
> The sizes are compile-time constants.  Create a vector with them,
> so that they can be inspected at compile time.
>
> 	* gcc/dwarf2cfi.cc (init_return_column_size): Remove.
> 	(init_one_dwarf_reg_size): Adjust.
> 	(generate_dwarf_reg_sizes): New function.  Extracted
> 	from expand_builtin_init_dwarf_reg_sizes.
> 	(expand_builtin_init_dwarf_reg_sizes): Call
> 	generate_dwarf_reg_sizes.
> 	* gcc/target.def (init_dwarf_reg_sizes_extra): Adjust
> 	hook signature.
> 	* gcc/config/msp430/msp430.cc
> 	(msp430_init_dwarf_reg_sizes_extra): Adjust.
> 	* gcc/config/rs6000.cc (rs6000_init_dwarf_reg_sizes_extra):
> 	Likewise.
> 	* gcc/doc/tm.texi: Update.

This series of 3 patches is fine.

Jeff



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] Compute a table of DWARF register sizes at compile
  2022-11-20 15:23   ` Jeff Law
@ 2023-01-02 15:20     ` Florian Weimer
  0 siblings, 0 replies; 6+ messages in thread
From: Florian Weimer @ 2023-01-02 15:20 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches

* Jeff Law:

> On 11/8/22 11:05, Florian Weimer via Gcc-patches wrote:
>> The sizes are compile-time constants.  Create a vector with them,
>> so that they can be inspected at compile time.
>>
>> 	* gcc/dwarf2cfi.cc (init_return_column_size): Remove.
>> 	(init_one_dwarf_reg_size): Adjust.
>> 	(generate_dwarf_reg_sizes): New function.  Extracted
>> 	from expand_builtin_init_dwarf_reg_sizes.
>> 	(expand_builtin_init_dwarf_reg_sizes): Call
>> 	generate_dwarf_reg_sizes.
>> 	* gcc/target.def (init_dwarf_reg_sizes_extra): Adjust
>> 	hook signature.
>> 	* gcc/config/msp430/msp430.cc
>> 	(msp430_init_dwarf_reg_sizes_extra): Adjust.
>> 	* gcc/config/rs6000.cc (rs6000_init_dwarf_reg_sizes_extra):
>> 	Likewise.
>> 	* gcc/doc/tm.texi: Update.
>
> This series of 3 patches is fine.

Thanks, now pushed (after polishing the ChangeLog snippets).

Florian


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-01-02 15:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-08 18:05 [PATCH 0/3] Further libgcc unwinder improvements Florian Weimer
2022-11-08 18:05 ` [PATCH 1/3] Compute a table of DWARF register sizes at compile Florian Weimer
2022-11-20 15:23   ` Jeff Law
2023-01-02 15:20     ` Florian Weimer
2022-11-08 18:05 ` [PATCH 2/3] Define __LIBGCC_DWARF_REG_SIZES_CONSTANT__ if DWARF register size is constant Florian Weimer
2022-11-08 18:05 ` [PATCH 3/3] libgcc: Specialize execute_cfa_program in DWARF unwinder for alignments Florian Weimer

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).