diff options
author | Richard Earnshaw <rearnsha@arm.com> | 2021-07-29 11:00:31 +0100 |
---|---|---|
committer | Richard Earnshaw <rearnsha@arm.com> | 2021-08-05 12:51:14 +0100 |
commit | c1cdabe3aab817d95a8db00a8b5e9f6bcdea936f (patch) | |
tree | 2e3b5461af89619f316ecefa9d46564aa7514d33 /gcc/config/arm | |
parent | 6a37d0331c25f23628d4308e5a75624005c223b2 (diff) | |
download | gcc-c1cdabe3aab817d95a8db00a8b5e9f6bcdea936f.zip gcc-c1cdabe3aab817d95a8db00a8b5e9f6bcdea936f.tar.gz gcc-c1cdabe3aab817d95a8db00a8b5e9f6bcdea936f.tar.bz2 |
arm: reorder assembler architecture directives [PR101723]
A change to the way gas interprets the .fpu directive in binutils-2.34
means that issuing .fpu will clear any features set by .arch_extension
that apply to the floating point or simd units. This unfortunately
causes problems for more recent versions of the architecture because
we currently emit .arch, .arch_extension and .fpu directives at
different times and try to suppress redundant changes.
This change addresses this by firstly unifying all the places where we
emit these directives to a single block of code and secondly
(re)emitting all the directives if any changes have been made to the
target options. Whilst this is slightly more than the strict minimum
it should be enough to catch all cases where a change could have
happened. The new code also emits the directives in the order: .arch,
.fpu, .arch_extension. This ensures that the additional architectural
extensions are not removed by a later .fpu directive.
Whilst writing this patch I also noticed that in the corner case where
the last function to be compiled had a non-standard set of
architecture flags, the assembler would add an incorrect set of
derived attributes for the file as a whole. Instead of reflecting the
command-line options it would reflect the flags from the last file in
the function. To address this I've also added a call to re-emit the
flags from the asm_file_end callback so the assembler will be in the
correct state when it finishes processing the intput.
There's some slight churn to the testsuite as a consequence of this,
because previously we had a hack to suppress emitting a .fpu directive
for one specific case, but with the new order this is no-longer
necessary.
gcc/ChangeLog:
PR target/101723
* config/arm/arm-cpus.in (generic-armv7-a): Add quirk to suppress
writing .cpu directive in asm output.
* config/arm/arm.c (arm_identify_fpu_from_isa): New variable.
(arm_last_printed_arch_string): Delete.
(arm_last-printed_fpu_string): Delete.
(arm_configure_build_target): If use of floating-point/SIMD is
disabled, remove all fp/simd related features from the target ISA.
(last_arm_targ_options): New variable.
(arm_print_asm_arch_directives): Add new parameters. Change order
of emitted directives and handle all cases here.
(arm_file_start): Always call arm_print_asm_arch_directives, move
all generation of .arch/.arch_extension here.
(arm_file_end): Call arm_print_asm_arch.
(arm_declare_function_name): Call arm_print_asm_arch_directives
instead of printing .arch/.fpu directives directly.
gcc/testsuite/ChangeLog:
PR target/101723
* gcc.target/arm/cortex-m55-nofp-flag-hard.c: Update expected output.
* gcc.target/arm/cortex-m55-nofp-flag-softfp.c: Likewise.
* gcc.target/arm/cortex-m55-nofp-nomve-flag-softfp.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_fpu1.c: Convert to dg-do assemble.
Add a non-no-op function body.
* gcc.target/arm/mve/intrinsics/mve_fpu2.c: Likewise.
* gcc.target/arm/pr98636.c (dg-options): Add -mfloat-abi=softfp.
* gcc.target/arm/attr-neon.c: Tighten scan-assembler tests.
* gcc.target/arm/attr-neon2.c: Use -Ofast, convert test to use
check-function-bodies.
* gcc.target/arm/attr-neon3.c: Likewise.
* gcc.target/arm/pr69245.c: Tighten scan-assembler match, but allow
multiple instances.
* gcc.target/arm/pragma_fpu_attribute.c: Likewise.
* gcc.target/arm/pragma_fpu_attribute_2.c: Likewise.
Diffstat (limited to 'gcc/config/arm')
-rw-r--r-- | gcc/config/arm/arm-cpus.in | 1 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 186 |
2 files changed, 78 insertions, 109 deletions
diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in index ab4b6ac..249995a 100644 --- a/gcc/config/arm/arm-cpus.in +++ b/gcc/config/arm/arm-cpus.in @@ -1080,6 +1080,7 @@ begin cpu generic-armv7-a cname genericv7a tune flags LDSCHED architecture armv7-a+fp + isa quirk_no_asmcpu option mp add mp option sec add sec option vfpv3-d16 add VFPv3 FP_DBL diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 273202a..11dafc7 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -79,10 +79,6 @@ typedef struct minipool_node Mnode; typedef struct minipool_fixup Mfix; -/* The last .arch and .fpu assembly strings that we printed. */ -static std::string arm_last_printed_arch_string; -static std::string arm_last_printed_fpu_string; - void (*arm_lang_output_object_attributes_hook)(void); struct four_ints @@ -334,6 +330,7 @@ static rtx_insn *thumb1_md_asm_adjust (vec<rtx> &, vec<rtx> &, vec<machine_mode> &, vec<const char *> &, vec<rtx> &, HARD_REG_SET &, location_t); +static const char *arm_identify_fpu_from_isa (sbitmap); /* Table of machine attributes. */ static const struct attribute_spec arm_attribute_table[] = @@ -3411,6 +3408,11 @@ arm_configure_build_target (struct arm_build_target *target, bitmap_ior (target->isa, target->isa, fpu_bits); } + /* If we have the soft-float ABI, clear any feature bits relating to use of + floating-point operations. They'll just confuse things later on. */ + if (arm_float_abi == ARM_FLOAT_ABI_SOFT) + bitmap_and_compl (target->isa, target->isa, isa_all_fpbits); + /* There may be implied bits which we still need to enable. These are non-named features which are needed to complete other sets of features, but cannot be enabled from arm-cpus.in due to being shared between @@ -28096,20 +28098,65 @@ arm_print_tune_info (void) (int) current_tune->sched_autopref); } +/* The last set of target options used to emit .arch directives, etc. This + could be a function-local static if it were not required to expose it as a + root to the garbage collector. */ +static GTY(()) cl_target_option *last_asm_targ_options = NULL; + /* Print .arch and .arch_extension directives corresponding to the current architecture configuration. */ static void -arm_print_asm_arch_directives () +arm_print_asm_arch_directives (FILE *stream, cl_target_option *targ_options) { + arm_build_target build_target; + /* If the target options haven't changed since the last time we were called + there is nothing to do. This should be sufficient to suppress the + majority of redundant work. */ + if (last_asm_targ_options == targ_options) + return; + + last_asm_targ_options = targ_options; + + build_target.isa = sbitmap_alloc (isa_num_bits); + arm_configure_build_target (&build_target, targ_options, false); + + if (build_target.core_name + && !bitmap_bit_p (build_target.isa, isa_bit_quirk_no_asmcpu)) + { + const char* truncated_name + = arm_rewrite_selected_cpu (build_target.core_name); + asm_fprintf (stream, "\t.cpu %s\n", truncated_name); + } + const arch_option *arch = arm_parse_arch_option_name (all_architectures, "-march", - arm_active_target.arch_name); + build_target.arch_name); auto_sbitmap opt_bits (isa_num_bits); gcc_assert (arch); - asm_fprintf (asm_out_file, "\t.arch %s\n", arm_active_target.arch_name); - arm_last_printed_arch_string = arm_active_target.arch_name; + if (strcmp (build_target.arch_name, "armv7ve") == 0) + { + /* Keep backward compatability for assemblers which don't support + armv7ve. Fortunately, none of the following extensions are reset + by a .fpu directive. */ + asm_fprintf (stream, "\t.arch armv7-a\n"); + asm_fprintf (stream, "\t.arch_extension virt\n"); + asm_fprintf (stream, "\t.arch_extension idiv\n"); + asm_fprintf (stream, "\t.arch_extension sec\n"); + asm_fprintf (stream, "\t.arch_extension mp\n"); + } + else + asm_fprintf (stream, "\t.arch %s\n", build_target.arch_name); + + /* The .fpu directive will reset any architecture extensions from the + assembler that relate to the fp/vector extensions. So put this out before + any .arch_extension directives. */ + const char *fpu_name = (TARGET_SOFT_FLOAT + ? "softvfp" + : arm_identify_fpu_from_isa (build_target.isa)); + asm_fprintf (stream, "\t.fpu %s\n", fpu_name); + if (!arch->common.extensions) return; @@ -28135,13 +28182,12 @@ arm_print_asm_arch_directives () && !TARGET_HAVE_MVE_FLOAT)) continue; - /* If every feature bit of this option is set in the target - ISA specification, print out the option name. However, - don't print anything if all the bits are part of the - FPU specification. */ - if (bitmap_subset_p (opt_bits, arm_active_target.isa) + /* If every feature bit of this option is set in the target ISA + specification, print out the option name. However, don't print + anything if all the bits are part of the FPU specification. */ + if (bitmap_subset_p (opt_bits, build_target.isa) && !bitmap_subset_p (opt_bits, isa_all_fpubits_internal)) - asm_fprintf (asm_out_file, "\t.arch_extension %s\n", opt->name); + asm_fprintf (stream, "\t.arch_extension %s\n", opt->name); } } } @@ -28151,46 +28197,23 @@ arm_file_start (void) { int val; + arm_print_asm_arch_directives + (asm_out_file, TREE_TARGET_OPTION (target_option_default_node)); + if (TARGET_BPABI) { - /* We don't have a specified CPU. Use the architecture to - generate the tags. - - Note: it might be better to do this unconditionally, then the - assembler would not need to know about all new CPU names as - they are added. */ - if (!arm_active_target.core_name) - { - /* armv7ve doesn't support any extensions. */ - if (strcmp (arm_active_target.arch_name, "armv7ve") == 0) - { - /* Keep backward compatability for assemblers - which don't support armv7ve. */ - asm_fprintf (asm_out_file, "\t.arch armv7-a\n"); - asm_fprintf (asm_out_file, "\t.arch_extension virt\n"); - asm_fprintf (asm_out_file, "\t.arch_extension idiv\n"); - asm_fprintf (asm_out_file, "\t.arch_extension sec\n"); - asm_fprintf (asm_out_file, "\t.arch_extension mp\n"); - arm_last_printed_arch_string = "armv7ve"; - } - else - arm_print_asm_arch_directives (); - } - else if (startswith (arm_active_target.core_name, "generic")) - { - asm_fprintf (asm_out_file, "\t.arch %s\n", - arm_active_target.core_name + 8); - arm_last_printed_arch_string = arm_active_target.core_name + 8; - } - else + /* If we have a named cpu, but we the assembler does not support that + name via .cpu, put out a cpu name attribute; but don't do this if the + name starts with the fictitious prefix, 'generic'. */ + if (arm_active_target.core_name + && bitmap_bit_p (arm_active_target.isa, isa_bit_quirk_no_asmcpu) + && !startswith (arm_active_target.core_name, "generic")) { const char* truncated_name = arm_rewrite_selected_cpu (arm_active_target.core_name); if (bitmap_bit_p (arm_active_target.isa, isa_bit_quirk_no_asmcpu)) asm_fprintf (asm_out_file, "\t.eabi_attribute 5, \"%s\"\n", truncated_name); - else - asm_fprintf (asm_out_file, "\t.cpu %s\n", truncated_name); } if (print_tune_info) @@ -28255,6 +28278,13 @@ arm_file_end (void) { int regno; + /* Just in case the last function output in the assembler had non-default + architecture directives, we force the assembler state back to the default + set, so that any 'calculated' build attributes are based on the default + options rather than the special options for that function. */ + arm_print_asm_arch_directives + (asm_out_file, TREE_TARGET_OPTION (target_option_default_node)); + if (NEED_INDICATE_EXEC_STACK) /* Add .note.GNU-stack. */ file_end_indicate_exec_stack (); @@ -33265,58 +33295,7 @@ arm_declare_function_name (FILE *stream, const char *name, tree decl) targ_options = TREE_TARGET_OPTION (target_option_current_node); gcc_assert (targ_options); - /* Only update the assembler .arch string if it is distinct from the last - such string we printed. arch_to_print is set conditionally in case - targ_options->x_arm_arch_string is NULL which can be the case - when cc1 is invoked directly without passing -march option. */ - std::string arch_to_print; - if (targ_options->x_arm_arch_string) - arch_to_print = targ_options->x_arm_arch_string; - - if (arch_to_print != arm_last_printed_arch_string) - { - std::string arch_name - = arch_to_print.substr (0, arch_to_print.find ("+")); - asm_fprintf (asm_out_file, "\t.arch %s\n", arch_name.c_str ()); - const arch_option *arch - = arm_parse_arch_option_name (all_architectures, "-march", - targ_options->x_arm_arch_string); - auto_sbitmap opt_bits (isa_num_bits); - - gcc_assert (arch); - if (arch->common.extensions) - { - for (const struct cpu_arch_extension *opt = arch->common.extensions; - opt->name != NULL; - opt++) - { - if (!opt->remove) - { - arm_initialize_isa (opt_bits, opt->isa_bits); - /* For the cases "-march=armv8.1-m.main+mve -mfloat-abi=soft" - and "-march=armv8.1-m.main+mve.fp -mfloat-abi=soft" MVE and - MVE with floating point instructions is disabled. So the - following check restricts the printing of ".arch_extension - mve" and ".arch_extension fp" (for mve.fp) in the assembly - file. MVE needs this special behaviour because the - feature bit "mve" and "mve_float" are not part of - "fpu bits", so they are not cleared when -mfloat-abi=soft - (i.e nofp) but the marco TARGET_HAVE_MVE and - TARGET_HAVE_MVE_FLOAT are disabled. */ - if ((bitmap_bit_p (opt_bits, isa_bit_mve) && !TARGET_HAVE_MVE) - || (bitmap_bit_p (opt_bits, isa_bit_mve_float) - && !TARGET_HAVE_MVE_FLOAT)) - continue; - if (bitmap_subset_p (opt_bits, arm_active_target.isa) - && !bitmap_subset_p (opt_bits, isa_all_fpubits_internal)) - asm_fprintf (asm_out_file, "\t.arch_extension %s\n", - opt->name); - } - } - } - - arm_last_printed_arch_string = arch_to_print; - } + arm_print_asm_arch_directives (stream, targ_options); fprintf (stream, "\t.syntax unified\n"); @@ -33334,17 +33313,6 @@ arm_declare_function_name (FILE *stream, const char *name, tree decl) else fprintf (stream, "\t.arm\n"); - std::string fpu_to_print - = TARGET_SOFT_FLOAT - ? "softvfp" : arm_identify_fpu_from_isa (arm_active_target.isa); - - if (!(!strcmp (fpu_to_print.c_str (), "softvfp") && TARGET_VFP_BASE) - && (fpu_to_print != arm_last_printed_arch_string)) - { - asm_fprintf (asm_out_file, "\t.fpu %s\n", fpu_to_print.c_str ()); - arm_last_printed_fpu_string = fpu_to_print; - } - if (TARGET_POKE_FUNCTION_NAME) arm_poke_function_name (stream, (const char *) name); } |