Matthieu Longo <[email protected]> writes:
> Architecture-specific CFI directives are currently declared an processed
> among others architecture-independent CFI directives in gcc/dwarf2* files.
> This approach creates confusion, specifically in the case of DWARF
> instructions in the vendor space and using the same instruction code.
>
> Such a clash currently happen between DW_CFA_GNU_window_save (used on
> SPARC) and DW_CFA_AARCH64_negate_ra_state (used on AArch64), and both
> having the same instruction code 0x2d.
> Then AArch64 compilers generates a SPARC CFI directive (.cfi_window_save)
> instead of .cfi_negate_ra_state, contrarilly to what is expected in
> [DWARF for the Arm 64-bit Architecture (AArch64)](https://github.com/
> ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst).
>
> This refactoring does not solve completely the problem, but improve the
> situation by moving some of the processing of those directives (more
> specifically their output in the assembly) to the backend via 2 target
> hooks:
> - DW_CFI_OPRND1_DESC: parse the first operand of the directive (if any).
> - OUTPUT_CFI_DIRECTIVE: output the CFI directive as a string.
>
> Additionally, this patch also contains a renaming of an enum used for
> return address mangling on AArch64.
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64.cc
> (aarch64_output_cfi_directive): New hook for CFI directives.
> (aarch64_dw_cfi_oprnd1_desc): Same.
> (TARGET_OUTPUT_CFI_DIRECTIVE): Hook for output_cfi_directive.
> (TARGET_DW_CFI_OPRND1_DESC): Hook for dw_cfi_oprnd1_desc.
> * config/sparc/sparc.cc
> (sparc_output_cfi_directive): New hook for CFI directives.
> (sparc_dw_cfi_oprnd1_desc): Same.
> (TARGET_OUTPUT_CFI_DIRECTIVE): Hook for output_cfi_directive.
> (TARGET_DW_CFI_OPRND1_DESC): Hook for dw_cfi_oprnd1_desc.
> * coretypes.h
> (struct dw_cfi_node): Forward declaration of CFI type from
> gcc/dwarf2out.h.
> (enum dw_cfi_oprnd_type): Same.
> * doc/tm.texi: Regenerated from doc/tm.texi.in.
> * doc/tm.texi.in: Add doc for OUTPUT_CFI_DIRECTIVE and
> DW_CFI_OPRND1_DESC.
> * dwarf2cfi.cc
> (struct dw_cfi_row): Update the description for window_save
> and ra_mangled.
> (cfi_equal_p): Adapt parameter of dw_cfi_oprnd1_desc.
> (dwarf2out_frame_debug_cfa_negate_ra_state): Use AArch64 CFI
> directive instead of the SPARC one.
> (change_cfi_row): Use the right CFI directive's name for RA
> mangling.
> (output_cfi): Remove explicit architecture-specific CFI
> directive DW_CFA_GNU_window_save that falls into default case.
> (output_cfi_directive): Use target hook as default.
> * dwarf2out.cc (dw_cfi_oprnd1_desc): Use target hook as default.
> * dwarf2out.h (enum dw_cfi_oprnd_type): specify underlying type
> of enum to allow forward declaration.
> (dw_cfi_oprnd1_desc): Change type of parameter.
> (output_cfi_directive): Use dw_cfi_ref instead of struct
> dw_cfi_node *.
> * target.def: Documentation for new hooks.
>
> libffi/ChangeLog:
>
> * include/ffi_cfi.h (cfi_negate_ra_state): Declare AArch64 cfi
> directive.
>
> libgcc/ChangeLog:
>
> * config/aarch64/aarch64-asm.h (PACIASP): Replace SPARC CFI
> directive by AArch64 one.
> (AUTIASP): Same.
>
> libitm/ChangeLog:
>
> * config/aarch64/sjlj.S: Replace SPARC CFI directive by
> AArch64 one.
>
> gcc/testsuite/ChangeLog:
>
> * g++.target/aarch64/pr94515-1.C: Replace SPARC CFI directive by
> AArch64 one.
> * g++.target/aarch64/pr94515-2.C: Same.
> ---
> gcc/config/aarch64/aarch64.cc | 32 +++++++++++++++++
> gcc/config/sparc/sparc.cc | 36 ++++++++++++++++++++
> gcc/coretypes.h | 6 ++++
> gcc/doc/tm.texi | 28 +++++++++++++++
> gcc/doc/tm.texi.in | 17 +++++++++
> gcc/dwarf2cfi.cc | 29 ++++++----------
> gcc/dwarf2out.cc | 13 ++++---
> gcc/dwarf2out.h | 10 +++---
> gcc/target.def | 20 +++++++++++
> gcc/testsuite/g++.target/aarch64/pr94515-1.C | 6 ++--
> gcc/testsuite/g++.target/aarch64/pr94515-2.C | 2 +-
> libffi/include/ffi_cfi.h | 2 ++
> libgcc/config/aarch64/aarch64-asm.h | 4 +--
> libitm/config/aarch64/sjlj.S | 10 +++---
> 14 files changed, 176 insertions(+), 39 deletions(-)
Generally looks good to me. Most of the comments below are very minor,
but there's also a question about the hook interface.
>
> [...]
> @@ -12621,6 +12630,33 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx
> x)
> fputs (")", file);
> }
>
> +/* This is called from gcc/dwarf2cfi.cc via TARGET_OUTPUT_CFI_DIRECTIVE.
> + It outputs SPARC-specific CFI directives (if any). */
I think we should use the same comments as for aarch64, i.e.:
/* Implement TARGET_OUTPUT_CFI_DIRECTIVE. */
...
/* Implement TARGET_DW_CFI_OPRND1_DESC. */
The idea is that the hook descriptions in target.def/tm.texi should be
self-contained.
> +static bool
> +sparc_output_cfi_directive (FILE *f, dw_cfi_ref cfi)
> +{
> + if (cfi->dw_cfi_opc == DW_CFA_GNU_window_save)
> + {
> + fprintf (f, "\t.cfi_window_save\n");
> + return true;
> + }
> + return false;
> +}
> +
> +/* This is called from gcc/dwarf2out.cc via TARGET_DW_CFI_OPRND1_DESC.
> + It describes for the GTY machinery what parts of the first operand
> + is used. */
> +static bool
> +sparc_dw_cfi_oprnd1_desc (dw_cfi_ref cfi, dw_cfi_oprnd_type_ref oprnd_type)
> +{
> + if (cfi->dw_cfi_opc == DW_CFA_GNU_window_save)
> + {
> + oprnd_type = dw_cfi_oprnd_unused;
> + return true;
> + }
> + return false;
> +}
> +
> /* Do whatever processing is required at the end of a file. */
>
> static void
> diff --git a/gcc/coretypes.h b/gcc/coretypes.h
> index 0544bb8fd97..3b622961b7a 100644
> --- a/gcc/coretypes.h
> +++ b/gcc/coretypes.h
> @@ -141,6 +141,12 @@ struct gomp_single;
> struct gomp_target;
> struct gomp_teams;
>
> +/* Forward declaration of CFI's and DWARF's types. */
> +struct dw_cfi_node;
> +using dw_cfi_ref = struct dw_cfi_node *;
It'd be good to remove the corresponding typedef in dwarf2out.h.
> +enum dw_cfi_oprnd_type: unsigned int;
> +using dw_cfi_oprnd_type_ref = enum dw_cfi_oprnd_type &;
IMO it'd better to avoid adding this, and instead just use
dw_cfi_oprnd_type &
directly.
I think the use of typedefs for pointers (as for dw_cfi_ref) was more
popular when the codebase was written in C, and where the typedef often
saved on a struct/union/enum tag. I don't think it's something we
should use for C++ references since it hides the fact that:
void foo (dw_cfi_ref x, dw_cfi_ref y) { ... x = y; ... }
is a normal copy whereas:
void foo (dw_cfi_oprnd_type_ref x, dw_cfi_oprnd_type_ref y) { ... x = y; ... }
isn't.
> +
> /* Subclasses of symtab_node, using indentation to show the class
> hierarchy. */
>
> [...]
> diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
> index 64cea3b1eda..051217d68b1 100644
> --- a/gcc/doc/tm.texi.in
> +++ b/gcc/doc/tm.texi.in
> @@ -3108,7 +3108,20 @@ used in .eh_frame or .debug_frame is different from
> that used in other
> debug info sections. Given a GCC hard register number, this macro
> should return the .eh_frame register number. The default is
> @code{DEBUGGER_REGNO (@var{regno})}.
> +@end defmac
> +
> +
> +@defmac OUTPUT_CFI_DIRECTIVE (@var{f}, @var{cfi})
> +
> +Define this macro if the target has additional CFI directives. Return
> +true if an architecture-specific directive was found, false otherwise.
> +@end defmac
> +
> +@defmac DW_CFI_OPRND1_DESC (@var{cfi}, @var{oprnd_type})
>
> +Define this macro if the target has additional CFI directives. Return
> +true if an architecture-specific directive was found and @var{oprnd_type}
> +is set, false otherwise and @var{oprnd_type} is not modified.
> @end defmac
The new hooks are proper target hooks rather than macros (which is good!)
so there's no need to have and document macros as well. (Macros are a
hold-over from before target hooks existed.)
> @defmac DWARF2_FRAME_REG_OUT (@var{regno}, @var{for_eh})
> [...]
> @@ -1547,17 +1549,13 @@ dwarf2out_frame_debug_cfa_window_save (void)
> cur_row->window_save = true;
> }
>
> -/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_NEGATE_RA_STATE.
> - Note: DW_CFA_GNU_window_save dwarf opcode is reused for toggling RA mangle
> - state, this is a target specific operation on AArch64 and can only be used
> - on other targets if they don't use the window save operation otherwise.
> */
> +/*A subroutine of dwarf2out_frame_debug, process REG_CFA_NEGATE_RA_STATE. */
Nit: should be a space before "A subroutine ...".
>
> static void
> dwarf2out_frame_debug_cfa_negate_ra_state (void)
> {
> dw_cfi_ref cfi = new_cfi ();
> -
> - cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
> + cfi->dw_cfi_opc = DW_CFA_AARCH64_negate_ra_state;
> add_cfi (cfi);
> cur_row->ra_mangled = !cur_row->ra_mangled;
> }
> [...]
> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
> index 357efaa5990..260593421df 100644
> --- a/gcc/dwarf2out.cc
> +++ b/gcc/dwarf2out.cc
> @@ -516,12 +516,11 @@ switch_to_frame_table_section (int for_eh, bool back)
> /* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */
>
> enum dw_cfi_oprnd_type
> -dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
> +dw_cfi_oprnd1_desc (dw_cfi_ref cfi)
> {
> - switch (cfi)
> + switch (cfi->dw_cfi_opc)
> {
> case DW_CFA_nop:
> - case DW_CFA_GNU_window_save:
> case DW_CFA_remember_state:
> case DW_CFA_restore_state:
> return dw_cfi_oprnd_unused;
> @@ -557,7 +556,13 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
> return dw_cfi_oprnd_loc;
>
> default:
> - gcc_unreachable ();
> + {
> + dw_cfi_oprnd_type oprnd_type;
> + if (targetm.dw_cfi_oprnd1_desc (cfi, oprnd_type))
Could you say why passing opcode isn't enough? I guess this is to do
with some of the changes that are coming later?
I think the correspondong:
> - return (cfi_oprnd_equal_p (dw_cfi_oprnd1_desc (opc),
> + return (cfi_oprnd_equal_p (dw_cfi_oprnd1_desc (a),
> &a->dw_cfi_oprnd1, &b->dw_cfi_oprnd1)
> && cfi_oprnd_equal_p (dw_cfi_oprnd2_desc (opc),
> &a->dw_cfi_oprnd2, &b->dw_cfi_oprnd2));
makes the corretness of cfi_equal_p a bit fuzzier/less obvious,
since it seems that dw_cfi_oprnd1_desc (a) is checking something
about a that is not checked for b.
Thanks,
Richard
> + return oprnd_type;
> + else
> + gcc_unreachable ();
> + }
> }
> }
>