about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml5
-rw-r--r--.github/workflows/failures.yml7
-rw-r--r--.github/workflows/gcc12.yml3
-rw-r--r--.github/workflows/m68k.yml3
-rw-r--r--.github/workflows/release.yml7
-rw-r--r--Cargo.lock126
-rw-r--r--Cargo.toml12
-rw-r--r--build_system/src/config.rs2
-rw-r--r--build_system/src/test.rs87
-rw-r--r--build_system/src/utils.rs2
-rw-r--r--example/mini_core.rs132
-rw-r--r--example/mini_core_hello_world.rs2
-rw-r--r--messages.ftl12
-rw-r--r--patches/0022-core-Disable-not-compiling-tests.patch13
-rw-r--r--patches/libgccjit12/0001-core-Disable-portable-simd-test.patch4
-rw-r--r--rust-toolchain2
-rw-r--r--src/abi.rs4
-rw-r--r--src/allocator.rs27
-rw-r--r--src/asm.rs31
-rw-r--r--src/attributes.rs22
-rw-r--r--src/back/lto.rs47
-rw-r--r--src/back/write.rs157
-rw-r--r--src/base.rs49
-rw-r--r--src/builder.rs139
-rw-r--r--src/callee.rs144
-rw-r--r--src/common.rs55
-rw-r--r--src/consts.rs14
-rw-r--r--src/context.rs46
-rw-r--r--src/debuginfo.rs32
-rw-r--r--src/declare.rs2
-rw-r--r--src/errors.rs53
-rw-r--r--src/gcc_util.rs85
-rw-r--r--src/int.rs29
-rw-r--r--src/intrinsic/llvm.rs25
-rw-r--r--src/intrinsic/mod.rs33
-rw-r--r--src/intrinsic/simd.rs516
-rw-r--r--src/lib.rs44
-rw-r--r--src/mono_item.rs13
-rw-r--r--src/type_.rs8
-rw-r--r--src/type_of.rs58
-rw-r--r--tests/failing-non-lto-tests.txt11
-rw-r--r--tests/failing-ui-tests.txt32
-rw-r--r--tests/hello-world/Cargo.lock14
-rw-r--r--tests/hello-world/Cargo.toml8
-rw-r--r--tests/hello-world/mylib/Cargo.lock5
-rw-r--r--tests/hello-world/mylib/Cargo.toml9
-rw-r--r--tests/hello-world/mylib/src/lib.rs7
-rw-r--r--tests/hello-world/src/main.rs4
-rw-r--r--tests/run/abort1.rs8
-rw-r--r--tests/run/abort2.rs8
-rw-r--r--tests/run/array.rs12
-rw-r--r--tests/run/asm.rs15
-rw-r--r--tests/run/assign.rs8
-rw-r--r--tests/run/closure.rs12
-rw-r--r--tests/run/condition.rs12
-rw-r--r--tests/run/fun_ptr.rs12
-rw-r--r--tests/run/mut_ref.rs8
-rw-r--r--tests/run/operations.rs12
-rw-r--r--tests/run/ptr_cast.rs12
-rw-r--r--tests/run/return-tuple.rs28
-rw-r--r--tests/run/slice.rs12
-rw-r--r--tests/run/static.rs8
62 files changed, 1244 insertions, 1065 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 704d7b9c2fd..efb4de5f5fb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -87,7 +87,7 @@ jobs:
 
     - name: Clean
       run: |
-        ./y.sh clean all      
+        ./y.sh clean all
 
     - name: Prepare dependencies
       run: |
@@ -95,9 +95,6 @@ jobs:
         git config --global user.name "User"
         ./y.sh prepare
 
-    - name: Add more failing tests because the sysroot is not compiled with LTO
-      run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     - name: Run tests
       run: |
         ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}
diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml
index 2c1ed9ad429..f33d9fcc582 100644
--- a/.github/workflows/failures.yml
+++ b/.github/workflows/failures.yml
@@ -90,15 +90,12 @@ jobs:
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       run: ./y.sh prepare
 
-    - name: Add more failing tests because the sysroot is not compiled with LTO
-      run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     - name: Run tests
       # TODO: re-enable those tests for libgccjit 12.
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       id: tests
       run: |
-        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} | tee output_log
+        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} 2>&1 | tee output_log
         rg --text "test result" output_log >> $GITHUB_STEP_SUMMARY
 
     - name: Run failing ui pattern tests for ICE
@@ -106,7 +103,7 @@ jobs:
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       id: ui-tests
       run: |
-        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --test-failing-ui-pattern-tests ${{ matrix.libgccjit_version.extra }} | tee output_log_ui
+        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --test-failing-ui-pattern-tests ${{ matrix.libgccjit_version.extra }} 2>&1 | tee output_log_ui
         if grep -q "the compiler unexpectedly panicked" output_log_ui; then
           echo "Error: 'the compiler unexpectedly panicked' found in output logs. CI Error!!"
           exit 1
diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml
index 7dcad21a02e..4c2ce91e86e 100644
--- a/.github/workflows/gcc12.yml
+++ b/.github/workflows/gcc12.yml
@@ -82,9 +82,6 @@ jobs:
     #- name: Add more failing tests for GCC 12
       #run: cat tests/failing-ui-tests12.txt >> tests/failing-ui-tests.txt
 
-    #- name: Add more failing tests because the sysroot is not compiled with LTO
-      #run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     #- name: Run tests
       #run: |
         #./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features
diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml
index 1c864e04413..69549dfeb5f 100644
--- a/.github/workflows/m68k.yml
+++ b/.github/workflows/m68k.yml
@@ -102,9 +102,6 @@ jobs:
         git config --global user.name "User"
         ./y.sh prepare --cross
 
-    - name: Add more failing tests because the sysroot is not compiled with LTO
-      run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     - name: Run tests
       run: |
         ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f0ff23cf0f8..f1ddb301acc 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -70,4 +70,9 @@ jobs:
       run: |
         # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros.
         echo -n 'lto = "fat"' >> build_system/build_sysroot/Cargo.toml
-        EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }}
+        EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }}
+
+    - name: Run y.sh cargo build
+      run: |
+        EMBED_LTO_BITCODE=1 CHANNEL="release" ./y.sh cargo build --release --manifest-path tests/hello-world/Cargo.toml
+        # TODO: grep the asm output for "call my_func" and fail if it is found.
diff --git a/Cargo.lock b/Cargo.lock
index 55d65c0ad7f..636e75b94a3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "aho-corasick"
@@ -13,15 +13,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "1.3.2"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bitflags"
-version = "2.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "boml"
@@ -30,12 +24,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5"
 
 [[package]]
