Matthieu Longo <matthieu.lo...@arm.com> writes:
> The previous implementation to emit build attributes did not support
> string values (asciz) in aeabi_subsection, and was not emitting values
> associated to tags in the assembly comments.
>
> This new approach provides a more user-friendly interface relying on
> typing, and improves the emitted assembly comments:
>   * aeabi_attribute:
>     ** Adds the interpreted value next to the tag in the assembly
>     comment.
>     ** Supports asciz values.
>   * aeabi_subsection:
>     ** Adds debug information for its parameters.
>     ** Auto-detects the attribute types when declaring the subsection.
>
> Additionally, it is also interesting to note that the code was moved
> to a separate file to improve modularity and "releave" the 1000-lines
> long aarch64.cc file from a few lines. Finally, it introduces a new
> namespace "aarch64::" for AArch64 backend which reduce the length of
> function names by not prepending 'aarch64_' to each of them.
>
> gcc/ChangeLog:
>
>    * config/aarch64/aarch64.cc
>    (aarch64_emit_aeabi_attribute): Delete.
>    (aarch64_emit_aeabi_subsection): Delete.
>    (aarch64_start_file): Use aeabi_subsection.
>    * config/aarch64/aarch64-dwarf-metadata.h: New file.
>
> gcc/testsuite/ChangeLog:
>
>    * gcc.target/aarch64/build-attributes/build-attribute-gcs.c:
>      Improve test to match debugging comments in assembly.
>    * gcc.target/aarch64/build-attributes/build-attribute-standard.c:
>      Likewise.

Generally this looks really nice!  Just some minor comments below.
Most of them are formatting nits; sorry that we don't have automatic
formatting to care of this stuff.

