diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 001506f8abf..e5a15b8b667 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -573,6 +573,8 @@ tm_p_file_list=@tm_p_file_list@
 tm_p_include_list=@tm_p_include_list@
 tm_d_file_list=@tm_d_file_list@
 tm_d_include_list=@tm_d_include_list@
+tm_rust_file_list=@tm_rust_file_list@
+tm_rust_include_list=@tm_rust_include_list@
 build_xm_file_list=@build_xm_file_list@
 build_xm_include_list=@build_xm_include_list@
 build_xm_defines=@build_xm_defines@
@@ -866,6 +868,7 @@ CONFIG_H  = config.h  $(host_xm_file_list)
 TCONFIG_H = tconfig.h $(xm_file_list)
 TM_P_H    = tm_p.h    $(tm_p_file_list)
 TM_D_H    = tm_d.h    $(tm_d_file_list)
+TM_RUST_H = tm_rust.h $(tm_rust_file_list)
 GTM_H     = tm.h      $(tm_file_list) insn-constants.h
 TM_H      = $(GTM_H) insn-flags.h $(OPTIONS_H)
 
@@ -928,6 +931,7 @@ TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h
 C_TARGET_H = c-family/c-target.h $(C_TARGET_DEF)
 COMMON_TARGET_H = common/common-target.h $(INPUT_H) $(COMMON_TARGET_DEF)
 D_TARGET_H = d/d-target.h $(D_TARGET_DEF)
+RUST_TARGET_H = rust/rust-target.h $(RUST_TARGET_DEF)
 MACHMODE_H = machmode.h mode-classes.def
 HOOKS_H = hooks.h
 HOSTHOOKS_DEF_H = hosthooks-def.h $(HOOKS_H)
@@ -1228,6 +1232,9 @@ CXX_TARGET_OBJS=@cxx_target_objs@
 # Target specific, D specific object file
 D_TARGET_OBJS=@d_target_objs@
 
+# Target specific, Rust specific object file
+RUST_TARGET_OBJS=@rust_target_objs@
+
 # Target specific, Fortran specific object file
 FORTRAN_TARGET_OBJS=@fortran_target_objs@
 
@@ -1937,6 +1944,7 @@ tconfig.h: cs-tconfig.h ; @true
 tm.h: cs-tm.h ; @true
 tm_p.h: cs-tm_p.h ; @true
 tm_d.h: cs-tm_d.h ; @true
+tm_rust.h: cs-tm_rust.h ; @true
 
 cs-config.h: Makefile
 	TARGET_CPU_DEFAULT="" \
@@ -1968,6 +1976,11 @@ cs-tm_d.h: Makefile
 	HEADERS="$(tm_d_include_list)" DEFINES="" \
 	$(SHELL) $(srcdir)/mkconfig.sh tm_d.h
 
+cs-tm_rust.h: Makefile
+	TARGET_CPU_DEFAULT="" \
+	HEADERS="$(tm_rust_include_list)" DEFINES="" \
+	$(SHELL) $(srcdir)/mkconfig.sh tm_rust.h
+
 # Don't automatically run autoconf, since configure.ac might be accidentally
 # newer than configure.  Also, this writes into the source directory which
 # might be on a read-only file system.  If configured for maintainer mode
@@ -2304,6 +2317,12 @@ default-d.o: config/default-d.cc
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+# Files used by the Rust language front end.
+
+default-rust.o: config/default-rust.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
 # Language-independent files.
 
 DRIVER_DEFINES = \
@@ -2609,6 +2628,15 @@ s-d-target-hooks-def-h: build/genhooks$(build_exeext)
 					     d/d-target-hooks-def.h
 	$(STAMP) s-d-target-hooks-def-h
 
+rust/rust-target-hooks-def.h: s-rust-target-hooks-def-h; @true
+
+s-rust-target-hooks-def-h: build/genhooks$(build_exeext)
+	$(RUN_GEN) build/genhooks$(build_exeext) "Rust Target Hook" \
+					     > tmp-rust-target-hooks-def.h
+	$(SHELL) $(srcdir)/../move-if-change tmp-rust-target-hooks-def.h \
+					     rust/rust-target-hooks-def.h
+	$(STAMP) s-rust-target-hooks-def-h
+
 # check if someone mistakenly only changed tm.texi.
 # We use a different pathname here to avoid a circular dependency.
 s-tm-texi: $(srcdir)/doc/../doc/tm.texi
@@ -2633,6 +2661,7 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in
 	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/c-family/c-target.def \
 	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/common/common-target.def \
 	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/d/d-target.def \
+	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/rust/rust-target.def \
 	  ); then \
 	  echo >&2 ; \
 	  echo You should edit $(srcdir)/doc/tm.texi.in rather than $(srcdir)/doc/tm.texi . >&2 ; \
@@ -2782,8 +2811,8 @@ s-gtype: $(EXTRA_GTYPE_DEPS) build/gengtype$(build_exeext) \
                     -r gtype.state
 	$(STAMP) s-gtype
 
-generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \
-       $(simple_generated_h) specs.h \
+generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_RUST_H) $(TM_H) multilib.h \
+	$(simple_generated_h) specs.h \
        tree-check.h genrtl.h insn-modes.h insn-modes-inline.h \
        tm-preds.h tm-constrs.h \
        $(ALL_GTFILES_H) gtype-desc.cc gtype-desc.h version.h \
@@ -2791,7 +2820,7 @@ generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \
        common/common-target-hooks-def.h pass-instances.def \
        gimple-match.cc generic-match.cc \
        c-family/c-target-hooks-def.h d/d-target-hooks-def.h \
-       case-cfn-macros.h \
+       rust/rust-target-hooks-def.h case-cfn-macros.h \
        cfn-operators.pd omp-device-properties.h
 
 #
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 4e3b15bb5e9..cdd4fb4392a 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -90,6 +90,9 @@
 #  tm_d_file		A list of headers with definitions of target hook
 #			macros for the D compiler.
 #
+#  tm_rust_file		A list of headers with definitions of target hook
+#			macros for the Rust compiler.
+#
 #  out_file		The name of the machine description C support
 #			file, if different from "$cpu_type/$cpu_type.c".
 #
@@ -146,6 +149,9 @@
 #  d_target_objs	List of extra target-dependent objects that be
 #			linked into the D compiler only.
 #
+#  rust_target_objs	List of extra target-dependent objects that be
+#			linked into the Rust compiler only.
+#
 #  fortran_target_objs	List of extra target-dependent objects that be
 #			linked into the fortran compiler only.
 #
@@ -201,6 +207,9 @@
 #
 #  target_has_targetdm	Set to yes or no depending on whether the target
 #			has its own definition of targetdm.
+#
+#  target_has_targetrustm	Set to yes or no depending on whether the target
+#			has its own definition of targetrustm.
 
 out_file=
 common_out_file=
@@ -217,6 +226,7 @@ extra_options=
 c_target_objs=
 cxx_target_objs=
 d_target_objs=
+rust_target_objs=
 fortran_target_objs=
 target_has_targetcm=no
 target_has_targetm_common=yes
@@ -391,6 +401,7 @@ i[34567]86-*-* | x86_64-*-*)
 	c_target_objs="i386-c.o"
 	cxx_target_objs="i386-c.o"
 	d_target_objs="i386-d.o"
+	rust_target_objs="i386-rust.o"
 	extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o i386-options.o i386-builtins.o i386-expand.o i386-features.o"
 	target_gtfiles="\$(srcdir)/config/i386/i386-builtins.cc \$(srcdir)/config/i386/i386-expand.cc \$(srcdir)/config/i386/i386-options.cc"
 	extra_options="${extra_options} fused-madd.opt"
@@ -560,10 +571,12 @@ esac
 
 tm_file=${cpu_type}/${cpu_type}.h
 tm_d_file=${cpu_type}/${cpu_type}.h
+tm_rust_file=${cpu_type}/${cpu_type}.h
 if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-protos.h
 then
 	tm_p_file=${cpu_type}/${cpu_type}-protos.h
 	tm_d_file="${tm_d_file} ${cpu_type}/${cpu_type}-protos.h"
+	tm_rust_file="${tm_rust_file} ${cpu_type}/${cpu_type}-protos.h"
 fi
 
 extra_modes=
@@ -3626,6 +3639,10 @@ if [ "$target_has_targetdm" = "no" ]; then
   d_target_objs="$d_target_objs default-d.o"
 fi
 
+if [ "$target_has_targetrustm" = "no" ]; then
+  rust_target_objs="$rust_target_objs default-rust.o"
+fi
+
 # Support for --with-cpu and related options (and a few unrelated options,
 # too).
 case ${with_cpu} in
diff --git a/gcc/config/default-rust.cc b/gcc/config/default-rust.cc
new file mode 100644
index 00000000000..a2754396e8c
--- /dev/null
+++ b/gcc/config/default-rust.cc
@@ -0,0 +1,26 @@
+/* Default Rust language target hooks initializer.
+   Copyright (C) 2020-2022 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 "memmodel.h"
+#include "tm_rust.h"
+#include "rust/rust-target.h"
+#include "rust/rust-target-def.h"
+
+struct gcc_targetrustm targetrustm = TARGETRUSTM_INITIALIZER;
diff --git a/gcc/config/dragonfly.h b/gcc/config/dragonfly.h
index 0235e62681d..15209f987ab 100644
--- a/gcc/config/dragonfly.h
+++ b/gcc/config/dragonfly.h
@@ -35,6 +35,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     }                                       \
   while (0)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in dragonflybsd.h - c++ undefines it and redefines it."
+/* TODO: ensure that this works correctly and the undef and redef reason is known */
+#endif
+#define TARGET_RUST_OS_INFO()                       \
+  do {                                              \
+    builtin_rust_info ("target_family", "unix");		\
+    builtin_rust_info ("target_os", "dragonfly");		\
+    builtin_rust_info ("target_vendor", "unknown"); \
+    builtin_rust_info ("target_env", "");			      \
+  } while (0)
+
 #undef  CPP_SPEC
 #define CPP_SPEC \
  "%(cpp_cpu) %(cpp_arch) %{posix:-D_POSIX_SOURCE}"