-name = "cc"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-
-[[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -43,30 +31,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "errno"
-version = "0.3.1"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
 dependencies = [
- "errno-dragonfly",
  "libc",
  "windows-sys",
 ]
 
 [[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
 name = "fastrand"
-version = "2.0.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "fm"
@@ -128,15 +105,15 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.150"
+version = "0.2.168"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
+checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.5"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "memchr"
@@ -155,22 +132,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "object"
-version = "0.30.4"
+name = "once_cell"
+version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
-dependencies = [
- "bitflags 1.3.2",
-]
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "regex"
@@ -196,18 +161,16 @@ dependencies = [
  "boml",
  "gccjit",
  "lang_tester",
- "object",
- "smallvec",
  "tempfile",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.38.8"
+version = "0.38.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
+checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
 dependencies = [
- "bitflags 2.4.0",
+ "bitflags",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -224,20 +187,14 @@ dependencies = [
 ]
 
 [[package]]
-name = "smallvec"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
-
-[[package]]
 name = "tempfile"
-version = "3.7.1"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall",
+ "once_cell",
  "rustix",
  "windows-sys",
 ]
@@ -318,22 +275,23 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.48.0"
+version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
  "windows-targets",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.48.1"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
+ "windows_i686_gnullvm",
  "windows_i686_msvc",
  "windows_x86_64_gnu",
  "windows_x86_64_gnullvm",
@@ -342,42 +300,48 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.0"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/Cargo.toml b/Cargo.toml
index c5570f6a270..63d37358561 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,18 +28,10 @@ gccjit = "2.4"
 # Local copy.
 #gccjit = { path = "../gccjit.rs" }
 
-object = { version = "0.30.1", default-features = false, features = [
-    "std",
-    "read",
-] }
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
-# TODO(antoyo): make tempfile optional.
-tempfile = "3.7.1"
-
 [dev-dependencies]
-lang_tester = "0.8.0"
-tempfile = "3.1.0"
 boml = "0.3.1"
+lang_tester = "0.8.0"
+tempfile = "3.7.1"
 
 [profile.dev]
 # By compiling dependencies with optimizations, performing tests gets much faster.
diff --git a/build_system/src/config.rs b/build_system/src/config.rs
index e381617be06..37b4b68950e 100644
--- a/build_system/src/config.rs
+++ b/build_system/src/config.rs
@@ -3,8 +3,8 @@ use std::ffi::OsStr;
 use std::path::{Path, PathBuf};
 use std::{env as std_env, fs};
 
-use boml::types::TomlValue;
 use boml::Toml;
+use boml::types::TomlValue;
 
 use crate::utils::{
     create_dir, create_symlink, get_os_name, get_sysroot_dir, run_command_with_output,
diff --git a/build_system/src/test.rs b/build_system/src/test.rs
index 06b3e446665..371fcb4bc30 100644
--- a/build_system/src/test.rs
+++ b/build_system/src/test.rs
@@ -1,6 +1,6 @@
 use std::collections::HashMap;
 use std::ffi::OsStr;
-use std::fs::{remove_dir_all, File};
+use std::fs::{File, remove_dir_all};
 use std::io::{BufRead, BufReader};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
@@ -93,6 +93,7 @@ struct TestArg {
     sysroot_panic_abort: bool,
     config_info: ConfigInfo,
     sysroot_features: Vec<String>,
+    keep_lto_tests: bool,
 }
 
 impl TestArg {
@@ -128,6 +129,9 @@ impl TestArg {
                 "--sysroot-panic-abort" => {
                     test_arg.sysroot_panic_abort = true;
                 }
+                "--keep-lto-tests" => {
+                    test_arg.keep_lto_tests = true;
+                }
                 "--sysroot-features" => match args.next() {
                     Some(feature) if !feature.is_empty() => {
                         test_arg.sysroot_features.push(feature);
@@ -194,7 +198,7 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> {
 }
 
 fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
-    let _ = std::fs::remove_dir_all(&args.config_info.cargo_target_dir);
+    let _ = remove_dir_all(&args.config_info.cargo_target_dir);
     let path = Path::new(&args.config_info.cargo_target_dir).join("gccjit");
     create_dir(&path)
 }
@@ -563,7 +567,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
             &"--stage",
             &"0",
             &"tests/assembly/asm",
-            &"--rustc-args",
+            &"--compiletest-rustc-args",
             &rustc_args,
         ],
         Some(&rust_dir),
@@ -835,8 +839,7 @@ fn valid_ui_error_pattern_test(file: &str) -> bool {
     .any(|to_ignore| file.ends_with(to_ignore))
 }
 
-#[rustfmt::skip]
-fn contains_ui_error_patterns(file_path: &Path) -> Result<bool, String> {
+fn contains_ui_error_patterns(file_path: &Path, keep_lto_tests: bool) -> Result<bool, String> {
     // Tests generating errors.
     let file = File::open(file_path)
         .map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?;
@@ -845,19 +848,22 @@ fn contains_ui_error_patterns(file_path: &Path) -> Result<bool, String> {
         if line.is_empty() {
             continue;
         }
-        if [
-            "//@ error-pattern:",
-            "//@ build-fail",
-            "//@ run-fail",
-            "-Cllvm-args",
-            "//~",
-            "thread",
-        ]
+        if ["//@ error-pattern:", "//@ build-fail", "//@ run-fail", "-Cllvm-args", "//~", "thread"]
             .iter()
             .any(|check| line.contains(check))
         {
             return Ok(true);
         }
+
+        if !keep_lto_tests
+            && (line.contains("-Clto")
+                || line.contains("-C lto")
+                || line.contains("compile-flags: -Clinker-plugin-lto"))
+            && !line.contains("-Clto=thin")
+        {
+            return Ok(true);
+        }
+
         if line.contains("//[") && line.contains("]~") {
             return Ok(true);
         }
@@ -903,7 +909,7 @@ where
                 rust_path.join("tests/ui"),
                 &mut |_dir| Ok(()),
                 &mut |file_path| {
-                    if contains_ui_error_patterns(file_path)? {
+                    if contains_ui_error_patterns(file_path, args.keep_lto_tests)? {
                         Ok(())
                     } else {
                         remove_file(file_path).map_err(|e| e.to_string())
@@ -928,7 +934,7 @@ where
                     .iter()
                     .any(|name| *name == dir_name)
                     {
-                        std::fs::remove_dir_all(dir).map_err(|error| {
+                        remove_dir_all(dir).map_err(|error| {
                             format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
                         })?;
                     }
@@ -940,27 +946,42 @@ where
 
             // These two functions are used to remove files that are known to not be working currently
             // with the GCC backend to reduce noise.
-            fn dir_handling(dir: &Path) -> Result<(), String> {
-                if dir.file_name().map(|name| name == "auxiliary").unwrap_or(true) {
-                    return Ok(());
-                }
+            fn dir_handling(keep_lto_tests: bool) -> impl Fn(&Path) -> Result<(), String> {
+                move |dir| {
+                    if dir.file_name().map(|name| name == "auxiliary").unwrap_or(true) {
+                        return Ok(());
+                    }
 
-                walk_dir(dir, &mut dir_handling, &mut file_handling, false)
-            }
-            fn file_handling(file_path: &Path) -> Result<(), String> {
-                if !file_path.extension().map(|extension| extension == "rs").unwrap_or(false) {
-                    return Ok(());
+                    walk_dir(
+                        dir,
+                        &mut dir_handling(keep_lto_tests),
+                        &mut file_handling(keep_lto_tests),
+                        false,
+                    )
                 }
-                let path_str = file_path.display().to_string().replace("\\", "/");
-                if valid_ui_error_pattern_test(&path_str) {
-                    return Ok(());
-                } else if contains_ui_error_patterns(file_path)? {
-                    return remove_file(&file_path);
+            }
+
+            fn file_handling(keep_lto_tests: bool) -> impl Fn(&Path) -> Result<(), String> {
+                move |file_path| {
+                    if !file_path.extension().map(|extension| extension == "rs").unwrap_or(false) {
+                        return Ok(());
+                    }
+                    let path_str = file_path.display().to_string().replace("\\", "/");
+                    if valid_ui_error_pattern_test(&path_str) {
+                        return Ok(());
+                    } else if contains_ui_error_patterns(file_path, keep_lto_tests)? {
+                        return remove_file(&file_path);
+                    }
+                    Ok(())
                 }
-                Ok(())
             }
 
-            walk_dir(rust_path.join("tests/ui"), &mut dir_handling, &mut file_handling, false)?;
+            walk_dir(
+                rust_path.join("tests/ui"),
+                &mut dir_handling(args.keep_lto_tests),
+                &mut file_handling(args.keep_lto_tests),
+                false,
+            )?;
         }
         let nb_parts = args.nb_parts.unwrap_or(0);
         if nb_parts > 0 {
@@ -1032,7 +1053,7 @@ where
             &"--stage",
             &"0",
             &format!("tests/{}", test_type),
-            &"--rustc-args",
+            &"--compiletest-rustc-args",
             &rustc_args,
         ],
         Some(&rust_path),
@@ -1173,7 +1194,7 @@ fn remove_files_callback<'a>(
                     files.split('\n').map(|line| line.trim()).filter(|line| !line.is_empty())
                 {
                     let path = rust_path.join(file);
-                    if let Err(e) = std::fs::remove_dir_all(&path) {
+                    if let Err(e) = remove_dir_all(&path) {
                         println!("Failed to remove directory `{}`: {}", path.display(), e);
                     }
                 }
diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs
index e338d1b4992..401c23948e5 100644
--- a/build_system/src/utils.rs
+++ b/build_system/src/utils.rs
@@ -1,7 +1,7 @@
 use std::collections::HashMap;
+use std::ffi::OsStr;
 #[cfg(unix)]
 use std::ffi::c_int;
-use std::ffi::OsStr;
 use std::fmt::Debug;
 use std::fs;
 #[cfg(unix)]
diff --git a/example/mini_core.rs b/example/mini_core.rs
index f47bfdad131..cdd151613df 100644
--- a/example/mini_core.rs
+++ b/example/mini_core.rs
@@ -44,32 +44,32 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
 impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
 
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
 
-impl<T: ?Sized> Receiver for &T {}
-impl<T: ?Sized> Receiver for &mut T {}
-impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {}
+impl<T: ?Sized> LegacyReceiver for &T {}
+impl<T: ?Sized> LegacyReceiver for &mut T {}
+impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
 
 #[lang = "copy"]
-pub unsafe trait Copy {}
-
-unsafe impl Copy for bool {}
-unsafe impl Copy for u8 {}
-unsafe impl Copy for u16 {}
-unsafe impl Copy for u32 {}
-unsafe impl Copy for u64 {}
-unsafe impl Copy for usize {}
-unsafe impl Copy for i8 {}
-unsafe impl Copy for i16 {}
-unsafe impl Copy for i32 {}
-unsafe impl Copy for isize {}
-unsafe impl Copy for f32 {}
-unsafe impl Copy for f64 {}
-unsafe impl Copy for char {}
-unsafe impl<'a, T: ?Sized> Copy for &'a T {}
-unsafe impl<T: ?Sized> Copy for *const T {}
-unsafe impl<T: ?Sized> Copy for *mut T {}
+pub trait Copy {}
+
+impl Copy for bool {}
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for u64 {}
+impl Copy for usize {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for isize {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+impl Copy for char {}
+impl<'a, T: ?Sized> Copy for &'a T {}
+impl<T: ?Sized> Copy for *const T {}
+impl<T: ?Sized> Copy for *mut T {}
 
 #[lang = "sync"]
 pub unsafe trait Sync {}
@@ -579,28 +579,70 @@ pub union MaybeUninit<T> {
 }
 
 pub mod intrinsics {
-    use crate::Sized;
-
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
-        #[rustc_safe_intrinsic]
-        pub fn size_of<T>() -> usize;
-        pub fn size_of_val<T: ?Sized>(val: *const T) -> usize;
-        #[rustc_safe_intrinsic]
-        pub fn min_align_of<T>() -> usize;
-        pub fn min_align_of_val<T: ?Sized>(val: *const T) -> usize;
-        pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
-        pub fn transmute<T, U>(e: T) -> U;
-        pub fn ctlz_nonzero<T>(x: T) -> u32;
-        #[rustc_safe_intrinsic]
-        pub fn needs_drop<T: ?Sized>() -> bool;
-        #[rustc_safe_intrinsic]
-        pub fn bitreverse<T>(x: T) -> T;
-        #[rustc_safe_intrinsic]
-        pub fn bswap<T>(x: T) -> T;
-        pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
-        pub fn unreachable() -> !;
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn size_of<T>() -> usize {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn min_align_of<T>() -> usize {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize) {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub unsafe fn transmute<T, U>(_e: T) -> U {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32 {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn needs_drop<T: ?::Sized>() -> bool {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn bitreverse<T>(_x: T) -> T {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn bswap<T>(_x: T) -> T {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize) {
+        loop {}
+    }
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub unsafe fn unreachable() -> ! {
+        loop {}
     }
 }
 
diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs
index 9f096e90220..dcfa34cb729 100644
--- a/example/mini_core_hello_world.rs
+++ b/example/mini_core_hello_world.rs
@@ -2,7 +2,7 @@
 
 #![feature(
     no_core, unboxed_closures, start, lang_items, never_type, linkage,
-    extern_types, thread_local, raw_ref_op
+    extern_types, thread_local
 )]
 #![no_core]
 #![allow(dead_code, internal_features, non_camel_case_types)]
diff --git a/messages.ftl b/messages.ftl
index 0235384445e..26ddc5732dd 100644
--- a/messages.ftl
+++ b/messages.ftl
@@ -8,8 +8,8 @@ codegen_gcc_invalid_minimum_alignment =
 codegen_gcc_lto_not_supported =
     LTO is not supported. You may get a linker error.
 
-codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together
-    .help = add the missing features in a `target_feature` attribute
+codegen_gcc_forbidden_ctarget_feature =
+    target feature `{$feature}` cannot be toggled with `-Ctarget-feature`
 
 codegen_gcc_unwinding_inline_asm =
     GCC backend does not support unwinding from inline asm
@@ -27,11 +27,15 @@ codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdyl
 codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
 
 codegen_gcc_unknown_ctarget_feature =
-    unknown feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = it is still passed through to the codegen backend
+    unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
     .possible_feature = you might have meant: `{$rust_feature}`
     .consider_filing_feature_request = consider filing a feature request
 
+codegen_gcc_unstable_ctarget_feature =
+    unstable feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = this feature is not stably supported; its behavior can change in the future
+
 codegen_gcc_missing_features =
     add the missing features in a `target_feature` attribute
 
diff --git a/patches/0022-core-Disable-not-compiling-tests.patch b/patches/0022-core-Disable-not-compiling-tests.patch
index b2ab05691ec..70e3e2ba7fe 100644
--- a/patches/0022-core-Disable-not-compiling-tests.patch
+++ b/patches/0022-core-Disable-not-compiling-tests.patch
@@ -1,7 +1,7 @@
-From 18793c6109890493ceb3ff36549849a36e3d8022 Mon Sep 17 00:00:00 2001
+From af0e237f056fa838c77463381a19b0dc993c0a35 Mon Sep 17 00:00:00 2001
 From: None <none@example.com>
 Date: Sun, 1 Sep 2024 11:42:17 -0400
-Subject: [PATCH] [core] Disable not compiling tests
+Subject: [PATCH] Disable not compiling tests
 
 ---
  library/core/tests/Cargo.toml | 14 ++++++++++++++
@@ -30,14 +30,15 @@ index 0000000..ca326ac
 +rand = { version = "0.8.5", default-features = false }
 +rand_xorshift = { version = "0.3.0", default-features = false }
 diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
-index 1e336bf..5800ebb 100644
+index a4a7946..ecfe43f 100644
 --- a/library/core/tests/lib.rs
 +++ b/library/core/tests/lib.rs
 @@ -1,4 +1,5 @@
  // tidy-alphabetical-start
 +#![cfg(test)]
- #![cfg_attr(bootstrap, feature(offset_of_nested))]
  #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
  #![cfg_attr(test, feature(cfg_match))]
---
-2.46.0
+ #![feature(alloc_layout_extra)]
+-- 
+2.47.1
+
diff --git a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
index da664d51b63..9ef5e0e4f46 100644
--- a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
+++ b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
@@ -27,6 +27,4 @@ index b71786c..cf484d5 100644
  mod slice;
  mod str;
  mod str_lossy;
--- 
-2.45.2
-
+-- 2.45.2
diff --git a/rust-toolchain b/rust-toolchain
index dca3b0c22e4..c4171310577 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-08-11"
+channel = "nightly-2024-12-11"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/src/abi.rs b/src/abi.rs
index 0a99e7213be..14fc23593f0 100644
--- a/src/abi.rs
+++ b/src/abi.rs
@@ -1,11 +1,11 @@
 #[cfg(feature = "master")]
 use gccjit::FnAttribute;
 use gccjit::{ToLValue, ToRValue, Type};
-use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
+use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
-use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::Ty;
+use rustc_middle::ty::layout::LayoutOf;
 #[cfg(feature = "master")]
 use rustc_session::config;
 use rustc_target::abi::call::{ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind};
diff --git a/src/allocator.rs b/src/allocator.rs
index deeb55e9d12..416f3231a13 100644
--- a/src/allocator.rs
+++ b/src/allocator.rs
@@ -1,15 +1,17 @@
-#[cfg(feature = "master")]
-use gccjit::FnAttribute;
 use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type};
+#[cfg(feature = "master")]
+use gccjit::{FnAttribute, VarAttribute};
 use rustc_ast::expand::allocator::{
-    alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
-    ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
+    ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
+    alloc_error_handler_name, default_fn_name, global_fn_name,
 };
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::OomStrategy;
 
 use crate::GccContext;
+#[cfg(feature = "master")]
+use crate::base::symbol_visibility_to_gcc;
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
@@ -70,12 +72,20 @@ pub(crate) unsafe fn codegen(
 
     let name = OomStrategy::SYMBOL.to_string();
     let global = context.new_global(None, GlobalKind::Exported, i8, name);
+    #[cfg(feature = "master")]
+    global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
+        tcx.sess.default_visibility(),
+    )));
     let value = tcx.sess.opts.unstable_opts.oom.should_panic();
     let value = context.new_rvalue_from_int(i8, value as i32);
     global.global_set_initializer_rvalue(value);
 
     let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
     let global = context.new_global(None, GlobalKind::Exported, i8, name);
+    #[cfg(feature = "master")]
+    global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
+        tcx.sess.default_visibility(),
+    )));
     let value = context.new_rvalue_from_int(i8, 0);
     global.global_set_initializer_rvalue(value);
 }
@@ -104,10 +114,11 @@ fn create_wrapper_function(
         false,
     );
 
-    if tcx.sess.default_hidden_visibility() {
-        #[cfg(feature = "master")]
-        func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
-    }
+    #[cfg(feature = "master")]
+    func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc(
+        tcx.sess.default_visibility(),
+    )));
+
     if tcx.sess.must_emit_unwind_tables() {
         // TODO(antoyo): emit unwind tables.
     }
diff --git a/src/asm.rs b/src/asm.rs
index 7c135289958..a1f9eab10e7 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -5,8 +5,8 @@ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_codegen_ssa::mir::operand::OperandValue;
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::{
-    AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef,
-    InlineAsmOperandRef,
+    AsmBuilderMethods, AsmCodegenMethods, BaseTypeCodegenMethods, BuilderMethods,
+    GlobalAsmOperandRef, InlineAsmOperandRef,
 };
 use rustc_middle::bug;
 use rustc_middle::ty::Instance;
@@ -186,7 +186,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                             // `clobber_abi` can add lots of clobbers that are not supported by the target,
                             // such as AVX-512 registers, so we just ignore unsupported registers
                             let is_target_supported =
-                                reg.reg_class().supported_types(asm_arch).iter().any(
+                                reg.reg_class().supported_types(asm_arch, true).iter().any(
                                     |&(_, feature)| {
                                         if let Some(feature) = feature {
                                             self.tcx
@@ -634,6 +634,9 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
             InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
+                unreachable!("clobber-only")
+            }
             InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
             InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
@@ -653,6 +656,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
             InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
             InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
             | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
                 unreachable!("clobber-only")
@@ -682,6 +686,12 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
+                unreachable!("clobber-only")
+            }
+            InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
             InlineAsmRegClass::Err => unreachable!(),
         },
     };
@@ -713,6 +723,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
             cx.type_vector(cx.type_i64(), 2)
         }
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
+            unreachable!("clobber-only")
+        }
         InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
         InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
@@ -723,6 +736,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
+            cx.type_vector(cx.type_i32(), 4)
+        }
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
         | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
             unreachable!("clobber-only")
@@ -757,6 +773,12 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
             S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
         ) => cx.type_i32(),
         InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
+            unreachable!("clobber-only")
+        }
+        InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
         InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
@@ -770,7 +792,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
     }
 }
 
-impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn codegen_global_asm(
         &self,
         template: &[InlineAsmTemplatePiece],
@@ -936,6 +958,7 @@ fn modifier_to_gcc(
         },
         InlineAsmRegClass::Avr(_) => None,
         InlineAsmRegClass::S390x(_) => None,
+        InlineAsmRegClass::Sparc(_) => None,
         InlineAsmRegClass::Msp430(_) => None,
         InlineAsmRegClass::M68k(_) => None,
         InlineAsmRegClass::CSKY(_) => None,
diff --git a/src/attributes.rs b/src/attributes.rs
index 5fdf2680aac..d20e13e15b9 100644
--- a/src/attributes.rs
+++ b/src/attributes.rs
@@ -7,11 +7,9 @@ use rustc_attr::InstructionSetAttr;
 #[cfg(feature = "master")]
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty;
-use rustc_span::symbol::sym;
 
 use crate::context::CodegenCx;
-use crate::errors::TiedTargetFeatures;
-use crate::gcc_util::{check_tied_features, to_gcc_features};
+use crate::gcc_util::to_gcc_features;
 
 /// Get GCC attribute for the provided inline heuristic.
 #[cfg(feature = "master")]
@@ -72,26 +70,10 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
         }
     }
 
-    let function_features = codegen_fn_attrs
+    let mut function_features = codegen_fn_attrs
         .target_features
         .iter()
         .map(|features| features.name.as_str())
-        .collect::<Vec<&str>>();
-
-    if let Some(features) = check_tied_features(
-        cx.tcx.sess,
-        &function_features.iter().map(|features| (*features, true)).collect(),
-    ) {
-        let span = cx
-            .tcx
-            .get_attr(instance.def_id(), sym::target_feature)
-            .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
-        cx.tcx.dcx().create_err(TiedTargetFeatures { features: features.join(", "), span }).emit();
-        return;
-    }
-
-    let mut function_features = function_features
-        .iter()
         .flat_map(|feat| to_gcc_features(cx.tcx.sess, feat).into_iter())
         .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match *x {
             InstructionSetAttr::ArmA32 => "-thumb-mode", // TODO(antoyo): support removing feature.
diff --git a/src/back/lto.rs b/src/back/lto.rs
index 6b2dbbbed67..8371a025d90 100644
--- a/src/back/lto.rs
+++ b/src/back/lto.rs
@@ -27,7 +27,7 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
 use rustc_codegen_ssa::traits::*;
-use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
+use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file};
 use rustc_data_structures::memmap::Mmap;
 use rustc_errors::{DiagCtxtHandle, FatalError};
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -35,15 +35,12 @@ use rustc_middle::bug;
 use rustc_middle::dep_graph::WorkProduct;
 use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
 use rustc_session::config::{CrateType, Lto};
-use tempfile::{tempdir, TempDir};
+use rustc_target::spec::RelocModel;
+use tempfile::{TempDir, tempdir};
 
 use crate::back::write::save_temp_bitcode;
 use crate::errors::{DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib};
-use crate::{to_gcc_opt_level, GccCodegenBackend, GccContext, SyncContext};
-
-/// We keep track of the computed LTO cache keys from the previous
-/// session to determine which CGUs we can reuse.
-//pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
+use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
 
 pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
     match crate_type {
@@ -54,7 +51,7 @@ pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
 
 struct LtoData {
     // TODO(antoyo): use symbols_below_threshold.
-    //symbols_below_threshold: Vec<CString>,
+    //symbols_below_threshold: Vec<String>,
     upstream_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     tmp_path: TempDir,
 }
@@ -83,7 +80,7 @@ fn prepare_lto(
 
     let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
         if info.level.is_below_threshold(export_threshold) || info.used {
-            Some(CString::new(name.as_str()).unwrap())
+            Some(name.clone())
         } else {
             None
         }
@@ -91,7 +88,7 @@ fn prepare_lto(
     let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
     let mut symbols_below_threshold = {
         let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold");
-        exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<CString>>()
+        exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<String>>()
     };
     info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
 
@@ -159,11 +156,7 @@ fn prepare_lto(
         }
     }
 
-    Ok(LtoData {
-        //symbols_below_threshold,
-        upstream_modules,
-        tmp_path,
-    })
+    Ok(LtoData { upstream_modules, tmp_path })
 }
 
 fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> {
@@ -191,7 +184,7 @@ pub(crate) fn run_fat(
         cached_modules,
         lto_data.upstream_modules,
         lto_data.tmp_path,
-        //&symbols_below_threshold,
+        //&lto_data.symbols_below_threshold,
     )
 }
 
@@ -202,7 +195,7 @@ fn fat_lto(
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
     mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     tmp_path: TempDir,
-    //symbols_below_threshold: &[*const libc::c_char],
+    //symbols_below_threshold: &[String],
 ) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
     let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module");
     info!("going for a fat lto");
@@ -272,7 +265,6 @@ fn fat_lto(
             }*/
         }
     };
-    let mut serialized_bitcode = Vec::new();
     {
         info!("using {:?} as a base module", module.name);
 
@@ -317,7 +309,6 @@ fn fat_lto(
                     unimplemented!("from uncompressed file")
                 }
             }
-            serialized_bitcode.push(bc_decoded);
         }
         save_temp_bitcode(cgcx, &module, "lto.input");
 
@@ -329,6 +320,7 @@ fn fat_lto(
             ptr as *const *const libc::c_char,
             symbols_below_threshold.len() as libc::size_t,
         );*/
+
         save_temp_bitcode(cgcx, &module, "lto.after-restriction");
         //}
     }
@@ -337,7 +329,7 @@ fn fat_lto(
     // of now.
     module.module_llvm.temp_dir = Some(tmp_path);
 
-    Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode })
+    Ok(LtoModuleCodegen::Fat(module))
 }
 
 pub struct ModuleBuffer(PathBuf);
@@ -365,8 +357,6 @@ pub(crate) fn run_thin(
     let dcx = cgcx.create_dcx();
     let dcx = dcx.handle();
     let lto_data = prepare_lto(cgcx, dcx)?;
-    /*let symbols_below_threshold =
-    symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
     if cgcx.opts.cg.linker_plugin_lto.enabled() {
         unreachable!(
             "We should never reach this case if the LTO step \
@@ -379,7 +369,8 @@ pub(crate) fn run_thin(
         modules,
         lto_data.upstream_modules,
         lto_data.tmp_path,
-        cached_modules, /*, &symbols_below_threshold*/
+        cached_modules,
+        //&lto_data.symbols_below_threshold,
     )
 }
 
@@ -430,7 +421,7 @@ fn thin_lto(
     serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     tmp_path: TempDir,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
-    //symbols_below_threshold: &[*const libc::c_char],
+    //_symbols_below_threshold: &[String],
 ) -> Result<(Vec<LtoModuleCodegen<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> {
     let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis");
     info!("going for that thin, thin LTO");
@@ -642,7 +633,13 @@ pub unsafe fn optimize_thin_module(
         }
     };
     let module = ModuleCodegen {
-        module_llvm: GccContext { context, should_combine_object_files, temp_dir: None },
+        module_llvm: GccContext {
+            context,
+            should_combine_object_files,
+            // TODO(antoyo): use the correct relocation model here.
+            relocation_model: RelocModel::Pic,
+            temp_dir: None,
+        },
         name: thin_module.name().to_string(),
         kind: ModuleKind::Regular,
     };
diff --git a/src/back/write.rs b/src/back/write.rs
index 802968979c7..51c5ba73e32 100644
--- a/src/back/write.rs
+++ b/src/back/write.rs
@@ -1,6 +1,6 @@
 use std::{env, fs};
 
-use gccjit::OutputKind;
+use gccjit::{Context, OutputKind};
 use rustc_codegen_ssa::back::link::ensure_removed;
 use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
@@ -10,6 +10,7 @@ use rustc_session::config::OutputType;
 use rustc_span::fatal_error::FatalError;
 use rustc_target::spec::SplitDebuginfo;
 
+use crate::base::add_pic_option;
 use crate::errors::CopyBitcode;
 use crate::{GccCodegenBackend, GccContext};
 
@@ -31,51 +32,87 @@ pub(crate) unsafe fn codegen(
 
         // NOTE: Only generate object files with GIMPLE when this environment variable is set for
         // now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit).
-        // TODO: remove this environment variable.
+        // TODO(antoyo): remove this environment variable.
         let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1");
 
         let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
         let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
 
-        if config.bitcode_needed() && fat_lto {
-            let _timer = cgcx
-                .prof
-                .generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
-
-            // TODO(antoyo)
-            /*if let Some(bitcode_filename) = bc_out.file_name() {
-                cgcx.prof.artifact_size(
-                    "llvm_bitcode",
-                    bitcode_filename.to_string_lossy(),
-                    data.len() as u64,
-                );
-            }*/
-
-            if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
+        if config.bitcode_needed() {
+            if fat_lto {
                 let _timer = cgcx
                     .prof
-                    .generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name);
-                context.add_command_line_option("-flto=auto");
-                context.add_command_line_option("-flto-partition=one");
-                // TODO: remove since we don't want fat objects when it is for Bitcode only.
-                context.add_command_line_option("-ffat-lto-objects");
-                context
-                    .compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
-            }
+                    .generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
 
-            if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
-                let _timer = cgcx
-                    .prof
-                    .generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name);
-                // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
-                //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
-
-                context.add_command_line_option("-flto=auto");
-                context.add_command_line_option("-flto-partition=one");
-                context.add_command_line_option("-ffat-lto-objects");
-                // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
-                context
-                    .compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
+                // TODO(antoyo)
+                /*if let Some(bitcode_filename) = bc_out.file_name() {
+                    cgcx.prof.artifact_size(
+                        "llvm_bitcode",
+                        bitcode_filename.to_string_lossy(),
+                        data.len() as u64,
+                    );
+                }*/
+
+                if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_emit_bitcode",
+                        &*module.name,
+                    );
+                    context.add_command_line_option("-flto=auto");
+                    context.add_command_line_option("-flto-partition=one");
+                    // TODO(antoyo): remove since we don't want fat objects when it is for Bitcode only.
+                    context.add_command_line_option("-ffat-lto-objects");
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
+
+                if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_embed_bitcode",
+                        &*module.name,
+                    );
+                    // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
+                    //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
+
+                    context.add_command_line_option("-flto=auto");
+                    context.add_command_line_option("-flto-partition=one");
+                    context.add_command_line_option("-ffat-lto-objects");
+                    // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
+            } else {
+                if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_emit_bitcode",
+                        &*module.name,
+                    );
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
+
+                if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
+                    // TODO(antoyo): we might want to emit to emit an error here, saying to set the
+                    // environment variable EMBED_LTO_BITCODE.
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_embed_bitcode",
+                        &*module.name,
+                    );
+                    // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
+                    //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
+
+                    // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
             }
         }
 
