[Rust,front-end,v1,3/4] Add Rust target hooks to ARM

Message ID 20220727134040.843750-4-philip.herron@embecosm.com
State New, archived
Headers
Series [Rust,front-end,v1,1/4] Add skeleton Rust front-end folder |

Commit Message

Li, Pan2 via Gcc-patches July 27, 2022, 1:40 p.m. UTC
  From: Philip Herron <philip.herron@embecosm.com>

This adds the nessecary target hooks for the arm target.

gcc/ChangeLog:

        * config.gcc: add rust_target_objs for arm

gcc/config/arm/ChangeLog:

	* arm-protos.h: define arm_rust_target_cpu_info
        * arm-rust.cc: new file to generate info
	* arm.h: define TARGET_RUST_CPU_INFO
	* bpabi.h: define TARGET_RUST_OS_INFO
	* freebsd.h: likewise
	* linux-eabi.h: likewise
	* linux-elf.h: likewise
	* netbsd-eabi.h: likewise
	* netbsd-elf.h: likewise
	* rtems.h: likewise
	* symbian.h: likewise
	* t-arm: compile arm-rust.cc
	* uclinux-eabi.h: define TARGET_RUST_OS_INFO
	* uclinux-elf.h: likewise
	* vxworks.h: likewise

Co-authored-by: SimplyTheOther <simplytheother@gmail.com>
---
 gcc/config.gcc                |   1 +
 gcc/config/arm/arm-protos.h   |   3 +
 gcc/config/arm/arm-rust.cc    | 304 ++++++++++++++++++++++++++++++++++
 gcc/config/arm/arm.h          |   3 +
 gcc/config/arm/bpabi.h        |  11 ++
 gcc/config/arm/freebsd.h      |   9 +
 gcc/config/arm/linux-eabi.h   |   8 +
 gcc/config/arm/linux-elf.h    |   5 +
 gcc/config/arm/netbsd-eabi.h  |  10 ++
 gcc/config/arm/netbsd-elf.h   |   8 +
 gcc/config/arm/rtems.h        |  14 ++
 gcc/config/arm/symbian.h      |  15 ++
 gcc/config/arm/t-arm          |   4 +
 gcc/config/arm/uclinux-eabi.h |  13 ++
 gcc/config/arm/uclinux-elf.h  |  12 ++
 gcc/config/arm/vxworks.h      |  14 ++
 16 files changed, 434 insertions(+)
 create mode 100644 gcc/config/arm/arm-rust.cc
  

Comments