diff --git a/gcc/config/freebsd-spec.h b/gcc/config/freebsd-spec.h
index 594487829b5..d0c6ece315f 100644
--- a/gcc/config/freebsd-spec.h
+++ b/gcc/config/freebsd-spec.h
@@ -49,6 +49,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 /* Define the default FreeBSD-specific per-CPU hook code.  */
 #define FBSD_TARGET_CPU_CPP_BUILTINS() do {} while (0)
 
+#define FBSD_TARGET_RUST_OS_INFO()					\
+  do {					\
+    builtin_rust_info ("target_family", "unix");		\
+    builtin_rust_info ("target_os", "freebsd");		\
+    builtin_rust_info ("target_vendor", "unknown"); \
+    builtin_rust_info ("target_env", "");			      \
+    /*TODO: is default per-CPU hook code required here?*/ \
+  } while (0)
+
 /* Provide a CPP_SPEC appropriate for FreeBSD.  We just deal with the GCC 
    option `-posix', and PIC issues.  */
 
diff --git a/gcc/config/freebsd.h b/gcc/config/freebsd.h
index d89ee7dfc97..5748645673c 100644
--- a/gcc/config/freebsd.h
+++ b/gcc/config/freebsd.h
@@ -32,6 +32,11 @@ along with GCC; see the file COPYING3.  If not see
 #undef  TARGET_OS_CPP_BUILTINS
 #define TARGET_OS_CPP_BUILTINS() FBSD_TARGET_OS_CPP_BUILTINS()
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in freebsd.h - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO() FBSD_TARGET_RUST_OS_INFO()
+
 #undef  CPP_SPEC
 #define CPP_SPEC FBSD_CPP_SPEC
 
diff --git a/gcc/config/fuchsia.h b/gcc/config/fuchsia.h
index 0baf6f1f385..98dee35d823 100644
--- a/gcc/config/fuchsia.h
+++ b/gcc/config/fuchsia.h
@@ -68,3 +68,19 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (false)
 
+#ifndef EXTRA_TARGET_RUST_OS_INFO
+#define EXTRA_TARGET_RUST_OS_INFO()
+#endif
+
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in fuchsia.h - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()		\
+  do {		\
+    builtin_rust_info ("target_family", "unix");		\
+	/*NOTE: target_family is subject to change if rustc decides to change it to non-unix*/ \
+    builtin_rust_info ("target_os", "fuchsia");		\
+    builtin_rust_info ("target_vendor", ""); \
+    builtin_rust_info ("target_env", "");			      \
+	EXTRA_TARGET_RUST_OS_INFO();		\
+  } while (0)
diff --git a/gcc/config/gnu.h b/gcc/config/gnu.h
index de2ead82be9..b0707148dd1 100644
--- a/gcc/config/gnu.h
+++ b/gcc/config/gnu.h
@@ -37,3 +37,15 @@ along with GCC.  If not, see <http://www.gnu.org/licenses/>.
 	builtin_version ("Hurd");		\
 	builtin_version ("CRuntime_Glibc");	\
     } while (0)
+
+#define GNU_USER_TARGET_RUST_OS_INFO()                                  \
+  do                                                                    \
+    { /*is this correct? or should os be "hurd"?*/                      \
+      builtin_rust_info ("target_family", "unix");                      \
+      builtin_rust_info ("target_os", "gnu");                           \
+      builtin_rust_info ("target_vendor", "unknown");                   \
+      builtin_rust_info ("target_env", "");                             \
+      /* TODO: is target_env required?*/                                \
+    }                                                                   \
+  while (0)
+
diff --git a/gcc/config/i386/crtdll.h b/gcc/config/i386/crtdll.h
index 75fede50fa0..5112e35389a 100644
--- a/gcc/config/i386/crtdll.h
+++ b/gcc/config/i386/crtdll.h
@@ -31,6 +31,18 @@ along with GCC; see the file COPYING3.  If not see
     }								\
   while (0)
 
+#ifdef EXTRA_TARGET_RUST_OS_INFO
+# error "EXTRA_TARGET_RUST_OS_INFO already defined in crtdll.h (i386) - c++ undefines it and redefines it."
+#endif
+#define EXTRA_TARGET_RUST_OS_INFO()					\
+  do {								\
+    builtin_rust_info ("target_family", "windows");	\
+    builtin_rust_info ("target_os", "windows");	\
+    builtin_rust_info ("target_vendor", "pc");	\
+    /*TODO: is this the right target_env? it says gnu tools up there, but env may change.*/ \
+    builtin_rust_info ("target_env", "gnu");	\
+  } while (0)
+
 #undef LIBGCC_SPEC
 #define LIBGCC_SPEC \
   "%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lcoldname -libmingwex -lcrtdll"
diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h
index 45150458cc5..097592a4617 100644
--- a/gcc/config/i386/cygming.h
+++ b/gcc/config/i386/cygming.h
@@ -151,6 +151,11 @@ along with GCC; see the file COPYING3.  If not see
   }									\
   while (0)
 
+#define TARGET_RUST_OS_INFO()					\
+  do {									\
+  	EXTRA_TARGET_RUST_OS_INFO ();					\
+  } while (0)
+
 /* Get tree.cc to declare a target-specific specialization of
    merge_decl_attributes.  */
 #define TARGET_DLLIMPORT_DECL_ATTRIBUTES 1
diff --git a/gcc/config/i386/cygwin.h b/gcc/config/i386/cygwin.h
index d06eda369cf..7657c2b3649 100644
--- a/gcc/config/i386/cygwin.h
+++ b/gcc/config/i386/cygwin.h
@@ -38,6 +38,16 @@ along with GCC; see the file COPYING3.  If not see
     }								\
   while (0)
 
+#define EXTRA_TARGET_RUST_OS_INFO()					\
+  do {								\
+    /*TODO: derived from llvm triple - rustc has no support for cygwin, but follows llvm triple*/ \
+    /*target_family is defined as unix due to posix-compliance, but this is subject to change*/ \
+    builtin_rust_info ("target_family", "unix");	\
+    builtin_rust_info ("target_os", "windows");	\
+    builtin_rust_info ("target_vendor", "unknown");	\
+    builtin_rust_info ("target_env", "cygnus");	\
+  } while (0)
+
 #undef CPP_SPEC
 #define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE} \
   %{!ansi:-Dunix} \
diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h
index a55f6b2b874..3654a50d158 100644
--- a/gcc/config/i386/darwin.h
+++ b/gcc/config/i386/darwin.h
@@ -40,6 +40,16 @@ along with GCC; see the file COPYING3.  If not see
     darwin_cpp_builtins (pfile);		\
   } while (0)
 
+#define TARGET_RUST_OS_INFO()		\
+  do {								\
+    builtin_rust_info ("target_family", "unix");	\
+    /*TODO: rust actually has "macos", "ios", and "tvos" for darwin targets, but gcc seems to have no*/ \
+    /*current support for them, so assuming that target_os is always macos for now*/ \
+    builtin_rust_info ("target_os", "macos");	\
+    builtin_rust_info ("target_vendor", "apple");	\
+    builtin_rust_info ("target_env", "");	\
+  } while (0)
+
 #undef PTRDIFF_TYPE
 #define PTRDIFF_TYPE (TARGET_64BIT ? "long int" : "int")
 
diff --git a/gcc/config/i386/djgpp.h b/gcc/config/i386/djgpp.h
index 909821e953b..bc65b77470e 100644
--- a/gcc/config/i386/djgpp.h
+++ b/gcc/config/i386/djgpp.h
@@ -57,6 +57,15 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (0)
 
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+    /*rustc has no support for this, so values are taken from rusty-dos' djgpp github issue guesses*/ \
+    builtin_rust_info ("target_family", "windows");	\
+    builtin_rust_info ("target_os", "msdos");	\
+    builtin_rust_info ("target_vendor", "pc");	\
+    builtin_rust_info ("target_env", "djgpp");	\
+  } while (0)
+
 #undef CPP_SPEC
 #define CPP_SPEC "-remap %{posix:-D_POSIX_SOURCE}"
 
diff --git a/gcc/config/i386/gnu-user-common.h b/gcc/config/i386/gnu-user-common.h
index cab9be2bfb7..f95f8c047d6 100644
--- a/gcc/config/i386/gnu-user-common.h
+++ b/gcc/config/i386/gnu-user-common.h
@@ -36,6 +36,11 @@ along with GCC; see the file COPYING3.  If not see
     }								\
   while (0)
 
+#define TARGET_RUST_OS_INFO()				\
+  do {								\
+    GNU_USER_TARGET_RUST_OS_INFO();			\
+  } while (0)
+
 #undef CPP_SPEC
 #define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
 
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index cf847751ac5..da360591e8f 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -281,6 +281,9 @@ extern void ix86_d_target_versions (void);
 extern void ix86_d_register_target_info (void);
 extern bool ix86_d_has_stdcall_convention (unsigned int *, unsigned int *);
 
+/* In i386-rust.cc  */
+extern void ix86_rust_target_cpu_info (void);
+
 /* In winnt.cc  */
 extern void i386_pe_unique_section (tree, int);
 extern void i386_pe_declare_function_type (FILE *, const char *, int);
