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..5c5479aafce 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -397,6 +397,12 @@
 #endif
 
 
+/* Define if your avr assembler supports .gnu_attribute 4. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_AVR_GNU_ATTRIBUTE_4
+#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..6ad8dcf2d26 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,63 @@ public:
   }
 }; // avr_pass_recompute_notes
 
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Determine whether there are vtable calls and set `avr_has_vtable_p'.
+
+static const pass_data avr_pass_data_uses_vtable =
+{
+  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_uses_vtable : public gimple_opt_pass
+{
+public:
+  avr_pass_uses_vtable (gcc::context *ctxt, const char *name)
+    : gimple_opt_pass (avr_pass_data_uses_vtable, ctxt)
+  {
+    this->name = name;
+  }
+
+  bool bb_uses_vtable (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)
+	  return true;
+      }
+    return false;
+  }
+
+  unsigned int execute (function *func ATTRIBUTE_UNUSED) final override
+  {
+#ifdef HAVE_AS_AVR_GNU_ATTRIBUTE_4
+    basic_block bb;
+    if (!avr_has_vtable_p)
+      FOR_ALL_BB_FN (bb, func)
+	if ((avr_has_vtable_p = bb_uses_vtable (bb)))
+	  break;
+#endif // HAVE_AS_AVR_GNU_ATTRIBUTE_4
+
+    return 0;
+  }
+}; // avr_pass_uses_vtable
+
 } // anonymous namespace
 
 
@@ -5828,6 +5887,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_has_vtable_p'.
+
+gimple_opt_pass *
+make_avr_pass_uses_vtable (gcc::context *ctxt)
+{
+  return new avr_pass_uses_vtable (ctxt, "avr-uses-vtable");
+}
+
 // 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..baa8a8eea5d 100644
--- a/gcc/config/avr/avr-passes.def
+++ b/gcc/config/avr/avr-passes.def
@@ -17,6 +17,11 @@
    along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
 
+/* A gimple pass that sets `avr_has_vtable_p', i.e. whether the target code
+   is using vtables.  Where the pass is inserted doesn't really matter.  */
+
+INSERT_PASS_AFTER (pass_musttail, 1, avr_pass_uses_vtable);
+
 /* 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..c15d2c5b2b0 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_has_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_uses_vtable (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..e30db9b8ea9 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_has_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.  */
@@ -12700,6 +12709,17 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p)
 		 decl, "progmem", "absdata");
 	}
     }
+
+#ifdef HAVE_AS_AVR_GNU_ATTRIBUTE_4
+  if (!avr_has_vtable_p
+      && decl
+      && DECL_P (decl))
+    {
+      const char *id = IDENTIFIER_POINTER (DECL_NAME (decl));
+      avr_has_vtable_p |= startswith (id, "_ZTV"); // vtable
+      avr_has_vtable_p |= startswith (id, "_ZTT"); // vtable table
+    }
+#endif // HAVE_AS_AVR_GNU_ATTRIBUTE_4
 }
 
 
@@ -12805,6 +12825,13 @@ 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_4
+  fprintf (asm_out_file, ".gnu_attribute %d,%d\n", Tag_GNU_AVR_VTABLE_AS,
+	   avr_has_vtable_p
+	   ? Val_GNU_AVR_VTABLE_RAM
+	   : Val_GNU_AVR_VTABLE_NONE);
+#endif // HAVE_AS_AVR_GNU_ATTRIBUTE_4
 }
 
 
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..44fc3b90250 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 4" >&5
+$as_echo_n "checking assembler for .gnu_attribute 4... " >&6; }
+if ${gcc_cv_as_avr_gnu_attribute_4+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_avr_gnu_attribute_4=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_4=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_4" >&5
+$as_echo "$gcc_cv_as_avr_gnu_attribute_4" >&6; }
+if test $gcc_cv_as_avr_gnu_attribute_4 = yes; then
+
+$as_echo "#define HAVE_AS_AVR_GNU_ATTRIBUTE_4 1" >>confdefs.h
+
 fi
 
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 1773706e70a..3904518785e 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 4], gcc_cv_as_avr_gnu_attribute_4,
+      [], [.gnu_attribute 4,1],,
+      [AC_DEFINE(HAVE_AS_AVR_GNU_ATTRIBUTE_4, 1,
+		[Define if your avr assembler supports .gnu_attribute 4.])])
+
     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