Richard Earnshaw July 27, 2022, 2:13 p.m. UTC | #1
On 27/07/2022 14:40, herron.philip--- via Gcc-patches wrote:
> From: Philip Herron <philip.herron@embecosm.com>
> 
> This adds the nessecary target hooks for the arm target.
> 
> gcc/ChangeLog:
> 
>          * config.gcc: add rust_target_objs for arm
> 
> gcc/config/arm/ChangeLog:
> 
> 	* arm-protos.h: define arm_rust_target_cpu_info
>          * arm-rust.cc: new file to generate info
> 	* arm.h: define TARGET_RUST_CPU_INFO
> 	* bpabi.h: define TARGET_RUST_OS_INFO
> 	* freebsd.h: likewise
> 	* linux-eabi.h: likewise
> 	* linux-elf.h: likewise
> 	* netbsd-eabi.h: likewise
> 	* netbsd-elf.h: likewise
> 	* rtems.h: likewise
> 	* symbian.h: likewise
> 	* t-arm: compile arm-rust.cc
> 	* uclinux-eabi.h: define TARGET_RUST_OS_INFO
> 	* uclinux-elf.h: likewise
> 	* vxworks.h: likewise
> 
> Co-authored-by: SimplyTheOther <simplytheother@gmail.com>
> ---
>   gcc/config.gcc                |   1 +
>   gcc/config/arm/arm-protos.h   |   3 +
>   gcc/config/arm/arm-rust.cc    | 304 ++++++++++++++++++++++++++++++++++
>   gcc/config/arm/arm.h          |   3 +
>   gcc/config/arm/bpabi.h        |  11 ++
>   gcc/config/arm/freebsd.h      |   9 +
>   gcc/config/arm/linux-eabi.h   |   8 +
>   gcc/config/arm/linux-elf.h    |   5 +
>   gcc/config/arm/netbsd-eabi.h  |  10 ++
>   gcc/config/arm/netbsd-elf.h   |   8 +
>   gcc/config/arm/rtems.h        |  14 ++
>   gcc/config/arm/symbian.h      |  15 ++
>   gcc/config/arm/t-arm          |   4 +
>   gcc/config/arm/uclinux-eabi.h |  13 ++
>   gcc/config/arm/uclinux-elf.h  |  12 ++
>   gcc/config/arm/vxworks.h      |  14 ++
>   16 files changed, 434 insertions(+)
>   create mode 100644 gcc/config/arm/arm-rust.cc
> 
> diff --git a/gcc/config.gcc b/gcc/config.gcc
> index cdd4fb4392a..9d686019b28 100644
> --- a/gcc/config.gcc
> +++ b/gcc/config.gcc
> @@ -368,6 +368,7 @@ arm*-*-*)
>   	c_target_objs="arm-c.o"
>   	cxx_target_objs="arm-c.o"
>   	d_target_objs="arm-d.o"
> +        rust_target_objs="arm-rust.o"
>   	extra_options="${extra_options} arm/arm-tables.opt"
>   	target_gtfiles="\$(srcdir)/config/arm/arm-builtins.cc \$(srcdir)/config/arm/arm-mve-builtins.h \$(srcdir)/config/arm/arm-mve-builtins.cc"
>   	;;
> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
> index f8aabbdae37..9513f96fdbc 100644
> --- a/gcc/config/arm/arm-protos.h
> +++ b/gcc/config/arm/arm-protos.h
> @@ -406,6 +406,9 @@ extern void arm_cpu_cpp_builtins (struct cpp_reader *);
>   extern void arm_d_target_versions (void);
>   extern void arm_d_register_target_info (void);
>   
> +/* Defined in arm-rust.c  */
> +extern void arm_rust_target_cpu_info (void);
> +
>   extern bool arm_is_constant_pool_ref (rtx);
>   
>   /* The bits in this mask specify which instruction scheduling options should
> diff --git a/gcc/config/arm/arm-rust.cc b/gcc/config/arm/arm-rust.cc
> new file mode 100644
> index 00000000000..7c83e3fa3a6
> --- /dev/null
> +++ b/gcc/config/arm/arm-rust.cc
> @@ -0,0 +1,304 @@
> +/* Subroutines for the Rust front end on the ARM architecture.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +
> +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/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "tm_p.h"
> +#include "rust/rust-target.h"
> +#include "rust/rust-target-def.h"
> +
> +/* Implement TARGET_RUST_CPU_INFO for ARM targets.  */
> +
> +void arm_rust_target_cpu_info(void) {
> +    rust_add_target_info("target_arch", "arm");
> +
> +    /* TODO: further research support for CLREX, acquire-release (lda/ldaex), slow-fp-brcc (slow FP
> +     * compare and branch), perfmon, trustzone, fpao, fuse-aes, fuse-literals, read-tp-hard, zcz,
> +     * prof-unpr, slow-vgetlni32, slow-vdup32, prefer-vmovsr, prefer-ishst, muxed-units, slow-odd-reg,
> +     * slow-load-D-subreg, wide-stride-vfp, dont-widen-vmovs, splat-vfp-neon, expand-fp-mlx,
> +     * vmlx-hazards, neon-fpmovs, neonfp (as in using neon for scalar fp), vldn-align,
> +     * nonpipelined-vfp, slowfpvmlx, slowfpvfmx, vmlx-forwarding, 32bit (prefer 32-bit Thumb),
> +     * loop-align, mve1beat, mve2beat, mve4beat, avoid-partial-cpsr, cheap-predictable-cpsr,
> +     * avoid-movs-shop, ret-addr-stack, no-branch-predictor, virtualization, nacl-trap, execute-only,
> +     * reserve-r9, no-movt, no-neg-immediates, use-misched, disable-postra-scheduler, lob (Low
> +     * Overhead Branch), noarm, cde - can't find them. */
> +    /* TODO: figure out if gcc has an equivalent to "fpregs" (floating-point registers even if only
> +     * used for integer - shared between VFP and MVE).  */

This doesn't look to be the right approach to me.  These feature bits 
are very definitely /internal/ to the compiler and should not be exposed 
directly to users.  There's no guarantee of stability and no direct 
guarantee that they map onto something usable in a target processor.

If you want something that's going to be reasonably stable, look at the 
architecture extension options, noting that some options are context 
dependent (so, for example, +fp means different things depending on the 
base architecture its applied to).

Your other option would be to look at the official architecture feature 
names (as defined in the various Arm ARM documents, but the GCC options 
try to follow those names quite closely for more modern revisions of the 
architecture.

Finally, this code will need to be reformatted in GNU style at some point.

> +    if (TARGET_VFPD32)
> +        rust_add_target_info("target_feature", "d32");
> +    bool hasFeatureVFP2 = bitmap_bit_p(arm_active_target.isa, isa_bit_vfpv2) && TARGET_VFP_DOUBLE;
> +    if (hasFeatureVFP2) {
> +        rust_add_target_info("target_feature", "vfp2");
> +
> +        // also added implied features that aren't separately supported in gcc
> +        rust_add_target_info("target_feature", "vfp2sp");
> +    }
> +    // minimal VFPv3 support - support for instruction set, not necessarily full
> +    bool minVFP3 = TARGET_VFP3 && bitmap_bit_p(arm_active_target.isa, isa_bit_vfpv2);
> +    if (minVFP3) {
> +        rust_add_target_info("target_feature", "vfp3d16sp");
> +
> +        if (TARGET_VFPD32)
> +            rust_add_target_info("target_feature", "vfp3sp");
> +
> +        if (TARGET_VFP_DOUBLE) {
> +            rust_add_target_info("target_feature", "vfp3d16");
> +
> +            if (TARGET_VFPD32) {
> +                rust_add_target_info("target_feature", "vfp3");
> +
> +                if (bitmap_bit_p(arm_active_target.isa, isa_bit_neon))
> +                    rust_add_target_info("target_feature", "neon");
> +            }
> +        }
> +    }
> +    bool hasFeatureVFP3 = minVFP3 && TARGET_VFP_DOUBLE && TARGET_VFPD32;
> +    bool hasFeatureFP16 = bitmap_bit_p(arm_active_target.isa, isa_bit_fp16conv);
> +    if (hasFeatureFP16)
> +        rust_add_target_info("target_info", "fp16");
> +    bool minVFP4 = minVFP3 && bitmap_bit_p(arm_active_target.isa, isa_bit_vfpv4) && hasFeatureFP16;
> +    if (minVFP4) {
> +        rust_add_target_info("target_feature", "vfp4d16sp");
> +
> +        if (TARGET_VFPD32)
> +            rust_add_target_info("target_feature", "vfp4sp");
> +
> +        if (TARGET_VFP_DOUBLE) {
> +            rust_add_target_info("target_feature", "vfp4d16");
> +
> +            if (TARGET_VFPD32) {
> +                rust_add_target_info("target_feature", "vfp4");
> +            }
> +        }
> +    }
> +    // NOTE: supposedly "fp-armv8" features in llvm are the same as "fpv5", so creating them based on
> +    // that
> +    bool minFP_ARMv8 = minVFP4 && TARGET_VFP5;
> +    if (minFP_ARMv8) {
> +        rust_add_target_info("target_feature", "fp-armv8d16sp");
> +
> +        if (TARGET_VFPD32)
> +            rust_add_target_info("target_feature", "fp-armv8sp");
> +
> +        if (TARGET_VFP_DOUBLE) {
> +            rust_add_target_info("target_feature", "fp-armv8d16");
> +
> +            if (TARGET_VFPD32) {
> +                rust_add_target_info("target_feature", "fp-armv8");
> +            }
> +        }
> +
> +        if (bitmap_bit_p(arm_active_target.isa, isa_bit_fp16)) {
> +            rust_add_target_info("target_feature", "fullfp16");
> +
> +            if (bitmap_bit_p(arm_active_target.isa, isa_bit_fp16fml))
> +                rust_add_target_info("target_feature", "fp16fml");
> +        }
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_tdiv))
> +        rust_add_target_info("target_feature", "hwdiv");
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_adiv))
> +        rust_add_target_info("target_feature", "hwdiv-arm");
> +    // TODO: I'm not sure if there's an exact correlation here (data barrier), so maybe research
> +    // There's also the question of whether this also means "full data barrier" ("fdb" in llvm)
> +    if (TARGET_HAVE_MEMORY_BARRIER)
> +        rust_add_target_info("target_feature", "db");
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cmse))
> +        rust_add_target_info("target_feature", "8msecext");
> +    /* TODO: note that sha2 is an option for aarch64 in gcc but not for arm, so no feature here
> +     * possible. The same goes for aes. However, as llvm has them as prerequisites for crypto, they
> +     * are enabled with it. */
> +    if (TARGET_CRYPTO) {
> +        rust_add_target_info("target_feature", "crypto");
> +        rust_add_target_info("target_feature", "sha2");
> +        rust_add_target_info("target_feature", "aes");
> +    }
> +    if (TARGET_CRC32)
> +        rust_add_target_info("target_feature", "crc");
> +    if (TARGET_DOTPROD)
> +        rust_add_target_info("target_feature", "dotprod");
> +    // TODO: supposedly gcc supports RAS, but I couldn't find the option, so leaving out "ras" for now
> +    if (TARGET_DSP_MULTIPLY)
> +        rust_add_target_info("target_feature", "dsp");
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_mp))
> +        rust_add_target_info("target_feature", "mp");
> +    // TODO: figure out the exact strict-align feature, which I'm pretty sure GCC has
> +    // TODO: figure out how to access long call data (which is in GCC) for "long-calls"
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_sb))
> +        rust_add_target_info("target_feature", "sb");
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_bf16))
> +        rust_add_target_info("target_feature", "bf16");
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_i8mm))
> +        rust_add_target_info("target_feature", "i8mm");
> +    switch (TARGET_ARM_ARCH_PROFILE) {
> +        case 'A':
> +            rust_add_target_info("target_feature", "aclass");
> +            break;
> +        case 'R':
> +            rust_add_target_info("target_feature", "rclass");
> +            break;
> +        case 'M':
> +            rust_add_target_info("target_feature", "mclass");
> +            break;
> +        default:
> +            fprintf(stderr, "Screwed up profile selection in arm-rust.c - unknown profile '%c'",
> +              TARGET_ARM_ARCH_PROFILE);
> +            break;
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_thumb2))
> +        rust_add_target_info("target_feature", "thumb2");
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv4)
> +        && bitmap_bit_p(arm_active_target.isa, isa_bit_notm)
> +        && bitmap_bit_p(arm_active_target.isa, isa_bit_thumb)) {
> +        rust_add_target_info("target_feature", "v4t");
> +
> +        if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv5t)) {
> +            rust_add_target_info("target_feature", "v5t");
> +
> +            if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv5te)) {
> +                rust_add_target_info("target_feature", "v5te");
> +
> +                if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv6)
> +                    && bitmap_bit_p(arm_active_target.isa, isa_bit_be8)) {
> +                    rust_add_target_info("target_feature", "v6");
> +
> +                    // note: this definition of "ARMv6m" listed as "suspect" in arm-cpus.in
> +                    rust_add_target_info("target_feature", "v6m");
> +
> +                    bool hasV8BaselineOps = bitmap_bit_p(arm_active_target.isa, isa_bit_armv8)
> +                                            && bitmap_bit_p(arm_active_target.isa, isa_bit_cmse)
> +                                            && bitmap_bit_p(arm_active_target.isa, isa_bit_tdiv);
> +                    if (hasV8BaselineOps)
> +                        rust_add_target_info("target_feature", "v8m");
> +
> +                    bool hasV6kOps = bitmap_bit_p(arm_active_target.isa, isa_bit_armv6k);
> +                    if (hasV6kOps) {
> +                        rust_add_target_info("target_feature", "v6k");
> +                    }
> +
> +                    if (bitmap_bit_p(arm_active_target.isa, isa_bit_thumb2) && hasV8BaselineOps
> +                        && hasV6kOps) {
> +                        rust_add_target_info("target_feature", "v6t2");
> +
> +                        // note that arm-cpus.in refers to this (ARMv7) as suspect
> +                        if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv7)) {
> +                            rust_add_target_info("target_feature", "v7");
> +
> +                            rust_add_target_info("target_feature", "v8m.main");
> +
> +                            if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_1m_main))
> +                                rust_add_target_info("target_feature", "v8.1m.main");
> +
> +                            // dummy: can't find feature acquire-release, so dummy true variable
> +                            bool hasAcquireRelease = true;
> +                            if (hasAcquireRelease && bitmap_bit_p(arm_active_target.isa, isa_bit_adiv)
> +                                && bitmap_bit_p(arm_active_target.isa, isa_bit_lpae)
> +                                && bitmap_bit_p(arm_active_target.isa, isa_bit_mp)
> +                                && bitmap_bit_p(arm_active_target.isa, isa_bit_sec)) {
> +                                rust_add_target_info("target_feature", "v8");
> +
> +                                if (TARGET_CRC32
> +                                    && bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_1)) {
> +                                    rust_add_target_info("target_feature", "v8.1a");
> +
> +                                    if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_2)) {
> +                                        rust_add_target_info("target_feature", "v8.2a");
> +
> +                                        if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_3)) {
> +                                            rust_add_target_info("target_feature", "v8.3a");
> +
> +                                            if (bitmap_bit_p(
> +                                                  arm_active_target.isa, isa_bit_armv8_4)) {
> +                                                rust_add_target_info("target_feature", "v8.4a");
> +                                                // note: llvm, but not gcc, also wants dotprod for
> +                                                // v8.4
> +
> +                                                if (bitmap_bit_p(arm_active_target.isa, isa_bit_sb)
> +                                                    && bitmap_bit_p(
> +                                                      arm_active_target.isa, isa_bit_predres)
> +                                                    && bitmap_bit_p(
> +                                                      arm_active_target.isa, isa_bit_armv8_5)) {
> +                                                    rust_add_target_info("target_feature", "v8.5a");
> +
> +                                                    if (bitmap_bit_p(
> +                                                          arm_active_target.isa, isa_bit_armv8_6))
> +                                                        rust_add_target_info(
> +                                                          "target_feature", "v8.6a");
> +                                                }
> +                                            }
> +                                        }
> +                                    }
> +                                }
> +                            }
> +                        }
> +                    }
> +                }
> +            }
> +        }
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_mve)
> +        && bitmap_bit_p(arm_active_target.isa, isa_bit_vfp_base)
> +        && bitmap_bit_p(arm_active_target.isa, isa_bit_armv7em)) {
> +        rust_add_target_info("target_feature", "mve");
> +
> +        if (minFP_ARMv8 && bitmap_bit_p(arm_active_target.isa, isa_bit_fp16)
> +            && bitmap_bit_p(arm_active_target.isa, isa_bit_mve_float))
> +            rust_add_target_info("target_feature", "mve.fp");
> +    }
> +    // Note: no direct option for "cde" found, but it is implicitly activated via cdecpx, so do it
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp0)) {
> +        rust_add_target_info("target_feature", "cdecp0");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp1)) {
> +        rust_add_target_info("target_feature", "cdecp1");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp2)) {
> +        rust_add_target_info("target_feature", "cdecp2");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp3)) {
> +        rust_add_target_info("target_feature", "cdecp3");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp4)) {
> +        rust_add_target_info("target_feature", "cdecp4");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp5)) {
> +        rust_add_target_info("target_feature", "cdecp5");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp6)) {
> +        rust_add_target_info("target_feature", "cdecp6");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp7)) {
> +        rust_add_target_info("target_feature", "cdecp7");
> +        rust_add_target_info("target_feature", "cde");
> +    }
> +    if (TARGET_SOFT_FLOAT)
> +        rust_add_target_info("target_feature", "soft-float");
> +    // should be correct option (i.e. thumb mode rather than just thumb-aware) as TARGET_ARM is
> +    // inverse
> +    if (TARGET_THUMB)
> +        rust_add_target_info("target_feature", "thumb-mode");
> +    // TODO: consider doing the processors as target features, but honestly they don't seem to fit
> +}
> diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
> index f479540812a..abaec9e71e6 100644
> --- a/gcc/config/arm/arm.h
> +++ b/gcc/config/arm/arm.h
> @@ -51,6 +51,9 @@ extern char arm_arch_name[];
>   #define TARGET_D_CPU_VERSIONS arm_d_target_versions
>   #define TARGET_D_REGISTER_CPU_TARGET_INFO arm_d_register_target_info
>   
> +/* Target CPU info for Rust.  */
> +#define TARGET_RUST_CPU_INFO arm_rust_target_cpu_info
> +
>   #include "config/arm/arm-opts.h"
>   
>   /* The processor for which instructions should be scheduled.  */
> diff --git a/gcc/config/arm/bpabi.h b/gcc/config/arm/bpabi.h
> index 70984ddd147..0df5dd0f31a 100644
> --- a/gcc/config/arm/bpabi.h
> +++ b/gcc/config/arm/bpabi.h
> @@ -104,6 +104,17 @@
>   #define TARGET_OS_CPP_BUILTINS() \
>     TARGET_BPABI_CPP_BUILTINS()
>   
> +#define BPABI_TARGET_RUST_OS_INFO() \
> +  do { \
> +    /*TODO: is this even an OS? What should go here?*/ \
> +  } while (0)
> +
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in bpabi.h - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO() \
> +  BPABI_TARGET_RUST_OS_INFO()
> +
>   /* The BPABI specifies the use of .{init,fini}_array.  Therefore, we
>      do not want GCC to put anything into the .{init,fini} sections.  */
>   #undef INIT_SECTION_ASM_OP
> diff --git a/gcc/config/arm/freebsd.h b/gcc/config/arm/freebsd.h
> index 2bd0dc97df3..d662ab005d6 100644
> --- a/gcc/config/arm/freebsd.h
> +++ b/gcc/config/arm/freebsd.h
> @@ -83,6 +83,15 @@
>       }						\
>     while (false)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in freebsd.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO() 		\
> +  do {						\
> +    FBSD_TARGET_RUST_OS_INFO ();		\
> +    BPABI_TARGET_RUST_OS_INFO ();		\
> +  } while (0)
> +
>   /* We default to a soft-float ABI so that binaries can run on all
>      target hardware.  */
>   #undef TARGET_DEFAULT_FLOAT_ABI
> diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h
> index 50cc0bc6d08..a255ac0f1a7 100644
> --- a/gcc/config/arm/linux-eabi.h
> +++ b/gcc/config/arm/linux-eabi.h
> @@ -33,6 +33,14 @@
>   #define EXTRA_TARGET_D_OS_VERSIONS()		\
>     ANDROID_TARGET_D_OS_VERSIONS();
>   
> +#define EXTRA_TARGET_RUST_OS_INFO()		\
> +  do { 						\
> +    BPABI_TARGET_RUST_OS_INFO();		\
> +    GNU_USER_TARGET_RUST_OS_INFO();		\
> +    ANDROID_TARGET_RUST_OS_INFO();		\
> +    /*TODO: ensure that this makes target_os 'linux' properly and stuff*/ \
> +  while (0)
> +
>   /* We default to a soft-float ABI so that binaries can run on all
>      target hardware.  If you override this to use the hard-float ABI then
>      change the setting of GLIBC_DYNAMIC_LINKER_DEFAULT as well.  */
> diff --git a/gcc/config/arm/linux-elf.h b/gcc/config/arm/linux-elf.h
> index df3da67c4f0..0859945ed05 100644
> --- a/gcc/config/arm/linux-elf.h
> +++ b/gcc/config/arm/linux-elf.h
> @@ -83,6 +83,11 @@
>       }						\
>     while (0)
>   
> +#define TARGET_RUST_OS_INFO()		\
> +   do {						\
> +	   GNU_USER_TARGET_RUST_OS_INFO();	\
> +   } while (0)
> +
>   /* Call the function profiler with a given profile label.  */
>   #undef  ARM_FUNCTION_PROFILER
>   #define ARM_FUNCTION_PROFILER(STREAM, LABELNO)  			\
> diff --git a/gcc/config/arm/netbsd-eabi.h b/gcc/config/arm/netbsd-eabi.h
> index c85fcd3e385..a47b2ca3776 100644
> --- a/gcc/config/arm/netbsd-eabi.h
> +++ b/gcc/config/arm/netbsd-eabi.h
> @@ -64,6 +64,16 @@
>       }						\
>     while (0)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in netbsd-eabi.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO()		\
> +  do {						\
> +  	if (TARGET_AAPCS_BASED)			\
> +      BPABI_TARGET_RUST_OS_INFO();		\
> +    NETBSD_TARGET_RUST_OS_INFO();		\
> +  } while (0)
> +
>   #undef SUBTARGET_CPP_SPEC
>   #define SUBTARGET_CPP_SPEC NETBSD_CPP_SPEC
>   
> diff --git a/gcc/config/arm/netbsd-elf.h b/gcc/config/arm/netbsd-elf.h
> index d239c734c5c..e74cdcc6503 100644
> --- a/gcc/config/arm/netbsd-elf.h
> +++ b/gcc/config/arm/netbsd-elf.h
> @@ -51,6 +51,14 @@
>       }					\
>     while (0)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in netbsd-elf.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO()	\
> +  do {					\
> +    NETBSD_TARGET_RUST_OS_INFO();	\
> +  } while (0)
> +
>   #undef SUBTARGET_CPP_SPEC
>   #define SUBTARGET_CPP_SPEC NETBSD_CPP_SPEC
>   
> diff --git a/gcc/config/arm/rtems.h b/gcc/config/arm/rtems.h
> index a569343451a..56f978bf73e 100644
> --- a/gcc/config/arm/rtems.h
> +++ b/gcc/config/arm/rtems.h
> @@ -33,4 +33,18 @@
>   	TARGET_BPABI_CPP_BUILTINS();    	\
>       } while (0)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in rtems.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO()		\
> +  do {					\
> +    /*note: as far as I know, rustc has no supported for rtems, so this is just guessed*/ \
> +    /*everything is subject to change, especially target_env and target_family - TODO*/ \
> +    builtin_rust_info ("target_family", "unix");	\
> +    builtin_rust_info ("target_os", "rtems");	\
> +    builtin_rust_info ("target_vendor", "unknown");	\
> +    builtin_rust_info ("target_env", "");	\
> +    BPABI_TARGET_RUST_OS_INFO();	\
> +  } while (0)
> +
>   #define ARM_DEFAULT_SHORT_ENUMS false
> diff --git a/gcc/config/arm/symbian.h b/gcc/config/arm/symbian.h
> index 7df39170180..81c7cc00a27 100644
> --- a/gcc/config/arm/symbian.h
> +++ b/gcc/config/arm/symbian.h
> @@ -78,6 +78,21 @@
>       }								\
>     while (false)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in symbian.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO()		\
> +  do {					\
> +    /*note: as far as I know, rustc has no supported for symbian, so this is just guessed*/ \
> +    /*everything is subject to change, especially target_env and target_vendor - TODO*/ \
> +    /*some triple examples i've seen are "arm-nokia-symbian-eabi" and possibly "arm-none-symbian-elf"*/ \
> +    builtin_rust_info ("target_family", "");	\
> +    builtin_rust_info ("target_os", "symbian");	\
> +    builtin_rust_info ("target_vendor", "unknown");	\
> +    builtin_rust_info ("target_env", "");	\
> +    BPABI_TARGET_RUST_OS_INFO();	\
> +  } while (0)
> +
>   /* On SymbianOS, these sections are not writable, so we use "a",
>      rather than "aw", for the section attributes.  */
>   #undef ARM_EABI_CTORS_SECTION_OP
> diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm
> index 041cc6ec045..d093f3c789c 100644
> --- a/gcc/config/arm/t-arm
> +++ b/gcc/config/arm/t-arm
> @@ -172,6 +172,10 @@ arm-d.o: $(srcdir)/config/arm/arm-d.cc
>   	$(COMPILE) $<
>   	$(POSTCOMPILE)
>   
> +arm-rust.o: $(srcdir)/config/arm/arm-rust.cc
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
> +
>   arm-common.o: arm-cpu-cdata.h
>   
>   driver-arm.o: arm-native.h
> diff --git a/gcc/config/arm/uclinux-eabi.h b/gcc/config/arm/uclinux-eabi.h
> index 362d2b5ebd8..54bf78cdc0d 100644
> --- a/gcc/config/arm/uclinux-eabi.h
> +++ b/gcc/config/arm/uclinux-eabi.h
> @@ -46,6 +46,19 @@
>       }						\
>     while (false)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in uclinux-eabi.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO()		\
> +  do {					\
> +    BPABI_TARGET_RUST_OS_INFO();	\
> +    /*note: as far as I know, rustc does not distinguish between uclinux and regular linux kernels*/ \
> +    builtin_rust_info ("target_family", "unix");	   \
> +    builtin_rust_info ("target_os", "linux");	      \
> +    builtin_rust_info ("target_vendor", "unknown");	\
> +    builtin_rust_info ("target_env", "gnu");	         \
> +  } while (0)
> +
>   #undef SUBTARGET_EXTRA_LINK_SPEC
>   #define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux_eabi -elf2flt" \
>     " --pic-veneer --target2=abs"
> diff --git a/gcc/config/arm/uclinux-elf.h b/gcc/config/arm/uclinux-elf.h
> index 921440d49bd..3fcaf2d6acb 100644
> --- a/gcc/config/arm/uclinux-elf.h
> +++ b/gcc/config/arm/uclinux-elf.h
> @@ -48,6 +48,18 @@
>       }						\
>     while (false)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in uclinux-elf.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#define TARGET_RUST_OS_INFO()		\
> +  do {					\
> +    /*note: as far as I know, rustc does not distinguish between uclinux and regular linux kernels*/ \
> +    builtin_rust_info ("target_family", "unix");	   \
> +    builtin_rust_info ("target_os", "linux");	      \
> +    builtin_rust_info ("target_vendor", "unknown");	\
> +    builtin_rust_info ("target_env", "gnu");	         \
> +  } while (0)
> +
>   /* The GNU C++ standard library requires that these macros be defined.  */
>   #undef CPLUSPLUS_CPP_SPEC
>   #define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
> diff --git a/gcc/config/arm/vxworks.h b/gcc/config/arm/vxworks.h
> index 2bcd01edc97..0d4989cb52a 100644
> --- a/gcc/config/arm/vxworks.h
> +++ b/gcc/config/arm/vxworks.h
> @@ -75,6 +75,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>       MAYBE_TARGET_BPABI_CPP_BUILTINS ();			\
>     } while (0)
>   
> +#ifdef TARGET_RUST_OS_INFO
> +# error "TARGET_RUST_OS_INFO already defined in vxworks.h (arm) - c++ undefines it and redefines it."
> +#endif
> +#ifdef BPABI_TARGET_RUST_OS_INFO
> +# define MAYBE_BPABI_TARGET_RUST_OS_INFO BPABI_TARGET_RUST_OS_INFO
> +#else
> +# define MAYBE_BPABI_TARGET_RUST_OS_INFO()
> +#endif
> +#define TARGET_RUST_OS_INFO()			\
> +  do {			\
> +    VXWORKS_TARGET_RUST_OS_INFO ();			\
> +    MAYBE_BPABI_TARGET_RUST_OS_INFO ();			\
> +  } while (0)
> +
>   #undef SUBTARGET_OVERRIDE_OPTIONS
>   #define SUBTARGET_OVERRIDE_OPTIONS VXWORKS_OVERRIDE_OPTIONS
>
  

