Here is an updated version 2 of the patch.

I am planning to also add .gnu_attribute for other aspects of
the ABI (Binutils patches are pending), and therefore I changed
some variable names to better fit the future features so I don't
have to touch parts of the patch again.

Moreover, scanning variables has been moved from encode_section_info
to avr_file_end.  The commit message and changelog are basically the
same:

--

This patch emits .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS) according
to the named address space used for C++ virtual tables.

Currently there are only two values possible:
- Val_GNU_AVR_VTABLE_NONE: The unit doesn't use vtables.
- Val_GNU_AVR_VTABLE_RAM:  There are vtables in the generic space.

The purpose of the patch is to tag object files with the vtable AS
for the case when future extensions support vtables in ASes other
than generic.

The patch has four parts:

1) Add a configure test to define HAVE_AS_AVR_GNU_ATTRIBUTE
   when Binutils support .gnu_attribute for AVR.
   The test may return true for older Binutils versions that
   effectively ignore the .gnu_attribute.

2) Set avr_uses_vtable_p when the code invokes an indirect call
   to a vtable entry.  This check is performed by a new mini
   pass that traverses gimple statements.

3) avr_file_end() sets avr_uses_vtable_p when the varpool contains
   a decl that represents a vtable.

4) avr_file_end() emits .gnu_attribute 4 according to avr_uses_vtable_p.

Again, this is for trunk.

Johann

--

gcc/
        * configure.ac [avr] <HAVE_AS_AVR_GNU_ATTRIBUTE>: Set
        according to gcc_GAS_CHECK_FEATURE for .gnu_attribute.
        * configure: Rebuild.
        * config.in: Rebuild.
        * config/avr/avr.h (avr_addrspace_t) <gnu_attr_val>: New field.
        * config/avr/avr.cc (avr_addrspace): Adjust initializer.
        (avr_uses_vtable_p): New global variable.
        (avr_file_end): Update avr_uses_vtable_p according to varpool,
        then output .gnu_attribute 4 according to avr_uses_vtable_p.
        * config/avr/avr-passes.cc (gimple.h): Include.
        (gimple-iterator.h): Include.
        (avr_pass_data_has): New pass data.
        (avr_pass_has): New gimple pass.
        (make_avr_pass_has): New function.
        * config/avr/avr-passes.def (avr_pass_has): Insert pass.
        * config/avr/avr-protos.h (avr_uses_vtable_p): New global var.
        (class gimple_opt_pass): Declare.
        (make_avr_pass_has): New proto.
        * config/avr/avr.md (Tag_GNU_AVR_VTABLE_AS)
        (Val_GNU_AVR_VTABLE_NONE, Val_GNU_AVR_VTABLE_RAM)
        (Val_GNU_AVR_VTABLE_FLASH, Val_GNU_AVR_VTABLE_FLASH1)
        (Val_GNU_AVR_VTABLE_FLASH2, Val_GNU_AVR_VTABLE_FLASH3)
        (Val_GNU_AVR_VTABLE_FLASH4, Val_GNU_AVR_VTABLE_FLASH5)
        (Val_GNU_AVR_VTABLE_FLASHX): Define constants.



Am 21.08.26 um 13:01 schrieb Georg-Johann Lay:
This patch emits .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS) according
to the named address space used for C++ virtual tables.

Currently there are only two values possible:
- Val_GNU_AVR_VTABLE_NONE: The unit doesn't use vtables.
- Val_GNU_AVR_VTABLE_RAM:  There are vtables in the generic space.

The purpose of the patch is to tag object files with the vtable AS
for the case when future extensions support vtables in ASes other
than generic.

The patch has four parts:

1) Add a configure test to define HAVE_AS_AVR_GNU_ATTRIBUTE_4
    when Binutils support PR34305, i.e. .gnu_attribute 4.
    The test may return true for older Binutils versions that
    effectively ignore the attribute.

2) Set avr_has_vtable_p when the code invokes an indirect call
    to a vtable entry.  This check is performed by a new mini
    pass that traverses gimple statements.

3) avr_encode_section_info() sets avr_has_vtable_p when a vtable
    object is emit.

4) avr_file_end() emits .gnu_attribute 4 according to avr_has_vtable_p.

Ok for trunk?

Johann

--