diff --git a/gcc/config/i386/i386-rust.cc b/gcc/config/i386/i386-rust.cc
new file mode 100644
index 00000000000..1441a63f32c
--- /dev/null
+++ b/gcc/config/i386/i386-rust.cc
@@ -0,0 +1,501 @@
+/* Subroutines for the Rust front end on the x86 architecture.
+   Copyright (C) 2020-2022 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 x86 targets.  */
+
+void
+ix86_rust_target_cpu_info (void)
+{
+    if (TARGET_64BIT) {
+        rust_add_target_info("target_arch", "x86_64");
+
+        if (TARGET_X32) {
+            // this means it uses 32-bit pointers with 64-bit, basically (ILP32)
+            //rust_add_target_info("target_pointer_width", "32");
+            // TODO: may also change x86_64-...-linux-gnu to x86_64-...-linux-gnux32
+
+            // is this better than just putting in pointer width outside of if statement?
+
+            /* TODO: compared to base linux, may also need to change max_atomic_width to 64, add "-mx32"
+             * to pre-link args, make stack_probes true, make has_elf_tls false, make needs_plt true.
+             * Also, still target_endian is "little", target_c_int_width is "32", maybe steal data layout
+             * later from rustc spec, target_os is "linux", target_env is "gnu", target_vendor is "unknown"
+             * There is no rustc support for non-gnu/linux targets with ILP32. */
+        }
+    } else {
+        rust_add_target_info("target_arch", "x86");
+    }
+
+  // features officially "stabilised" in rustc
+  if (TARGET_MMX)
+    rust_add_target_info("target_feature", "mmx");
+  if (TARGET_SSE)
+    rust_add_target_info("target_feature", "sse");
+  if (TARGET_SSE2)
+    rust_add_target_info("target_feature", "sse2");
+  if (TARGET_SSE3)
+    rust_add_target_info("target_feature", "sse3");
+  if (TARGET_SSSE3)
+    rust_add_target_info("target_feature", "ssse3");
+  if (TARGET_SSE4_1)
+    rust_add_target_info("target_feature", "sse4.1");
+  if (TARGET_SSE4_2)
+    rust_add_target_info("target_feature", "sse4.2");
+  if (TARGET_AES)
+    rust_add_target_info("target_feature", "aes");
+  if (TARGET_SHA)
+    rust_add_target_info("target_feature", "sha");
+  if (TARGET_AVX)
+    rust_add_target_info("target_feature", "avx");
+  if (TARGET_AVX2)
+    rust_add_target_info("target_feature", "avx2");
+  if (TARGET_AVX512F)
+    rust_add_target_info("target_feature", "avx512f");
+  if (TARGET_AVX512ER)
+    rust_add_target_info("target_feature", "avx512er");
+  if (TARGET_AVX512CD)
+    rust_add_target_info("target_feature", "avx512cd");
+  if (TARGET_AVX512PF)
+    rust_add_target_info("target_feature", "avx512pf");
+  if (TARGET_AVX512DQ)
+    rust_add_target_info("target_feature", "avx512dq");
+  if (TARGET_AVX512BW)
+    rust_add_target_info("target_feature", "avx512bw");
+  if (TARGET_AVX512VL)
+    rust_add_target_info("target_feature", "avx512vl");
+  if (TARGET_AVX512VBMI)
+    rust_add_target_info("target_feature", "avx512vbmi");
+  if (TARGET_AVX512IFMA)
+    rust_add_target_info("target_feature", "avx512ifma");
+  if (TARGET_AVX512VPOPCNTDQ)
+    rust_add_target_info("target_feature", "avx512vpopcntdq");
+  if (TARGET_FMA)
+    rust_add_target_info("target_feature", "fma");
+  if (TARGET_RTM)
+    rust_add_target_info("target_feature", "rtm");
+  if (TARGET_SSE4A)
+    rust_add_target_info("target_feature", "sse4a");
+  if (TARGET_BMI) {
+    rust_add_target_info("target_feature", "bmi1");
+    rust_add_target_info("target_feature", "bmi");
+  }
+  if (TARGET_BMI2)
+    rust_add_target_info("target_feature", "bmi2");
+  if (TARGET_LZCNT)
+    rust_add_target_info("target_feature", "lzcnt");
+  if (TARGET_TBM)
+    rust_add_target_info("target_feature", "tbm");
+  if (TARGET_POPCNT)
+    rust_add_target_info("target_feature", "popcnt");
+  if (TARGET_RDRND) {
+    rust_add_target_info("target_feature", "rdrand");
+    rust_add_target_info("target_feature", "rdrnd");
+  }
+  if (TARGET_F16C)
+    rust_add_target_info("target_feature", "f16c");
+  if (TARGET_RDSEED)
+    rust_add_target_info("target_feature", "rdseed");
+  if (TARGET_ADX)
+    rust_add_target_info("target_feature", "adx");
+  if (TARGET_FXSR)
+    rust_add_target_info("target_feature", "fxsr");
+  if (TARGET_XSAVE)
+    rust_add_target_info("target_feature", "xsave");
+  if (TARGET_XSAVEOPT)
+    rust_add_target_info("target_feature", "xsaveopt");
+  if (TARGET_XSAVEC)
+    rust_add_target_info("target_feature", "xsavec");
+  if (TARGET_XSAVES)
+    rust_add_target_info("target_feature", "xsaves");
+  if (TARGET_VPCLMULQDQ) {
+    rust_add_target_info("target_feature", "pclmulqdq");
+    rust_add_target_info("target_feature", "vpclmulqdq");
+  }
+  if (TARGET_CMPXCHG16B)
+    rust_add_target_info("target_feature", "cmpxchg16b");
+  if (TARGET_MOVBE)
+    rust_add_target_info("target_feature", "movbe");
+
+  // features derived from llvm not yet in rustc:
+  if (TARGET_64BIT)
+    rust_add_target_info("target_feature", "64bit-mode");
+  else if (TARGET_CODE16)
+    rust_add_target_info("target_feature", "16bit-mode");
+  else
+    rust_add_target_info("target_feature", "32bit-mode");
+  
+  // TODO: assuming that the TARGET_80387 (which seems to mean "hard float") is also required for x87
+  if (TARGET_80387 && (ix86_fpmath & FPMATH_387) != 0)
+    rust_add_target_info("target_feature", "x87");
+
+  // nopl: hard-coded (as gcc doesn't technically have feature) to return true for cpu arches with it
+  // maybe refactor into switch if multiple options
+  bool hasNOPL = ix86_arch == PROCESSOR_PENTIUMPRO || ix86_arch == PROCESSOR_PENTIUM4 
+    || ix86_arch == PROCESSOR_NOCONA || ix86_arch == PROCESSOR_CORE2 || ix86_arch == PROCESSOR_NEHALEM 
+    || ix86_arch == PROCESSOR_BONNELL || ix86_arch == PROCESSOR_SILVERMONT 
+    || ix86_arch == PROCESSOR_GOLDMONT || ix86_arch == PROCESSOR_GOLDMONT_PLUS 
+    || ix86_arch == PROCESSOR_TREMONT || ix86_arch == PROCESSOR_SANDYBRIDGE 
+    || ix86_arch == PROCESSOR_HASWELL || ix86_arch == PROCESSOR_SKYLAKE 
+    || ix86_arch == PROCESSOR_SKYLAKE_AVX512 || ix86_arch == PROCESSOR_CANNONLAKE 
+    || ix86_arch == PROCESSOR_CASCADELAKE  || ix86_arch == PROCESSOR_COOPERLAKE 
+    || ix86_arch == PROCESSOR_ICELAKE_CLIENT || ix86_arch == PROCESSOR_ICELAKE_SERVER 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_KNL || ix86_arch == PROCESSOR_KNM 
+    || ix86_arch == PROCESSOR_AMDFAM10 || ix86_arch == PROCESSOR_BTVER1 || ix86_arch == PROCESSOR_BTVER2 
+    || ix86_arch == PROCESSOR_BDVER1 || ix86_arch == PROCESSOR_BDVER2 || ix86_arch == PROCESSOR_BDVER3 
+    || ix86_arch == PROCESSOR_BDVER4 || ix86_arch == PROCESSOR_ZNVER1 || ix86_arch == PROCESSOR_ZNVER2 
+    || ix86_arch == PROCESSOR_ATHLON || ix86_arch == PROCESSOR_K8; 
+  // this list should be exhaustive
+  if (hasNOPL)
+    rust_add_target_info("target_feature", "nopl");
+  if (TARGET_CMOVE)
+    rust_add_target_info("target_feature", "cmov");
+  if (TARGET_CMPXCHG8B)
+    rust_add_target_info("target_feature", "cx8");
+  if (TARGET_3DNOW)
+    rust_add_target_info("target_feature", "3dnow");
+  if (TARGET_3DNOW_A)
+    rust_add_target_info("target_feature", "3dnowa");
+  if (TARGET_64BIT)
+    rust_add_target_info("target_feature", "64bit");
+  if (TARGET_CMPXCHG16B)
+    rust_add_target_info("target_feature", "cx16");
+
+  bool hasSlowSHLD = ix86_arch == PROCESSOR_AMDFAM10 || ix86_arch == PROCESSOR_BTVER1 
+    || ix86_arch == PROCESSOR_BTVER2 || ix86_arch == PROCESSOR_BDVER1 || ix86_arch == PROCESSOR_BDVER2 
+    || ix86_arch == PROCESSOR_BDVER3 || ix86_arch == PROCESSOR_BDVER4 || ix86_arch == PROCESSOR_ZNVER1 
+    || ix86_arch == PROCESSOR_ZNVER2 || ix86_arch == PROCESSOR_ATHLON || ix86_arch == PROCESSOR_K8; 
+  // TODO: this is not ideal as it marks the baseline x86-64 CPU as having it - only AMD ones do
+  if (hasSlowSHLD)
+    rust_add_target_info("target_feature", "slow-shld");
+  if (ix86_arch == PROCESSOR_SILVERMONT)
+    rust_add_target_info("target_feature", "slow-pmulld");
+  if (ix86_arch == PROCESSOR_KNL || ix86_arch == PROCESSOR_KNM)
+    rust_add_target_info("target_feature", "slow-pmaddwd");
+
+  bool hasSlowUnaligned16 = ix86_arch == PROCESSOR_BONNELL || ix86_arch == PROCESSOR_GENERIC 
+    || ix86_arch == PROCESSOR_I386 || ix86_arch == PROCESSOR_I486 || ix86_arch == PROCESSOR_PENTIUM 
+    || ix86_arch == PROCESSOR_PENTIUMPRO || ix86_arch == PROCESSOR_PENTIUM4 
+    || ix86_arch == PROCESSOR_NOCONA || ix86_arch == PROCESSOR_CORE2 || ix86_arch == PROCESSOR_K6 
+    || ix86_arch == PROCESSOR_ATHLON || ix86_arch == PROCESSOR_K8 || ix86_arch == PROCESSOR_GEODE;
+  if (hasSlowUnaligned16)
+    rust_add_target_info("target_feature", "slow-unaligned-mem-16");
+  if (ix86_arch == PROCESSOR_SANDYBRIDGE)
+    rust_add_target_info("target_feature", "slow-unaligned-mem-32");
+  if (TARGET_PREFETCHWT1)
+    rust_add_target_info("target_feature", "prefetchwt1");
+  if (TARGET_AVX512VBMI2)
+    rust_add_target_info("target_feature", "avx512vbmi2");
+  if (TARGET_PKU)
+    rust_add_target_info("target_feature", "pku");
+  if (TARGET_AVX512VNNI)
+    rust_add_target_info("target_feature", "avx512vnni");
+  if (TARGET_AVX512BF16)
+    rust_add_target_info("target_feature", "avx512bf16");
+  if (TARGET_AVX512BITALG)
+    rust_add_target_info("target_feature", "avx512bitalg");
+  if (TARGET_AVX512VP2INTERSECT)
+    rust_add_target_info("target_feature", "avx512vp2intersect");
+  if (TARGET_PCLMUL)
+    rust_add_target_info("target_feature", "pclmul");
+  if (TARGET_GFNI)
+    rust_add_target_info("target_feature", "gfni");
+  if (TARGET_FMA4)
+    rust_add_target_info("target_feature", "fma4");
+  if (TARGET_XOP)
+    rust_add_target_info("target_feature", "xop");
+
+  // this is only enabled by choice in llvm, never by default - TODO determine if gcc enables it
+  // rust_add_target_info("target_feature", "sse-unaligned-mem");
+
+  if (TARGET_VAES)
+    rust_add_target_info("target_feature", "vaes");
+  if (TARGET_LWP)
+    rust_add_target_info("target_feature", "lwp");
+  if (TARGET_FSGSBASE)
+    rust_add_target_info("target_feature", "fsgsbase");
+  if (TARGET_SHSTK)
+    rust_add_target_info("target_feature", "shstk");
+  if (TARGET_PRFCHW)
+    rust_add_target_info("target_feature", "prfchw");
+  if (TARGET_SAHF) // would this be better as TARGET_USE_SAHF?
+    rust_add_target_info("target_feature", "sahf");
+  if (TARGET_MWAITX)
+    rust_add_target_info("target_feature", "mwaitx");
+  if (TARGET_CLZERO)
+    rust_add_target_info("target_feature", "clzero");
+  if (TARGET_CLDEMOTE)
+    rust_add_target_info("target_feature", "cldemote");
+  if (TARGET_PTWRITE)
+    rust_add_target_info("target_feature", "ptwrite");
+  // TODO: add amx-tile, amx-int8, amx-bf16 features when gcc supports them 
+
+  // TODO: can't find any gcc option relating to using LEA for adjusting stack pointer, so hardcoding
+  if (ix86_arch == PROCESSOR_BONNELL)
+    rust_add_target_info("target_feature", "lea-sp");
+
+  // TODO: confirm that this is what it actually refers to
+  if (TARGET_USE_8BIT_IDIV)
+    rust_add_target_info("target_feature", "idivl-to-divb");
+
+  /* TODO: can't find any gcc option corresponding to idivq-to-divl - does gcc perform this optimisation?
+   * if so, add that feature (use 32-bit divide for positive values less than 2^32) */
+  /* bool llvmHasSlowDivide64 = ix86_arch == PROCESSOR_SANDYBRIDGE || ix86_arch == PROCESSOR_HASWELL 
+    || ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_CASCADELAKE 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_COOPERLAKE 
+    || ix86_arch == PROCESSOR_BONNELL || ix86_arch == PROCESSOR_SILVERMONT || ix86_arch == PROCESSOR_KNL 
+    || ix86_arch == PROCESSOR_KNM || ix86_arch == PROCESSOR_K8;*/
+
+  if (TARGET_PAD_SHORT_FUNCTION)
+    rust_add_target_info("target_feature", "pad-short-functions");
+
+  // TODO: gcc seems to not record whether INVPCID exists, so basing it on llvm
+  bool hasINVPCID = ix86_arch == PROCESSOR_HASWELL || ix86_arch == PROCESSOR_SKYLAKE 
+    || ix86_arch == PROCESSOR_SKYLAKE_AVX512 || ix86_arch == PROCESSOR_CANNONLAKE 
+    || ix86_arch == PROCESSOR_ICELAKE_CLIENT || ix86_arch == PROCESSOR_ICELAKE_SERVER 
+    || ix86_arch == PROCESSOR_CASCADELAKE || ix86_arch == PROCESSOR_TIGERLAKE 
+    || ix86_arch == PROCESSOR_COOPERLAKE; 
+  if (hasINVPCID)
+    rust_add_target_info("target_feature", "invpcid");
+  if (TARGET_SGX)
+    rust_add_target_info("target_feature", "sgx");
+  if (TARGET_CLFLUSHOPT)
+    rust_add_target_info("target_feature", "clflushopt");
+  if (TARGET_CLWB)
+    rust_add_target_info("target_feature", "clwb");
+  if (TARGET_WBNOINVD)
+    rust_add_target_info("target_feature", "wbnoinvd");
+  if (TARGET_RDPID)
+    rust_add_target_info("target_feature", "rdpid");
+  if (TARGET_WAITPKG)
+    rust_add_target_info("target_feature", "waitpkg");
+  if (TARGET_ENQCMD)
+    rust_add_target_info("target_feature", "enqcmd");
+
+  // these are only enabled by choice in llvm, never by default - TODO determine if gcc supports them
+  // rust_add_target_info("target_feature", "serialize");
+  // rust_add_target_info("target_feature", "tsxldtrk");
+
+  // TODO: gcc seems to not record whether to avoid memory operanded instructions, so basing it on llvm
+  bool hasSlowTwoMemOps = ix86_arch == PROCESSOR_BONNELL || ix86_arch == PROCESSOR_SILVERMONT 
+    || ix86_arch == PROCESSOR_GOLDMONT || ix86_arch == PROCESSOR_GOLDMONT_PLUS 
+    || ix86_arch == PROCESSOR_TREMONT || ix86_arch == PROCESSOR_KNL || ix86_arch == PROCESSOR_KNM; 
+  if (hasSlowTwoMemOps)
+    rust_add_target_info("target_feature", "slow-two-mem-ops");
+
+  // TODO: gcc seems to not record whether LEA needs input at AG stage, so basing it on llvm
+  // TODO: maybe something to do with X86_TUNE_OPT_AGU?
+  if (ix86_arch == PROCESSOR_BONNELL)
+    rust_add_target_info("target_feature", "lea-uses-ag");
+
+  // TODO: gcc seems to not record whether LEA with certain arguments is slow, so basing it on llvm
+  // TODO: maybe TARGET_AVOID_LEA_FOR_ADDR has something to do with it?
+  bool hasSlowLEA = ix86_arch == PROCESSOR_SILVERMONT || ix86_arch == PROCESSOR_GOLDMONT 
+    || ix86_arch == PROCESSOR_GOLDMONT_PLUS || ix86_arch == PROCESSOR_TREMONT;
+  if (hasSlowLEA)
+    rust_add_target_info("target_feature", "slow-lea");
+  
+  // TODO: gcc seems to not record whether LEA with 3 ops or certain regs is slow, so basing it on llvm
+  // TODO: maybe TARGET_AVOID_LEA_FOR_ADDR has something to do with it?
+  bool hasSlow3OpsLEA = ix86_arch == PROCESSOR_SANDYBRIDGE || ix86_arch == PROCESSOR_HASWELL 
+    || ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_CASCADELAKE 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_COOPERLAKE 
+    || ix86_arch == PROCESSOR_KNL || ix86_arch == PROCESSOR_KNM || ix86_arch == PROCESSOR_K8; 
+  if (hasSlow3OpsLEA)
+    rust_add_target_info("target_feature", "slow-3ops-lea");
+
+  // TODO: assuming that this is equivalent option - it strictly doesn't cover same cpus
+  if (!TARGET_USE_INCDEC)
+    rust_add_target_info("target_feature", "slow-incdec");
+  // TODO: assuming that this mask actually refers to "hard float" and not x87 specifically
+  if (!TARGET_80387)
+    rust_add_target_info("target_feature", "soft-float");
+
+  // TODO: gcc seems to not record if LZCNT/TZCNT has false deps on dest register, so basing it on llvm
+  if (ix86_arch == PROCESSOR_HASWELL)
+    rust_add_target_info("target_feature", "false-deps-lzcnt-tzcnt");
+
+  if (TARGET_PCONFIG)
+    rust_add_target_info("target_feature", "pconfig");
+
+  // TODO: gcc seems to not record if variable-mask shuffles are fast, so basing it on llvm
+  bool hasFastVariableShuffle = ix86_arch == PROCESSOR_HASWELL || ix86_arch == PROCESSOR_SKYLAKE 
+    || ix86_arch == PROCESSOR_SKYLAKE_AVX512 || ix86_arch == PROCESSOR_CANNONLAKE 
+    || ix86_arch == PROCESSOR_ICELAKE_CLIENT || ix86_arch == PROCESSOR_ICELAKE_SERVER 
+    || ix86_arch == PROCESSOR_CASCADELAKE || ix86_arch == PROCESSOR_TIGERLAKE 
+    || ix86_arch == PROCESSOR_COOPERLAKE; 
+  if (hasFastVariableShuffle)
+    rust_add_target_info("target_feature", "fast-variable-shuffle");
+
+  // TODO: ensure that this actually refers to the right thing - difference in gcc and llvm description
+  if (TARGET_VZEROUPPER)
+    rust_add_target_info("target_feature", "vzeroupper");
+
+  // option based on llvm arch analysis as gcc tuning costs seem to indicate a different result
+  bool hasFastScalarFSQRT = ix86_arch == PROCESSOR_SANDYBRIDGE || ix86_arch == PROCESSOR_HASWELL 
+    || ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_CASCADELAKE 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_COOPERLAKE;
+  if (hasFastScalarFSQRT)
+    rust_add_target_info("target_feature", "fast-scalar-fsqrt");
+
+  // option also based on llvm arch analysis 
+  bool hasFastVectorFSQRT = ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_CASCADELAKE 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_COOPERLAKE;
+  if (hasFastVectorFSQRT)
+    rust_add_target_info("target_feature", "fast-vector-fsqrt");
+
+  bool hasFastLZCNT = ix86_arch == PROCESSOR_BTVER2 || ix86_arch == PROCESSOR_ZNVER1 
+    || ix86_arch == PROCESSOR_ZNVER2;
+  if (hasFastLZCNT)
+    rust_add_target_info("target_feature", "fast-lzcnt");
+
+  if (ix86_arch == PROCESSOR_SILVERMONT)
+    rust_add_target_info("target_feature", "fast-7bytenop");
+
+  bool hasFast11ByteNOP = ix86_arch == PROCESSOR_BDVER1 || ix86_arch == PROCESSOR_BDVER2 
+    || ix86_arch == PROCESSOR_BDVER3 || ix86_arch == PROCESSOR_BDVER4;
+  if (hasFast11ByteNOP)
+    rust_add_target_info("target_feature", "fast-11bytenop");
+
+  bool hasFast15ByteNOP = ix86_arch == PROCESSOR_SANDYBRIDGE || ix86_arch == PROCESSOR_HASWELL 
+    || ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_CASCADELAKE 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_COOPERLAKE 
+    || ix86_arch == PROCESSOR_BTVER1 || ix86_arch == PROCESSOR_BTVER2
+    || ix86_arch == PROCESSOR_ZNVER1 || ix86_arch == PROCESSOR_ZNVER2;
+  if (hasFast15ByteNOP)
+    rust_add_target_info("target_feature", "fast-15bytenop");
+
+  bool hasFastSHLDRotate = ix86_arch == PROCESSOR_SANDYBRIDGE || ix86_arch == PROCESSOR_HASWELL 
+    || ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_CASCADELAKE 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_COOPERLAKE;
+  if (hasFastSHLDRotate)
+    rust_add_target_info("target_feature", "fast-shld-rotate");
+
+  bool hasERMSB = ix86_arch == PROCESSOR_HASWELL || ix86_arch == PROCESSOR_SKYLAKE 
+    || ix86_arch == PROCESSOR_SKYLAKE_AVX512 || ix86_arch == PROCESSOR_CANNONLAKE 
+    || ix86_arch == PROCESSOR_ICELAKE_CLIENT || ix86_arch == PROCESSOR_ICELAKE_SERVER 
+    || ix86_arch == PROCESSOR_CASCADELAKE || ix86_arch == PROCESSOR_TIGERLAKE 
+    || ix86_arch == PROCESSOR_COOPERLAKE; 
+  if (hasERMSB)
+    rust_add_target_info("target_feature", "ermsbd");
+
+  // TODO: may exist in gcc as tune macros, but not sure, so based on llvm arches
+  bool hasBranchFusion = ix86_arch == PROCESSOR_BDVER1 || ix86_arch == PROCESSOR_BDVER2 
+    || ix86_arch == PROCESSOR_BDVER3 || ix86_arch == PROCESSOR_BDVER4 || ix86_arch == PROCESSOR_ZNVER1 
+    || ix86_arch == PROCESSOR_ZNVER2;
+  if (hasBranchFusion)
+    rust_add_target_info("target_feature", "branchfusion");
+
+  // TODO: again, may exist as tune macros, but again based on llvm arches
+  bool hasMacroFusion = ix86_arch == PROCESSOR_CORE2 || ix86_arch == PROCESSOR_NEHALEM 
+    || ix86_arch == PROCESSOR_SANDYBRIDGE || ix86_arch == PROCESSOR_HASWELL 
+    || ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_CASCADELAKE 
+    || ix86_arch == PROCESSOR_TIGERLAKE || ix86_arch == PROCESSOR_COOPERLAKE || ix86_arch == PROCESSOR_K8;
+  if (hasMacroFusion)
+    rust_add_target_info("target_feature", "macrofusion");
+
+  // TODO: is this equivalent to TARGET_USE_GATHER?
+  bool hasFastGather = ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512 
+    || ix86_arch == PROCESSOR_CASCADELAKE || ix86_arch == PROCESSOR_COOPERLAKE 
+    || ix86_arch == PROCESSOR_CANNONLAKE || ix86_arch == PROCESSOR_ICELAKE_CLIENT 
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER || ix86_arch == PROCESSOR_TIGERLAKE 
+    || ix86_arch == PROCESSOR_KNL || ix86_arch == PROCESSOR_KNM;
+  if (hasFastGather)
+    rust_add_target_info("target_feature", "fast-gather");
+
+  if (TARGET_PREFER_AVX128)
+    rust_add_target_info("target_feature", "prefer-128-bit");
+  if (TARGET_PREFER_AVX256)
+    rust_add_target_info("target_feature", "prefer-256-bit");
+
+  bool preferMaskRegisters = ix86_arch == PROCESSOR_KNL || ix86_arch == PROCESSOR_KNM;
+  if (preferMaskRegisters)
+    rust_add_target_info("target_feature", "prefer-mask-registers");
+
+  /* TODO: add retpoline-indirect-calls, retpoline-indirect-branches, retpoline, retpoline-external-thunk, 
+   * lvi-cfi (LVI control flow integrity), seses (speculative execution side-effect suppression)
+   * lvi-load-hardening if gcc gets support */
+
+  if (TARGET_MOVDIRI)
+    rust_add_target_info("target_feature", "movdiri");
+  if (TARGET_MOVDIR64B)
+    rust_add_target_info("target_feature", "movdir64b");
+
+  bool hasFastBEXTR = ix86_arch == PROCESSOR_BTVER2 || ix86_arch == PROCESSOR_BDVER2 
+    || ix86_arch == PROCESSOR_BDVER3 || ix86_arch == PROCESSOR_BDVER4 || ix86_arch == PROCESSOR_ZNVER1 
+    || ix86_arch == PROCESSOR_ZNVER2;
+  if (hasFastBEXTR)
+    rust_add_target_info("target_feature", "fast-bextr");
+
+  if (ix86_arch == PROCESSOR_BTVER2)
+    rust_add_target_info("target_feature", "fast-hops");
+
+  bool hasFastScalarShiftMasks = ix86_arch == PROCESSOR_AMDFAM10 || ix86_arch == PROCESSOR_BTVER1 
+    || ix86_arch == PROCESSOR_BTVER2 || ix86_arch == PROCESSOR_BDVER1 || ix86_arch == PROCESSOR_BDVER2 
+    || ix86_arch == PROCESSOR_BDVER3 || ix86_arch == PROCESSOR_BDVER4 || ix86_arch == PROCESSOR_ZNVER1 
+    || ix86_arch == PROCESSOR_ZNVER2 || ix86_arch == PROCESSOR_K8;
+  if (hasFastScalarShiftMasks)
+    rust_add_target_info("target_feature", "fast-scalar-shift-masks");
+
+  bool hasFastVectorShiftMasks = ix86_arch == PROCESSOR_BTVER1 || ix86_arch == PROCESSOR_BTVER2;
+  if (hasFastVectorShiftMasks)
+    rust_add_target_info("target_feature", "fast-vector-shift-masks");
+
+  bool useGoldmontDivSqrtCosts = ix86_arch == PROCESSOR_GOLDMONT || ix86_arch == PROCESSOR_GOLDMONT_PLUS 
+    || ix86_arch == PROCESSOR_TREMONT;
+  if (useGoldmontDivSqrtCosts)
+    rust_add_target_info("target_feature", "use-glm-div-sqrt-costs");
+  
+  // TODO: determine if gcc supports alias analysis (in which case "use-aa" is defined)
+
+  // features not supported by llvm but important enough for c frontend to define macros for
+  /*if (TARGET_AVX5124VNNIW)
+    rust_add_target_info("target_feature", "avx5124vnniw");
+  if (TARGET_AVX5124FMAPS)
+    rust_add_target_info("target_feature", "avx5124fmaps");
+  if (TARGET_ABM)
+    rust_add_target_info("target_feature", "abm");
+  if ((ix86_fpmath & FPMATH_SSE) && TARGET_SSE)
+    ; //def_or_undef (parse_in, "__SSE_MATH__");
+  if ((ix86_fpmath & FPMATH_SSE) && TARGET_SSE2)
+    ; //def_or_undef (parse_in, "__SSE2_MATH__");
+  if (TARGET_MMX_WITH_SSE)
+    ; //def_or_undef (parse_in, "__MMX_WITH_SSE__");
+  if (TARGET_IAMCU)
+    rust_add_target_info("target_feature", "iamcu");*/
+}
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index f16df633e84..93d5de5cd61 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -613,6 +613,9 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
 #define TARGET_D_REGISTER_CPU_TARGET_INFO ix86_d_register_target_info
 #define TARGET_D_HAS_STDCALL_CONVENTION ix86_d_has_stdcall_convention
 