Patch

diff --git a/gcc/config.gcc b/gcc/config.gcc
index cdd4fb4392a..9d686019b28 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -368,6 +368,7 @@  arm*-*-*)
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
 	d_target_objs="arm-d.o"
+        rust_target_objs="arm-rust.o"
 	extra_options="${extra_options} arm/arm-tables.opt"
 	target_gtfiles="\$(srcdir)/config/arm/arm-builtins.cc \$(srcdir)/config/arm/arm-mve-builtins.h \$(srcdir)/config/arm/arm-mve-builtins.cc"
 	;;
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index f8aabbdae37..9513f96fdbc 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -406,6 +406,9 @@  extern void arm_cpu_cpp_builtins (struct cpp_reader *);
 extern void arm_d_target_versions (void);
 extern void arm_d_register_target_info (void);
 
+/* Defined in arm-rust.c  */
+extern void arm_rust_target_cpu_info (void);
+
 extern bool arm_is_constant_pool_ref (rtx);
 
 /* The bits in this mask specify which instruction scheduling options should
diff --git a/gcc/config/arm/arm-rust.cc b/gcc/config/arm/arm-rust.cc
new file mode 100644
index 00000000000..7c83e3fa3a6
--- /dev/null
+++ b/gcc/config/arm/arm-rust.cc
@@ -0,0 +1,304 @@ 
+/* Subroutines for the Rust front end on the ARM architecture.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tm_p.h"
+#include "rust/rust-target.h"
+#include "rust/rust-target-def.h"
+
+/* Implement TARGET_RUST_CPU_INFO for ARM targets.  */
+
+void arm_rust_target_cpu_info(void) {
+    rust_add_target_info("target_arch", "arm");
+
+    /* TODO: further research support for CLREX, acquire-release (lda/ldaex), slow-fp-brcc (slow FP
+     * compare and branch), perfmon, trustzone, fpao, fuse-aes, fuse-literals, read-tp-hard, zcz,
+     * prof-unpr, slow-vgetlni32, slow-vdup32, prefer-vmovsr, prefer-ishst, muxed-units, slow-odd-reg,
+     * slow-load-D-subreg, wide-stride-vfp, dont-widen-vmovs, splat-vfp-neon, expand-fp-mlx,
+     * vmlx-hazards, neon-fpmovs, neonfp (as in using neon for scalar fp), vldn-align,
+     * nonpipelined-vfp, slowfpvmlx, slowfpvfmx, vmlx-forwarding, 32bit (prefer 32-bit Thumb),
+     * loop-align, mve1beat, mve2beat, mve4beat, avoid-partial-cpsr, cheap-predictable-cpsr,
+     * avoid-movs-shop, ret-addr-stack, no-branch-predictor, virtualization, nacl-trap, execute-only,
+     * reserve-r9, no-movt, no-neg-immediates, use-misched, disable-postra-scheduler, lob (Low
+     * Overhead Branch), noarm, cde - can't find them. */
+    /* TODO: figure out if gcc has an equivalent to "fpregs" (floating-point registers even if only
+     * used for integer - shared between VFP and MVE).  */
+    if (TARGET_VFPD32)
+        rust_add_target_info("target_feature", "d32");
+    bool hasFeatureVFP2 = bitmap_bit_p(arm_active_target.isa, isa_bit_vfpv2) && TARGET_VFP_DOUBLE;
+    if (hasFeatureVFP2) {
+        rust_add_target_info("target_feature", "vfp2");
+
+        // also added implied features that aren't separately supported in gcc
+        rust_add_target_info("target_feature", "vfp2sp");
+    }
+    // minimal VFPv3 support - support for instruction set, not necessarily full
+    bool minVFP3 = TARGET_VFP3 && bitmap_bit_p(arm_active_target.isa, isa_bit_vfpv2);
+    if (minVFP3) {
+        rust_add_target_info("target_feature", "vfp3d16sp");
+
+        if (TARGET_VFPD32)
+            rust_add_target_info("target_feature", "vfp3sp");
+
+        if (TARGET_VFP_DOUBLE) {
+            rust_add_target_info("target_feature", "vfp3d16");
+
+            if (TARGET_VFPD32) {
+                rust_add_target_info("target_feature", "vfp3");
+
+                if (bitmap_bit_p(arm_active_target.isa, isa_bit_neon))
+                    rust_add_target_info("target_feature", "neon");
+            }
+        }
+    }
+    bool hasFeatureVFP3 = minVFP3 && TARGET_VFP_DOUBLE && TARGET_VFPD32;
+    bool hasFeatureFP16 = bitmap_bit_p(arm_active_target.isa, isa_bit_fp16conv);
+    if (hasFeatureFP16)
+        rust_add_target_info("target_info", "fp16");
+    bool minVFP4 = minVFP3 && bitmap_bit_p(arm_active_target.isa, isa_bit_vfpv4) && hasFeatureFP16;
+    if (minVFP4) {
+        rust_add_target_info("target_feature", "vfp4d16sp");
+
+        if (TARGET_VFPD32)
+            rust_add_target_info("target_feature", "vfp4sp");
+
+        if (TARGET_VFP_DOUBLE) {
+            rust_add_target_info("target_feature", "vfp4d16");
+
+            if (TARGET_VFPD32) {
+                rust_add_target_info("target_feature", "vfp4");
+            }
+        }
+    }
+    // NOTE: supposedly "fp-armv8" features in llvm are the same as "fpv5", so creating them based on
+    // that
+    bool minFP_ARMv8 = minVFP4 && TARGET_VFP5;
+    if (minFP_ARMv8) {
+        rust_add_target_info("target_feature", "fp-armv8d16sp");
+
+        if (TARGET_VFPD32)
+            rust_add_target_info("target_feature", "fp-armv8sp");
+
+        if (TARGET_VFP_DOUBLE) {
+            rust_add_target_info("target_feature", "fp-armv8d16");
+
+            if (TARGET_VFPD32) {
+                rust_add_target_info("target_feature", "fp-armv8");
+            }
+        }
+
+        if (bitmap_bit_p(arm_active_target.isa, isa_bit_fp16)) {
+            rust_add_target_info("target_feature", "fullfp16");
+
+            if (bitmap_bit_p(arm_active_target.isa, isa_bit_fp16fml))
+                rust_add_target_info("target_feature", "fp16fml");
+        }
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_tdiv))
+        rust_add_target_info("target_feature", "hwdiv");
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_adiv))
+        rust_add_target_info("target_feature", "hwdiv-arm");
+    // TODO: I'm not sure if there's an exact correlation here (data barrier), so maybe research
+    // There's also the question of whether this also means "full data barrier" ("fdb" in llvm)
+    if (TARGET_HAVE_MEMORY_BARRIER)
+        rust_add_target_info("target_feature", "db");
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cmse))
+        rust_add_target_info("target_feature", "8msecext");
+    /* TODO: note that sha2 is an option for aarch64 in gcc but not for arm, so no feature here
+     * possible. The same goes for aes. However, as llvm has them as prerequisites for crypto, they
+     * are enabled with it. */
+    if (TARGET_CRYPTO) {
+        rust_add_target_info("target_feature", "crypto");
+        rust_add_target_info("target_feature", "sha2");
+        rust_add_target_info("target_feature", "aes");
+    }
+    if (TARGET_CRC32)
+        rust_add_target_info("target_feature", "crc");
+    if (TARGET_DOTPROD)
+        rust_add_target_info("target_feature", "dotprod");
+    // TODO: supposedly gcc supports RAS, but I couldn't find the option, so leaving out "ras" for now
+    if (TARGET_DSP_MULTIPLY)
+        rust_add_target_info("target_feature", "dsp");
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_mp))
+        rust_add_target_info("target_feature", "mp");
+    // TODO: figure out the exact strict-align feature, which I'm pretty sure GCC has
+    // TODO: figure out how to access long call data (which is in GCC) for "long-calls"
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_sb))
+        rust_add_target_info("target_feature", "sb");
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_bf16))
+        rust_add_target_info("target_feature", "bf16");
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_i8mm))
+        rust_add_target_info("target_feature", "i8mm");
+    switch (TARGET_ARM_ARCH_PROFILE) {
+        case 'A':
+            rust_add_target_info("target_feature", "aclass");
+            break;
+        case 'R':
+            rust_add_target_info("target_feature", "rclass");
+            break;
+        case 'M':
+            rust_add_target_info("target_feature", "mclass");
+            break;
+        default:
+            fprintf(stderr, "Screwed up profile selection in arm-rust.c - unknown profile '%c'",
+              TARGET_ARM_ARCH_PROFILE);
+            break;
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_thumb2))
+        rust_add_target_info("target_feature", "thumb2");
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv4)
+        && bitmap_bit_p(arm_active_target.isa, isa_bit_notm)
+        && bitmap_bit_p(arm_active_target.isa, isa_bit_thumb)) {
+        rust_add_target_info("target_feature", "v4t");
+
+        if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv5t)) {
+            rust_add_target_info("target_feature", "v5t");
+
+            if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv5te)) {
+                rust_add_target_info("target_feature", "v5te");
+
+                if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv6)
+                    && bitmap_bit_p(arm_active_target.isa, isa_bit_be8)) {
+                    rust_add_target_info("target_feature", "v6");
+
+                    // note: this definition of "ARMv6m" listed as "suspect" in arm-cpus.in
+                    rust_add_target_info("target_feature", "v6m");
+
+                    bool hasV8BaselineOps = bitmap_bit_p(arm_active_target.isa, isa_bit_armv8)
+                                            && bitmap_bit_p(arm_active_target.isa, isa_bit_cmse)
+                                            && bitmap_bit_p(arm_active_target.isa, isa_bit_tdiv);
+                    if (hasV8BaselineOps)
+                        rust_add_target_info("target_feature", "v8m");
+
+                    bool hasV6kOps = bitmap_bit_p(arm_active_target.isa, isa_bit_armv6k);
+                    if (hasV6kOps) {
+                        rust_add_target_info("target_feature", "v6k");
+                    }
+
+                    if (bitmap_bit_p(arm_active_target.isa, isa_bit_thumb2) && hasV8BaselineOps
+                        && hasV6kOps) {
+                        rust_add_target_info("target_feature", "v6t2");
+
+                        // note that arm-cpus.in refers to this (ARMv7) as suspect
+                        if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv7)) {
+                            rust_add_target_info("target_feature", "v7");
+
+                            rust_add_target_info("target_feature", "v8m.main");
+
+                            if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_1m_main))
+                                rust_add_target_info("target_feature", "v8.1m.main");
+
+                            // dummy: can't find feature acquire-release, so dummy true variable
+                            bool hasAcquireRelease = true;
+                            if (hasAcquireRelease && bitmap_bit_p(arm_active_target.isa, isa_bit_adiv)
+                                && bitmap_bit_p(arm_active_target.isa, isa_bit_lpae)
+                                && bitmap_bit_p(arm_active_target.isa, isa_bit_mp)
+                                && bitmap_bit_p(arm_active_target.isa, isa_bit_sec)) {
+                                rust_add_target_info("target_feature", "v8");
+
+                                if (TARGET_CRC32
+                                    && bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_1)) {
+                                    rust_add_target_info("target_feature", "v8.1a");
+
+                                    if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_2)) {
+                                        rust_add_target_info("target_feature", "v8.2a");
+
+                                        if (bitmap_bit_p(arm_active_target.isa, isa_bit_armv8_3)) {
+                                            rust_add_target_info("target_feature", "v8.3a");
+
+                                            if (bitmap_bit_p(
+                                                  arm_active_target.isa, isa_bit_armv8_4)) {
+                                                rust_add_target_info("target_feature", "v8.4a");
+                                                // note: llvm, but not gcc, also wants dotprod for
+                                                // v8.4
+
+                                                if (bitmap_bit_p(arm_active_target.isa, isa_bit_sb)
+                                                    && bitmap_bit_p(
+                                                      arm_active_target.isa, isa_bit_predres)
+                                                    && bitmap_bit_p(
+                                                      arm_active_target.isa, isa_bit_armv8_5)) {
+                                                    rust_add_target_info("target_feature", "v8.5a");
+
+                                                    if (bitmap_bit_p(
+                                                          arm_active_target.isa, isa_bit_armv8_6))
+                                                        rust_add_target_info(
+                                                          "target_feature", "v8.6a");
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_mve)
+        && bitmap_bit_p(arm_active_target.isa, isa_bit_vfp_base)
+        && bitmap_bit_p(arm_active_target.isa, isa_bit_armv7em)) {
+        rust_add_target_info("target_feature", "mve");
+
+        if (minFP_ARMv8 && bitmap_bit_p(arm_active_target.isa, isa_bit_fp16)
+            && bitmap_bit_p(arm_active_target.isa, isa_bit_mve_float))
+            rust_add_target_info("target_feature", "mve.fp");
+    }
+    // Note: no direct option for "cde" found, but it is implicitly activated via cdecpx, so do it
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp0)) {
+        rust_add_target_info("target_feature", "cdecp0");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp1)) {
+        rust_add_target_info("target_feature", "cdecp1");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp2)) {
+        rust_add_target_info("target_feature", "cdecp2");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp3)) {
+        rust_add_target_info("target_feature", "cdecp3");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp4)) {
+        rust_add_target_info("target_feature", "cdecp4");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp5)) {
+        rust_add_target_info("target_feature", "cdecp5");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp6)) {
+        rust_add_target_info("target_feature", "cdecp6");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (bitmap_bit_p(arm_active_target.isa, isa_bit_cdecp7)) {
+        rust_add_target_info("target_feature", "cdecp7");
+        rust_add_target_info("target_feature", "cde");
+    }
+    if (TARGET_SOFT_FLOAT)
+        rust_add_target_info("target_feature", "soft-float");
+    // should be correct option (i.e. thumb mode rather than just thumb-aware) as TARGET_ARM is
+    // inverse
+    if (TARGET_THUMB)
+        rust_add_target_info("target_feature", "thumb-mode");
+    // TODO: consider doing the processors as target features, but honestly they don't seem to fit
+}
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index f479540812a..abaec9e71e6 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -51,6 +51,9 @@  extern char arm_arch_name[];
 #define TARGET_D_CPU_VERSIONS arm_d_target_versions
 #define TARGET_D_REGISTER_CPU_TARGET_INFO arm_d_register_target_info
 