gcc/
     * configure.ac [avr] <HAVE_AS_AVR_GNU_ATTRIBUTE_4>: Set
     according to gcc_GAS_CHECK_FEATURE for .gnu_attribute 4.
     * configure: Rebuild.
     * config.in: Rebuild.
     * config/avr/avr.h (avr_addrspace_t) <gnu_attr_val>: New field.
     * config/avr/avr.cc (avr_addrspace): Adjust initializer.
     (avr_has_vtable_p): New global variable.
     (avr_encode_section_info) <avr_has_vtable_p>: Set it if
     the hook is called for a vtable.
     (avr_file_end): Output .gnu_attribute 4.
     * config/avr/avr-passes.cc (gimple.h): Include.
     (gimple-iterator.h): Include.
     (avr_pass_data_uses_vtable): New pass data.
     (avr_pass_uses_vtable): New gimple pass.
     (make_avr_pass_uses_vtable): New function.
     * config/avr/avr-passes.def (avr_pass_uses_vtable): Insert pass.
     * config/avr/avr-protos.h (avr_has_vtable_p): New global var.
     (class gimple_opt_pass): Declare.
     (make_avr_pass_uses_vtable): New proto.
     * config/avr/avr.md (Tag_GNU_AVR_VTABLE_AS)
     (Val_GNU_AVR_VTABLE_NONE, Val_GNU_AVR_VTABLE_RAM)
     (Val_GNU_AVR_VTABLE_FLASH, Val_GNU_AVR_VTABLE_FLASH1)
     (Val_GNU_AVR_VTABLE_FLASH2, Val_GNU_AVR_VTABLE_FLASH3)
     (Val_GNU_AVR_VTABLE_FLASH4, Val_GNU_AVR_VTABLE_FLASH5)
     (Val_GNU_AVR_VTABLE_FLASHX): Define constants.
diff --git a/gcc/config.in b/gcc/config.in
index 34ff1b1cb99..b90caa0dd57 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -397,6 +397,12 @@
 #endif
 
 
+/* Define if your avr assembler supports .gnu_attribute. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_AVR_GNU_ATTRIBUTE
+#endif
+
+
 /* Define if your avr assembler supports -mgcc-isr option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_AVR_MGCCISR_OPTION
diff --git a/gcc/config/avr/avr-passes.cc b/gcc/config/avr/avr-passes.cc
index 9df3c0e945c..71f6a4ca6e5 100644
--- a/gcc/config/avr/avr-passes.cc
+++ b/gcc/config/avr/avr-passes.cc
@@ -29,6 +29,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
 #include "diagnostic-core.h"
 #include "cfghooks.h"
 #include "cfganal.h"
@@ -5533,6 +5535,65 @@ public:
   }
 }; // avr_pass_recompute_notes
 
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Determine whether there are vtable calls, and set `avr_uses_vtable_p'.
+
+static const pass_data avr_pass_data_has =
+{
+  GIMPLE_PASS,   // type
+  "",            // name (will be patched)
+  OPTGROUP_NONE, // optinfo_flags
+  TV_NONE,       // tv_id
+  PROP_cfg | PROP_ssa, // properties_required
+  0,             // properties_provided
+  0,             // properties_destroyed
+  0,             // todo_flags_start
+  0              // todo_flags_finish
+};
+
+class avr_pass_has : public gimple_opt_pass
+{
+public:
+  avr_pass_has (gcc::context *ctxt, const char *name)
+    : gimple_opt_pass (avr_pass_data_has, ctxt)
+  {
+    this->name = name;
+  }
+
+  void scan_bb (basic_block bb)
+  {
+    gimple_stmt_iterator gsi;
+    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+	tree fncall;
+	gimple *stmt = gsi_stmt (gsi);
+
+	if (is_gimple_call (stmt)
+	    && (fncall = gimple_call_fn (stmt))
+	    && TREE_CODE (fncall) == OBJ_TYPE_REF)
+	  avr_uses_vtable_p = true;
+      }
+  }
+
+#ifndef HAVE_AS_AVR_GNU_ATTRIBUTE
+  bool gate (function *) final override
+  {
+    return false;
+  }
+#endif // !HAVE_AS_AVR_GNU_ATTRIBUTE
+
+  unsigned int execute (function *func) final override
+  {
+    basic_block bb;
+    FOR_ALL_BB_FN (bb, func)
+      scan_bb (bb);
+
+    return 0;
+  }
+}; // avr_pass_has
+
 } // anonymous namespace
 
 
@@ -5828,6 +5889,14 @@ avr_split_ldst (rtx *xop)
 // according to the pass declaration in avr-passes.def.  GCC's pass
 // manager uses these function to create the respective pass object.
 
+// This pass sets `avr_uses_vtable_p'.
+
+gimple_opt_pass *
+make_avr_pass_has (gcc::context *ctxt)
+{
+  return new avr_pass_has (ctxt, "avr-has");
+}
+
 // Optimize results of the casesi expander for modes < SImode.
 
 rtl_opt_pass *
diff --git a/gcc/config/avr/avr-passes.def b/gcc/config/avr/avr-passes.def
index fd535e65401..d50285c3f89 100644
--- a/gcc/config/avr/avr-passes.def
+++ b/gcc/config/avr/avr-passes.def
@@ -17,6 +17,12 @@
    along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
 
+/* A gimple pass that sets `avr_uses_vtable_p', i.e. whether the target
+   code is using vtables.  Where the pass is inserted doesn't really matter,
+   though it should be an SSA pass that runs after LTO streaming.  */
+
+INSERT_PASS_AFTER (pass_musttail, 1, avr_pass_has);
+
 /* A post reload optimization pass that fuses PLUS insns with CONST_INT
    addend with a load or store insn to get POST_INC or PRE_DEC addressing.
    It can also fuse two PLUSes to a single one, which may occur due to
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 9013745d914..c91c6efc29b 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -194,12 +194,15 @@ extern void asm_output_float (FILE *file, REAL_VALUE_TYPE n);
 #endif
 
 extern bool avr_have_dimode;
+extern bool avr_uses_vtable_p;
 
 /* From avr-passes.cc */
 
 namespace gcc { class context; }
 class rtl_opt_pass;
