This patch outputs .gnu_attribute tags for the bit sizes
of long double (12 = Tag_GNU_AVR_BITS_LONG_DOUBLE) resp.
double (8 = Tag_GNU_AVR_BITS_DOUBLE).
The recently introduced gimple mini-pass avr_pass_has
scans the code for the presence of [long] double, and
avr_file_end performs similar scans on the varpool.
There are cases where libgcc shares multilibs when they
don't depend on -m[long-]double=X, so that just emitting
.gnu_attribute *.X according to -m[long-]double=X is too strict.
The patch uses the .gnu_attribute's as introduced in
https://sourceware.org/PR34557 (Binutils 2.48).
The Binutils patch is currently under review:
https://sourceware.org/pipermail/binutils/2026-August/150970.html
This GCC patch is atop of
https://gcc.gnu.org/pipermail/gcc-patches/2026-August/728536.html
which introduces avr_pass_has and does the configure work to
determine HAVE_AS_AVR_GNU_ATTRIBUTE.
The patch passes without new regressions.
Ok for trunk?
Johann
--
PR target/127032
gcc/
* config/avr/avr.md (Tag_GNU_AVR_BITS_LONG_DOUBLE)
(Tag_GNU_AVR_BITS_DOUBLE): New define_constants.
* config/avr/avr.cc (avr_uses_long_double_p)
(avr_uses_double_p): New static variables.
(avr_find_double): New function.
(avr_file_end) [HAVE_AS_AVR_GNU_ATTRIBUTE]: Run avr_find_double
on each varpool node. Output .gnu_attribute according to
avr_uses_long_double_p and avr_uses_double_p.
* config/avr/avr-passes.cc (gimple-walk.h): Include.
(avr_pass_has) <op_callback>: New static method.
<scan_bb>: Use it in walk_gimple_op.
<execute>: Set up walk_stmt_info and pass it to scan_bb.
* config/avr/avr-passes.def (avr_pass_has): Adjust comment.
* config/avr/avr-protos.h (avr_find_double): New proto.diff --git a/gcc/config/avr/avr-passes.cc b/gcc/config/avr/avr-passes.cc
index 13bc1b125da..769520f3ec9 100644
--- a/gcc/config/avr/avr-passes.cc
+++ b/gcc/config/avr/avr-passes.cc
@@ -32,6 +32,7 @@
#include "tree.h"
#include "gimple.h"
#include "gimple-iterator.h"
+#include "gimple-walk.h"
#include "diagnostic-core.h"
#include "cfghooks.h"
#include "cfganal.h"
@@ -5560,7 +5561,11 @@ public:
//////////////////////////////////////////////////////////////////////////////
-// Determine whether there are vtable calls, and set `avr_uses_vtable_p'.
+// Determine whether the target code uses some features:
+// - avr_uses_vtable_p: Are there vtable calls?
+// - avr_uses_double_p: Is double being used?
+// - avr_uses_long_double_p: Is long double being used?
+// In any case, avr_file_end handles objects in static storage.
static const pass_data avr_pass_data_has =
{
@@ -5584,7 +5589,24 @@ public:
this->name = name;
}
- void scan_bb (basic_block bb)
+ static tree op_callback (tree *t, int *walk_subtrees, void *data)
+ {
+ // Almost all of a function's data is piped through SSA_NAMEs, so that
+ // for the purpose of avr_uses_[long_]double_p it is sufficient to look
+ // at these and compile-time constants.
+ if (SSA_VAR_P (*t)
+ || TREE_CODE (*t) == REAL_CST
+ || TREE_CODE (*t) == COMPLEX_CST)
+ {
+ walk_stmt_info *wi = (walk_stmt_info *) data;
+ avr_find_double (TREE_TYPE (*t), wi->pset);
+ }
+
+ *walk_subtrees = 1;
+ return NULL_TREE;
+ }
+
+ void scan_bb (basic_block bb, walk_stmt_info &wi)
{
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -5596,6 +5618,8 @@ public:
&& (fncall = gimple_call_fn (stmt))
&& TREE_CODE (fncall) == OBJ_TYPE_REF)
avr_uses_vtable_p = true;
+
+ walk_gimple_op (stmt, op_callback, &wi);
}
}
@@ -5608,9 +5632,13 @@ public:
unsigned int execute (function *func) final override
{
+ hash_set<tree> hset;
+ walk_stmt_info wi;
+ wi.pset = &hset;
+
basic_block bb;
FOR_ALL_BB_FN (bb, func)
- scan_bb (bb);
+ scan_bb (bb, wi);
return 0;
}
diff --git a/gcc/config/avr/avr-passes.def b/gcc/config/avr/avr-passes.def
index d50285c3f89..95d82f8f0a5 100644
--- a/gcc/config/avr/avr-passes.def
+++ b/gcc/config/avr/avr-passes.def
@@ -17,8 +17,11 @@
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,
+/* A gimple pass that sets
+ `avr_uses_vtable_p', i.e. whether the target code is using vtables.
+ `avr_uses_double_p', i.e. whether the target code is using double.
+ `avr_uses_long_double_p', i.e. whether the target code is using long double.
+ 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);
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index c91c6efc29b..8a971c0813e 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -38,6 +38,7 @@ extern void avr_declare_function_name (FILE *, const char *, tree);
extern void asm_output_external (FILE *file, tree decl, char *name);
extern int avr_progmem_p (tree decl, tree attributes);
extern bool avr_addr_space_supported_p (addr_space_t, location_t loc = UNKNOWN_LOCATION);
+extern void avr_find_double (tree typ, hash_set<tree> *pset);
#ifdef RTX_CODE /* inside TREE_CODE */
extern void avr_init_cumulative_args (CUMULATIVE_ARGS*, tree, rtx, tree);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index dfc4d4526d8..cad3ff3bfea 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -256,7 +256,16 @@ bool avr_need_clear_bss_p = false;
bool avr_need_copy_data_p = false;
bool avr_has_rodata_p = false;
+/* Features used by the target code that are affected by the chosen ABI.
+ Output as .gnu_attribute in order to guarantee that only compatible
+ objects files are linked together.
+ Notice that for the latter two cases, there are loop holes like
+ sizeof(double). Just mapping -mdouble=X to a .gnu_attribute *,X
+ would be too strict since libgcc may reuse a multilib provided it
+ doesn't depend on -m[long-]double. */
bool avr_uses_vtable_p = false;
+static bool avr_uses_double_p = false;
+static bool avr_uses_long_double_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
@@ -12795,6 +12804,41 @@ avr_file_start (void)
}
+/* Scan TYP for the occurence of [long] double, and set `avr_uses_double_p'
+ and `avr_uses_long_double_p' accordingly. This is used by avr_file_end()
+ and also by the avr_pass_has gimple pass.
+ walk_tree() doesn't quite fit the puropse, so cook our own. */
+
+void
+avr_find_double (tree typ, hash_set<tree> *pset)
+{
+ if (typ == NULL_TREE
+ || typ == error_mark_node
+ || pset->add (typ))
+ return;
+
+ if (POINTER_TYPE_P (typ))
+ return avr_find_double (TREE_TYPE (typ), pset);
+
+ if (TREE_CODE (typ) == ARRAY_TYPE)
+ return avr_find_double (strip_array_types (typ), pset);
+
+ if (RECORD_OR_UNION_TYPE_P (typ))
+ {
+ for (tree fld = TYPE_FIELDS (typ); fld; fld = DECL_CHAIN (fld))
+ if (TREE_CODE (fld) == FIELD_DECL)
+ avr_find_double (TREE_TYPE (fld), pset);
+ return;
+ }
+
+ if (VECTOR_FLOAT_TYPE_P (typ) || COMPLEX_FLOAT_TYPE_P (typ))
+ typ = TREE_TYPE (typ);
+
+ avr_uses_double_p |= TYPE_MAIN_VARIANT (typ) == double_type_node;
+ avr_uses_long_double_p |= TYPE_MAIN_VARIANT (typ) == long_double_type_node;
+}
+
+
/* Implement `TARGET_ASM_FILE_END'. */
/* Outputs to the stdio stream FILE some
appropriate text to go at the end of an assembler file. */
@@ -12816,9 +12860,9 @@ avr_file_end (void)
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. */
+ /* Output .gnu_attribute to tag object files with aspects of the ABI. */
+ hash_set<tree> hset;
varpool_node *vnode;
FOR_EACH_VARIABLE (vnode)
@@ -12826,11 +12870,26 @@ avr_file_end (void)
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
+
+ avr_find_double (TREE_TYPE (vnode->decl), &hset);
}
+ // .gnu_attribute 4: The named address space for C++ virtual tables.
if (avr_uses_vtable_p)
fprintf (asm_out_file, ".gnu_attribute %d,%d\n",
Tag_GNU_AVR_VTABLE_AS, Val_GNU_AVR_VTABLE_RAM);
+
+ // .gnu_attribute 8: The bitsize of double, or 0 if not used.
+ if (avr_uses_double_p)
+ fprintf (asm_out_file, ".gnu_attribute %d,%d\n",
+ Tag_GNU_AVR_BITS_DOUBLE,
+ (int) (CHAR_BIT * int_size_in_bytes (double_type_node)));
+
+ // .gnu_attribute 12: The bitsize of long double, or 0 if not used.
+ if (avr_uses_long_double_p)
+ fprintf (asm_out_file, ".gnu_attribute %d,%d\n",
+ Tag_GNU_AVR_BITS_LONG_DOUBLE,
+ (int) (CHAR_BIT * int_size_in_bytes (long_double_type_node)));
#endif // HAVE_AS_AVR_GNU_ATTRIBUTE
}
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 26ae9e501c9..405055bb077 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -113,7 +113,7 @@ (define_constants
(GASISR_Done 0)
])
-;; Vtables address space are hard-coded in Binutils include/elf/avr.h.
+;; Repeat values for .gnu_attribute from Binutils include/elf/avr.h.
(define_constants
[(Tag_GNU_AVR_VTABLE_AS 4)
(Val_GNU_AVR_VTABLE_NONE 0)
@@ -125,6 +125,9 @@ (define_constants
(Val_GNU_AVR_VTABLE_FLASH4 6)
(Val_GNU_AVR_VTABLE_FLASH5 7)
(Val_GNU_AVR_VTABLE_FLASHX 8)
+
+ (Tag_GNU_AVR_BITS_DOUBLE 8)
+ (Tag_GNU_AVR_BITS_LONG_DOUBLE 12)
])
(include "predicates.md")