+/* Target CPU info for Rust.  */
+#define TARGET_RUST_CPU_INFO arm_rust_target_cpu_info
+
 #include "config/arm/arm-opts.h"
 
 /* The processor for which instructions should be scheduled.  */
diff --git a/gcc/config/arm/bpabi.h b/gcc/config/arm/bpabi.h
index 70984ddd147..0df5dd0f31a 100644
--- a/gcc/config/arm/bpabi.h
+++ b/gcc/config/arm/bpabi.h
@@ -104,6 +104,17 @@ 
 #define TARGET_OS_CPP_BUILTINS() \
   TARGET_BPABI_CPP_BUILTINS()
 
+#define BPABI_TARGET_RUST_OS_INFO() \
+  do { \
+    /*TODO: is this even an OS? What should go here?*/ \
+  } while (0)
+
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in bpabi.h - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO() \
+  BPABI_TARGET_RUST_OS_INFO()
+
 /* The BPABI specifies the use of .{init,fini}_array.  Therefore, we
    do not want GCC to put anything into the .{init,fini} sections.  */
 #undef INIT_SECTION_ASM_OP
diff --git a/gcc/config/arm/freebsd.h b/gcc/config/arm/freebsd.h
index 2bd0dc97df3..d662ab005d6 100644
--- a/gcc/config/arm/freebsd.h
+++ b/gcc/config/arm/freebsd.h
@@ -83,6 +83,15 @@ 
     }						\
   while (false)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in freebsd.h (arm) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO() 		\
