The previous code had several issues. 1. XALLOCAVEC does not create any objects, so invocating the non-POD poly_uint16 assignment operator is undefined. 2. The default constructor of poly-ints does not create a zero poly-int object (unlike what happens with regular ints). 3. The register size array must have DWARF_FRAME_REGISTERS + 1 elements. The extra element can be DWARF_FRAME_RETURN_COLUMN or DWARF_ALT_FRAME_RETURN_COLUMN.
To fix problem 3, merely increasing the array size is sufficient, but it inhibits the x86-64 register size optimization in libgcc because it does not use the extra register, so it has size zero. To re-enable the optimization, expose the maximum used register to libgcc. This is sufficient for the optimizers to figure out that the memcpy call in uw_install_context_1 has a fixed size argument on x86-64. This restores bootstrap on aarch64-linux-gnu and powerpc64-linux-gnu. Not sure about test suite results yet, I need to check the baseline. gcc/ * debug.h (dwarf_reg_sizes_constant): Remove declaration. (dwarf_single_register_size): New struct. * dwarf2cfi.cc (generate_dwarf_reg_sizes): Initialize extra register size. Use in-place new for initialization. Remove unnecessary memset. (dwarf_reg_sizes_constant): Remove. (dwarf_single_register_size::dwarf_single_register_size): New constructor based on removed dwarf_reg_sizes_constant function. Allocate extra size element. (expand_builtin_init_dwarf_reg_sizes): Allocate extra size element. * target.def (init_dwarf_reg_sizes_extra): Mention extra size element. * doc/tm.texi: Update. gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Switch to dwarf_single_register_size for obtaining DWARF register sizes. Define __LIBGCC_DWARF_REG_MAXIMUM__. libgcc/ * unwind-dw2.c (dwarf_reg_size): Use __LIBGCC_DWARF_REG_MAXIMUM__. --- gcc/c-family/c-cppbuiltin.cc | 12 ++++++++---- gcc/debug.h | 13 ++++++++++++- gcc/doc/tm.texi | 2 +- gcc/dwarf2cfi.cc | 45 +++++++++++++++++++++++++++----------------- gcc/target.def | 2 +- libgcc/unwind-dw2.c | 7 +++++-- 6 files changed, 55 insertions(+), 26 deletions(-) diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index ddfd63b8eb9..8098aca41e8 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1522,10 +1522,14 @@ c_cpp_builtins (cpp_reader *pfile) 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); + dwarf_single_register_size srs; + if (srs.common_size > 0) + { + builtin_define_with_int_value ("__LIBGCC_DWARF_REG_SIZES_CONSTANT__", + srs.common_size); + builtin_define_with_int_value ("__LIBGCC_DWARF_REG_MAXIMUM__", + srs.maximum_register); + } } builtin_define_with_int_value ("__LIBGCC_DWARF_CIE_DATA_ALIGNMENT__", DWARF_CIE_DATA_ALIGNMENT); diff --git a/gcc/debug.h b/gcc/debug.h index 4fe9f3570ac..2e843da8b41 100644 --- a/gcc/debug.h +++ b/gcc/debug.h @@ -245,7 +245,18 @@ extern const struct gcc_debug_hooks vmsdbg_debug_hooks; /* Dwarf2 frame information. */ -extern int dwarf_reg_sizes_constant (); +/* Query size information about DWARF registers. */ +struct dwarf_single_register_size +{ + dwarf_single_register_size(); + + /* The common register size, or 0 if the register size varies. */ + unsigned int common_size; + + /* The maximum register number that is actually present. Registers + above the maximum are size zero even if common_size is positive. */ + unsigned int maximum_register; +}; extern void dwarf2out_begin_prologue (unsigned int, unsigned int, const char *); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index b6d7900f212..eb29cfb95aa 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -9847,7 +9847,7 @@ sizes of those pieces in the table used by the unwinder at runtime. It will be called by @code{generate_dwarf_reg_sizes} after filling in a single size corresponding to each hard register; @var{sizes} is the address of the table. It will contain -@code{DWARF_FRAME_REGISTERS} elements when this hook is called. +@code{DWARF_FRAME_REGISTERS + 1} 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 d5a27dc36c5..5bd12e070b3 100644 --- a/gcc/dwarf2cfi.cc +++ b/gcc/dwarf2cfi.cc @@ -291,11 +291,10 @@ init_one_dwarf_reg_size (int regno, machine_mode regmode, static void generate_dwarf_reg_sizes (poly_uint16 *sizes) { - for (unsigned int i = 0; i < DWARF_FRAME_REGISTERS; i++) - sizes[i] = poly_uint16{}; + for (unsigned int i = 0; i <= DWARF_FRAME_REGISTERS; i++) + new (&sizes[i]) poly_uint16(0); init_one_dwarf_reg_state init_state{}; - memset ((char *)&init_state, 0, sizeof (init_state)); for (unsigned int i = 0; i < FIRST_PSEUDO_REGISTER; i++) { @@ -334,27 +333,39 @@ 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 () +dwarf_single_register_size::dwarf_single_register_size() { - poly_uint16 *sizes = XALLOCAVEC (poly_uint16, DWARF_FRAME_REGISTERS); + poly_uint16 *sizes = XALLOCAVEC (poly_uint16, DWARF_FRAME_REGISTERS + 1); generate_dwarf_reg_sizes (sizes); - int result; - for (unsigned int i = 0; i < DWARF_FRAME_REGISTERS; i++) + /* Find the last register number actually in use. */ + for (int i = DWARF_FRAME_REGISTERS; i >= 0; --i) + { + unsigned short value; + if (!sizes[i].is_constant (&value) || value != 0) + { + maximum_register = i; + break; + } + } + + /* Check for a common register size among the used registers. */ + for (unsigned int i = 0; i <= maximum_register; ++i) { unsigned short value; if (!sizes[i].is_constant (&value)) - return 0; + { + common_size = 0; + break; + } if (i == 0) - result = value; - else if (result != value) - return 0; + common_size = value; + else if (common_size != value) + { + common_size = 0; + break; + } } - return result; } /* Generate code to initialize the dwarf register size table located @@ -363,7 +374,7 @@ dwarf_reg_sizes_constant () void expand_builtin_init_dwarf_reg_sizes (tree address) { - poly_uint16 *sizes = XALLOCAVEC (poly_uint16, DWARF_FRAME_REGISTERS); + poly_uint16 *sizes = XALLOCAVEC (poly_uint16, DWARF_FRAME_REGISTERS + 1); generate_dwarf_reg_sizes (sizes); scalar_int_mode mode = SCALAR_INT_TYPE_MODE (char_type_node); diff --git a/gcc/target.def b/gcc/target.def index da5dd31d7a4..dfffc534f83 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4042,7 +4042,7 @@ sizes of those pieces in the table used by the unwinder at runtime.\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{sizes} is the address of the table. It will contain\n\ -@code{DWARF_FRAME_REGISTERS} elements when this hook is called.", +@code{DWARF_FRAME_REGISTERS + 1} elements when this hook is called.", void, (poly_uint16 *sizes), nullptr) /* Fetch the fixed register(s) which hold condition codes, for diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c index 792338c1e38..7a173487061 100644 --- a/libgcc/unwind-dw2.c +++ b/libgcc/unwind-dw2.c @@ -150,9 +150,12 @@ struct _Unwind_Context #ifdef __LIBGCC_DWARF_REG_SIZES_CONSTANT__ static inline unsigned char -dwarf_reg_size (int index __attribute__ ((__unused__))) +dwarf_reg_size (unsigned int index) { - return __LIBGCC_DWARF_REG_SIZES_CONSTANT__; + if (index <= __LIBGCC_DWARF_REG_MAXIMUM__) + return __LIBGCC_DWARF_REG_SIZES_CONSTANT__; + else + return 0; } #else /* Byte size of every register managed by these routines. */ base-commit: 201c21b0e847679645df1af3dd13459274f41047