+class gimple_opt_pass;
 
+extern gimple_opt_pass *make_avr_pass_has (gcc::context *);
 extern rtl_opt_pass *make_avr_pass_fuse_add (gcc::context *);
 extern rtl_opt_pass *make_avr_pass_fuse_move (gcc::context *);
 extern rtl_opt_pass *make_avr_pass_pre_proep (gcc::context *);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 084ee2d3715..dfc4d4526d8 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -108,15 +108,22 @@
    enum from avr.h (or designated initialized must be used).  */
 const avr_addrspace_t avr_addrspace[ADDR_SPACE_COUNT] =
 {
-  { ADDR_SPACE_RAM,  0, 2, "", 0, nullptr },
-  { ADDR_SPACE_FLASH,  1, 2, "__flash",   0, ".progmem.data" },
-  { ADDR_SPACE_FLASH1, 1, 2, "__flash1",  1, ".progmem1.data" },
-  { ADDR_SPACE_FLASH2, 1, 2, "__flash2",  2, ".progmem2.data" },
-  { ADDR_SPACE_FLASH3, 1, 2, "__flash3",  3, ".progmem3.data" },
-  { ADDR_SPACE_FLASH4, 1, 2, "__flash4",  4, ".progmem4.data" },
-  { ADDR_SPACE_FLASH5, 1, 2, "__flash5",  5, ".progmem5.data" },
-  { ADDR_SPACE_FLASHX, 1, 3, "__flashx",  0, ".progmemx.data" },
-  { ADDR_SPACE_MEMX, 1, 3, "__memx",  0, ".progmemx.data" },
+  { ADDR_SPACE_RAM,  0, 2, "", 0, nullptr, Val_GNU_AVR_VTABLE_RAM },
+  { ADDR_SPACE_FLASH,  1, 2, "__flash",	 0, ".progmem.data",
+					    Val_GNU_AVR_VTABLE_FLASH },
+  { ADDR_SPACE_FLASH1, 1, 2, "__flash1", 1, ".progmem1.data",
+					    Val_GNU_AVR_VTABLE_FLASH1 },
+  { ADDR_SPACE_FLASH2, 1, 2, "__flash2", 2, ".progmem2.data",
+					    Val_GNU_AVR_VTABLE_FLASH2 },
+  { ADDR_SPACE_FLASH3, 1, 2, "__flash3", 3, ".progmem3.data",
+					    Val_GNU_AVR_VTABLE_FLASH3 },
+  { ADDR_SPACE_FLASH4, 1, 2, "__flash4", 4, ".progmem4.data",
+					    Val_GNU_AVR_VTABLE_FLASH4 },
+  { ADDR_SPACE_FLASH5, 1, 2, "__flash5", 5, ".progmem5.data",
+					    Val_GNU_AVR_VTABLE_FLASH5 },
+  { ADDR_SPACE_FLASHX, 1, 3, "__flashx", 0, ".progmemx.data",
+					    Val_GNU_AVR_VTABLE_FLASHX },
+  { ADDR_SPACE_MEMX, 1, 3, "__memx", 0, ".progmemx.data", -1 },
 };
 
 
@@ -249,6 +256,8 @@ bool avr_need_clear_bss_p = false;
 bool avr_need_copy_data_p = false;
 bool avr_has_rodata_p = false;
 
+bool avr_uses_vtable_p = false;
+
 /* Counts how often pass avr-fuse-add has been executed.  It is kept in
    sync with cfun->machine->n_avr_fuse_add_executed and serves as an
    insn condition for shift insn splitters.  */