+/* Target CPU info for Rust.  */
+#define TARGET_RUST_CPU_INFO ix86_rust_target_cpu_info 
+
 #ifndef CC1_SPEC
 #define CC1_SPEC "%(cc1_cpu) "
 #endif
diff --git a/gcc/config/i386/linux-common.h b/gcc/config/i386/linux-common.h
index efa7fb2072c..25aa5f368f2 100644
--- a/gcc/config/i386/linux-common.h
+++ b/gcc/config/i386/linux-common.h
@@ -30,6 +30,23 @@ along with GCC; see the file COPYING3.  If not see
 #define EXTRA_TARGET_D_OS_VERSIONS()		\
   ANDROID_TARGET_D_OS_VERSIONS();
 
+#define EXTRA_TARGET_RUST_OS_INFO()		\
+  ANDROID_TARGET_RUST_OS_INFO();
+// TODO: decide on whether following c frontend style or d one - leaning towards c
+
+
+/*#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in linux-common.h (i386) - c++ undefines it and redefines it."
+# error "note that this above error (linux-common-i386) is expected due to already defining EXTRA_TARGET stuff"
+#endif*/
+/* This is previously defined in gnu-user-common.h, but has no linux-specific info.  */
+#undef TARGET_RUST_OS_INFO 
+#define TARGET_RUST_OS_INFO()               \
+  do {                                      \
+    GNU_USER_TARGET_RUST_OS_INFO();         \
+    ANDROID_TARGET_RUST_OS_INFO();          \
+  } while (0)
+
 #undef CC1_SPEC
 #define CC1_SPEC \
   LINUX_OR_ANDROID_CC (GNU_USER_TARGET_CC1_SPEC, \
diff --git a/gcc/config/i386/lynx.h b/gcc/config/i386/lynx.h
index baa62c14986..ecc10264dde 100644
--- a/gcc/config/i386/lynx.h
+++ b/gcc/config/i386/lynx.h
@@ -25,6 +25,15 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (0)
 
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+    /*TODO: not supported by rustc and so subject to change - based on llvm triple*/ \
+    builtin_rust_info ("target_family", "unix");	\
+    builtin_rust_info ("target_os", "lynxos");	\
+    builtin_rust_info ("target_vendor", "unknown");	\
+    builtin_rust_info ("target_env", "");	\
+  } while (0)
+
 /* The svr4 ABI for the i386 says that records and unions are returned
    in memory.  */
 
diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h
index d3ca0cd0279..e5381de9f90 100644
--- a/gcc/config/i386/mingw32.h
+++ b/gcc/config/i386/mingw32.h
@@ -65,6 +65,14 @@ along with GCC; see the file COPYING3.  If not see
     }								\
   while (0)
 
+#define EXTRA_TARGET_RUST_OS_INFO()					\
+  do {								\
+    builtin_rust_info ("target_family", "windows");	\
+    builtin_rust_info ("target_os", "windows");	\
+    builtin_rust_info ("target_vendor", "pc");	\
+    builtin_rust_info ("target_env", "gnu");	\
+  } while (0)
+
 #ifndef TARGET_USE_PTHREAD_BY_DEFAULT
 #define SPEC_PTHREAD1 "pthread"
 #define SPEC_PTHREAD2 "!no-pthread"
diff --git a/gcc/config/i386/netbsd-elf.h b/gcc/config/i386/netbsd-elf.h
index b1d7d484ce7..aa60438ea77 100644
--- a/gcc/config/i386/netbsd-elf.h
+++ b/gcc/config/i386/netbsd-elf.h
@@ -26,6 +26,11 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (0)
 
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+    NETBSD_TARGET_RUST_OS_INFO();		\
+  } while (0)
+
 
 /* Extra specs needed for NetBSD/i386 ELF.  */
 