@@ -123,6 +160,8 @@ pub(crate) unsafe fn codegen(
 
                         // NOTE: without -fuse-linker-plugin, we get the following error:
                         // lto1: internal compiler error: decompressed stream: Destination buffer is too small
+                        // TODO(antoyo): since we do not do LTO when the linker is invoked anymore, perhaps
+                        // the following flag is not necessary anymore.
                         context.add_driver_option("-fuse-linker-plugin");
                     }
 
@@ -131,11 +170,43 @@ pub(crate) unsafe fn codegen(
                     // /usr/bin/ld: cannot find -lgcc_s: No such file or directory
                     context.add_driver_option("-nostdlib");
 
-                    // NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o.
-                    context.compile_to_file(
-                        OutputKind::Executable,
-                        obj_out.to_str().expect("path to str"),
-                    );
+                    let path = obj_out.to_str().expect("path to str");
+
+                    if fat_lto {
+                        let lto_path = format!("{}.lto", path);
+                        // FIXME(antoyo): The LTO frontend generates the following warning:
+                        // ../build_sysroot/sysroot_src/library/core/src/num/dec2flt/lemire.rs:150:15: warning: type of ‘_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E’ does not match original declaration [-Wlto-type-mismatch]
+                        // 150 |     let (lo5, hi5) = POWER_OF_FIVE_128[index];
+                        //     |               ^
+                        // lto1: note: ‘_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E’ was previously declared here
+                        //
+                        // This option is to mute it to make the UI tests pass with LTO enabled.
+                        context.add_driver_option("-Wno-lto-type-mismatch");
+                        // NOTE: this doesn't actually generate an executable. With the above
+                        // flags, it combines the .o files together in another .o.
+                        context.compile_to_file(OutputKind::Executable, &lto_path);
+
+                        let context = Context::default();
+                        if cgcx.target_arch == "x86" || cgcx.target_arch == "x86_64" {
+                            // NOTE: it seems we need to use add_driver_option instead of
+                            // add_command_line_option here because we use the LTO frontend via gcc.
+                            context.add_driver_option("-masm=intel");
+                        }
+
+                        // NOTE: these two options are needed to invoke LTO to produce an object file.
+                        // We need to initiate a second compilation because the arguments "-x lto"
+                        // needs to be at the very beginning.
+                        context.add_driver_option("-x");
+                        context.add_driver_option("lto");
+                        add_pic_option(&context, module.module_llvm.relocation_model);
+                        context.add_driver_option(lto_path);
+
+                        context.compile_to_file(OutputKind::ObjectFile, path);
+                    } else {
+                        // NOTE: this doesn't actually generate an executable. With the above
+                        // flags, it combines the .o files together in another .o.
+                        context.compile_to_file(OutputKind::Executable, path);
+                    }
                 } else {
                     context.compile_to_file(
                         OutputKind::ObjectFile,
diff --git a/src/base.rs b/src/base.rs
index 2838aad1afe..c9701fb9885 100644
--- a/src/base.rs
+++ b/src/base.rs
@@ -3,10 +3,10 @@ use std::env;
 use std::sync::Arc;
 use std::time::Instant;
 
-use gccjit::{CType, FunctionType, GlobalKind};
+use gccjit::{CType, Context, FunctionType, GlobalKind};
 use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
 use rustc_codegen_ssa::mono_item::MonoItemExt;
-use rustc_codegen_ssa::traits::DebugInfoMethods;
+use rustc_codegen_ssa::traits::DebugInfoCodegenMethods;
 use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
 use rustc_middle::dep_graph;
 use rustc_middle::mir::mono::Linkage;
@@ -15,21 +15,32 @@ use rustc_middle::mir::mono::Visibility;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::DebugInfo;
 use rustc_span::Symbol;
-use rustc_target::spec::PanicStrategy;
+#[cfg(feature = "master")]
+use rustc_target::spec::SymbolVisibility;
+use rustc_target::spec::{PanicStrategy, RelocModel};
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
-use crate::{gcc_util, new_context, GccContext, LockedTargetInfo, SyncContext};
+use crate::{GccContext, LockedTargetInfo, SyncContext, gcc_util, new_context};
 
 #[cfg(feature = "master")]
-pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility {
-    match linkage {
+pub fn visibility_to_gcc(visibility: Visibility) -> gccjit::Visibility {
+    match visibility {
         Visibility::Default => gccjit::Visibility::Default,
         Visibility::Hidden => gccjit::Visibility::Hidden,
         Visibility::Protected => gccjit::Visibility::Protected,
     }
 }
 
+#[cfg(feature = "master")]
+pub fn symbol_visibility_to_gcc(visibility: SymbolVisibility) -> gccjit::Visibility {
+    match visibility {
+        SymbolVisibility::Hidden => gccjit::Visibility::Hidden,
+        SymbolVisibility::Protected => gccjit::Visibility::Protected,
+        SymbolVisibility::Interposable => gccjit::Visibility::Default,
+    }
+}
+
 pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
     match linkage {
         Linkage::External => GlobalKind::Imported,
@@ -140,9 +151,7 @@ pub fn compile_codegen_unit(
             });
         }
 
-        if tcx.sess.relocation_model() == rustc_target::spec::RelocModel::Static {
-            context.add_command_line_option("-fno-pie");
-        }
+        add_pic_option(&context, tcx.sess.relocation_model());
 
         let target_cpu = gcc_util::target_cpu(tcx.sess);
         if target_cpu != "generic" {
@@ -236,6 +245,7 @@ pub fn compile_codegen_unit(
             name: cgu_name.to_string(),
             module_llvm: GccContext {
                 context: Arc::new(SyncContext::new(context)),
+                relocation_model: tcx.sess.relocation_model(),
                 should_combine_object_files: false,
                 temp_dir: None,
             },
@@ -245,3 +255,24 @@ pub fn compile_codegen_unit(
 
     (module, cost)
 }
+
+pub fn add_pic_option<'gcc>(context: &Context<'gcc>, relocation_model: RelocModel) {
+    match relocation_model {
+        rustc_target::spec::RelocModel::Static => {
+            context.add_command_line_option("-fno-pie");
+            context.add_driver_option("-fno-pie");
+        }
+        rustc_target::spec::RelocModel::Pic => {
+            context.add_command_line_option("-fPIC");
+            // NOTE: we use both add_command_line_option and add_driver_option because the usage in
+            // this module (compile_codegen_unit) requires add_command_line_option while the usage
+            // in the back::write module (codegen) requires add_driver_option.
+            context.add_driver_option("-fPIC");
+        }
+        rustc_target::spec::RelocModel::Pie => {
+            context.add_command_line_option("-fPIE");
+            context.add_driver_option("-fPIE");
+        }
+        model => eprintln!("Unsupported relocation model: {:?}", model),
+    }
+}
diff --git a/src/builder.rs b/src/builder.rs
index 098058f54ca..89e5cf1b8c6 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -7,32 +7,32 @@ use gccjit::{
     BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type,
     UnaryOp,
 };
-use rustc_apfloat::{ieee, Float, Round, Status};
+use rustc_abi as abi;
+use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout, WrappingRange};
+use rustc_apfloat::{Float, Round, Status, ieee};
+use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::common::{
     AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
 };
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::{
-    BackendTypes, BaseTypeMethods, BuilderMethods, ConstMethods, HasCodegen, LayoutTypeMethods,
-    OverflowOp, StaticBuilderMethods,
+    BackendTypes, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods,
+    LayoutTypeCodegenMethods, OverflowOp, StaticBuilderMethods,
 };
-use rustc_codegen_ssa::MemFlags;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers,
-    TyAndLayout,
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
 };
-use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
-use rustc_span::def_id::DefId;
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_span::Span;
+use rustc_span::def_id::DefId;
 use rustc_target::abi::call::FnAbi;
-use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange};
-use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
+use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi};
 
-use crate::common::{type_is_pointer, SignType, TypeReflection};
+use crate::common::{SignType, TypeReflection, type_is_pointer};
 use crate::context::CodegenCx;
 use crate::intrinsic::llvm;
 use crate::type_of::LayoutGccExt;
@@ -155,11 +155,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         // NOTE: not sure why, but we have the wrong type here.
         let int_type = compare_exchange.get_param(2).to_rvalue().get_type();
         let src = self.context.new_bitcast(self.location, src, int_type);
-        self.context.new_call(
-            self.location,
-            compare_exchange,
-            &[dst, expected, src, weak, order, failure_order],
-        )
+        self.context.new_call(self.location, compare_exchange, &[
+            dst,
+            expected,
+            src,
+            weak,
+            order,
+            failure_order,
+        ])
     }
 
     pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) {
@@ -454,10 +457,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> HasCodegen<'tcx> for Builder<'_, 'gcc, 'tcx> {
-    type CodegenCx = CodegenCx<'gcc, 'tcx>;
-}
-
 impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.cx.tcx()
@@ -471,8 +470,6 @@ impl HasDataLayout for Builder<'_, '_, '_> {
 }
 
 impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
-    type LayoutOfResult = TyAndLayout<'tcx>;
-
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
         self.cx.handle_layout_err(err, span, ty)
@@ -480,8 +477,6 @@ impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
 }
 
 impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