> ---
>  gcc/config/aarch64/aarch64-dwarf-metadata.h   | 247 ++++++++++++++++++
>  gcc/config/aarch64/aarch64.cc                 |  43 +--
>  .../build-attributes/build-attribute-gcs.c    |   4 +-
>  .../build-attribute-standard.c                |   4 +-
>  4 files changed, 261 insertions(+), 37 deletions(-)
>  create mode 100644 gcc/config/aarch64/aarch64-dwarf-metadata.h
>
> diff --git a/gcc/config/aarch64/aarch64-dwarf-metadata.h 
> b/gcc/config/aarch64/aarch64-dwarf-metadata.h
> new file mode 100644
> index 00000000000..9638bc7702f
> --- /dev/null
> +++ b/gcc/config/aarch64/aarch64-dwarf-metadata.h
> @@ -0,0 +1,247 @@
> +/* Machine description for AArch64 architecture.
> +   Copyright (C) 2009-2024 Free Software Foundation, Inc.
> +   Contributed by ARM Ltd.
> +
> +   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.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with GCC; see the file COPYING3.  If not see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_AARCH64_DWARF_METADATA_H
> +#define GCC_AARCH64_DWARF_METADATA_H
> +
> +#include <type_traits>
> +#include <cstdint>

As mentioned in the part 1 review, we need to include system headers
via system.h.  These two should be included by default, though,
so I think they can just be removed.

> +#include <vec.h>

"vec.h"

> +
> +namespace aarch64 {
> +
> +enum attr_val_type: uint8_t
> +{
> +  uleb128 = 0x0,
> +  asciz = 0x1,
> +};
> +
> +enum BA_TagFeature_t: uint8_t
> +{
> +  Tag_Feature_BTI = 1,
> +  Tag_Feature_PAC = 2,
> +  Tag_Feature_GCS = 3,
> +};
> +
> +template <typename T_tag, typename T_val>
> +struct aeabi_attribute
> +{
> +  T_tag tag;
> +  T_val value;
> +};
> +
> +template <typename T_tag, typename T_val>
> +aeabi_attribute<T_tag, T_val>
> +make_aeabi_attribute (T_tag tag, T_val val)
> +{
> +  return aeabi_attribute<T_tag, T_val>{tag, val};
> +}
> +
> +namespace details {
> +
> +constexpr const char*

Formatting nit, but: space before "*", even here.  Same below.

> +to_c_str (bool b)
> +{
> +  return b ? "true" : "false";
> +}
> +
> +constexpr const char*
> +to_c_str (const char *s)
> +{
> +  return s;
> +}
> +
> +constexpr const char*
> +to_c_str (attr_val_type t)
> +{
> +  const char *s = nullptr;
> +  switch (t) {
> +    case uleb128:
> +      s = "ULEB128";
> +      break;
> +    case asciz:
> +      s = "asciz";
> +      break;
> +  }

Formatting nit: the opening brace should be on its own line, indented like so:

  switch (t)
    {
    case uleb128:
      s = "ULEB128";
      break;
    case asciz:
      s = "asciz";
      break;
    }

However...

> +  return s;

...we are unfortunately limited to C++11 constexprs, so I think this needs
to be:

  return (t == uleb128 ? "ULEB128"
          : t == asciz ? "asciz"
          : nullptr);

if we want it to be treated as a constant for all builds.

> +}
> +
> +constexpr const char*
> +to_c_str (BA_TagFeature_t feature)
> +{
> +  const char *s = nullptr;
> +  switch (feature) {
> +    case Tag_Feature_BTI:
> +      s = "Tag_Feature_BTI";
> +      break;
> +    case Tag_Feature_PAC:
> +      s = "Tag_Feature_PAC";
> +      break;
> +    case Tag_Feature_GCS:
> +      s = "Tag_Feature_GCS";
> +      break;
> +  }
> +  return s;

Similarly here, I think we need to use ?: to get constexprs for C++11.

> +}
> +
> +template <
> +  typename T,
> +  typename = typename std::enable_if<std::is_unsigned<T>::value, T>::type
> +>
> +constexpr const char*
> +aeabi_attr_str_fmt (T phantom __attribute__((unused)))
> +{
> +    return "\t.aeabi_attribute %u, %u";

Formatting nit: should be indented by 2 spaces only.  Similarly below.

> +}
> +
> +constexpr const char*
> +aeabi_attr_str_fmt (const char *phantom __attribute__((unused)))
> +{
> +    return "\t.aeabi_attribute %u, \"%s\"";
> +}
> +
> +template <
> +  typename T,
> +  typename = typename std::enable_if<std::is_unsigned<T>::value, T>::type
> +>
> +constexpr uint8_t
> +aeabi_attr_val_for_fmt (T value)
> +{
> +  return static_cast<uint8_t>(value);
> +}
> +
> +constexpr const char*
> +aeabi_attr_val_for_fmt (const char *s)
> +{
> +  return s;
> +}
> +
> +template <typename T_tag, typename T_val>
> +void write (FILE *out_file, aeabi_attribute<T_tag, T_val> const &attr)
> +{
> +  asm_fprintf (out_file, aeabi_attr_str_fmt(T_val{}),

Formatting nit, but: space before "(" for each call in this function.
Same for the functions below.

> +            attr.tag, aeabi_attr_val_for_fmt(attr.value));
> +  if (flag_debug_asm)
> +    asm_fprintf (out_file, "\t%s %s: %s", ASM_COMMENT_START,
> +              to_c_str(attr.tag), to_c_str(attr.value));
> +  asm_fprintf (out_file, "\n");
> +}
> +
> +template <
> +  typename T,
> +  typename = typename std::enable_if<std::is_unsigned<T>::value, T>::type
> +>
> +constexpr attr_val_type
> +deduce_attr_av_type (T value __attribute__((unused)))
> +{
> +  return attr_val_type::uleb128;
> +}
> +
> +constexpr attr_val_type
> +deduce_attr_av_type (const char* value __attribute__((unused)))
> +{
> +  return attr_val_type::asciz;
> +}
> +
> +} // namespace details
> +
> +/* AEABI subsections can be public or private.  A subsection is public if it 
> is
> +   prefixed with "aeabi", private otherwise.  The header of an AEABI 
> subsection
> +   is composed of a name (usually a vendor name), a status whether it is
> +   optional or not, and the expected type of its associated attributes 
> (ULEB128
> +   or asciz).  Note: The attributes in the same subsection have all the same
> +   type. An attribute is composed of a tag identifier (ULEB128), and its 
> value
> +   (ULEB128 or asciz).
> +
> +   Syntax:
> +     .aeabi_subsection NameOfTheSubsection: string (=asciz),
> +                    Optional: boolean (=ULEB128),
> +                    AttributeValueType: enum{ULEB128, asciz} (=ULEB128)
> +     [
> +       .aeabi_attribute  TagIdentifier: ULEB128,
> +                      TagValue: Variant[ULEB128|asciz]
> +     ]*
> +
> +   Example:
> +     .aeabi_subsection .aeabi-feature-and-bits, 1, 0
> +                    // Optional: true, AttrValType: ULEB128
> +     .aeabi_attribute 3, 1 // Tag_Feature_GCS: true
> +
> +   Note: The textual representations of the tag and its value are emitted as 
> a
> +   comment along their numerical representations to annotate the assembler
> +   output when the developer flag '-dA' is provided.  */
> +template <
> +  typename T_tag, /* The type of a tag.  */
> +  typename T_val, /* The type of a value.  */
> +  size_t N = 0    /* The number of expected attributes if we know it.  */
> +>
> +class aeabi_subsection
> +{
> +  public:
> +    aeabi_subsection (const char *name, bool optional):
> +      name_(name),
> +      optional_(optional),
> +      avtype_(details::deduce_attr_av_type (T_val{}))

Formatting nit, should be indented as:

class aeabi_subsection
{
public:
  aeabi_subsection (const char *name, bool optional)
    : name_ (name)
      ...

But the usual GCC style is to use an "m_" prefix for private members,
rather than a "_" suffix.

> +    {}
> +
> +    /* Append an attribute to the subsection.  */
> +    void
> +    append (aeabi_attribute<T_tag, T_val> &&attr)
> +    {
> +      attributes_.quick_push (std::move(attr));
> +    }
> +
> +    /* Write the data to the assembly file.  */
> +    void
> +    write (FILE *out_file) const
> +    {
> +      asm_fprintf (out_file, "\t.aeabi_subsection %s, %u, %u",
> +                name_, static_cast<uint8_t>(optional_),
> +                static_cast<uint8_t>(avtype_));
> +      if (flag_debug_asm)
> +     asm_fprintf (out_file, "\t%s Optional: %s, AttrValType: %s",
> +                  ASM_COMMENT_START,
> +                  details::to_c_str(optional_),
> +                  details::to_c_str(avtype_));
> +      asm_fprintf (out_file, "\n");
> +
> +      for (auto const& attr: attributes_)

"auto const &attr : attributes_"

> +      {
> +     details::write (out_file, attr);
> +      }

Formatting nit, but: no braces for single statements.

> +    }
> +
> +    /* Indicate if the subsection is empty.  */
> +    bool empty() const

Space before "(" even for empty arguments.  (I agree it looks silly.)

Thanks,
Richard

> +    {
> +      return attributes_.is_empty ();
> +    }
> +
> +  private:
> +    const char *name_;
> +    bool optional_;
> +    attr_val_type avtype_;
> +    auto_vec<aeabi_attribute<T_tag, T_val>, N> attributes_;
> +};
> +
> +} // namespace aarch64
> +
> +#endif /* GCC_AARCH64_DWARF_METADATA_H */
> \ No newline at end of file
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 61e0248817f..0cc8a5ee9ad 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -83,6 +83,7 @@
>  #include "rtlanal.h"
>  #include "tree-dfa.h"
>  #include "asan.h"
> +#include "aarch64-dwarf-metadata.h"
>  #include "aarch64-feature-deps.h"
>  #include "config/arm/aarch-common.h"
>  #include "config/arm/aarch-common-protos.h"
> @@ -24677,33 +24678,6 @@ aarch64_post_cfi_startproc (FILE *f, tree ignored 
> ATTRIBUTE_UNUSED)
>       asm_fprintf (f, "\t.cfi_b_key_frame\n");
>  }
>  
> -/* This function is used to emit an AEABI attribute with tag and its 
> associated
> -   value.  We emit the numerical value of the tag and the textual tags as
> -   comment so that anyone reading the assembler output will know which tag is
> -   being set.
> -   example: .aeabi_attribute 3, 1 // Tag_Feature_GCS  */
> -
> -void
> -aarch64_emit_aeabi_attribute (const char *name, uint8_t num, uint8_t val)
> -{
> -  asm_fprintf (asm_out_file, "\t.aeabi_attribute %u, %u", num, val);
> -  if (flag_debug_asm)
> -    asm_fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, name);
> -  asm_fprintf (asm_out_file, "\n");
> -}
> -
> -/* This function is used to emit an AEABI subsection with vendor name,
> -   optional status and value type.
> -   example: .aeabi_subsection .aeabi-feature-and-bits, 1, 0  */
> -
> -void
> -aarch64_emit_aeabi_subsection (const char *name, uint8_t num, uint8_t val)
> -{
> -  asm_fprintf (asm_out_file, "\t.aeabi_subsection %s, %u, %u\n",
> -            name, num, val);
> -}
> -
> -
>  /* Implements TARGET_ASM_FILE_START.  Output the assembly header.  */
>  
>  static void
> @@ -24727,18 +24701,21 @@ aarch64_start_file (void)
>  /* Emit gcs build attributes only when building a native AArch64-hosted
>     compiler.  */
>  #if defined(__aarch64__)
> +  using namespace aarch64;
> +  aeabi_subsection<BA_TagFeature_t, bool, 3>
> +    aeabi_subsec (".aeabi-feature-and-bits", true);
> +
>    /* Check the current assembly supports gcs build attributes, if not
>       fallback to .note.gnu.property section.  */
>    #ifdef HAVE_AS_BUILD_ATTRIBUTES_GCS
> -    if (aarch64_gcs_enabled ())
> -      {
> -     aarch64_emit_aeabi_subsection (".aeabi-feature-and-bits", 1, 0);
> -     aarch64_emit_aeabi_attribute ("Tag_Feature_GCS", 3, 1);
> -      }
> +    aeabi_subsec.append (
> +      make_aeabi_attribute (Tag_Feature_GCS, aarch64_gcs_enabled ()));
>    #endif
> +  if (!aeabi_subsec.empty ())
> +    aeabi_subsec.write(asm_out_file);
>  #endif
>  
> -   default_file_start ();
> +  default_file_start ();
>  }
>  
>  /* Emit load exclusive.  */
> diff --git 
> a/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-gcs.c 
> b/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-gcs.c
> index ce43a79c1d0..7b241a2c889 100644
> --- a/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-gcs.c
> +++ b/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-gcs.c
> @@ -6,7 +6,7 @@ int main()
>    return 0;
>  }
>  
> -/* { dg-final { scan-assembler "\.aeabi_subsection \.aeabi-feature-and-bits, 
> 1, 0" } } */
> -/* { dg-final { scan-assembler "\.aeabi_attribute 3, 1\t\/\/ 
> Tag_Feature_GCS" } } */
> +/* { dg-final { scan-assembler "\.aeabi_subsection \.aeabi-feature-and-bits, 
> 1, 0\t\/\/ Optional: true, AttrValType: ULEB128" } } */
> +/* { dg-final { scan-assembler "\.aeabi_attribute 3, 1\t\/\/ 
> Tag_Feature_GCS: true" } } */
>  /* { dg-final { scan-assembler "\.section\t\.note\.gnu\.property" } } */
>  /* { dg-final { scan-assembler "\.word\t4\t\/\/ 
> GNU_PROPERTY_AARCH64_FEATURE_1_AND \\(GCS\\)" } } */
> \ No newline at end of file
> diff --git 
> a/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-standard.c
>  
> b/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-standard.c
> index fd175f8137f..5c3c8738040 100644
> --- 
> a/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-standard.c
> +++ 
> b/gcc/testsuite/gcc.target/aarch64/build-attributes/build-attribute-standard.c
> @@ -6,7 +6,7 @@ int main()
>    return 0;
>  }
>  
> -/* { dg-final { scan-assembler "\.aeabi_subsection \.aeabi-feature-and-bits, 
> 1, 0" } } */
> -/* { dg-final { scan-assembler "\.aeabi_attribute 3, 1\t\/\/ 
> Tag_Feature_GCS" } } */
> +/* { dg-final { scan-assembler "\.aeabi_subsection \.aeabi-feature-and-bits, 
> 1, 0\t\/\/ Optional: true, AttrValType: ULEB128" } } */
> +/* { dg-final { scan-assembler "\.aeabi_attribute 3, 1\t\/\/ 
> Tag_Feature_GCS: true" } } */
>  /* { dg-final { scan-assembler "\.section\t\.note\.gnu\.property" } } */
>  /* { dg-final { scan-assembler "\.word\t7\t\/\/ 
> GNU_PROPERTY_AARCH64_FEATURE_1_AND \\(BTI, PAC, GCS\\)" } } */
> \ No newline at end of file

Reply via email to