diff --git a/gcc/config/i386/netbsd64.h b/gcc/config/i386/netbsd64.h
index 656fd45af6f..7eba96b9ec0 100644
--- a/gcc/config/i386/netbsd64.h
+++ b/gcc/config/i386/netbsd64.h
@@ -26,6 +26,11 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (0)
 
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+    NETBSD_TARGET_RUST_OS_INFO();		\
+  } while (0)
+
 
 /* Extra specs needed for NetBSD/x86-64 ELF.  */
 
diff --git a/gcc/config/i386/nto.h b/gcc/config/i386/nto.h
index 5df300918d9..6b92d5924be 100644
--- a/gcc/config/i386/nto.h
+++ b/gcc/config/i386/nto.h
@@ -36,6 +36,18 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (0)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in nto.h (i386) - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+    /*TODO: not supported by rustc and so subject to change - based on triple found online*/ \
+    builtin_rust_info ("target_family", "unix");	\
+    builtin_rust_info ("target_os", "nto");	\
+    builtin_rust_info ("target_vendor", "pc");	\
+    builtin_rust_info ("target_env", "qnx");	\
+  } while (0)
+
 #undef THREAD_MODEL_SPEC
 #define THREAD_MODEL_SPEC "posix"
 
diff --git a/gcc/config/i386/openbsdelf.h b/gcc/config/i386/openbsdelf.h
index 2176e79495c..060ae0f6afa 100644
--- a/gcc/config/i386/openbsdelf.h
+++ b/gcc/config/i386/openbsdelf.h
@@ -25,6 +25,11 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (0)
 
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+    OPENBSD_TARGET_RUST_OS_INFO();		\
+  } while (0)
+
 #undef DBX_REGISTER_NUMBER
 #define DBX_REGISTER_NUMBER(n) \
   (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n])
diff --git a/gcc/config/i386/rdos.h b/gcc/config/i386/rdos.h
index 9549977cbf8..c185d0efc2f 100644
--- a/gcc/config/i386/rdos.h
+++ b/gcc/config/i386/rdos.h
@@ -37,3 +37,14 @@ along with GCC; see the file COPYING3.  If not see
       builtin_assert ("system=rdos");		\
     }						\
   while (0)
+
+#define TARGET_RUST_OS_INFO()		\
+  do {						\
+    /*TODO: not supported by rustc and so subject to change - based on triple found online*/ \
+    /*this seems to not refer to the 70s Data General RDOS, but one partly compatible with win32*/ \
+    /*as such, target_family could be windows*/ \
+    builtin_rust_info ("target_family", "");	\
+    builtin_rust_info ("target_os", "rdos");	\
+    builtin_rust_info ("target_vendor", "pc");	\
+    builtin_rust_info ("target_env", "");	\
+  } while (0)
diff --git a/gcc/config/i386/rtemself.h b/gcc/config/i386/rtemself.h
index a6035ffdad1..2f1cbdaf23f 100644
--- a/gcc/config/i386/rtemself.h
+++ b/gcc/config/i386/rtemself.h
@@ -33,3 +33,13 @@
 	builtin_assert ("system=rtems");	\
     }						\
   while (0)
+
+#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*/ \
+    builtin_rust_info ("target_family", "unix");			\
+    builtin_rust_info ("target_os", "rtems");			\
+    builtin_rust_info ("target_vendor", "unknown");			\
+    builtin_rust_info ("target_env", "");			\
+  } while (0)
diff --git a/gcc/config/i386/t-i386 b/gcc/config/i386/t-i386
index 4e2a0efc615..61ddfcab6ba 100644
--- a/gcc/config/i386/t-i386
+++ b/gcc/config/i386/t-i386
@@ -46,6 +46,10 @@ i386-d.o: $(srcdir)/config/i386/i386-d.cc
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+i386-rust.o: $(srcdir)/config/i386/i386-rust.cc
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
 i386-options.o: $(srcdir)/config/i386/i386-options.cc
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gcc/config/i386/vxworks.h b/gcc/config/i386/vxworks.h
index 3b8eb6f3a59..af1f42abcb3 100644
--- a/gcc/config/i386/vxworks.h
+++ b/gcc/config/i386/vxworks.h
@@ -113,6 +113,11 @@ along with GCC; see the file COPYING3.  If not see
     }							\
   while (0)
 
+#define TARGET_RUST_OS_INFO()			\
+  do {							\
+    VXWORKS_TARGET_RUST_OS_INFO();			\
+  } while (0)
+
 #undef  CPP_SPEC
 #define CPP_SPEC VXWORKS_ADDITIONAL_CPP_SPEC
 #undef  CC1_SPEC
diff --git a/gcc/config/kfreebsd-gnu.h b/gcc/config/kfreebsd-gnu.h
index f74a627bc43..d8892bf4bc5 100644
--- a/gcc/config/kfreebsd-gnu.h
+++ b/gcc/config/kfreebsd-gnu.h
@@ -35,6 +35,14 @@ along with GCC; see the file COPYING3.  If not see
 	builtin_version ("CRuntime_Glibc");	\
     } while (0)
 
+#define GNU_USER_TARGET_RUST_OS_INFO()		\
+    do {					\
+  builtin_rust_info ("target_family", "unix");			\
+  builtin_rust_info ("target_os", "kfreebsd");			\
+  builtin_rust_info ("target_vendor", "unknown");			\
+  builtin_rust_info ("target_env", "gnu");			\
+    } while (0)
+
 #define GNU_USER_DYNAMIC_LINKER        GLIBC_DYNAMIC_LINKER
 #define GNU_USER_DYNAMIC_LINKER32      GLIBC_DYNAMIC_LINKER32
 #define GNU_USER_DYNAMIC_LINKER64      GLIBC_DYNAMIC_LINKER64
diff --git a/gcc/config/kopensolaris-gnu.h b/gcc/config/kopensolaris-gnu.h
index 8379f960b8b..bdeb29a635d 100644
--- a/gcc/config/kopensolaris-gnu.h
+++ b/gcc/config/kopensolaris-gnu.h
@@ -36,5 +36,17 @@ along with GCC; see the file COPYING3.  If not see
 	builtin_version ("CRuntime_Glibc");	\
     } while (0)
 
+#ifdef GNU_USER_TARGET_RUST_OS_INFO
+# error # error "TARGET_RUST_OS_INFO already defined in kopensolaris-gnu.h - c++ undefines it and redefines it."
+#endif
+#define GNU_USER_TARGET_RUST_OS_INFO()		\
+    do {					\
+  builtin_rust_info ("target_family", "unix");			\
+  builtin_rust_info ("target_os", "kopensolaris");			\
+  /*the target_os is maybe not right but i can't find any better atm*/ \
+  builtin_rust_info ("target_vendor", "unknown");			\
+  builtin_rust_info ("target_env", "gnu");			\
+    } while (0)
+
 #undef GNU_USER_DYNAMIC_LINKER
 #define GNU_USER_DYNAMIC_LINKER "/lib/ld.so.1"
diff --git a/gcc/config/linux-android.h b/gcc/config/linux-android.h
index cf340660adb..3d5548e3eb3 100644
--- a/gcc/config/linux-android.h
+++ b/gcc/config/linux-android.h
@@ -31,6 +31,18 @@
 	  builtin_version ("Android");				\
     } while (0)
 