-    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
-
     #[inline]
     fn handle_fn_abi_err(
         &self,
@@ -503,6 +498,7 @@ impl<'a, 'gcc, 'tcx> Deref for Builder<'a, 'gcc, 'tcx> {
 
 impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> {
     type Value = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Value;
+    type Metadata = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Metadata;
     type Function = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Function;
     type BasicBlock = <CodegenCx<'gcc, 'tcx> as BackendTypes>::BasicBlock;
     type Type = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Type;
@@ -525,6 +521,8 @@ fn set_rvalue_location<'a, 'gcc, 'tcx>(
 }
 
 impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
+    type CodegenCx = CodegenCx<'gcc, 'tcx>;
+
     fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> {
         Builder::with_cx(cx, block)
     }
@@ -1001,12 +999,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         ) {
             let vr = scalar.valid_range(bx);
             match scalar.primitive() {
-                abi::Int(..) => {
+                abi::Primitive::Int(..) => {
                     if !scalar.is_always_valid(bx) {
                         bx.range_metadata(load, vr);
                     }
                 }
-                abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
+                abi::Primitive::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
                     bx.nonnull_metadata(load);
                 }
                 _ => {}
@@ -1018,11 +1016,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
             OperandValue::Ref(place.val)
         } else if place.layout.is_gcc_immediate() {
             let load = self.load(place.layout.gcc_type(self), place.val.llval, place.val.align);
-            if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
+            if let abi::BackendRepr::Scalar(ref scalar) = place.layout.backend_repr {
                 scalar_load_metadata(self, load, scalar);
             }
             OperandValue::Immediate(self.to_immediate(load, place.layout))
-        } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
+        } else if let abi::BackendRepr::ScalarPair(ref a, ref b) = place.layout.backend_repr {
             let b_offset = a.size(self).align_to(b.align(self).abi);
 
             let mut load = |i, scalar: &abi::Scalar, align| {
@@ -1078,11 +1076,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         let align = dest.val.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
         cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align));
 
-        let next = self.inbounds_gep(
-            self.backend_type(cg_elem.layout),
-            current.to_rvalue(),
-            &[self.const_usize(1)],
-        );
+        let next = self.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[
+            self.const_usize(1),
+        ]);
         self.llbb().add_assignment(self.location, current, next);
         self.br(header_bb);
 
@@ -1125,6 +1121,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         self.llbb().add_assignment(self.location, modified_destination, val);
         // TODO(antoyo): handle `MemFlags::NONTEMPORAL`.
         // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
+        // When adding support for NONTEMPORAL, make sure to not just emit MOVNT on x86; see the
+        // LLVM backend for details.
         self.cx.context.new_rvalue_zero(self.type_i32())
     }
 
@@ -1733,16 +1731,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
         self.fptoint_sat(true, val, dest_ty)
     }
-
-    fn instrprof_increment(
-        &mut self,
-        _fn_name: RValue<'gcc>,
-        _hash: RValue<'gcc>,
-        _num_counters: RValue<'gcc>,
-        _index: RValue<'gcc>,
-    ) {
-        unimplemented!();
-    }
 }
 
 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
@@ -1919,15 +1907,20 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         v2: RValue<'gcc>,
         mask: RValue<'gcc>,
     ) -> RValue<'gcc> {
-        let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
+        // NOTE: if the `mask` is a constant value, the following code will copy it in many places,
+        // which will make GCC create a lot (+4000) local variables in some cases.
+        // So we assign it to an explicit local variable once to avoid this.
+        let func = self.current_func();
+        let mask_var = func.new_local(self.location, mask.get_type(), "mask");
+        let block = self.block;
+        block.add_assignment(self.location, mask_var, mask);
+        let mask = mask_var.to_rvalue();
 
         // TODO(antoyo): use a recursive unqualified() here.
         let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");
         let element_type = vector_type.get_element_type();
         let vec_num_units = vector_type.get_num_units();
 
-        let mask_num_units = struct_type.get_field_count();
-        let mut vector_elements = vec![];
         let mask_element_type = if element_type.is_integral() {
             element_type
         } else {
@@ -1938,19 +1931,41 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             #[cfg(not(feature = "master"))]
             self.int_type
         };
-        for i in 0..mask_num_units {
-            let field = struct_type.get_field(i as i32);
-            vector_elements.push(self.context.new_cast(
-                self.location,
-                mask.access_field(self.location, field).to_rvalue(),
-                mask_element_type,
-            ));
-        }
+
+        // NOTE: this condition is needed because we call shuffle_vector in the implementation of
+        // simd_gather.
+        let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() {
+            let mask_num_units = vector_type.get_num_units();
+            let mut mask_elements = vec![];
+            for i in 0..mask_num_units {
+                let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
+                mask_elements.push(self.context.new_cast(
+                    self.location,
+                    self.extract_element(mask, index).to_rvalue(),
+                    mask_element_type,
+                ));
+            }
+            mask_elements
+        } else {
+            let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
+            let mask_num_units = struct_type.get_field_count();
+            let mut mask_elements = vec![];
+            for i in 0..mask_num_units {
+                let field = struct_type.get_field(i as i32);
+                mask_elements.push(self.context.new_cast(
+                    self.location,
+                    mask.access_field(self.location, field).to_rvalue(),
+                    mask_element_type,
+                ));
+            }
+            mask_elements
+        };
+        let mask_num_units = mask_elements.len();
 
         // NOTE: the mask needs to be the same length as the input vectors, so add the missing
         // elements in the mask if needed.
         for _ in mask_num_units..vec_num_units {
-            vector_elements.push(self.context.new_rvalue_zero(mask_element_type));
+            mask_elements.push(self.context.new_rvalue_zero(mask_element_type));
         }
 
         let result_type = self.context.new_vector_type(element_type, mask_num_units as u64);
@@ -1994,7 +2009,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
 
         let new_mask_num_units = std::cmp::max(mask_num_units, vec_num_units);
         let mask_type = self.context.new_vector_type(mask_element_type, new_mask_num_units as u64);
-        let mask = self.context.new_rvalue_from_vector(self.location, mask_type, &vector_elements);
+        let mask = self.context.new_rvalue_from_vector(self.location, mask_type, &mask_elements);
         let result = self.context.new_rvalue_vector_perm(self.location, v1, v2, mask);
 
         if vec_num_units != mask_num_units {
@@ -2336,9 +2351,9 @@ impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> {
     }
 }
 
-impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
-    fn param_env(&self) -> ParamEnv<'tcx> {
-        self.cx.param_env()
+impl<'tcx> HasTypingEnv<'tcx> for Builder<'_, '_, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.cx.typing_env()
     }
 }
 
@@ -2354,6 +2369,12 @@ impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> {
     }
 }
 
+impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> {
+    fn x86_abi_opt(&self) -> X86Abi {
+        self.cx.x86_abi_opt()
+    }
+}
+
 pub trait ToGccComp {
     fn to_gcc_comparison(&self) -> ComparisonOp;
 }
diff --git a/src/callee.rs b/src/callee.rs
index 9ad2e90122f..e9682a84d0f 100644
--- a/src/callee.rs
+++ b/src/callee.rs
@@ -72,96 +72,74 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
 
         attributes::from_fn_attrs(cx, func, instance);
 
-        let instance_def_id = instance.def_id();
-
-        // TODO(antoyo): set linkage and attributes.
-
-        // Apply an appropriate linkage/visibility value to our item that we
-        // just declared.
-        //
-        // This is sort of subtle. Inside our codegen unit we started off
-        // compilation by predefining all our own `MonoItem` instances. That
-        // is, everything we're codegenning ourselves is already defined. That
-        // means that anything we're actually codegenning in this codegen unit
-        // will have hit the above branch in `get_declared_value`. As a result,
-        // we're guaranteed here that we're declaring a symbol that won't get
-        // defined, or in other words we're referencing a value from another
-        // codegen unit or even another crate.
-        //
-        // So because this is a foreign value we blanket apply an external
-        // linkage directive because it's coming from a different object file.
-        // The visibility here is where it gets tricky. This symbol could be
-        // referencing some foreign crate or foreign library (an `extern`
-        // block) in which case we want to leave the default visibility. We may
-        // also, though, have multiple codegen units. It could be a
-        // monomorphization, in which case its expected visibility depends on
-        // whether we are sharing generics or not. The important thing here is
-        // that the visibility we apply to the declaration is the same one that
-        // has been applied to the definition (wherever that definition may be).
-        let is_generic =
-            instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
-
-        if is_generic {
-            // This is a monomorphization. Its expected visibility depends
-            // on whether we are in share-generics mode.
-
-            if cx.tcx.sess.opts.share_generics() {
-                // We are in share_generics mode.
-
-                if let Some(instance_def_id) = instance_def_id.as_local() {
-                    // This is a definition from the current crate. If the
-                    // definition is unreachable for downstream crates or
-                    // the current crate does not re-export generics, the
-                    // definition of the instance will have been declared
-                    // as `hidden`.
-                    if cx.tcx.is_unreachable_local_definition(instance_def_id)
+        #[cfg(feature = "master")]
+        {
+            let instance_def_id = instance.def_id();
+
+            // TODO(antoyo): set linkage and attributes.
+
+            // Apply an appropriate linkage/visibility value to our item that we
+            // just declared.
+            //
+            // This is sort of subtle. Inside our codegen unit we started off
+            // compilation by predefining all our own `MonoItem` instances. That
+            // is, everything we're codegenning ourselves is already defined. That
+            // means that anything we're actually codegenning in this codegen unit
+            // will have hit the above branch in `get_declared_value`. As a result,
+            // we're guaranteed here that we're declaring a symbol that won't get
+            // defined, or in other words we're referencing a value from another
+            // codegen unit or even another crate.
+            //
+            // So because this is a foreign value we blanket apply an external
+            // linkage directive because it's coming from a different object file.
+            // The visibility here is where it gets tricky. This symbol could be
+            // referencing some foreign crate or foreign library (an `extern`
+            // block) in which case we want to leave the default visibility. We may
+            // also, though, have multiple codegen units. It could be a
+            // monomorphization, in which case its expected visibility depends on
+            // whether we are sharing generics or not. The important thing here is
+            // that the visibility we apply to the declaration is the same one that
+            // has been applied to the definition (wherever that definition may be).
+            let is_generic = instance.args.non_erasable_generics().next().is_some();
+
+            let is_hidden = if is_generic {
+                // This is a monomorphization of a generic function.
+                if !(cx.tcx.sess.opts.share_generics()
+                    || tcx.codegen_fn_attrs(instance_def_id).inline
+                        == rustc_attr::InlineAttr::Never)
+                {
+                    // When not sharing generics, all instances are in the same
+                    // crate and have hidden visibility.
+                    true
+                } else if let Some(instance_def_id) = instance_def_id.as_local() {
+                    // This is a monomorphization of a generic function
+                    // defined in the current crate. It is hidden if:
+                    // - the definition is unreachable for downstream
+                    //   crates, or
+                    // - the current crate does not re-export generics
+                    //   (because the crate is a C library or executable)
+                    cx.tcx.is_unreachable_local_definition(instance_def_id)
                         || !cx.tcx.local_crate_exports_generics()
-                    {
-                        #[cfg(feature = "master")]
-                        func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                    }
                 } else {
                     // This is a monomorphization of a generic function
-                    // defined in an upstream crate.
-                    if instance.upstream_monomorphization(tcx).is_some() {
-                        // This is instantiated in another crate. It cannot
-                        // be `hidden`.
-                    } else {
-                        // This is a local instantiation of an upstream definition.
-                        // If the current crate does not re-export it
-                        // (because it is a C library or an executable), it
-                        // will have been declared `hidden`.
-                        if !cx.tcx.local_crate_exports_generics() {
-                            #[cfg(feature = "master")]
-                            func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                        }
-                    }
+                    // defined in an upstream crate. It is hidden if:
+                    // - it is instantiated in this crate, and
+                    // - the current crate does not re-export generics
+                    instance.upstream_monomorphization(tcx).is_none()
+                        && !cx.tcx.local_crate_exports_generics()
                 }
             } else {
-                // When not sharing generics, all instances are in the same
-                // crate and have hidden visibility
-                #[cfg(feature = "master")]
+                // This is a non-generic function. It is hidden if:
+                // - it is instantiated in the local crate, and
+                //   - it is defined an upstream crate (non-local), or
+                //   - it is not reachable
+                cx.tcx.is_codegened_item(instance_def_id)
+                    && (!instance_def_id.is_local()
+                        || !cx.tcx.is_reachable_non_generic(instance_def_id))
+            };
+            if is_hidden {
                 func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
             }
-        } else {
-            // This is a non-generic function
-            if cx.tcx.is_codegened_item(instance_def_id) {
-                // This is a function that is instantiated in the local crate
-
-                if instance_def_id.is_local() {
-                    // This is function that is defined in the local crate.
-                    // If it is not reachable, it is hidden.
-                    if !cx.tcx.is_reachable_non_generic(instance_def_id) {
-                        #[cfg(feature = "master")]
-                        func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                    }
-                } else {
-                    // This is a function from an upstream crate that has
-                    // been instantiated here. These are always hidden.
-                    #[cfg(feature = "master")]
-                    func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                }
-            }
         }
 
         func
diff --git a/src/common.rs b/src/common.rs
index c849d833d73..f43743fc2a4 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -1,9 +1,13 @@
 use gccjit::{LValue, RValue, ToRValue, Type};
-use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods};
-use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
+use rustc_abi as abi;
+use rustc_abi::HasDataLayout;
+use rustc_abi::Primitive::Pointer;
+use rustc_codegen_ssa::traits::{
+    BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
+};
 use rustc_middle::mir::Mutability;
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_target::abi::{self, HasDataLayout, Pointer};
 
 use crate::consts::const_alloc_to_gcc;
 use crate::context::CodegenCx;
@@ -55,7 +59,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool {
     typ.get_pointee().is_some()
 }
 
-impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
         if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
     }
@@ -78,22 +82,14 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.const_undef(typ)
     }
 
-    fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
-        self.gcc_int(typ, int)
-    }
-
-    fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
-        self.gcc_uint(typ, int)
-    }
-
-    fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
-        self.gcc_uint_big(typ, num)
-    }
-
     fn const_bool(&self, val: bool) -> RValue<'gcc> {
         self.const_uint(self.type_i1(), val as u64)
     }
 
+    fn const_i8(&self, i: i8) -> RValue<'gcc> {
+        self.const_int(self.type_i8(), i as i64)
+    }
+
     fn const_i16(&self, i: i16) -> RValue<'gcc> {
         self.const_int(self.type_i16(), i as i64)
     }
@@ -102,8 +98,12 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.const_int(self.type_i32(), i as i64)
     }
 
-    fn const_i8(&self, i: i8) -> RValue<'gcc> {
-        self.const_int(self.type_i8(), i as i64)
+    fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
+        self.gcc_int(typ, int)
+    }
+
+    fn const_u8(&self, i: u8) -> RValue<'gcc> {
+        self.const_uint(self.type_u8(), i as u64)
     }
 
     fn const_u32(&self, i: u32) -> RValue<'gcc> {
@@ -128,8 +128,12 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.const_uint(self.usize_type, i)
     }
 
-    fn const_u8(&self, i: u8) -> RValue<'gcc> {
-        self.const_uint(self.type_u8(), i as u64)
+    fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
+        self.gcc_uint(typ, int)
+    }
+
+    fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
+        self.gcc_uint_big(typ, num)
     }
 
     fn const_real(&self, typ: Type<'gcc>, val: f64) -> RValue<'gcc> {
@@ -160,6 +164,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
     }
 
+    fn const_vector(&self, values: &[RValue<'gcc>]) -> RValue<'gcc> {
+        let typ = self.type_vector(values[0].get_type(), values.len() as u64);
+        self.context.new_rvalue_from_vector(None, typ, values)
+    }
+
     fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
         // TODO(antoyo)
         None
@@ -217,10 +226,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                         value
                     }
                     GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
-                    GlobalAlloc::VTable(ty, trait_ref) => {
+                    GlobalAlloc::VTable(ty, dyn_ty) => {
                         let alloc = self
                             .tcx
-                            .global_alloc(self.tcx.vtable_allocation((ty, trait_ref)))
+                            .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
                             .unwrap_memory();
                         let init = const_alloc_to_gcc(self, alloc);
                         self.static_addr_of(init, alloc.inner().align, None)
@@ -238,7 +247,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                 if !matches!(layout.primitive(), Pointer(_)) {
                     self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
                 } else {
-                    self.const_bitcast(ptr, ty)
+                    self.context.new_cast(None, ptr, ty)
                 }
             }
         }
diff --git a/src/consts.rs b/src/consts.rs
index 38a626bf73f..1631ecfeecf 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -1,11 +1,13 @@
 #[cfg(feature = "master")]
 use gccjit::{FnAttribute, VarAttribute, Visibility};
 use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type};
-use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, StaticMethods};
+use rustc_codegen_ssa::traits::{
+    BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
+};
 use rustc_hir::def::DefKind;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