@@ -12805,6 +12814,24 @@ avr_file_end (void)
 
   if (avr_need_clear_bss_p)
     fputs (".global __do_clear_bss\n", asm_out_file);
+
+#ifdef HAVE_AS_AVR_GNU_ATTRIBUTE
+  /* Output .gnu_attribute to tag object files with aspects of the ABI.
+     .gnu_attribute 4: The named address space for C++ virtual tables.  */
+
+  varpool_node *vnode;
+
+  FOR_EACH_VARIABLE (vnode)
+    {
+      const char *id = IDENTIFIER_POINTER (DECL_NAME (vnode->decl));
+      avr_uses_vtable_p |= startswith (id, "_ZTV"); // vtable
+      avr_uses_vtable_p |= startswith (id, "_ZTT"); // vtable table
+    }
+
+  if (avr_uses_vtable_p)
+    fprintf (asm_out_file, ".gnu_attribute %d,%d\n",
+	     Tag_GNU_AVR_VTABLE_AS, Val_GNU_AVR_VTABLE_RAM);
+#endif // HAVE_AS_AVR_GNU_ATTRIBUTE
 }
 
 
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
index 3c0b1b4283b..0923fa26196 100644
--- a/gcc/config/avr/avr.h
+++ b/gcc/config/avr/avr.h
@@ -38,6 +38,9 @@ typedef struct
 
   /* Section prefix, e.g. ".progmem1.data"  */
   const char *section_name;
+
+  /* Value for Tag_GNU_AVR_VTABLE_AS (4) is 1 + id.  */
+  int gnu_attr_val;
 } avr_addrspace_t;
 
 extern const avr_addrspace_t avr_addrspace[];
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index eb344ea4e70..26ae9e501c9 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -113,6 +113,20 @@ (define_constants
    (GASISR_Done     0)
    ])
 
+;; Vtables address space are hard-coded in Binutils include/elf/avr.h.
+(define_constants
+ [(Tag_GNU_AVR_VTABLE_AS 4)
+  (Val_GNU_AVR_VTABLE_NONE   0)
+  (Val_GNU_AVR_VTABLE_RAM    1)
+  (Val_GNU_AVR_VTABLE_FLASH  2)
+  (Val_GNU_AVR_VTABLE_FLASH1 3)
+  (Val_GNU_AVR_VTABLE_FLASH2 4)
+  (Val_GNU_AVR_VTABLE_FLASH3 5)
+  (Val_GNU_AVR_VTABLE_FLASH4 6)
+  (Val_GNU_AVR_VTABLE_FLASH5 7)
+  (Val_GNU_AVR_VTABLE_FLASHX 8)
+  ])
+
 (include "predicates.md")
 (include "constraints.md")
 
diff --git a/gcc/configure b/gcc/configure
index f8501781474..43ca45144b8 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -29149,6 +29149,38 @@ if test $gcc_cv_as_avr_mgccisr = yes; then
 
 $as_echo "#define HAVE_AS_AVR_MGCCISR_OPTION 1" >>confdefs.h
 
+fi
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .gnu_attribute" >&5
+$as_echo_n "checking assembler for .gnu_attribute... " >&6; }
+if ${gcc_cv_as_avr_gnu_attribute+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_avr_gnu_attribute=no
+  if test x"$gcc_cv_as" != x; then
+    $as_echo '.gnu_attribute 4,1' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_avr_gnu_attribute=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_avr_gnu_attribute" >&5
+$as_echo "$gcc_cv_as_avr_gnu_attribute" >&6; }
+if test $gcc_cv_as_avr_gnu_attribute = yes; then
+
+$as_echo "#define HAVE_AS_AVR_GNU_ATTRIBUTE 1" >>confdefs.h
+
 fi
 
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 1773706e70a..075b6b68ffa 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4739,6 +4739,11 @@ AS_HELP_STRING([--disable-fix-cortex-a53-843419],
       [AC_DEFINE(HAVE_AS_AVR_MGCCISR_OPTION, 1,
 		[Define if your avr assembler supports -mgcc-isr option.])])
 
+    gcc_GAS_CHECK_FEATURE([.gnu_attribute], gcc_cv_as_avr_gnu_attribute,
+      [], [.gnu_attribute 4,1],,
+      [AC_DEFINE(HAVE_AS_AVR_GNU_ATTRIBUTE, 1,
+		[Define if your avr assembler supports .gnu_attribute.])])
+
     avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`"
     # Check how default linker description file implements .rodata for
     # avrxmega3 (PR21472).  avr-gcc assumes .rodata is *not* loaded to

Reply via email to