+#define ANDROID_TARGET_RUST_OS_INFO()				\
+    do {							\
+  if (TARGET_ANDROID)	{				\
+    builtin_rust_info ("target_family", "unix");				\
+    builtin_rust_info ("target_os", "android");				\
+    builtin_rust_info ("target_vendor", "unknown");				\
+    builtin_rust_info ("target_env", "");				\
+  } else {				\
+    builtin_rust_info ("target_os", "linux");				\
+  }	/*this else is required if I'm intepreting structure of defines correctly*/			\
+    } while (0)
+
 #if ANDROID_DEFAULT
 # define NOANDROID "mno-android"
 #else
diff --git a/gcc/config/linux.h b/gcc/config/linux.h
index 74f70793d90..13a714b9e81 100644
--- a/gcc/config/linux.h
+++ b/gcc/config/linux.h
@@ -71,6 +71,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 	  builtin_version ("CRuntime_Musl");			\
     } while (0)
 
+#define GNU_USER_TARGET_RUST_OS_INFO()				\
+    do {							\
+  builtin_rust_info ("target_family", "unix");			\
+  builtin_rust_info ("target_vendor", "unknown");			\
+  /*is there way of determining target_os and target_env here since could also be android?*/		\
+  /*target_vendor may not be "unknown" - FIXME ensure it is*/  \
+  if (OPTION_GLIBC)			\
+      builtin_rust_info ("target_env", "gnu");			\
+  else if (OPTION_MUSL)			\
+      builtin_rust_info ("target_env", "musl");			\
+  else /*TODO: determine if bionic and uclibc are considered to be different envs in rustc*/ \
+      builtin_rust_info ("target_env", "");			\
+    } while (0)
+
 /* Determine which dynamic linker to use depending on whether GLIBC or
    uClibc or Bionic or musl is the default C library and whether
    -muclibc or -mglibc or -mbionic or -mmusl has been passed to change
diff --git a/gcc/config/netbsd.h b/gcc/config/netbsd.h
index 9e46a0fff02..8e6bd0a2675 100644
--- a/gcc/config/netbsd.h
+++ b/gcc/config/netbsd.h
@@ -29,6 +29,15 @@ along with GCC; see the file COPYING3.  If not see
     }						\
   while (0)
 
+/* TARGET_RUST_OS_INFO() common to all NetBSD targets.  */
+#define NETBSD_TARGET_RUST_OS_INFO()		\
+  do {		\
+    builtin_rust_info ("target_family", "unix");			\
+    builtin_rust_info ("target_os", "netbsd");			\
+    builtin_rust_info ("target_vendor", "unknown");			\
+    builtin_rust_info ("target_env", "");			\
+  } while (0)
+
 /* CPP_SPEC parts common to all NetBSD targets.  */
 #define NETBSD_CPP_SPEC				\
   "%{posix:-D_POSIX_SOURCE} \
diff --git a/gcc/config/openbsd.h b/gcc/config/openbsd.h
index 54be2225492..d91e1e9d8d7 100644
--- a/gcc/config/openbsd.h
+++ b/gcc/config/openbsd.h
@@ -102,6 +102,14 @@ while (0)
     }						\
   while (0)
 
+#define OPENBSD_TARGET_RUST_OS_INFO()		\
+  do {		\
+    builtin_rust_info ("target_family", "unix");		\
+    builtin_rust_info ("target_os", "openbsd");		\
+    builtin_rust_info ("target_vendor", "unknown"); \
+    builtin_rust_info ("target_env", "");			      \
+  } while(0)
+
 /* CPP_SPEC appropriate for OpenBSD. We deal with -posix and -pthread.
    XXX the way threads are handled currently is not very satisfying,
    since all code must be compiled with -pthread to work. 
diff --git a/gcc/config/phoenix.h b/gcc/config/phoenix.h
index d9eef357370..e9dbbd0b2ae 100644
--- a/gcc/config/phoenix.h
+++ b/gcc/config/phoenix.h
@@ -26,6 +26,18 @@ along with GCC; see the file COPYING3.  If not see
       builtin_assert ("system=unix");      \
     } while (0)
 
+#ifdef TARGET_RUST_OS_INFO
+# error "TARGET_RUST_OS_INFO already defined in phoenix.h - c++ undefines it and redefines it."
+#endif
+#define TARGET_RUST_OS_INFO()                       \
+  do {                                              \
+    builtin_rust_info ("target_family", "unix");		\
+    builtin_rust_info ("target_os", "phoenix");		  \
+    builtin_rust_info ("target_vendor", "unknown"); \
+    builtin_rust_info ("target_env", "");			      \
+    /*TODO: ensure these values are correct*/       \
+  } while(0)
+
 #define STD_LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}"
 
 /* This will prevent selecting 'unsigned long int' instead of 'unsigned int' as 'uint32_t' in stdint-newlib.h. */
diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h
index e22c70c45ae..8cf2164c284 100644
--- a/gcc/config/sol2.h
+++ b/gcc/config/sol2.h
@@ -124,6 +124,16 @@ along with GCC; see the file COPYING3.  If not see
     solaris_override_options ();			\
   } while (0)
 
+#define EXTRA_TARGET_RUST_OS_INFO()
+#define TARGET_RUST_OS_INFO()			\
+  do {			\
+    builtin_rust_info ("target_family", "unix");			\
+    builtin_rust_info ("target_os", "solaris");			\
+    builtin_rust_info ("target_vendor", "sun");			\
+    builtin_rust_info ("target_env", "");			\
+    EXTRA_TARGET_RUST_OS_INFO();			\
+  } while (0)
+
 #if DEFAULT_ARCH32_P
 #define MULTILIB_DEFAULTS { "m32" }
 #else
diff --git a/gcc/config/vxworks.h b/gcc/config/vxworks.h
index 6a5f2f8f2ec..4811b428455 100644
--- a/gcc/config/vxworks.h
+++ b/gcc/config/vxworks.h
@@ -337,6 +337,14 @@ extern void vxworks_asm_out_destructor (rtx symbol, int priority);
     }									\
   while (0)
 
+#define VXWORKS_TARGET_RUST_OS_INFO()					\
+  do {					\
+    builtin_rust_info ("target_family", "unix");			\
+    builtin_rust_info ("target_os", "vxworks");			\
+    builtin_rust_info ("target_vendor", "wrs");			\
+    builtin_rust_info ("target_env", "gnu");			\
+  } while (0)
+
 /* For specific CPU macro definitions expected by the system headers,
    different versions of VxWorks expect different forms of macros,
    such as "_VX_CPU=..." on Vx7 and some variants of Vx6, or "CPU=..."
diff --git a/gcc/config/vxworksae.h b/gcc/config/vxworksae.h
index 0cc45467ab8..dc1dbe15ff1 100644
--- a/gcc/config/vxworksae.h
+++ b/gcc/config/vxworksae.h
@@ -77,6 +77,15 @@ along with GCC; see the file COPYING3.  If not see
     }                                                                   \
   while (0)
 
+#define VXWORKS_TARGET_RUST_OS_INFO()					\
+  do {					\
+    builtin_rust_info ("target_family", "unix");			\
+    builtin_rust_info ("target_os", "vxworks");			\
+    builtin_rust_info ("target_vendor", "wrs");			\
+    builtin_rust_info ("target_env", "gnu");			\
+    /*is env correct? vxworks.h implies that this might not come with a gnu toolchain*/ \
+  } while (0)
+
 /* Do VxWorks-specific parts of TARGET_OPTION_OVERRIDE.  */
 
 /* None of the VxWorks AE/653/MILS ports to date has native TLS support.  */
diff --git a/gcc/configure b/gcc/configure
index 62872d132ea..44cab9654d9 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -644,6 +644,7 @@ ISLLIBS
 GMPINC
 GMPLIBS
 target_cpu_default
+rust_target_objs
 d_target_objs
 fortran_target_objs
 cxx_target_objs
@@ -652,6 +653,8 @@ use_gcc_stdint
 xm_defines
 xm_include_list
 xm_file_list
+tm_rust_include_list
+tm_rust_file_list
 tm_d_include_list
 tm_d_file_list
 tm_p_include_list
@@ -13010,6 +13013,7 @@ fi
 tm_file="${tm_file} defaults.h"
 tm_p_file="${tm_p_file} tm-preds.h"
 tm_d_file="${tm_d_file} defaults.h"
+tm_rust_file="${tm_rust_file} defaults.h"
 host_xm_file="auto-host.h ansidecl.h ${host_xm_file}"
 build_xm_file="${build_auto} ansidecl.h ${build_xm_file}"
 # We don't want ansidecl.h in target files, write code there in ISO/GNU C.
@@ -13418,6 +13422,21 @@ for f in $tm_d_file; do
   esac
 done
 
+tm_rust_file_list=
+tm_rust_include_list="options.h insn-constants.h"
+for f in $tm_rust_file; do
+  case $f in
+    defaults.h )
+       tm_rust_file_list="${tm_rust_file_list} \$(srcdir)/$f"
+       tm_rust_include_list="${tm_rust_include_list} $f"
+       ;;
+    * )
+       tm_rust_file_list="${tm_rust_file_list} \$(srcdir)/config/$f"
+       tm_rust_include_list="${tm_rust_include_list} config/$f"
+       ;;
+  esac
+done
+
 xm_file_list=
 xm_include_list=
 for f in $xm_file; do
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 446747311a6..c54e9f40796 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2114,6 +2114,7 @@ AC_SUBST(HAVE_AUTO_BUILD)
 tm_file="${tm_file} defaults.h"
 tm_p_file="${tm_p_file} tm-preds.h"
 tm_d_file="${tm_d_file} defaults.h"
+tm_rust_file="${tm_rust_file} defaults.h"
 host_xm_file="auto-host.h ansidecl.h ${host_xm_file}"
 build_xm_file="${build_auto} ansidecl.h ${build_xm_file}"
 # We don't want ansidecl.h in target files, write code there in ISO/GNU C.