-    self, read_target_uint, ConstAllocation, ErrorHandled, Scalar as InterpScalar,
+    self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint,
 };
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::layout::LayoutOf;
@@ -38,7 +40,7 @@ fn set_global_alignment<'gcc, 'tcx>(
     gv.set_alignment(align.bytes() as i32);
 }
 
-impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
     fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
         // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the
         // following:
@@ -144,7 +146,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
 
         // Wasm statics with custom link sections get special treatment as they
         // go into custom sections of the wasm executable.
-        if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+        if self.tcx.sess.target.is_like_wasm {
             if let Some(_section) = attrs.link_section {
                 unimplemented!();
             }
@@ -213,7 +215,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         let gcc_type = if nested {
             self.type_i8()
         } else {
-            let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+            let ty = instance.ty(self.tcx, ty::TypingEnv::fully_monomorphized());
             self.layout_of(ty).gcc_type(self)
         };
 
@@ -250,7 +252,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
             let global = self.declare_global(
                 sym,
                 gcc_type,
-                GlobalKind::Exported,
+                GlobalKind::Imported,
                 is_tls,
                 fn_attrs.link_section,
             );
diff --git a/src/context.rs b/src/context.rs
index 9756f0faae2..c81c53359fd 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -5,22 +5,23 @@ use gccjit::{
 };
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::errors as ssa_errors;
-use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods};
-use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY};
+use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods};
+use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError,
-    LayoutOfHelpers, TyAndLayout,
+    FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
+    LayoutOfHelpers,
 };
-use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::source_map::respan;
-use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::call::FnAbi;
+use rustc_span::{DUMMY_SP, Span};
 use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
-use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi};
+use rustc_target::spec::{
+    HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
+};
 
 use crate::callee::get_fn;
 use crate::common::SignType;
@@ -143,7 +144,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         supports_f128_type: bool,
     ) -> Self {
         let create_type = |ctype, rust_type| {
-            let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap();
+            let layout = tcx
+                .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type))
+                .unwrap();
             let align = layout.align.abi.bytes();
             #[cfg(feature = "master")]
             {
@@ -382,6 +385,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
 
 impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
     type Value = RValue<'gcc>;
+    type Metadata = RValue<'gcc>;
+    // TODO(antoyo): change to Function<'gcc>.
     type Function = RValue<'gcc>;
 
     type BasicBlock = Block<'gcc>;
@@ -393,7 +398,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
     type DIVariable = (); // TODO(antoyo)
 }
 
-impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn vtables(
         &self,
     ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
@@ -457,7 +462,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
             Some(def_id) if !wants_msvc_seh(self.sess()) => {
                 let instance = ty::Instance::expect_resolve(
                     tcx,
-                    ty::ParamEnv::reveal_all(),
+                    self.typing_env(),
                     def_id,
                     ty::List::empty(),
                     DUMMY_SP,
@@ -538,9 +543,16 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
-    type LayoutOfResult = TyAndLayout<'tcx>;
+impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
+    fn x86_abi_opt(&self) -> X86Abi {
+        X86Abi {
+            regparm: self.tcx.sess.opts.unstable_opts.regparm,
+            reg_struct_return: self.tcx.sess.opts.unstable_opts.reg_struct_return,
+        }
+    }
+}
 
+impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
         if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
@@ -552,8 +564,6 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
 }
 
 impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
-    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
-
     #[inline]
     fn handle_fn_abi_err(
         &self,
@@ -579,9 +589,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
     }
 }
 
-impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
-    fn param_env(&self) -> ParamEnv<'tcx> {
-        ParamEnv::reveal_all()
+impl<'tcx, 'gcc> HasTypingEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
     }
 }
 
diff --git a/src/debuginfo.rs b/src/debuginfo.rs
index c2adca34748..6aeb656c1ab 100644
--- a/src/debuginfo.rs
+++ b/src/debuginfo.rs
@@ -2,7 +2,7 @@ use std::ops::Range;
 
 use gccjit::{Location, RValue};
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
-use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
+use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods};
 use rustc_data_structures::sync::Lrc;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{Idx, IndexVec};
@@ -10,8 +10,8 @@ use rustc_middle::mir::{self, Body, SourceScope};
 use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
 use rustc_session::config::DebugInfo;
 use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
-use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Size;
+use rustc_target::abi::call::FnAbi;
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
@@ -48,6 +48,14 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
     fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) {
         self.location = Some(dbg_loc);
     }
+
+    fn clear_dbg_loc(&mut self) {
+        self.location = None;
+    }
+
+    fn get_dbg_loc(&self) -> Option<Self::DILocation> {
+        self.location
+    }
 }
 
 /// Generate the `debug_context` in an MIR Body.
@@ -105,15 +113,15 @@ fn make_mir_scope<'gcc, 'tcx>(
     let scope_data = &mir.source_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
         make_mir_scope(cx, _instance, mir, variables, debug_context, instantiated, parent);
-        debug_context.scopes[parent]
+        debug_context.scopes[parent].unwrap()
     } else {
         // The root is the function itself.
         let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
-        debug_context.scopes[scope] = DebugScope {
+        debug_context.scopes[scope] = Some(DebugScope {
             file_start_pos: file.start_pos,
             file_end_pos: file.end_position(),
-            ..debug_context.scopes[scope]
-        };
+            ..debug_context.scopes[scope].unwrap()
+        });
         instantiated.insert(scope);
         return;
     };
@@ -122,7 +130,7 @@ fn make_mir_scope<'gcc, 'tcx>(
         if !vars.contains(scope) && scope_data.inlined.is_none() {
             // Do not create a DIScope if there are no variables defined in this
             // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
-            debug_context.scopes[scope] = parent_scope;
+            debug_context.scopes[scope] = Some(parent_scope);
             instantiated.insert(scope);
             return;
         }
@@ -149,12 +157,12 @@ fn make_mir_scope<'gcc, 'tcx>(
     // TODO(tempdragon): dbg_scope: Add support for scope extension here.
     inlined_at.or(p_inlined_at);
 
-    debug_context.scopes[scope] = DebugScope {
+    debug_context.scopes[scope] = Some(DebugScope {
         dbg_scope,
         inlined_at,
         file_start_pos: loc.file.start_pos,
         file_end_pos: loc.file.end_position(),
-    };
+    });
     instantiated.insert(scope);
 }
 
@@ -202,7 +210,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn create_vtable_debuginfo(
         &self,
         _ty: Ty<'tcx>,
@@ -224,12 +232,12 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         }
 
         // Initialize fn debug context (including scopes).
-        let empty_scope = DebugScope {
+        let empty_scope = Some(DebugScope {
             dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
-        };
+        });
         let mut fn_debug_context = FunctionDebugContext {
             scopes: IndexVec::from_elem(empty_scope, mir.source_scopes.as_slice()),
             inlined_function_scopes: Default::default(),
diff --git a/src/declare.rs b/src/declare.rs
index aa7709488e6..442488b7fd6 100644
--- a/src/declare.rs
+++ b/src/declare.rs
@@ -1,7 +1,7 @@
 #[cfg(feature = "master")]
 use gccjit::{FnAttribute, ToRValue};
 use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
-use rustc_codegen_ssa::traits::BaseTypeMethods;
+use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::abi::call::FnAbi;
diff --git a/src/errors.rs b/src/errors.rs
index 6bada3d334c..6b4f9d301d8 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,9 +1,6 @@
-use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
 
-use crate::fluent_generated as fluent;
-
 #[derive(Diagnostic)]
 #[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
 #[note]
@@ -20,6 +17,19 @@ pub(crate) struct UnknownCTargetFeature<'a> {
     pub rust_feature: PossibleFeature<'a>,
 }
 
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_unstable_ctarget_feature)]
+#[note]
+pub(crate) struct UnstableCTargetFeature<'a> {
+    pub feature: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_forbidden_ctarget_feature)]
+pub(crate) struct ForbiddenCTargetFeature<'a> {
+    pub feature: &'a str,
+}
+
 #[derive(Subdiagnostic)]
 pub(crate) enum PossibleFeature<'a> {
     #[help(codegen_gcc_possible_feature)]
@@ -29,10 +39,6 @@ pub(crate) enum PossibleFeature<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc_lto_not_supported)]
-pub(crate) struct LTONotSupported;
-
-#[derive(Diagnostic)]
 #[diag(codegen_gcc_unwinding_inline_asm)]
 pub(crate) struct UnwindingInlineAsm {
     #[primary_span]
@@ -46,15 +52,6 @@ pub(crate) struct InvalidMinimumAlignment {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc_tied_target_features)]
-#[help]
-pub(crate) struct TiedTargetFeatures {
-    #[primary_span]
-    pub span: Span,
-    pub features: String,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_gcc_copy_bitcode)]
 pub(crate) struct CopyBitcode {
     pub err: std::io::Error,
@@ -78,27 +75,3 @@ pub(crate) struct LtoDylib;
 pub(crate) struct LtoBitcodeFromRlib {
     pub gcc_err: String,
 }
-
-pub(crate) struct TargetFeatureDisableOrEnable<'a> {
-    pub features: &'a [&'a str],
-    pub span: Option<Span>,
-    pub missing_features: Option<MissingFeatures>,
-}
-
-#[derive(Subdiagnostic)]
-#[help(codegen_gcc_missing_features)]
-pub(crate) struct MissingFeatures;
-
-impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        let mut diag = Diag::new(dcx, level, fluent::codegen_gcc_target_feature_disable_or_enable);
-        if let Some(span) = self.span {
-            diag.span(span);
-        };
-        if let Some(missing_features) = self.missing_features {
-            diag.subdiagnostic(missing_features);
-        }
-        diag.arg("features", self.features.join(", "));
-        diag
-    }
-}
diff --git a/src/gcc_util.rs b/src/gcc_util.rs
index 5308ccdb614..56d89b43500 100644
--- a/src/gcc_util.rs
+++ b/src/gcc_util.rs
@@ -1,14 +1,16 @@
 #[cfg(feature = "master")]
 use gccjit::Context;
+use rustc_codegen_ssa::codegen_attrs::check_tied_features;
+use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
 use rustc_session::Session;
-use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
-use smallvec::{smallvec, SmallVec};
+use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
+use smallvec::{SmallVec, smallvec};
 
 use crate::errors::{
-    PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
-    UnknownCTargetFeaturePrefix,
+    ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
+    UnstableCTargetFeature,
 };
 
 /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
@@ -44,7 +46,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     );
 
     // -Ctarget-features
-    let supported_features = sess.target.supported_target_features();
+    let known_features = sess.target.rust_target_features();
     let mut featsmap = FxHashMap::default();
     let feats = sess
         .opts
@@ -63,37 +65,49 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
                 }
             };
 
+            // Get the backend feature name, if any.
+            // This excludes rustc-specific features, that do not get passed down to GCC.
             let feature = backend_feature_name(s)?;
             // Warn against use of GCC specific feature names on the CLI.
-            if diagnostics && !supported_features.iter().any(|&(v, _, _)| v == feature) {
-                let rust_feature = supported_features.iter().find_map(|&(rust_feature, _, _)| {
-                    let gcc_features = to_gcc_features(sess, rust_feature);
-                    if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) {
-                        Some(rust_feature)
-                    } else {
-                        None
+            if diagnostics {
+                let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
+                match feature_state {
+                    None => {
+                        let rust_feature =
+                            known_features.iter().find_map(|&(rust_feature, _, _)| {
+                                let gcc_features = to_gcc_features(sess, rust_feature);
+                                if gcc_features.contains(&feature)
+                                    && !gcc_features.contains(&rust_feature)
+                                {
+                                    Some(rust_feature)
+                                } else {
+                                    None
+                                }
+                            });
+                        let unknown_feature = if let Some(rust_feature) = rust_feature {
+                            UnknownCTargetFeature {
+                                feature,
+                                rust_feature: PossibleFeature::Some { rust_feature },
+                            }
+                        } else {
+                            UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                        };
+                        sess.dcx().emit_warn(unknown_feature);
                     }
-                });
-                let unknown_feature = if let Some(rust_feature) = rust_feature {
-                    UnknownCTargetFeature {
-                        feature,
-                        rust_feature: PossibleFeature::Some { rust_feature },
+                    Some(&(_, Stability::Stable, _)) => {}
+                    Some(&(_, Stability::Unstable(_), _)) => {
+                        // An unstable feature. Warn about using it.
+                        sess.dcx().emit_warn(UnstableCTargetFeature { feature });
                     }
-                } else {
-                    UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
-                };
-                sess.dcx().emit_warn(unknown_feature);
-            }
+                    Some(&(_, Stability::Forbidden { .. }, _)) => {
+                        sess.dcx().emit_err(ForbiddenCTargetFeature { feature });
+                    }
+                }
 
-            if diagnostics {
                 // FIXME(nagisa): figure out how to not allocate a full hashset here.
                 featsmap.insert(feature, enable_disable == '+');
             }
 
-            // rustc-specific features do not get passed down to GCC…
-            if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-                return None;
-            }
             // ... otherwise though we run through `to_gcc_features` when
             // passing requests down to GCC. This means that all in-language
             // features also work on the command line instead of having two
@@ -185,23 +199,6 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
     }
 }
 
-// Given a map from target_features to whether they are enabled or disabled,
-// ensure only valid combinations are allowed.
-pub fn check_tied_features(
-    sess: &Session,
-    features: &FxHashMap<&str, bool>,
-) -> Option<&'static [&'static str]> {
-    for tied in sess.target.tied_target_features() {
-        // Tied features must be set to the same value, or not set at all
-        let mut tied_iter = tied.iter();
-        let enabled = features.get(tied_iter.next().unwrap());
-        if tied_iter.any(|feature| enabled != features.get(feature)) {
-            return Some(tied);
-        }
-    }
-    None
-}
-
 fn arch_to_gcc(name: &str) -> &str {
     match name {
         "M68020" => "68020",
diff --git a/src/int.rs b/src/int.rs
index 1893d5a17dc..02b760dc733 100644
--- a/src/int.rs
+++ b/src/int.rs
@@ -4,10 +4,10 @@
 
 use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp};
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
-use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp};
-use rustc_middle::ty::{ParamEnv, Ty};
-use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode};
+use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp};
+use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::Endian;
+use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode};
 use rustc_target::spec;
 
 use crate::builder::{Builder, ToGccComp};
@@ -380,7 +380,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         let overflow_field = self.context.new_field(self.location, self.bool_type, "overflow");
 
         let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]);