+  do {						\
+    FBSD_TARGET_RUST_OS_INFO ();		\
+    BPABI_TARGET_RUST_OS_INFO ();		\
+  } while (0)
+
 /* We default to a soft-float ABI so that binaries can run on all
    target hardware.  */
 #undef TARGET_DEFAULT_FLOAT_ABI
diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h
index 50cc0bc6d08..a255ac0f1a7 100644
--- a/gcc/config/arm/linux-eabi.h
+++ b/gcc/config/arm/linux-eabi.h
@@ -33,6 +33,14 @@ 
 #define EXTRA_TARGET_D_OS_VERSIONS()		\
   ANDROID_TARGET_D_OS_VERSIONS();
 
+#define EXTRA_TARGET_RUST_OS_INFO()		\
+  do { 						\
+    BPABI_TARGET_RUST_OS_INFO();		\
+    GNU_USER_TARGET_RUST_OS_INFO();		\
+    ANDROID_TARGET_RUST_OS_INFO();		\
+    /*TODO: ensure that this makes target_os 'linux' properly and stuff*/ \
+  while (0)
+
 /* We default to a soft-float ABI so that binaries can run on all
    target hardware.  If you override this to use the hard-float ABI then
    change the setting of GLIBC_DYNAMIC_LINKER_DEFAULT as well.  */
diff --git a/gcc/config/arm/linux-elf.h b/gcc/config/arm/linux-elf.h
index df3da67c4f0..0859945ed05 100644
--- a/gcc/config/arm/linux-elf.h
+++ b/gcc/config/arm/linux-elf.h
@@ -83,6 +83,11 @@ 
     }						\
   while (0)
 