@@ -2371,6 +2372,21 @@ for f in $tm_d_file; do
   esac
 done
 
+tm_rust_file_list=
+tm_rust_include_list="options.h insn-constants.h"
+for f in $tm_rust_file; do
+  case $f in
+    defaults.h )
+       tm_rust_file_list="${tm_rust_file_list} \$(srcdir)/$f"
+       tm_rust_include_list="${tm_rust_include_list} $f"
+       ;;
+    * )
+       tm_rust_file_list="${tm_rust_file_list} \$(srcdir)/config/$f"
+       tm_rust_include_list="${tm_rust_include_list} config/$f"
+       ;;
+  esac
+done
+
 xm_file_list=
 xm_include_list=
 for f in $xm_file; do
@@ -7350,6 +7366,8 @@ AC_SUBST(tm_p_file_list)
 AC_SUBST(tm_p_include_list)
 AC_SUBST(tm_d_file_list)
 AC_SUBST(tm_d_include_list)
+AC_SUBST(tm_rust_file_list)
+AC_SUBST(tm_rust_include_list)
 AC_SUBST(xm_file_list)
 AC_SUBST(xm_include_list)
 AC_SUBST(xm_defines)
@@ -7358,6 +7376,7 @@ AC_SUBST(c_target_objs)
 AC_SUBST(cxx_target_objs)
 AC_SUBST(fortran_target_objs)
 AC_SUBST(d_target_objs)
+AC_SUBST(rust_target_objs)
 AC_SUBST(target_cpu_default)
 
 AC_SUBST_FILE(language_hooks)
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index b0ea39884aa..2ccda74c979 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -53,6 +53,7 @@ through the macros defined in the @file{.h} file.
 * PCH Target::          Validity checking for precompiled headers.
 * C++ ABI::             Controlling C++ ABI changes.
 * D Language and ABI::  Controlling D ABI changes.
+* Rust Language and ABI:: Controlling Rust ABI changes.
 * Named Address Spaces:: Adding support for named address spaces
 * Misc::                Everything else.
 @end menu
@@ -11065,6 +11066,22 @@ if they have external linkage.  If this flag is false, then instantiated
 decls will be emitted as weak symbols.  The default is @code{false}.
 @end deftypevr
 
+@node Rust Language and ABI
+@section Rust ABI parameters
+@cindex parameters, rust abi
+
+@deftypefn {Rust Target Hook} void TARGET_RUST_CPU_INFO (void)
+Declare all environmental CPU info and features relating to the target CPU
+using the function @code{rust_add_target_info}, which takes a string representing
+the feature key and a string representing the feature value.  Configuration pairs
+predefined by this hook apply to all files that are being compiled.
+@end deftypefn
+
+@deftypefn {Rust Target Hook} void TARGET_RUST_OS_INFO (void)
+Similar to @code{TARGET_RUST_CPU_INFO}, but is used for configuration info
+relating to the target operating system.
+@end deftypefn
+
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index f869ddd5e5b..c90c90f97a4 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -53,6 +53,7 @@ through the macros defined in the @file{.h} file.
 * PCH Target::          Validity checking for precompiled headers.
 * C++ ABI::             Controlling C++ ABI changes.
 * D Language and ABI::  Controlling D ABI changes.
+* Rust Language and ABI:: Controlling Rust ABI changes.
 * Named Address Spaces:: Adding support for named address spaces
 * Misc::                Everything else.
 @end menu
@@ -7327,6 +7328,14 @@ floating-point support; they are not included in this mechanism.
 
 @hook TARGET_D_TEMPLATES_ALWAYS_COMDAT
 
+@node Rust Language and ABI
+@section Rust ABI parameters
+@cindex parameters, rust abi
+
+@hook TARGET_RUST_CPU_INFO
+
+@hook TARGET_RUST_OS_INFO
+
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/gcc/genhooks.cc b/gcc/genhooks.cc
index 6bae85d7b8d..4e1338d21b7 100644
--- a/gcc/genhooks.cc
+++ b/gcc/genhooks.cc
@@ -35,6 +35,7 @@ static struct hook_desc hook_array[] = {
 #include "c-family/c-target.def"
 #include "common/common-target.def"
 #include "d/d-target.def"
+#include "rust/rust-target.def"
 #undef DEFHOOK
 };
 
diff --git a/gcc/rust/rust-target-def.h b/gcc/rust/rust-target-def.h
new file mode 100644
index 00000000000..94c3f9f9a23
--- /dev/null
+++ b/gcc/rust/rust-target-def.h
@@ -0,0 +1,20 @@
+/* rust-target-def.h -- Default initializers for Rust target hooks.
+   Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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 this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "rust/rust-target-hooks-def.h"
+#include "tree.h"
+#include "hooks.h"
diff --git a/gcc/rust/rust-target.def b/gcc/rust/rust-target.def
new file mode 100644
index 00000000000..6d1ccaf8ad1
--- /dev/null
+++ b/gcc/rust/rust-target.def
@@ -0,0 +1,89 @@
+/* rust-target.def -- Target hook definitions for the Rust front end.
+   Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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 this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* See target-hooks-macros.h for details of macros that should be
+   provided by the including file, and how to use them here.  */
+
+#include "target-hooks-macros.h"
+
+#undef HOOK_TYPE
+#define HOOK_TYPE "Rust Target Hook"
+
+HOOK_VECTOR (TARGETRUSTM_INITIALIZER, gcc_targetrustm)
+
+#undef HOOK_PREFIX
+#define HOOK_PREFIX "TARGET_"
+
+/* Environmental CPU info and features (e.g. endianness, pointer size) relating to the target CPU.  */
+DEFHOOK
+(rust_cpu_info,
+ "Declare all environmental CPU info and features relating to the target CPU\n\
+using the function @code{rust_add_target_info}, which takes a string representing\n\
+the feature key and a string representing the feature value.  Configuration pairs\n\
+predefined by this hook apply to all files that are being compiled.",
+ void, (void),
+ hook_void_void)
+
+// TODO: remove: format of DEFHOOK is return type, (param types), default value for function that it translates to
+
+/* Environmental OS info relating to the target OS.  */
+DEFHOOK
+(/*d_os_versions*/rust_os_info,
+ "Similar to @code{TARGET_RUST_CPU_INFO}, but is used for configuration info\n\
+relating to the target operating system.",
+ void, (void),
+ hook_void_void)
+
+/* The sizeof CRITICAL_SECTION or pthread_mutex_t.  */
+/*DEFHOOK
+(d_critsec_size,
+ "Returns the size of the data structure used by the target operating system\n\
+for critical sections and monitors.  For example, on Microsoft Windows this\n\
+would return the @code{sizeof(CRITICAL_SECTION)}, while other platforms that\n\
+implement pthreads would return @code{sizeof(pthread_mutex_t)}.",
+ unsigned, (void),
+ hook_uint_void_0)*/
+
+ /* TODO: add more if required. Possible ones include static C runtime, target_env
+  * or vendor (if not covered by OS), and flags from the driver that may or may not
+  * require a target hook (might instead require a different type of hook) like 
+  * test, debug_assertions, and proc_macro. */
+
+ /* TODO: rustc target support by tier:
+  *   Tier 1 (definitely work):
+  *   -  i686-pc-windows-gnu
+  *   -  i686-pc-windows-msvc
+  *   -  i686-unknown-linux-gnu
+  *   -  x86_64-apple-darwin
+  *   -  x86_64-pc-windows-gnu
+  *   -  x86_64-pc-windows-msvc
+  *   -  x86_64-unknown-linux-gnu
+  *   - Basically, 32-bit and 64-bit x86 for windows (MinGW and MSVC), gnu/linux, and osx
+  *   Other tiers have too much crap, but basic breakdown is:
+  *   Tier 2:
+  *   -  archs: ARM64 (aarch64), ARMv7, ARMv6, asm.js, i586 (32-bit x86 without SSE), mips, 
+  *      mips64, powerpc, powerpc64, risc-v, s390x, sparc, webasm, netbsd, redox (does gcc have support?),
+  *      cloudabi (never head of it; i imagine no gcc support)
+  *   -  oses: ios, fuchsia, android, windows (msvc and mingw), gnu/linux, freebsd, netbsd
+  *   Tier 2.5:
+  *   - powerpc SPE linux, various cloudabi stuff, sparc
+  *   Tier 3:
+  *   - more obscure stuff like UWP support, vxworks, openbsd, dragonflybsd, haiku, bitrig, windows xp,
+  *     cuda, hexagon, and combinations of them and earlier stuff */
+
+/* Close the 'struct gcc_targetrustm' definition.  */
+HOOK_VECTOR_END (C90_EMPTY_HACK)
diff --git a/gcc/rust/rust-target.h b/gcc/rust/rust-target.h
new file mode 100644
index 00000000000..743ac518ebb
--- /dev/null
+++ b/gcc/rust/rust-target.h
@@ -0,0 +1,47 @@
+/* rust-target.h -- Data structure definitions for target-specific Rust
+   behavior. Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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 this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_RUST_TARGET_H
+#define GCC_RUST_TARGET_H
+
+#include "target.h"
+#include "tm.h"
+#include "memmodel.h"
+#include "tm_p.h"
+
+// TODO: find out what this stuff actually does
+#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
+// #define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (*NAME) PARAMS;
+#define DEFHOOK_UNDOC DEFHOOK
+#define HOOKSTRUCT(FRAGMENT) FRAGMENT
+
+#include "rust-target.def"
+
+/* Each target can provide their own.  */
+extern struct gcc_targetrustm targetrustm;
+/* Some kind of structure to store all rust hook macros (like the
+ * TARGET_RUST_CPU_INFO). This is required to store the function pointers for
+ * the target hooks so that the frontend can call them
+ * and it calls the correct target-specific function.  */
+
+/* Used by target to add predefined version idenditiers.  */
+// extern void d_add_builtin_version (const char *);
+/* Used by target to add target-related info.  */
+extern void
+rust_add_target_info (const char *key, const char *value);
+
+#endif