-        let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap();
+        let layout = self
+            .tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ret_ty))
+            .unwrap();
 
         let arg_abi = ArgAbi { layout, mode: PassMode::Direct(ArgAttributes::new()) };
         let mut fn_abi = FnAbi {
@@ -395,11 +398,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
 
         let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
 
-        let return_type = self.context.new_struct_type(
-            self.location,
-            "result_overflow",
-            &[result_field, overflow_field],
-        );
+        let return_type = self
+            .context
+            .new_struct_type(self.location, "result_overflow", &[result_field, overflow_field]);
         let result = if indirect {
             let return_value =
                 self.current_func().new_local(self.location, return_type.as_type(), "return_value");
@@ -416,11 +417,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             );
             self.llbb().add_eval(
                 self.location,
-                self.context.new_call(
-                    self.location,
-                    func,
-                    &[return_value.get_address(self.location), lhs, rhs],
-                ),
+                self.context.new_call(self.location, func, &[
+                    return_value.get_address(self.location),
+                    lhs,
+                    rhs,
+                ]),
             );
             return_value.to_rvalue()
         } else {
diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs
index 7a8fe134cfc..0a448ded6b1 100644
--- a/src/intrinsic/llvm.rs
+++ b/src/intrinsic/llvm.rs
@@ -1,7 +1,6 @@
 use std::borrow::Cow;
 
-use gccjit::{CType, Context};
-use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp};
+use gccjit::{CType, Context, Function, FunctionPtrType, RValue, ToRValue, UnaryOp};
 use rustc_codegen_ssa::traits::BuilderMethods;
 
 use crate::builder::Builder;
@@ -688,12 +687,11 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
                 let field2 = builder.context.new_field(None, args[1].get_type(), "carryResult");
                 let struct_type =
                     builder.context.new_struct_type(None, "addcarryResult", &[field1, field2]);
-                return_value = builder.context.new_struct_constructor(
-                    None,
-                    struct_type.as_type(),
-                    None,
-                    &[return_value, last_arg.dereference(None).to_rvalue()],
-                );
+                return_value =
+                    builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[
+                        return_value,
+                        last_arg.dereference(None).to_rvalue(),
+                    ]);
             }
         }
         "__builtin_ia32_stmxcsr" => {
@@ -718,12 +716,11 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
             let field2 = builder.context.new_field(None, return_value.get_type(), "success");
             let struct_type =
                 builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]);
-            return_value = builder.context.new_struct_constructor(
-                None,
-                struct_type.as_type(),
-                None,
-                &[random_number, success_variable.to_rvalue()],
-            );
+            return_value =
+                builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[
+                    random_number,
+                    success_variable.to_rvalue(),
+                ]);
         }
         "fma" => {
             let f16_type = builder.context.new_c_type(CType::Float16);
diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs
index d95a7782fa0..a50f716db3a 100644
--- a/src/intrinsic/mod.rs
+++ b/src/intrinsic/mod.rs
@@ -7,28 +7,28 @@ use std::iter;
 #[cfg(feature = "master")]
 use gccjit::FunctionType;
 use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
+use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::common::IntPredicate;
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::{
-    ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods,
+    ArgAbiBuilderMethods, BuilderMethods, ConstCodegenMethods, IntrinsicCallBuilderMethods,
 };
 #[cfg(feature = "master")]
-use rustc_codegen_ssa::traits::{BaseTypeMethods, MiscMethods};
-use rustc_codegen_ssa::MemFlags;
+use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, MiscCodegenMethods};
 use rustc_middle::bug;
-use rustc_middle::ty::layout::LayoutOf;
 #[cfg(feature = "master")]
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance, Ty};
-use rustc_span::{sym, Span, Symbol};
-use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_span::{Span, Symbol, sym};
 use rustc_target::abi::HasDataLayout;
+use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::spec::PanicStrategy;
 #[cfg(feature = "master")]
 use rustc_target::spec::abi::Abi;
-use rustc_target::spec::PanicStrategy;
 
 #[cfg(feature = "master")]
 use crate::abi::FnAbiGccExt;
@@ -66,6 +66,9 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
         sym::log2f64 => "log2",
         sym::fmaf32 => "fmaf",
         sym::fmaf64 => "fma",
+        // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation
+        sym::fmuladdf32 => "fmaf", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f32
+        sym::fmuladdf64 => "fma",  // TODO: use gcc intrinsic analogous to llvm.fmuladd.f64
         sym::fabsf32 => "fabsf",
         sym::fabsf64 => "fabs",
         sym::minnumf32 => "fminf",
@@ -94,7 +97,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
     Some(cx.context.get_builtin_function(gcc_name))
 }
 
-impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
     fn codegen_intrinsic_call(
         &mut self,
         instance: Instance<'tcx>,
@@ -104,7 +107,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         span: Span,
     ) -> Result<(), Instance<'tcx>> {
         let tcx = self.tcx;
-        let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+        let callee_ty = instance.ty(tcx, self.typing_env());
 
         let (def_id, fn_args) = match *callee_ty.kind() {
             ty::FnDef(def_id, fn_args) => (def_id, fn_args),
@@ -112,7 +115,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         };
 
         let sig = callee_ty.fn_sig(tcx);
-        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig);
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = tcx.item_name(def_id);
@@ -136,8 +139,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                 )
             }
-            sym::likely => self.expect(args[0].immediate(), true),
-            sym::unlikely => self.expect(args[0].immediate(), false),
             sym::is_val_statically_known => {
                 let a = args[0].immediate();
                 let builtin = self.context.get_builtin_function("__builtin_constant_p");
@@ -291,13 +292,13 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
             }
 
             sym::raw_eq => {
-                use rustc_target::abi::Abi::*;
+                use rustc_abi::BackendRepr::*;
                 let tp_ty = fn_args.type_at(0);
                 let layout = self.layout_of(tp_ty).layout;
-                let _use_integer_compare = match layout.abi() {
+                let _use_integer_compare = match layout.backend_repr() {
                     Scalar(_) | ScalarPair(_, _) => true,
                     Uninhabited | Vector { .. } => false,
-                    Aggregate { .. } => {
+                    Memory { .. } => {
                         // For rusty ABIs, small aggregates are actually passed
                         // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
                         // so we re-use that same threshold here.
@@ -441,7 +442,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 }
 
-impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+impl<'a, 'gcc, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
     fn store_fn_arg(
         &mut self,
         arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs
index 79b345982c6..1be452e5d05 100644
--- a/src/intrinsic/simd.rs
+++ b/src/intrinsic/simd.rs
@@ -10,14 +10,13 @@ use rustc_codegen_ssa::errors::ExpectedPointerMutability;
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_codegen_ssa::mir::operand::OperandRef;
 use rustc_codegen_ssa::mir::place::PlaceRef;
-use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
+use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
 #[cfg(feature = "master")]
 use rustc_hir as hir;
 use rustc_middle::mir::BinOp;
-use rustc_middle::span_bug;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{Span, Symbol, sym};
 use rustc_target::abi::{Align, Size};
 
 use crate::builder::Builder;
@@ -56,15 +55,18 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     }
 
     let tcx = bx.tcx();
-    let sig =
-        tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
+    let sig = tcx.normalize_erasing_late_bound_regions(
+        ty::TypingEnv::fully_monomorphized(),
+        callee_ty.fn_sig(tcx),
+    );
     let arg_tys = sig.inputs();
 
     if name == sym::simd_select_bitmask {
-        require_simd!(
-            arg_tys[1],
-            InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
-        );
+        require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument {
+            span,
+            name,
+            ty: arg_tys[1]
+        });
         let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
 
         let expected_int_bits = (len.max(8) - 1).next_power_of_two();
@@ -76,8 +78,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
             ty::Array(elem, len)
                 if matches!(*elem.kind(), ty::Uint(ty::UintTy::U8))
-                    && len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
-                        == Some(expected_bytes) =>
+                    && len
+                        .try_to_target_usize(bx.tcx)
+                        .expect("expected monomorphic const in codegen")
+                        == expected_bytes =>
             {
                 let place = PlaceRef::alloca(bx, args[0].layout);
                 args[0].val.store(bx, place);
@@ -136,17 +140,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
-        require!(
-            in_len == out_len,
-            InvalidMonomorphization::ReturnLengthInputType {
-                span,
-                name,
-                in_len,
-                in_ty,
-                ret_ty,
-                out_len
-            }
-        );
+        require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType {
+            span,
+            name,
+            in_len,
+            in_ty,
+            ret_ty,
+            out_len
+        });
         require!(
             bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
             InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty }
@@ -268,17 +269,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         let lo_nibble =
             bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &lo_nibble_elements);
 
-        let mask = bx.context.new_rvalue_from_vector(
-            None,
-            long_byte_vector_type,
-            &vec![bx.context.new_rvalue_from_int(bx.u8_type, 0x0f); byte_vector_type_size as _],
-        );
-
-        let four_vec = bx.context.new_rvalue_from_vector(
-            None,
-            long_byte_vector_type,
-            &vec![bx.context.new_rvalue_from_int(bx.u8_type, 4); byte_vector_type_size as _],
-        );
+        let mask = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &vec![
+            bx.context
+                .new_rvalue_from_int(
+                    bx.u8_type, 0x0f
+                );
+            byte_vector_type_size
+                as _
+        ]);
+
+        let four_vec = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &vec![
+                bx.context
+                    .new_rvalue_from_int(
+                        bx.u8_type, 4
+                    );
+                byte_vector_type_size
+                    as _
+            ]);
 
         // Step 2: Byte-swap the input.
         let swapped = simd_bswap(bx, args[0].immediate());
@@ -369,31 +376,33 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     }
 
     if name == sym::simd_shuffle {
-        // Make sure this is actually an array, since typeck only checks the length-suffixed
-        // version of this intrinsic.
-        let n: u64 = match *args[2].layout.ty.kind() {
-            ty::Array(ty, len) if matches!(*ty.kind(), ty::Uint(ty::UintTy::U32)) => {
-                len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
-                    || span_bug!(span, "could not evaluate shuffle index array length"),
-                )
-            }
-            _ => return_error!(InvalidMonomorphization::SimdShuffle {
-                span,
-                name,
-                ty: args[2].layout.ty
-            }),
+        // Make sure this is actually a SIMD vector.
+        let idx_ty = args[2].layout.ty;
+        let n: u64 = if idx_ty.is_simd()
+            && matches!(*idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
+        {
+            idx_ty.simd_size_and_type(bx.cx.tcx).0
+        } else {
+            return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty })
         };
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
-        require!(
-            out_len == n,
-            InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
-        );
-        require!(
-            in_elem == out_ty,
-            InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
-        );
+        require!(out_len == n, InvalidMonomorphization::ReturnLength {
+            span,
+            name,
+            in_len: n,
+            ret_ty,
+            out_len
+        });
+        require!(in_elem == out_ty, InvalidMonomorphization::ReturnElement {
+            span,
+            name,
+            in_elem,
+            in_ty,
+            ret_ty,
+            out_ty
+        });
 
         let vector = args[2].immediate();
 
@@ -402,16 +411,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
     #[cfg(feature = "master")]
     if name == sym::simd_insert {
-        require!(
-            in_elem == arg_tys[2],
-            InvalidMonomorphization::InsertedType {
-                span,
-                name,
-                in_elem,
-                in_ty,
-                out_ty: arg_tys[2]
-            }
-        );
+        require!(in_elem == arg_tys[2], InvalidMonomorphization::InsertedType {
+            span,
+            name,
+            in_elem,
+            in_ty,
+            out_ty: arg_tys[2]
+        });
         let vector = args[0].immediate();
         let index = args[1].immediate();
         let value = args[2].immediate();
@@ -425,10 +431,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
     #[cfg(feature = "master")]
     if name == sym::simd_extract {
-        require!(
-            ret_ty == in_elem,
-            InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
-        );
+        require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType {
+            span,
+            name,
+            in_elem,
+            in_ty,
+            ret_ty
+        });
         let vector = args[0].immediate();
         return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue());
     }
@@ -436,15 +445,18 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     if name == sym::simd_select {
         let m_elem_ty = in_elem;
         let m_len = in_len;
-        require_simd!(
-            arg_tys[1],
-            InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
-        );
+        require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument {
+            span,
+            name,
+            ty: arg_tys[1]
+        });
         let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
-        require!(
-            m_len == v_len,
-            InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
-        );
+        require!(m_len == v_len, InvalidMonomorphization::MismatchedLengths {
+            span,
+            name,
+            m_len,
+            v_len
+        });
         match *m_elem_ty.kind() {
             ty::Int(_) => {}
             _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
@@ -456,27 +468,25 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
 
-        require!(
-            in_len == out_len,
-            InvalidMonomorphization::ReturnLengthInputType {
-                span,
-                name,
-                in_len,
-                in_ty,
-                ret_ty,
-                out_len
-            }
-        );
+        require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType {
+            span,
+            name,
+            in_len,
+            in_ty,
+            ret_ty,
+            out_len
+        });
 
         match *in_elem.kind() {
             ty::RawPtr(p_ty, _) => {
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
-                    bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
+                    bx.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
+                });
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
+                    span,
+                    name,
+                    ty: in_elem
                 });
-                require!(
-                    metadata.is_unit(),
-                    InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
-                );
             }
             _ => {
                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
@@ -485,12 +495,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         match *out_elem.kind() {
             ty::RawPtr(p_ty, _) => {
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
-                    bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
+                    bx.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
+                });
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
+                    span,
+                    name,
+                    ty: out_elem
                 });
-                require!(
-                    metadata.is_unit(),
-                    InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }
-                );
             }
             _ => {
                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
@@ -513,17 +524,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
 
-        require!(
-            in_len == out_len,
-            InvalidMonomorphization::ReturnLengthInputType {
-                span,
-                name,
-                in_len,
-                in_ty,
-                ret_ty,
-                out_len
-            }
-        );
+        require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType {
+            span,
+            name,
+            in_len,
+            in_ty,
+            ret_ty,
+            out_len
+        });
 
         match *in_elem.kind() {
             ty::RawPtr(_, _) => {}
@@ -552,17 +560,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
 
-        require!(
-            in_len == out_len,
-            InvalidMonomorphization::ReturnLengthInputType {
-                span,
-                name,
-                in_len,
-                in_ty,
-                ret_ty,
-                out_len
-            }
-        );
+        require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType {
+            span,
+            name,
+            in_len,
+            in_ty,
+            ret_ty,
+            out_len
+        });
 
         match *in_elem.kind() {
             ty::Uint(ty::UintTy::Usize) => {}
@@ -591,17 +596,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     if name == sym::simd_cast || name == sym::simd_as {
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
-        require!(
-            in_len == out_len,
-            InvalidMonomorphization::ReturnLengthInputType {
-                span,
-                name,
-                in_len,
-                in_ty,
-                ret_ty,
-                out_len
-            }
-        );
+        require!(in_len == out_len, InvalidMonomorphization::ReturnLengthInputType {
+            span,
+            name,
+            in_len,
+            in_ty,
+            ret_ty,
+            out_len
+        });
         // casting cares about nominal type, not just structural type
         if in_elem == out_elem {
             return Ok(args[0].immediate());
@@ -627,17 +629,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         match (in_style, out_style) {
             (Style::Unsupported, Style::Unsupported) => {
-                require!(
-                    false,
-                    InvalidMonomorphization::UnsupportedCast {
-                        span,
-                        name,
-                        in_ty,
-                        in_elem,
-                        ret_ty,
-                        out_elem
-                    }
-                );
+                require!(false, InvalidMonomorphization::UnsupportedCast {
+                    span,
+                    name,
+                    in_ty,
+                    in_elem,
+                    ret_ty,
+                    out_elem
+                });
             }
             _ => return Ok(bx.context.convert_vector(None, args[0].immediate(), llret_ty)),
         }
@@ -701,8 +700,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             }
             ty::Array(elem, len)
                 if matches!(*elem.kind(), ty::Uint(ty::UintTy::U8))
-                    && len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
-                        == Some(expected_bytes) =>
+                    && len
+                        .try_to_target_usize(bx.tcx)
+                        .expect("expected monomorphic const in codegen")
+                        == expected_bytes =>
             {
                 // Zero-extend iN to the array length:
                 let ze = bx.zext(result, bx.type_ix(expected_bytes * 8));
@@ -771,6 +772,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             sym::simd_flog => "log",
             sym::simd_floor => "floor",
             sym::simd_fma => "fma",
+            sym::simd_relaxed_fma => "fma", // FIXME: this should relax to non-fused multiply-add when necessary
             sym::simd_fpowi => "__builtin_powi",
             sym::simd_fpow => "pow",
             sym::simd_fsin => "sin",
@@ -827,6 +829,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             | sym::simd_flog
             | sym::simd_floor
             | sym::simd_fma
+            | sym::simd_relaxed_fma
             | sym::simd_fpow
             | sym::simd_fpowi
             | sym::simd_fsin
@@ -911,47 +914,45 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         // All types must be simd vector types
         require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
-        require_simd!(
-            arg_tys[1],
-            InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
-        );
-        require_simd!(
-            arg_tys[2],
-            InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
-        );
+        require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond {
+            span,
+            name,
+            ty: arg_tys[1]
+        });
+        require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird {
+            span,
+            name,
+            ty: arg_tys[2]
+        });
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
         // Of the same length:
         let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
-        require!(
-            in_len == out_len,
-            InvalidMonomorphization::SecondArgumentLength {
-                span,
-                name,
-                in_len,
-                in_ty,
-                arg_ty: arg_tys[1],
-                out_len
-            }
-        );
-        require!(
-            in_len == out_len2,
-            InvalidMonomorphization::ThirdArgumentLength {
-                span,
-                name,
-                in_len,
-                in_ty,
-                arg_ty: arg_tys[2],
-                out_len: out_len2
-            }
-        );
+        require!(in_len == out_len, InvalidMonomorphization::SecondArgumentLength {
+            span,
+            name,
+            in_len,
+            in_ty,
+            arg_ty: arg_tys[1],
+            out_len
+        });
+        require!(in_len == out_len2, InvalidMonomorphization::ThirdArgumentLength {
+            span,
+            name,
+            in_len,
+            in_ty,
+            arg_ty: arg_tys[2],
+            out_len: out_len2
+        });
 
         // The return type must match the first argument type
-        require!(
-            ret_ty == in_ty,
-            InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
-        );
+        require!(ret_ty == in_ty, InvalidMonomorphization::ExpectedReturnType {
+            span,
+            name,
+            in_ty,
+            ret_ty
+        });
 
         // This counts how many pointers
         fn ptr_count(t: Ty<'_>) -> usize {
@@ -978,18 +979,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 (ptr_count(element_ty1), non_ptr(element_ty1))
             }
             _ => {
-                require!(
-                    false,
-                    InvalidMonomorphization::ExpectedElementType {
-                        span,
-                        name,
-                        expected_element: element_ty1,
-                        second_arg: arg_tys[1],
-                        in_elem,
-                        in_ty,
-                        mutability: ExpectedPointerMutability::Not,
-                    }
-                );
+                require!(false, InvalidMonomorphization::ExpectedElementType {
+                    span,
+                    name,
+                    expected_element: element_ty1,
+                    second_arg: arg_tys[1],
+                    in_elem,
+                    in_ty,
+                    mutability: ExpectedPointerMutability::Not,
+                });
                 unreachable!();
             }
         };