+#define TARGET_RUST_OS_INFO()		\
+   do {						\
+	   GNU_USER_TARGET_RUST_OS_INFO();	\
+   } while (0)
+
 /* Call the function profiler with a given profile label.  */
 #undef  ARM_FUNCTION_PROFILER
 #define ARM_FUNCTION_PROFILER(STREAM, LABELNO)  			\
diff --git a/gcc/config/arm/netbsd-eabi.h b/gcc/config/arm/netbsd-eabi.h
index c85fcd3e385..a47b2ca3776 100644
--- a/gcc/config/arm/netbsd-eabi.h
+++ b/gcc/config/arm/netbsd-eabi.h
@@ -64,6 +64,16 @@ 
     }						\
   while (0)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in netbsd-eabi.h (arm) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+  	if (TARGET_AAPCS_BASED)			\
+      BPABI_TARGET_RUST_OS_INFO();		\
+    NETBSD_TARGET_RUST_OS_INFO();		\
+  } while (0)
+
 #undef SUBTARGET_CPP_SPEC
 #define SUBTARGET_CPP_SPEC NETBSD_CPP_SPEC
 
diff --git a/gcc/config/arm/netbsd-elf.h b/gcc/config/arm/netbsd-elf.h
index d239c734c5c..e74cdcc6503 100644
--- a/gcc/config/arm/netbsd-elf.h
+++ b/gcc/config/arm/netbsd-elf.h
@@ -51,6 +51,14 @@ 
     }					\
   while (0)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in netbsd-elf.h (arm) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()	\