@@ -1002,15 +1000,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         match *element_ty2.kind() {
             ty::Int(_) => (),
             _ => {
-                require!(
-                    false,
-                    InvalidMonomorphization::ThirdArgElementType {
-                        span,
-                        name,
-                        expected_element: element_ty2,
-                        third_arg: arg_tys[2]
-                    }
-                );
+                require!(false, InvalidMonomorphization::ThirdArgElementType {
+                    span,
+                    name,
+                    expected_element: element_ty2,
+                    third_arg: arg_tys[2]
+                });
             }
         }
 
@@ -1034,40 +1029,36 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         // All types must be simd vector types
         require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
-        require_simd!(
-            arg_tys[1],
-            InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
-        );
-        require_simd!(
-            arg_tys[2],
-            InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
-        );
+        require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond {
+            span,
+            name,
+            ty: arg_tys[1]
+        });
+        require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird {
+            span,
+            name,
+            ty: arg_tys[2]
+        });
 
         // Of the same length:
         let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
-        require!(
-            in_len == element_len1,
-            InvalidMonomorphization::SecondArgumentLength {
-                span,
-                name,
-                in_len,
-                in_ty,
-                arg_ty: arg_tys[1],
-                out_len: element_len1
-            }
-        );
-        require!(
-            in_len == element_len2,
-            InvalidMonomorphization::ThirdArgumentLength {
-                span,
-                name,
-                in_len,
-                in_ty,
-                arg_ty: arg_tys[2],
-                out_len: element_len2
-            }
-        );
+        require!(in_len == element_len1, InvalidMonomorphization::SecondArgumentLength {
+            span,
+            name,
+            in_len,
+            in_ty,
+            arg_ty: arg_tys[1],
+            out_len: element_len1
+        });
+        require!(in_len == element_len2, InvalidMonomorphization::ThirdArgumentLength {
+            span,
+            name,
+            in_len,
+            in_ty,
+            arg_ty: arg_tys[2],
+            out_len: element_len2
+        });
 
         // This counts how many pointers
         fn ptr_count(t: Ty<'_>) -> usize {
@@ -1095,18 +1086,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 (ptr_count(element_ty1), non_ptr(element_ty1))
             }
             _ => {
-                require!(
-                    false,
-                    InvalidMonomorphization::ExpectedElementType {
-                        span,
-                        name,
-                        expected_element: element_ty1,
-                        second_arg: arg_tys[1],
-                        in_elem,
-                        in_ty,
-                        mutability: ExpectedPointerMutability::Mut,
-                    }
-                );
+                require!(false, InvalidMonomorphization::ExpectedElementType {
+                    span,
+                    name,
+                    expected_element: element_ty1,
+                    second_arg: arg_tys[1],
+                    in_elem,
+                    in_ty,
+                    mutability: ExpectedPointerMutability::Mut,
+                });
                 unreachable!();
             }
         };
@@ -1118,15 +1106,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         match *element_ty2.kind() {
             ty::Int(_) => (),
             _ => {
-                require!(
-                    false,
-                    InvalidMonomorphization::ThirdArgElementType {
-                        span,
-                        name,
-                        expected_element: element_ty2,
-                        third_arg: arg_tys[2]
-                    }
-                );
+                require!(false, InvalidMonomorphization::ThirdArgElementType {
+                    span,
+                    name,
+                    expected_element: element_ty2,
+                    third_arg: arg_tys[2]
+                });
             }
         }
 
@@ -1293,10 +1278,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         ($name:ident : $vec_op:expr, $float_reduce:ident, $ordered:expr, $op:ident,
          $identity:expr) => {
             if name == sym::$name {
-                require!(
-                    ret_ty == in_elem,
-                    InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
-                );
+                require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType {
+                    span,
+                    name,
+                    in_elem,
+                    in_ty,
+                    ret_ty
+                });
                 return match *in_elem.kind() {
                     ty::Int(_) | ty::Uint(_) => {
                         let r = bx.vector_reduce_op(args[0].immediate(), $vec_op);
@@ -1362,10 +1350,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     macro_rules! minmax_red {
         ($name:ident: $int_red:ident, $float_red:ident) => {
             if name == sym::$name {
-                require!(
-                    ret_ty == in_elem,
-                    InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
-                );
+                require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType {
+                    span,
+                    name,
+                    in_elem,
+                    in_ty,
+                    ret_ty
+                });
                 return match *in_elem.kind() {
                     ty::Int(_) | ty::Uint(_) => Ok(bx.$int_red(args[0].immediate())),
                     ty::Float(_) => Ok(bx.$float_red(args[0].immediate())),
@@ -1389,10 +1380,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         ($name:ident : $op:expr, $boolean:expr) => {
             if name == sym::$name {
                 let input = if !$boolean {
-                    require!(
-                        ret_ty == in_elem,
-                        InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
-                    );
+                    require!(ret_ty == in_elem, InvalidMonomorphization::ReturnType {
+                        span,
+                        name,
+                        in_elem,
+                        in_ty,
+                        ret_ty
+                    });
                     args[0].immediate()
                 } else {
                     match *in_elem.kind() {
diff --git a/src/lib.rs b/src/lib.rs
index fdbf53e1b1a..11d71ea40d0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -24,6 +24,17 @@
 #![deny(clippy::pattern_type_mismatch)]
 #![allow(clippy::needless_lifetimes)]
 
+// Some "regular" crates we want to share with rustc
+extern crate object;
+extern crate smallvec;
+// FIXME(antoyo): clippy bug: remove the #[allow] when it's fixed.
+#[allow(unused_extern_crates)]
+extern crate tempfile;
+#[macro_use]
+extern crate tracing;
+
+// The rustc crates we need
+extern crate rustc_abi;
 extern crate rustc_apfloat;
 extern crate rustc_ast;
 extern crate rustc_attr;
@@ -42,8 +53,6 @@ extern crate rustc_middle;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
-#[macro_use]
-extern crate tracing;
 
 // This prevents duplicating functions and statics that are already part of the host rustc process.
 #[allow(unused_extern_crates)]
@@ -51,7 +60,6 @@ extern crate rustc_driver;
 
 mod abi;
 mod allocator;
-mod archive;
 mod asm;
 mod attributes;
 mod back;
@@ -82,7 +90,6 @@ use std::sync::atomic::Ordering;
 use std::sync::{Arc, Mutex};
 
 use back::lto::{ThinBuffer, ThinData};
-use errors::LTONotSupported;
 use gccjit::{CType, Context, OptimizationLevel};
 #[cfg(feature = "master")]
 use gccjit::{TargetInfo, Version};
@@ -96,15 +103,16 @@ use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBacken
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::IntoDynSyncSend;
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
+use rustc_errors::DiagCtxtHandle;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::Providers;
-use rustc_session::config::{Lto, OptLevel, OutputFilenames};
 use rustc_session::Session;
-use rustc_span::fatal_error::FatalError;
+use rustc_session::config::{OptLevel, OutputFilenames};
 use rustc_span::Symbol;
+use rustc_span::fatal_error::FatalError;
+use rustc_target::spec::RelocModel;
 use tempfile::TempDir;
 
 use crate::back::lto::ModuleBuffer;
@@ -195,10 +203,6 @@ impl CodegenBackend for GccCodegenBackend {
         #[cfg(feature = "master")]
         gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
 
-        if sess.lto() == Lto::Thin {
-            sess.dcx().emit_warn(LTONotSupported {});
-        }
-
         #[cfg(not(feature = "master"))]
         {
             let temp_dir = TempDir::new().expect("cannot create temporary directory");
@@ -254,17 +258,6 @@ impl CodegenBackend for GccCodegenBackend {
             .join(sess)
     }
 
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        use rustc_codegen_ssa::back::link::link_binary;
-
-        link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
-    }
-
     fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
         target_features(sess, allow_unstable, &self.target_info)
     }
@@ -301,6 +294,7 @@ impl ExtraBackendMethods for GccCodegenBackend {
     ) -> Self::Module {
         let mut mods = GccContext {
             context: Arc::new(SyncContext::new(new_context(tcx))),
+            relocation_model: tcx.sess.relocation_model(),
             should_combine_object_files: false,
             temp_dir: None,
         };
@@ -332,6 +326,9 @@ impl ExtraBackendMethods for GccCodegenBackend {
 
 pub struct GccContext {
     context: Arc<SyncContext>,
+    /// This field is needed in order to be able to set the flag -fPIC when necessary when doing
+    /// LTO.
+    relocation_model: RelocModel,
     should_combine_object_files: bool,
     // Temporary directory used by LTO. We keep it here so that it's not removed before linking.
     temp_dir: Option<TempDir>,
@@ -484,8 +481,9 @@ pub fn target_features(
 ) -> Vec<Symbol> {
     // TODO(antoyo): use global_gcc_features.
     sess.target
-        .supported_target_features()
+        .rust_target_features()
         .iter()
+        .filter(|&&(_, gate, _)| gate.is_supported())
         .filter_map(|&(feature, gate, _)| {
             if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
                 Some(feature)
diff --git a/src/mono_item.rs b/src/mono_item.rs
index ba81dea49d5..239902df7f0 100644
--- a/src/mono_item.rs
+++ b/src/mono_item.rs
@@ -1,19 +1,19 @@
 #[cfg(feature = "master")]
 use gccjit::{FnAttribute, VarAttribute};
-use rustc_codegen_ssa::traits::PreDefineMethods;
+use rustc_codegen_ssa::traits::PreDefineCodegenMethods;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 
 use crate::context::CodegenCx;
 use crate::type_of::LayoutGccExt;
 use crate::{attributes, base};
 
-impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     #[cfg_attr(not(feature = "master"), allow(unused_variables))]
     fn predefine_static(
         &self,
@@ -27,11 +27,8 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
         // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out
         // the gcc type from the actual evaluated initializer.
-        let ty = if nested {
-            self.tcx.types.unit
-        } else {
-            instance.ty(self.tcx, ty::ParamEnv::reveal_all())
-        };
+        let ty =
+            if nested { self.tcx.types.unit } else { instance.ty(self.tcx, self.typing_env()) };
         let gcc_type = self.layout_of(ty).gcc_type(self);
 
         let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
diff --git a/src/type_.rs b/src/type_.rs
index e20234c5ce7..4ea5544721d 100644
--- a/src/type_.rs
+++ b/src/type_.rs
@@ -5,7 +5,9 @@ use std::convert::TryInto;
 use gccjit::CType;
 use gccjit::{RValue, Struct, Type};
 use rustc_codegen_ssa::common::TypeKind;
-use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods};
+use rustc_codegen_ssa::traits::{
+    BaseTypeCodegenMethods, DerivedTypeCodegenMethods, TypeMembershipCodegenMethods,
+};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::{bug, ty};
 use rustc_target::abi::{AddressSpace, Align, Integer, Size};
@@ -121,7 +123,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn type_i8(&self) -> Type<'gcc> {
         self.i8_type
     }
@@ -381,4 +383,4 @@ pub fn struct_fields<'gcc, 'tcx>(
     (result, packed)
 }
 
-impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {}
+impl<'gcc, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {}
diff --git a/src/type_of.rs b/src/type_of.rs
index d85ed4f12ff..0efdf36da48 100644
--- a/src/type_of.rs
+++ b/src/type_of.rs
@@ -1,16 +1,18 @@
 use std::fmt::Write;
 
 use gccjit::{Struct, Type};
-use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
+use rustc_abi as abi;
+use rustc_abi::Primitive::*;
+use rustc_abi::{BackendRepr, FieldsShape, Integer, PointeeInfo, Size, Variants};
+use rustc_codegen_ssa::traits::{
+    BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods,
+};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
+use rustc_target::abi::TyAbiInterface;
 use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
-use rustc_target::abi::{
-    self, Abi, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
-    Variants,
-};
 
 use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
 use crate::context::CodegenCx;
@@ -58,9 +60,9 @@ fn uncached_gcc_type<'gcc, 'tcx>(
     layout: TyAndLayout<'tcx>,
     defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>,
 ) -> Type<'gcc> {
-    match layout.abi {
-        Abi::Scalar(_) => bug!("handled elsewhere"),
-        Abi::Vector { ref element, count } => {
+    match layout.backend_repr {
+        BackendRepr::Scalar(_) => bug!("handled elsewhere"),
+        BackendRepr::Vector { ref element, count } => {
             let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
             let element =
                 // NOTE: gcc doesn't allow pointer types in vectors.
@@ -72,7 +74,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(
                 };
             return cx.context.new_vector_type(element, count);
         }
-        Abi::ScalarPair(..) => {
+        BackendRepr::ScalarPair(..) => {
             return cx.type_struct(
                 &[
                     layout.scalar_pair_element_gcc_type(cx, 0),
@@ -81,7 +83,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(
                 false,
             );
         }
-        Abi::Uninhabited | Abi::Aggregate { .. } => {}
+        BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {}
     }
 
     let name = match *layout.ty.kind() {
@@ -174,16 +176,21 @@ pub trait LayoutGccExt<'tcx> {
 
 impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
     fn is_gcc_immediate(&self) -> bool {
-        match self.abi {
-            Abi::Scalar(_) | Abi::Vector { .. } => true,
-            Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false,
+        match self.backend_repr {
+            BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true,
+            BackendRepr::ScalarPair(..) | BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {
+                false
+            }
         }
     }
 
     fn is_gcc_scalar_pair(&self) -> bool {
-        match self.abi {
-            Abi::ScalarPair(..) => true,
-            Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false,
+        match self.backend_repr {
+            BackendRepr::ScalarPair(..) => true,
+            BackendRepr::Uninhabited
+            | BackendRepr::Scalar(_)
+            | BackendRepr::Vector { .. }
+            | BackendRepr::Memory { .. } => false,
         }
     }
 
@@ -195,7 +202,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
     /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
     /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
     /// If the type is an unsized struct, the regular layout is generated,
-    /// with the inner-most trailing unsized field using the "minimal unit"
+    /// with the innermost trailing unsized field using the "minimal unit"
     /// of that field's type - this is useful for taking the address of
     /// that field and ensuring the struct has the right alignment.
     fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
@@ -203,9 +210,9 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
         // This must produce the same result for `repr(transparent)` wrappers as for the inner type!
         // In other words, this should generally not look at the type at all, but only at the
         // layout.
-        if let Abi::Scalar(ref scalar) = self.abi {
+        if let BackendRepr::Scalar(ref scalar) = self.backend_repr {
             // Use a different cache for scalars because pointers to DSTs
-            // can be either fat or thin (data pointers of fat pointers).
+            // can be either wide or thin (data pointers of wide pointers).
             if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
                 return ty;
             }
@@ -213,9 +220,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
                 // NOTE: we cannot remove this match like in the LLVM codegen because the call
                 // to fn_ptr_backend_type handle the on-stack attribute.
                 // TODO(antoyo): find a less hackish way to hande the on-stack attribute.
-                ty::FnPtr(sig) => {
-                    cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
-                }
+                ty::FnPtr(sig_tys, hdr) => cx
+                    .fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig_tys.with(hdr), ty::List::empty())),
                 _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
             };
             cx.scalar_types.borrow_mut().insert(self.ty, ty);
@@ -260,7 +266,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
     }
 
     fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
-        if let Abi::Scalar(ref scalar) = self.abi {
+        if let BackendRepr::Scalar(ref scalar) = self.backend_repr {
             if scalar.is_bool() {
                 return cx.type_i1();
             }
@@ -298,8 +304,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
         // This must produce the same result for `repr(transparent)` wrappers as for the inner type!
         // In other words, this should generally not look at the type at all, but only at the
         // layout.
-        let (a, b) = match self.abi {
-            Abi::ScalarPair(ref a, ref b) => (a, b),
+        let (a, b) = match self.backend_repr {
+            BackendRepr::ScalarPair(ref a, ref b) => (a, b),
             _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
         };
         let scalar = [a, b][index];
@@ -331,7 +337,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
         layout.gcc_type(self)
     }
diff --git a/tests/failing-non-lto-tests.txt b/tests/failing-non-lto-tests.txt
deleted file mode 100644
index 384dfdc26fb..00000000000
--- a/tests/failing-non-lto-tests.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-tests/ui/issues/issue-44056.rs
-tests/ui/lto/fat-lto.rs
-tests/ui/lto/debuginfo-lto.rs
-tests/ui/lto/lto-many-codegen-units.rs
-tests/ui/lto/issue-100772.rs
-tests/ui/lto/lto-rustc-loads-linker-plugin.rs
-tests/ui/panic-runtime/lto-unwind.rs
-tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs
-tests/ui/sepcomp/sepcomp-lib-lto.rs
-tests/ui/lto/lto-opt-level-s.rs
-tests/ui/lto/lto-opt-level-z.rs
diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt
index cb38c164838..082958bfe1f 100644
--- a/tests/failing-ui-tests.txt
+++ b/tests/failing-ui-tests.txt
@@ -6,7 +6,6 @@ tests/ui/functions-closures/parallel-codegen-closures.rs
 tests/ui/linkage-attr/linkage1.rs
 tests/ui/lto/dylib-works.rs
 tests/ui/numbers-arithmetic/saturating-float-casts.rs
-tests/ui/polymorphization/promoted-function.rs
 tests/ui/sepcomp/sepcomp-cci.rs
 tests/ui/sepcomp/sepcomp-extern.rs
 tests/ui/sepcomp/sepcomp-fns-backwards.rs
@@ -70,20 +69,22 @@ tests/ui/mir/mir_heavy_promoted.rs
 tests/ui/consts/const_cmp_type_id.rs
 tests/ui/consts/issue-73976-monomorphic.rs
 tests/ui/consts/issue-94675.rs
-tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs
-tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
+tests/ui/traits/const-traits/const-drop-fail.rs
+tests/ui/traits/const-traits/const-drop.rs
 tests/ui/runtime/on-broken-pipe/child-processes.rs
-tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs
-tests/ui/sanitizer/cfi-async-closures.rs
-tests/ui/sanitizer/cfi-closures.rs
-tests/ui/sanitizer/cfi-complex-receiver.rs
-tests/ui/sanitizer/cfi-coroutine.rs
-tests/ui/sanitizer/cfi-drop-in-place.rs
-tests/ui/sanitizer/cfi-drop-no-principal.rs
-tests/ui/sanitizer/cfi-fn-ptr.rs
-tests/ui/sanitizer/cfi-self-ref.rs
-tests/ui/sanitizer/cfi-supertraits.rs
-tests/ui/sanitizer/cfi-virtual-auto.rs
+tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
+tests/ui/sanitizer/cfi/async-closures.rs
+tests/ui/sanitizer/cfi/closures.rs
+tests/ui/sanitizer/cfi/complex-receiver.rs
+tests/ui/sanitizer/cfi/coroutine.rs
+tests/ui/sanitizer/cfi/drop-in-place.rs
+tests/ui/sanitizer/cfi/drop-no-principal.rs
+tests/ui/sanitizer/cfi/fn-ptr.rs
+tests/ui/sanitizer/cfi/self-ref.rs
+tests/ui/sanitizer/cfi/supertraits.rs
+tests/ui/sanitizer/cfi/virtual-auto.rs
+tests/ui/sanitizer/cfi/sized-associated-ty.rs
+tests/ui/sanitizer/cfi/can-reveal-opaques.rs
 tests/ui/sanitizer/kcfi-mangling.rs
 tests/ui/statics/const_generics.rs
 tests/ui/backtrace/dylib-dep.rs
@@ -120,5 +121,4 @@ tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs
 tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
 tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
 tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
-tests/ui/sanitizer/cfi-sized-associated-ty.rs
-tests/ui/sanitizer/cfi-can-reveal-opaques.rs
+tests/ui/simd/simd-bitmask-notpow2.rs
diff --git a/tests/hello-world/Cargo.lock b/tests/hello-world/Cargo.lock
new file mode 100644
index 00000000000..fe252db4425
--- /dev/null
+++ b/tests/hello-world/Cargo.lock
@@ -0,0 +1,14 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "hello_world"
+version = "0.0.0"
+dependencies = [
+ "mylib",
+]
+
+[[package]]
+name = "mylib"
+version = "0.1.0"
diff --git a/tests/hello-world/Cargo.toml b/tests/hello-world/Cargo.toml
index 0b8cdc63fbe..c6e22f642f6 100644
--- a/tests/hello-world/Cargo.toml
+++ b/tests/hello-world/Cargo.toml
@@ -1,4 +1,12 @@
 [package]
 name = "hello_world"
+edition = "2024"
 
 [dependencies]
+mylib = { path = "mylib" }
+
+[profile.dev]
+lto = "thin"
+
+[profile.release]
+lto = "fat"
diff --git a/tests/hello-world/mylib/Cargo.lock b/tests/hello-world/mylib/Cargo.lock
new file mode 100644
index 00000000000..c8a0bfc6354
--- /dev/null
+++ b/tests/hello-world/mylib/Cargo.lock
@@ -0,0 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "mylib"
+version = "0.1.0"
diff --git a/tests/hello-world/mylib/Cargo.toml b/tests/hello-world/mylib/Cargo.toml
new file mode 100644
index 00000000000..d15f62bfb6d
--- /dev/null
+++ b/tests/hello-world/mylib/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "mylib"
+version = "0.1.0"
+authors = ["Antoni Boucher <bouanto@zoho.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/tests/hello-world/mylib/src/lib.rs b/tests/hello-world/mylib/src/lib.rs
new file mode 100644
index 00000000000..8d3d111bd19
--- /dev/null
+++ b/tests/hello-world/mylib/src/lib.rs
@@ -0,0 +1,7 @@
+pub fn my_func(a: i32, b: i32) -> i32 {
+    let mut res = a;
+    for i in a..b {
+        res += i;
+    }
+    res
+}
diff --git a/tests/hello-world/src/main.rs b/tests/hello-world/src/main.rs
index e7a11a969c0..71c78d364ac 100644
--- a/tests/hello-world/src/main.rs
+++ b/tests/hello-world/src/main.rs
@@ -1,3 +1,5 @@
+use mylib::my_func;
+
 fn main() {
-    println!("Hello, world!");
+    println!("{}", my_func(5, 10));
 }
diff --git a/tests/run/abort1.rs b/tests/run/abort1.rs
index 44297e12779..696197d7377 100644
--- a/tests/run/abort1.rs
+++ b/tests/run/abort1.rs
@@ -33,9 +33,11 @@ pub(crate) unsafe auto trait Freeze {}
 mod intrinsics {
     use super::Sized;
 
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/abort2.rs b/tests/run/abort2.rs
index ce816927123..714cd6c0f38 100644
--- a/tests/run/abort2.rs
+++ b/tests/run/abort2.rs
@@ -33,9 +33,11 @@ pub(crate) unsafe auto trait Freeze {}
 mod intrinsics {
     use super::Sized;
 
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/array.rs b/tests/run/array.rs
index 432f11ad8d4..9d04ba10b23 100644
--- a/tests/run/array.rs
+++ b/tests/run/array.rs
@@ -33,8 +33,8 @@ impl Copy for i8 {}
 impl Copy for i16 {}
 impl<T: ?Sized> Copy for *mut T {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
@@ -106,9 +106,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/asm.rs b/tests/run/asm.rs
index 56f2aac3d0a..4e05d026868 100644
--- a/tests/run/asm.rs
+++ b/tests/run/asm.rs
@@ -3,12 +3,10 @@
 // Run-time:
 //   status: 0
 
-#![feature(asm_const)]
-
-#[cfg(target_arch="x86_64")]
+#[cfg(target_arch = "x86_64")]
 use std::arch::{asm, global_asm};
 
-#[cfg(target_arch="x86_64")]
+#[cfg(target_arch = "x86_64")]
 global_asm!(
     "
     .global add_asm
@@ -22,7 +20,7 @@ extern "C" {
     fn add_asm(a: i64, b: i64) -> i64;
 }
 
-#[cfg(target_arch="x86_64")]
+#[cfg(target_arch = "x86_64")]
 pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) {
     asm!(
         "rep movsb",
@@ -33,7 +31,7 @@ pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) {
     );
 }
 
-#[cfg(target_arch="x86_64")]
+#[cfg(target_arch = "x86_64")]
 fn asm() {
     unsafe {
         asm!("nop");
@@ -178,9 +176,8 @@ fn asm() {
     assert_eq!(array1, array2);
 }
 
-#[cfg(not(target_arch="x86_64"))]
-fn asm() {
-}
+#[cfg(not(target_arch = "x86_64"))]
+fn asm() {}
 
 fn main() {
     asm();
diff --git a/tests/run/assign.rs b/tests/run/assign.rs
index e105d64a8ad..2a47f0c2966 100644
--- a/tests/run/assign.rs
+++ b/tests/run/assign.rs
@@ -56,9 +56,11 @@ mod libc {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/closure.rs b/tests/run/closure.rs
index 00e61cc001f..6f7210b5d07 100644
--- a/tests/run/closure.rs
+++ b/tests/run/closure.rs
@@ -35,8 +35,8 @@ impl Copy for u8 {}
 impl Copy for i8 {}
 impl<T: ?Sized> Copy for *mut T {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
@@ -98,9 +98,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/condition.rs b/tests/run/condition.rs
index 7b05b7decd3..01af6fa8280 100644
--- a/tests/run/condition.rs
+++ b/tests/run/condition.rs
@@ -36,8 +36,8 @@ impl Copy for i8 {}
 impl Copy for u8 {}
 impl<T: ?Sized> Copy for *mut T {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
@@ -109,9 +109,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/fun_ptr.rs b/tests/run/fun_ptr.rs
index 4e96f376555..a2e304c1e37 100644
--- a/tests/run/fun_ptr.rs
+++ b/tests/run/fun_ptr.rs
@@ -30,8 +30,8 @@ impl Copy for i8 {}
 impl Copy for i16 {}
 impl<T: ?Sized> Copy for *mut T {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
@@ -103,9 +103,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/mut_ref.rs b/tests/run/mut_ref.rs
index 5a3f72b6904..3ae79338216 100644
--- a/tests/run/mut_ref.rs
+++ b/tests/run/mut_ref.rs
@@ -58,9 +58,11 @@ mod libc {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/operations.rs b/tests/run/operations.rs
index d697bd921cd..0e44fc580b8 100644
--- a/tests/run/operations.rs
+++ b/tests/run/operations.rs
@@ -38,8 +38,8 @@ pub trait Deref {
     fn deref(&self) -> &Self::Target;
 }
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
@@ -64,9 +64,11 @@ mod libc {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/ptr_cast.rs b/tests/run/ptr_cast.rs
index a94279182d6..d66d5b2a8cb 100644
--- a/tests/run/ptr_cast.rs
+++ b/tests/run/ptr_cast.rs
@@ -30,8 +30,8 @@ impl Copy for i8 {}
 impl Copy for i16 {}
 impl<T: ?Sized> Copy for *mut T {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
@@ -103,9 +103,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 }
 
 mod intrinsics {
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/return-tuple.rs b/tests/run/return-tuple.rs
index 8d40deb8c85..f2a5a2e4384 100644
--- a/tests/run/return-tuple.rs
+++ b/tests/run/return-tuple.rs
@@ -15,18 +15,18 @@
 #[lang = "copy"]
 pub unsafe trait Copy {}
 
-unsafe impl Copy for bool {}
-unsafe impl Copy for u8 {}
-unsafe impl Copy for u16 {}
-unsafe impl Copy for u32 {}
-unsafe impl Copy for u64 {}
-unsafe impl Copy for usize {}
-unsafe impl Copy for i8 {}
-unsafe impl Copy for i16 {}
-unsafe impl Copy for i32 {}
-unsafe impl Copy for isize {}
-unsafe impl Copy for f32 {}
-unsafe impl Copy for char {}
+impl Copy for bool {}
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for u64 {}
+impl Copy for usize {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for isize {}
+impl Copy for f32 {}
+impl Copy for char {}
 
 mod libc {
     #[link(name = "c")]
@@ -43,8 +43,8 @@ mod libc {
 #[lang = "sized"]
 pub trait Sized {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
diff --git a/tests/run/slice.rs b/tests/run/slice.rs
index e86fc823a1a..32f4c604058 100644
--- a/tests/run/slice.rs
+++ b/tests/run/slice.rs
@@ -28,8 +28,8 @@ impl Copy for i32 {}
 impl Copy for u32 {}
 impl<T: ?Sized> Copy for *mut T {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
@@ -103,9 +103,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 mod intrinsics {
     use super::Sized;
 
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }
 
diff --git a/tests/run/static.rs b/tests/run/static.rs
index 6247e08f5e3..a17ea2a4893 100644
--- a/tests/run/static.rs
+++ b/tests/run/static.rs
@@ -46,9 +46,11 @@ pub(crate) unsafe auto trait Freeze {}
 mod intrinsics {
     use super::Sized;
 
-    extern "rust-intrinsic" {
-        #[rustc_safe_intrinsic]
-        pub fn abort() -> !;
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    #[rustc_intrinsic_must_be_overridden]
+    pub fn abort() -> ! {
+        loop {}
     }
 }