+  do {					\
+    NETBSD_TARGET_RUST_OS_INFO();	\
+  } while (0)
+
 #undef SUBTARGET_CPP_SPEC
 #define SUBTARGET_CPP_SPEC NETBSD_CPP_SPEC
 
diff --git a/gcc/config/arm/rtems.h b/gcc/config/arm/rtems.h
index a569343451a..56f978bf73e 100644
--- a/gcc/config/arm/rtems.h
+++ b/gcc/config/arm/rtems.h
@@ -33,4 +33,18 @@ 
 	TARGET_BPABI_CPP_BUILTINS();    	\
     } while (0)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in rtems.h (arm) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()		\
+  do {					\
+    /*note: as far as I know, rustc has no supported for rtems, so this is just guessed*/ \
+    /*everything is subject to change, especially target_env and target_family - TODO*/ \
+    builtin_rust_info ("target_family", "unix");	\
+    builtin_rust_info ("target_os", "rtems");	\
+    builtin_rust_info ("target_vendor", "unknown");	\
+    builtin_rust_info ("target_env", "");	\
+    BPABI_TARGET_RUST_OS_INFO();	\
+  } while (0)
+
 #define ARM_DEFAULT_SHORT_ENUMS false
diff --git a/gcc/config/arm/symbian.h b/gcc/config/arm/symbian.h
index 7df39170180..81c7cc00a27 100644
--- a/gcc/config/arm/symbian.h
+++ b/gcc/config/arm/symbian.h
@@ -78,6 +78,21 @@ 
     }								\
   while (false)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in symbian.h (arm) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()		\
+  do {					\
+    /*note: as far as I know, rustc has no supported for symbian, so this is just guessed*/ \
+    /*everything is subject to change, especially target_env and target_vendor - TODO*/ \
+    /*some triple examples i've seen are "arm-nokia-symbian-eabi" and possibly "arm-none-symbian-elf"*/ \
+    builtin_rust_info ("target_family", "");	\
+    builtin_rust_info ("target_os", "symbian");	\
+    builtin_rust_info ("target_vendor", "unknown");	\
+    builtin_rust_info ("target_env", "");	\
+    BPABI_TARGET_RUST_OS_INFO();	\
+  } while (0)
+
 /* On SymbianOS, these sections are not writable, so we use "a",
    rather than "aw", for the section attributes.  */
 #undef ARM_EABI_CTORS_SECTION_OP
diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm
index 041cc6ec045..d093f3c789c 100644
--- a/gcc/config/arm/t-arm
+++ b/gcc/config/arm/t-arm
@@ -172,6 +172,10 @@  arm-d.o: $(srcdir)/config/arm/arm-d.cc
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+arm-rust.o: $(srcdir)/config/arm/arm-rust.cc
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
 arm-common.o: arm-cpu-cdata.h
 
 driver-arm.o: arm-native.h
diff --git a/gcc/config/arm/uclinux-eabi.h b/gcc/config/arm/uclinux-eabi.h
index 362d2b5ebd8..54bf78cdc0d 100644
--- a/gcc/config/arm/uclinux-eabi.h
+++ b/gcc/config/arm/uclinux-eabi.h
@@ -46,6 +46,19 @@ 
     }						\
   while (false)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in uclinux-eabi.h (arm) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()		\
+  do {					\
+    BPABI_TARGET_RUST_OS_INFO();	\
+    /*note: as far as I know, rustc does not distinguish between uclinux and regular linux kernels*/ \
+    builtin_rust_info ("target_family", "unix");	   \
+    builtin_rust_info ("target_os", "linux");	      \
+    builtin_rust_info ("target_vendor", "unknown");	\
+    builtin_rust_info ("target_env", "gnu");	         \
+  } while (0)
+
 #undef SUBTARGET_EXTRA_LINK_SPEC
 #define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux_eabi -elf2flt" \
   " --pic-veneer --target2=abs"
diff --git a/gcc/config/arm/uclinux-elf.h b/gcc/config/arm/uclinux-elf.h
index 921440d49bd..3fcaf2d6acb 100644
--- a/gcc/config/arm/uclinux-elf.h
+++ b/gcc/config/arm/uclinux-elf.h
@@ -48,6 +48,18 @@ 
     }						\
   while (false)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in uclinux-elf.h (arm) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()		\
+  do {					\
+    /*note: as far as I know, rustc does not distinguish between uclinux and regular linux kernels*/ \
+    builtin_rust_info ("target_family", "unix");	   \
+    builtin_rust_info ("target_os", "linux");	      \
+    builtin_rust_info ("target_vendor", "unknown");	\
+    builtin_rust_info ("target_env", "gnu");	         \
+  } while (0)
+
 /* The GNU C++ standard library requires that these macros be defined.  */
 #undef CPLUSPLUS_CPP_SPEC
 #define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
diff --git a/gcc/config/arm/vxworks.h b/gcc/config/arm/vxworks.h
index 2bcd01edc97..0d4989cb52a 100644
--- a/gcc/config/arm/vxworks.h
+++ b/gcc/config/arm/vxworks.h
@@ -75,6 +75,20 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     MAYBE_TARGET_BPABI_CPP_BUILTINS ();			\
   } while (0)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in vxworks.h (arm) - c++ undefines it and redefines it."
+#endif
+#ifdef BPABI_TARGET_RUST_OS_INFO
+# define MAYBE_BPABI_TARGET_RUST_OS_INFO BPABI_TARGET_RUST_OS_INFO
+#else
+# define MAYBE_BPABI_TARGET_RUST_OS_INFO()
+#endif
+#define TARGET_RUST_OS_INFO()			\
+  do {			\
+    VXWORKS_TARGET_RUST_OS_INFO ();			\
+    MAYBE_BPABI_TARGET_RUST_OS_INFO ();			\
+  } while (0)
+
 #undef SUBTARGET_OVERRIDE_OPTIONS
 #define SUBTARGET_OVERRIDE_OPTIONS VXWORKS_OVERRIDE_OPTIONS