Merge from rustc
This commit is contained in:
commit
97633d8e60
330 changed files with 4797 additions and 4702 deletions
|
@ -46,24 +46,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5e7afe85cadb55c4c1176268a2ac046fdff8dfaeca39e18581b9dc319ca9e"
|
||||
checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bitset"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ab25ef3be935a80680e393183e1f94ef507e93a24a8369494d2c6818aedb3e3"
|
||||
checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900a19b84545924f1851cbfe386962edfc4ecbc3366a254825cf1ecbcda8ba08"
|
||||
checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cranelift-bforest",
|
||||
|
@ -78,48 +78,49 @@ dependencies = [
|
|||
"log",
|
||||
"regalloc2",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c73b2395ffe9e7b4fdf7e2ebc052e7e27af13f68a964985346be4da477a5fc"
|
||||
checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d9ed0854e96a4ff0879bff39d078de8dea7f002721c9494c1fdb4e1baa86ccc"
|
||||
checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-control"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4aca921dd422e781409de0129c255768fec5dec1dae83239b497fb9138abb89"
|
||||
checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d770e6605eccee15b49decdd82cd26f2b6404767802471459ea49c57379a98"
|
||||
checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96"
|
||||
dependencies = [
|
||||
"cranelift-bitset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29268711cb889cb39215b10faf88b9087d4c9e1d2633581e4f722a2bf4bb4ef9"
|
||||
checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
|
@ -129,15 +130,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc65156f010aed1985767ad1bff0eb8d186743b7b03e23d0c17604a253e3f356"
|
||||
checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ba6b46367a4f466cfb1abe32793fa1a0f96d862251491b01a44726b8ed9445"
|
||||
checksum = "62699329d4ced20fe281fbaef45e11b473b7ab310491b4bdebcd8b818a8ef7fe"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
@ -155,9 +156,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "007607022a4883ebdffc46c0925e2e10babf2a565ae78518034ade722aa825d2"
|
||||
checksum = "2f20b0b51ba962dac30fc7e812b86e4390d908acd4f59bcc8ac7610a8f3e0977"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
@ -166,9 +167,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8bf9b361eaf5a7627647270fabf1dc910d993edbeaf272a652c107861ebe9c2"
|
||||
checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
|
@ -177,9 +178,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30ca5c38fa00c0cd943035391bdcc84ed00748f17c66c682e410f5a62f234d44"
|
||||
checksum = "ee231640a7ecceedd0f1f2782d9288db6a6908cc70675ed9427e3bf0ea6daacd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
@ -363,6 +364,26 @@ dependencies = [
|
|||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slice-group-by"
|
||||
version = "0.3.1"
|
||||
|
@ -412,9 +433,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||
|
||||
[[package]]
|
||||
name = "wasmtime-jit-icache-coherence"
|
||||
version = "26.0.0"
|
||||
version = "27.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e458e6a1a010a53f86ac8d75837c0c6b2ce3e54b7503b2f1dc5629a4a541f5a"
|
||||
checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
|
|
|
@ -8,12 +8,12 @@ crate-type = ["dylib"]
|
|||
|
||||
[dependencies]
|
||||
# These have to be in sync with each other
|
||||
cranelift-codegen = { version = "0.113.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.113.0" }
|
||||
cranelift-module = { version = "0.113.0" }
|
||||
cranelift-native = { version = "0.113.0" }
|
||||
cranelift-jit = { version = "0.113.0", optional = true }
|
||||
cranelift-object = { version = "0.113.0" }
|
||||
cranelift-codegen = { version = "0.114.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.114.0" }
|
||||
cranelift-module = { version = "0.114.0" }
|
||||
cranelift-native = { version = "0.114.0" }
|
||||
cranelift-jit = { version = "0.114.0", optional = true }
|
||||
cranelift-object = { version = "0.114.0" }
|
||||
target-lexicon = "0.12.0"
|
||||
gimli = { version = "0.31", default-features = false, features = ["write"] }
|
||||
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::path::{Dirs, RelPath};
|
||||
use crate::path::Dirs;
|
||||
use crate::prepare::GitRepo;
|
||||
use crate::utils::{CargoProject, Compiler, spawn_and_wait};
|
||||
use crate::{CodegenBackend, SysrootKind, build_sysroot};
|
||||
|
@ -20,7 +20,7 @@ pub(crate) fn run(
|
|||
rustup_toolchain_name: Option<&str>,
|
||||
bootstrap_host_compiler: &Compiler,
|
||||
) {
|
||||
RelPath::DOWNLOAD.ensure_exists(dirs);
|
||||
std::fs::create_dir_all(&dirs.download_dir).unwrap();
|
||||
ABI_CAFE_REPO.fetch(dirs);
|
||||
ABI_CAFE_REPO.patch(dirs);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::io::Write;
|
|||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::path::Dirs;
|
||||
use crate::prepare::GitRepo;
|
||||
use crate::rustc_info::get_file_name;
|
||||
use crate::utils::{Compiler, spawn_and_wait};
|
||||
|
@ -39,11 +39,11 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
};
|
||||
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
|
||||
let cargo_clif = RelPath::DIST
|
||||
.to_path(dirs)
|
||||
let cargo_clif = dirs
|
||||
.dist_dir
|
||||
.join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-"));
|
||||
let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml");
|
||||
let target_dir = RelPath::BUILD.join("simple_raytracer").to_path(dirs);
|
||||
let target_dir = dirs.build_dir.join("simple_raytracer");
|
||||
|
||||
let clean_cmd = format!(
|
||||
"RUSTC=rustc cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
|
@ -68,7 +68,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
target_dir = target_dir.display(),
|
||||
);
|
||||
|
||||
let bench_compile_markdown = RelPath::DIST.to_path(dirs).join("bench_compile.md");
|
||||
let bench_compile_markdown = dirs.dist_dir.join("bench_compile.md");
|
||||
|
||||
let bench_compile = hyperfine_command(
|
||||
1,
|
||||
|
@ -92,7 +92,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
|
||||
|
||||
let bench_run_markdown = RelPath::DIST.to_path(dirs).join("bench_run.md");
|
||||
let bench_run_markdown = dirs.dist_dir.join("bench_run.md");
|
||||
|
||||
let raytracer_cg_llvm = Path::new(".").join(get_file_name(
|
||||
&bootstrap_host_compiler.rustc,
|
||||
|
@ -120,7 +120,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
],
|
||||
&bench_run_markdown,
|
||||
);
|
||||
bench_run.current_dir(RelPath::BUILD.to_path(dirs));
|
||||
bench_run.current_dir(&dirs.build_dir);
|
||||
spawn_and_wait(bench_run);
|
||||
|
||||
if let Some(gha_step_summary) = gha_step_summary.as_mut() {
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::rustc_info::get_file_name;
|
|||
use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env};
|
||||
use crate::utils::{CargoProject, Compiler, LogGroup};
|
||||
|
||||
static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
|
||||
static CG_CLIF: CargoProject = CargoProject::new(&RelPath::source("."), "cg_clif");
|
||||
|
||||
pub(crate) fn build_backend(
|
||||
dirs: &Dirs,
|
||||
|
|
|
@ -22,9 +22,9 @@ pub(crate) fn build_sysroot(
|
|||
|
||||
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
|
||||
|
||||
let dist_dir = RelPath::DIST.to_path(dirs);
|
||||
let dist_dir = &dirs.dist_dir;
|
||||
|
||||
ensure_empty_dir(&dist_dir);
|
||||
ensure_empty_dir(dist_dir);
|
||||
fs::create_dir_all(dist_dir.join("bin")).unwrap();
|
||||
fs::create_dir_all(dist_dir.join("lib")).unwrap();
|
||||
|
||||
|
@ -55,7 +55,7 @@ pub(crate) fn build_sysroot(
|
|||
let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc);
|
||||
let wrapper_path = dist_dir.join(&wrapper_name);
|
||||
build_cargo_wrapper_cmd
|
||||
.arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
|
||||
.arg(dirs.source_dir.join("scripts").join(&format!("{wrapper}.rs")))
|
||||
.arg("-o")
|
||||
.arg(&wrapper_path)
|
||||
.arg("-Cstrip=debuginfo");
|
||||
|
@ -85,7 +85,7 @@ pub(crate) fn build_sysroot(
|
|||
&cg_clif_dylib_path,
|
||||
sysroot_kind,
|
||||
);
|
||||
host.install_into_sysroot(&dist_dir);
|
||||
host.install_into_sysroot(dist_dir);
|
||||
|
||||
if !is_native {
|
||||
build_sysroot_for_triple(
|
||||
|
@ -99,7 +99,7 @@ pub(crate) fn build_sysroot(
|
|||
&cg_clif_dylib_path,
|
||||
sysroot_kind,
|
||||
)
|
||||
.install_into_sysroot(&dist_dir);
|
||||
.install_into_sysroot(dist_dir);
|
||||
}
|
||||
|
||||
let mut target_compiler = {
|
||||
|
@ -143,10 +143,10 @@ impl SysrootTarget {
|
|||
}
|
||||
}
|
||||
|
||||
static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib");
|
||||
static STDLIB_SRC: RelPath = RelPath::build("stdlib");
|
||||
static STANDARD_LIBRARY: CargoProject =
|
||||
CargoProject::new(&STDLIB_SRC.join("library/sysroot"), "stdlib_target");
|
||||
static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup");
|
||||
CargoProject::new(&RelPath::build("stdlib/library/sysroot"), "stdlib_target");
|
||||
static RTSTARTUP_SYSROOT: RelPath = RelPath::build("rtstartup");
|
||||
|
||||
fn build_sysroot_for_triple(
|
||||
dirs: &Dirs,
|
||||
|
@ -247,6 +247,7 @@ fn build_clif_sysroot_for_triple(
|
|||
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
|
||||
build_cmd.arg("--release");
|
||||
build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128");
|
||||
build_cmd.arg(format!("-Zroot-dir={}", STDLIB_SRC.to_path(dirs).display()));
|
||||
build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
|
||||
build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
|
||||
if compiler.triple.contains("apple") {
|
||||
|
@ -281,13 +282,14 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
|
|||
return None;
|
||||
}
|
||||
|
||||
RTSTARTUP_SYSROOT.ensure_fresh(dirs);
|
||||
let rtstartup_sysroot = RTSTARTUP_SYSROOT.to_path(dirs);
|
||||
ensure_empty_dir(&rtstartup_sysroot);
|
||||
|
||||
let rtstartup_src = STDLIB_SRC.to_path(dirs).join("library").join("rtstartup");
|
||||
let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
|
||||
|
||||
for file in ["rsbegin", "rsend"] {
|
||||
let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
|
||||
let obj = rtstartup_sysroot.join(format!("{file}.o"));
|
||||
let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
|
||||
build_rtstartup_cmd
|
||||
.arg("--target")
|
||||
|
|
|
@ -185,12 +185,11 @@ fn main() {
|
|||
frozen,
|
||||
};
|
||||
|
||||
path::RelPath::BUILD.ensure_exists(&dirs);
|
||||
std::fs::create_dir_all(&dirs.build_dir).unwrap();
|
||||
|
||||
{
|
||||
// Make sure we always explicitly specify the target dir
|
||||
let target =
|
||||
path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);
|
||||
let target = dirs.build_dir.join("target_dir_should_be_set_explicitly");
|
||||
env::set_var("CARGO_TARGET_DIR", &target);
|
||||
let _ = std::fs::remove_file(&target);
|
||||
std::fs::File::create(target).unwrap();
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::utils::ensure_empty_dir;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Dirs {
|
||||
pub(crate) source_dir: PathBuf,
|
||||
|
@ -16,54 +13,34 @@ pub(crate) struct Dirs {
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum PathBase {
|
||||
Source,
|
||||
Download,
|
||||
Build,
|
||||
Dist,
|
||||
}
|
||||
|
||||
impl PathBase {
|
||||
fn to_path(self, dirs: &Dirs) -> PathBuf {
|
||||
match self {
|
||||
PathBase::Source => dirs.source_dir.clone(),
|
||||
PathBase::Download => dirs.download_dir.clone(),
|
||||
PathBase::Build => dirs.build_dir.clone(),
|
||||
PathBase::Dist => dirs.dist_dir.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum RelPath {
|
||||
Base(PathBase),
|
||||
Join(&'static RelPath, &'static str),
|
||||
pub(crate) struct RelPath {
|
||||
base: PathBase,
|
||||
suffix: &'static str,
|
||||
}
|
||||
|
||||
impl RelPath {
|
||||
pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source);
|
||||
pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download);
|
||||
pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build);
|
||||
pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist);
|
||||
pub(crate) const fn source(suffix: &'static str) -> RelPath {
|
||||
RelPath { base: PathBase::Source, suffix }
|
||||
}
|
||||
|
||||
pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts");
|
||||
pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches");
|
||||
|
||||
pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath {
|
||||
RelPath::Join(self, suffix)
|
||||
pub(crate) const fn build(suffix: &'static str) -> RelPath {
|
||||
RelPath { base: PathBase::Build, suffix }
|
||||
}
|
||||
|
||||
pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
|
||||
match self {
|
||||
RelPath::Base(base) => base.to_path(dirs),
|
||||
RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
|
||||
fs::create_dir_all(self.to_path(dirs)).unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
|
||||
let path = self.to_path(dirs);
|
||||
ensure_empty_dir(&path);
|
||||
self.base.to_path(dirs).join(self.suffix)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::path::{Dirs, RelPath};
|
|||
use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait};
|
||||
|
||||
pub(crate) fn prepare(dirs: &Dirs) {
|
||||
RelPath::DOWNLOAD.ensure_exists(dirs);
|
||||
std::fs::create_dir_all(&dirs.download_dir).unwrap();
|
||||
crate::tests::RAND_REPO.fetch(dirs);
|
||||
crate::tests::REGEX_REPO.fetch(dirs);
|
||||
}
|
||||
|
@ -79,13 +79,13 @@ impl GitRepo {
|
|||
|
||||
fn download_dir(&self, dirs: &Dirs) -> PathBuf {
|
||||
match self.url {
|
||||
GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo).to_path(dirs),
|
||||
GitRepoUrl::Github { user: _, repo } => dirs.download_dir.join(repo),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn source_dir(&self) -> RelPath {
|
||||
match self.url {
|
||||
GitRepoUrl::Github { user: _, repo } => RelPath::BUILD.join(repo),
|
||||
GitRepoUrl::Github { user: _, repo } => RelPath::build(repo),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ impl GitRepo {
|
|||
}
|
||||
|
||||
let source_lockfile =
|
||||
RelPath::PATCHES.to_path(dirs).join(format!("{}-lock.toml", self.patch_name));
|
||||
dirs.source_dir.join("patches").join(format!("{}-lock.toml", self.patch_name));
|
||||
let target_lockfile = download_dir.join("Cargo.lock");
|
||||
if source_lockfile.exists() {
|
||||
assert!(!target_lockfile.exists());
|
||||
|
@ -191,7 +191,7 @@ fn init_git_repo(repo_dir: &Path) {
|
|||
}
|
||||
|
||||
fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
|
||||
let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs))
|
||||
let mut patches: Vec<_> = fs::read_dir(dirs.source_dir.join("patches"))
|
||||
.unwrap()
|
||||
.map(|entry| entry.unwrap().path())
|
||||
.filter(|path| path.extension() == Some(OsStr::new("patch")))
|
||||
|
|
|
@ -7,10 +7,10 @@ use crate::path::{Dirs, RelPath};
|
|||
use crate::prepare::{GitRepo, apply_patches};
|
||||
use crate::rustc_info::get_default_sysroot;
|
||||
use crate::shared_utils::rustflags_from_env;
|
||||
use crate::utils::{CargoProject, Compiler, LogGroup, spawn_and_wait};
|
||||
use crate::utils::{CargoProject, Compiler, LogGroup, ensure_empty_dir, spawn_and_wait};
|
||||
use crate::{CodegenBackend, SysrootKind, build_sysroot, config};
|
||||
|
||||
static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
|
||||
static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::build("example");
|
||||
|
||||
struct TestCase {
|
||||
config: &'static str,
|
||||
|
@ -92,10 +92,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
|
||||
TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
|
||||
TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
|
||||
TestCase::custom("aot.polymorphize_coroutine", &|runner| {
|
||||
runner.run_rustc(&["example/polymorphize_coroutine.rs", "-Zpolymorphize"]);
|
||||
runner.run_out_command("polymorphize_coroutine", &[]);
|
||||
}),
|
||||
TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]),
|
||||
TestCase::custom("aot.gen_block_iterate", &|runner| {
|
||||
runner.run_rustc([
|
||||
|
@ -129,11 +125,11 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github(
|
|||
|
||||
static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target");
|
||||
|
||||
static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("portable-simd");
|
||||
static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd");
|
||||
|
||||
static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target");
|
||||
|
||||
static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests");
|
||||
static LIBCORE_TESTS_SRC: RelPath = RelPath::build("coretests");
|
||||
|
||||
static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "coretests_target");
|
||||
|
||||
|
@ -162,7 +158,7 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
|||
&LIBCORE_TESTS_SRC.to_path(&runner.dirs),
|
||||
);
|
||||
|
||||
let source_lockfile = RelPath::PATCHES.to_path(&runner.dirs).join("coretests-lock.toml");
|
||||
let source_lockfile = runner.dirs.source_dir.join("patches/coretests-lock.toml");
|
||||
let target_lockfile = LIBCORE_TESTS_SRC.to_path(&runner.dirs).join("Cargo.lock");
|
||||
fs::copy(source_lockfile, target_lockfile).unwrap();
|
||||
|
||||
|
@ -267,7 +263,9 @@ pub(crate) fn run_tests(
|
|||
stdlib_source.clone(),
|
||||
);
|
||||
|
||||
BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
|
||||
let path = BUILD_EXAMPLE_OUT_DIR.to_path(dirs);
|
||||
ensure_empty_dir(&path);
|
||||
|
||||
runner.run_testsuite(NO_SYSROOT_SUITE);
|
||||
} else {
|
||||
eprintln!("[SKIP] no_sysroot tests");
|
||||
|
|
|
@ -93,7 +93,7 @@ impl CargoProject {
|
|||
}
|
||||
|
||||
pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
|
||||
RelPath::BUILD.join(self.target).to_path(dirs)
|
||||
dirs.build_dir.join(self.target)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
|
@ -42,7 +42,6 @@ aot.float-minmax-pass
|
|||
aot.mod_bench
|
||||
aot.issue-72793
|
||||
aot.issue-59326
|
||||
aot.polymorphize_coroutine
|
||||
aot.neon
|
||||
aot.gen_block_iterate
|
||||
aot.raw-dylib
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::ops::Coroutine;
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
run_coroutine::<i32>();
|
||||
}
|
||||
|
||||
fn run_coroutine<T>() {
|
||||
let mut coroutine = #[coroutine]
|
||||
|| {
|
||||
yield;
|
||||
return;
|
||||
};
|
||||
Pin::new(&mut coroutine).resume(());
|
||||
}
|
|
@ -8,6 +8,9 @@
|
|||
unboxed_closures
|
||||
)]
|
||||
#![allow(internal_features)]
|
||||
// FIXME once abi_unsupported_vector_types is a hard error disable the foo test when the respective
|
||||
// target feature is not enabled.
|
||||
#![allow(abi_unsupported_vector_types)]
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::arch::x86_64::*;
|
||||
|
|
|
@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644
|
|||
@@ -1,3 +1,4 @@
|
||||
+#![cfg(test)]
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||
#![cfg_attr(test, feature(cfg_match))]
|
||||
--
|
||||
2.21.0 (Apple Git-122)
|
||||
|
|
|
@ -14,10 +14,9 @@ diff --git a/lib.rs b/lib.rs
|
|||
index 1e336bf..35e6f54 100644
|
||||
--- a/lib.rs
|
||||
+++ b/lib.rs
|
||||
@@ -2,7 +2,6 @@
|
||||
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
|
||||
@@ -2,6 +2,5 @@
|
||||
#![cfg(test)]
|
||||
// tidy-alphabetical-start
|
||||
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||
#![cfg_attr(test, feature(cfg_match))]
|
||||
#![feature(alloc_layout_extra)]
|
||||
|
|
|
@ -4,22 +4,23 @@ Date: Fri, 9 Aug 2024 15:44:51 +0000
|
|||
Subject: [PATCH] Disable f16 and f128 in compiler-builtins
|
||||
|
||||
---
|
||||
library/sysroot/Cargo.toml | 2 +-
|
||||
library/liballoc/Cargo.toml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
|
||||
diff --git a/library/liballoc/Cargo.toml b/library/liballoc/Cargo.toml
|
||||
index 7165c3e48af..968552ad435 100644
|
||||
--- a/library/sysroot/Cargo.toml
|
||||
+++ b/library/sysroot/Cargo.toml
|
||||
--- a/library/alloc/Cargo.toml
|
||||
+++ b/library/alloc/Cargo.toml
|
||||
@@ -11,7 +11,7 @@ test = { path = "../test" }
|
||||
edition = "2021"
|
||||
|
||||
# Forward features to the `std` crate as necessary
|
||||
[features]
|
||||
-default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
|
||||
+default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind", "compiler-builtins-no-f16-f128"]
|
||||
backtrace = ["std/backtrace"]
|
||||
compiler-builtins-c = ["std/compiler-builtins-c"]
|
||||
compiler-builtins-mem = ["std/compiler-builtins-mem"]
|
||||
[dependencies]
|
||||
core = { path = "../core" }
|
||||
-compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std', 'no-f16-f128'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
--
|
||||
2.34.1
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-11-09"
|
||||
channel = "nightly-2024-12-06"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
profile = "minimal"
|
||||
|
|
|
@ -33,6 +33,11 @@ fn main() {
|
|||
args.push(OsString::from("--sysroot"));
|
||||
args.push(OsString::from(sysroot.to_str().unwrap()));
|
||||
}
|
||||
if passed_args.is_empty() {
|
||||
// Don't pass any arguments when the user didn't pass any arguments
|
||||
// either to ensure the help message is shown.
|
||||
args.clear();
|
||||
}
|
||||
args.extend(passed_args);
|
||||
|
||||
let rustc = if let Some(rustc) = option_env!("RUSTC") {
|
||||
|
|
|
@ -35,13 +35,14 @@ full-bootstrap = true
|
|||
local-rebuild = true
|
||||
|
||||
[rust]
|
||||
download-rustc = false
|
||||
codegen-backends = ["cranelift"]
|
||||
deny-warnings = false
|
||||
verbose-tests = false
|
||||
# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is
|
||||
# disabled bootstrap will crash trying to copy llvm tools for the bootstrap
|
||||
# compiler.
|
||||
llvm_tools = false
|
||||
llvm-tools = false
|
||||
|
||||
EOF
|
||||
popd
|
||||
|
|
|
@ -11,22 +11,5 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
|
|||
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
||||
cp -r ../src compiler/rustc_codegen_cranelift/src
|
||||
|
||||
# FIXME(rust-lang/rust#132719) remove once it doesn't break without this patch
|
||||
cat <<EOF | git apply -
|
||||
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
|
||||
index 3394f2a84a0..cb980dd4d7c 100644
|
||||
--- a/src/bootstrap/src/core/build_steps/compile.rs
|
||||
+++ b/src/bootstrap/src/core/build_steps/compile.rs
|
||||
@@ -1976,7 +1976,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
- {
|
||||
+ if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
|
||||
// \`llvm-strip\` is used by rustc, which is actually just a symlink to \`llvm-objcopy\`,
|
||||
// so copy and rename \`llvm-objcopy\`.
|
||||
let src_exe = exe("llvm-objcopy", target_compiler.host);
|
||||
EOF
|
||||
|
||||
./x.py build --stage 1 library/std
|
||||
popd
|
||||
|
|
|
@ -57,6 +57,7 @@ rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't
|
|||
rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
|
||||
rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes
|
||||
rm -r tests/run-make/embed-source-dwarf # embedding sources in debuginfo
|
||||
rm tests/ui/simd-abi-checks.rs # vector types >128bits not yet supported
|
||||
|
||||
# requires LTO
|
||||
rm -r tests/run-make/cdylib
|
||||
|
@ -75,6 +76,8 @@ rm -r tests/ui/instrument-coverage/
|
|||
rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
|
||||
rm tests/ui/asm/aarch64/type-f16.rs
|
||||
rm tests/ui/float/conv-bits-runtime-const.rs
|
||||
rm tests/ui/consts/const-eval/float_methods.rs
|
||||
rm tests/ui/match/match-float.rs
|
||||
|
||||
# optimization tests
|
||||
# ==================
|
||||
|
|
|
@ -125,8 +125,9 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
returns: Vec<AbiParam>,
|
||||
args: &[Value],
|
||||
) -> Cow<'_, [Value]> {
|
||||
if self.tcx.sess.target.is_like_windows {
|
||||
let (mut params, mut args): (Vec<_>, Vec<_>) = params
|
||||
// Pass i128 arguments by-ref on Windows.
|
||||
let (params, args): (Vec<_>, Cow<'_, [_]>) = if self.tcx.sess.target.is_like_windows {
|
||||
let (params, args): (Vec<_>, Vec<_>) = params
|
||||
.into_iter()
|
||||
.zip(args)
|
||||
.map(|(param, &arg)| {
|
||||
|
@ -140,29 +141,42 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
})
|
||||
.unzip();
|
||||
|
||||
let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128;
|
||||
(params, args.into())
|
||||
} else {
|
||||
(params, args.into())
|
||||
};
|
||||
|
||||
if indirect_ret_val {
|
||||
params.insert(0, AbiParam::new(self.pointer_type));
|
||||
let ret_ptr = self.create_stack_slot(16, 16);
|
||||
args.insert(0, ret_ptr.get_addr(self));
|
||||
self.lib_call_unadjusted(name, params, vec![], &args);
|
||||
return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]);
|
||||
// Return i128 using a return area pointer on Windows and s390x.
|
||||
let adjust_ret_param =
|
||||
if self.tcx.sess.target.is_like_windows || self.tcx.sess.target.arch == "s390x" {
|
||||
returns.len() == 1 && returns[0].value_type == types::I128
|
||||
} else {
|
||||
return self.lib_call_unadjusted(name, params, returns, &args);
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
|
||||
self.lib_call_unadjusted(name, params, returns, args)
|
||||
if adjust_ret_param {
|
||||
let mut params = params;
|
||||
let mut args = args.to_vec();
|
||||
|
||||
params.insert(0, AbiParam::new(self.pointer_type));
|
||||
let ret_ptr = self.create_stack_slot(16, 16);
|
||||
args.insert(0, ret_ptr.get_addr(self));
|
||||
|
||||
self.lib_call_unadjusted(name, params, vec![], &args);
|
||||
|
||||
Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())])
|
||||
} else {
|
||||
Cow::Borrowed(self.lib_call_unadjusted(name, params, returns, &args))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lib_call_unadjusted(
|
||||
fn lib_call_unadjusted(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: Vec<AbiParam>,
|
||||
returns: Vec<AbiParam>,
|
||||
args: &[Value],
|
||||
) -> Cow<'_, [Value]> {
|
||||
) -> &[Value] {
|
||||
let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv };
|
||||
let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
|
||||
let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
|
||||
|
@ -175,7 +189,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
}
|
||||
let results = self.bcx.inst_results(call_inst);
|
||||
assert!(results.len() <= 2, "{}", results.len());
|
||||
Cow::Borrowed(results)
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,8 +394,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
def_id,
|
||||
fn_args,
|
||||
source_info.span,
|
||||
)
|
||||
.polymorphize(fx.tcx);
|
||||
);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
if target.is_some() {
|
||||
|
@ -684,7 +697,7 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
target: BasicBlock,
|
||||
) {
|
||||
let ty = drop_place.layout().ty;
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty);
|
||||
|
||||
if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) =
|
||||
drop_instance.def
|
||||
|
|
|
@ -6,6 +6,7 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
|||
use cranelift_module::ModuleError;
|
||||
use rustc_ast::InlineAsmOptions;
|
||||
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::InlineAsmMacro;
|
||||
|
@ -16,6 +17,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||
|
||||
use crate::constant::ConstantCx;
|
||||
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
|
||||
use crate::enable_verifier;
|
||||
use crate::inline_asm::codegen_naked_asm;
|
||||
use crate::prelude::*;
|
||||
use crate::pretty_clif::CommentWriter;
|
||||
|
@ -169,12 +171,13 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
|
||||
pub(crate) fn compile_fn(
|
||||
cx: &mut crate::CodegenCx,
|
||||
profiler: &SelfProfilerRef,
|
||||
cached_context: &mut Context,
|
||||
module: &mut dyn Module,
|
||||
codegened_func: CodegenedFunction,
|
||||
) {
|
||||
let _timer =
|
||||
cx.profiler.generic_activity_with_arg("compile function", &*codegened_func.symbol_name);
|
||||
profiler.generic_activity_with_arg("compile function", &*codegened_func.symbol_name);
|
||||
|
||||
let clif_comments = codegened_func.clif_comments;
|
||||
|
||||
|
@ -212,7 +215,7 @@ pub(crate) fn compile_fn(
|
|||
};
|
||||
|
||||
// Define function
|
||||
cx.profiler.generic_activity("define function").run(|| {
|
||||
profiler.generic_activity("define function").run(|| {
|
||||
context.want_disasm = cx.should_write_ir;
|
||||
match module.define_function(codegened_func.func_id, context) {
|
||||
Ok(()) => {}
|
||||
|
@ -253,7 +256,7 @@ pub(crate) fn compile_fn(
|
|||
|
||||
// Define debuginfo for function
|
||||
let debug_context = &mut cx.debug_context;
|
||||
cx.profiler.generic_activity("generate debug info").run(|| {
|
||||
profiler.generic_activity("generate debug info").run(|| {
|
||||
if let Some(debug_context) = debug_context {
|
||||
codegened_func.func_debug_cx.unwrap().finalize(
|
||||
debug_context,
|
||||
|
@ -264,11 +267,11 @@ pub(crate) fn compile_fn(
|
|||
});
|
||||
}
|
||||
|
||||
pub(crate) fn verify_func(
|
||||
tcx: TyCtxt<'_>,
|
||||
writer: &crate::pretty_clif::CommentWriter,
|
||||
func: &Function,
|
||||
) {
|
||||
fn verify_func(tcx: TyCtxt<'_>, writer: &crate::pretty_clif::CommentWriter, func: &Function) {
|
||||
if !enable_verifier(tcx.sess) {
|
||||
return;
|
||||
}
|
||||
|
||||
tcx.prof.generic_activity("verify clif ir").run(|| {
|
||||
let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder());
|
||||
match cranelift_codegen::verify_function(&func, &flags) {
|
||||
|
@ -670,8 +673,7 @@ fn codegen_stmt<'tcx>(
|
|||
def_id,
|
||||
args,
|
||||
)
|
||||
.unwrap()
|
||||
.polymorphize(fx.tcx),
|
||||
.unwrap(),
|
||||
);
|
||||
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
|
||||
lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout));
|
||||
|
@ -757,8 +759,7 @@ fn codegen_stmt<'tcx>(
|
|||
def_id,
|
||||
args,
|
||||
ty::ClosureKind::FnOnce,
|
||||
)
|
||||
.polymorphize(fx.tcx);
|
||||
);
|
||||
let func_ref = fx.get_function_ref(instance);
|
||||
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
|
||||
lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout()));
|
||||
|
@ -1084,7 +1085,7 @@ fn codegen_panic_inner<'tcx>(
|
|||
|
||||
let def_id = fx.tcx.require_lang_item(lang_item, span);
|
||||
|
||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||
let instance = Instance::mono(fx.tcx, def_id);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
fx.bcx.ins().trap(TrapCode::user(2).unwrap());
|
||||
|
|
|
@ -81,26 +81,6 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
match bin_op {
|
||||
BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
|
||||
BinOp::Add | BinOp::Sub => None,
|
||||
BinOp::Mul if is_signed => {
|
||||
let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
|
||||
let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
|
||||
let lhs = lhs.load_scalar(fx);
|
||||
let rhs = rhs.load_scalar(fx);
|
||||
let oflow_ptr = oflow.to_ptr().get_addr(fx);
|
||||
let res = fx.lib_call_unadjusted(
|
||||
"__muloti4",
|
||||
vec![
|
||||
AbiParam::new(types::I128),
|
||||
AbiParam::new(types::I128),
|
||||
AbiParam::new(fx.pointer_type),
|
||||
],
|
||||
vec![AbiParam::new(types::I128)],
|
||||
&[lhs, rhs, oflow_ptr],
|
||||
)[0];
|
||||
let oflow = oflow.to_cvalue(fx).load_scalar(fx);
|
||||
let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
|
||||
Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
|
||||
}
|
||||
BinOp::Mul => {
|
||||
let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
|
||||
let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
|
||||
|
@ -110,7 +90,12 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
AbiParam::new(types::I128),
|
||||
];
|
||||
let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
fx.lib_call("__rust_u128_mulo", param_types, vec![], &args);
|
||||
fx.lib_call(
|
||||
if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" },
|
||||
param_types,
|
||||
vec![],
|
||||
&args,
|
||||
);
|
||||
Some(out_place.to_cvalue(fx))
|
||||
}
|
||||
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
use std::env;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn bool_env_var(key: &str) -> bool {
|
||||
env::var(key).as_deref() == Ok("1")
|
||||
}
|
||||
|
||||
/// The mode to use for compilation.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CodegenMode {
|
||||
|
@ -16,19 +9,6 @@ pub enum CodegenMode {
|
|||
JitLazy,
|
||||
}
|
||||
|
||||
impl FromStr for CodegenMode {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"aot" => Ok(CodegenMode::Aot),
|
||||
"jit" => Ok(CodegenMode::Jit),
|
||||
"jit-lazy" => Ok(CodegenMode::JitLazy),
|
||||
_ => Err(format!("Unknown codegen mode `{}`", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BackendConfig {
|
||||
|
@ -41,51 +21,22 @@ pub struct BackendConfig {
|
|||
///
|
||||
/// Defaults to the value of `CG_CLIF_JIT_ARGS`.
|
||||
pub jit_args: Vec<String>,
|
||||
|
||||
/// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
|
||||
/// once before passing the clif ir to Cranelift for compilation.
|
||||
///
|
||||
/// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is
|
||||
/// compiled with debug assertions enabled or false otherwise. Can be set using
|
||||
/// `-Cllvm-args=enable_verifier=...`.
|
||||
pub enable_verifier: bool,
|
||||
|
||||
/// Don't cache object files in the incremental cache. Useful during development of cg_clif
|
||||
/// to make it possible to use incremental mode for all analyses performed by rustc without
|
||||
/// caching object files when their content should have been changed by a change to cg_clif.
|
||||
///
|
||||
/// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false
|
||||
/// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`.
|
||||
pub disable_incr_cache: bool,
|
||||
}
|
||||
|
||||
impl Default for BackendConfig {
|
||||
fn default() -> Self {
|
||||
BackendConfig {
|
||||
codegen_mode: CodegenMode::Aot,
|
||||
jit_args: {
|
||||
match std::env::var("CG_CLIF_JIT_ARGS") {
|
||||
Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(),
|
||||
Err(std::env::VarError::NotPresent) => vec![],
|
||||
Err(std::env::VarError::NotUnicode(s)) => {
|
||||
panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s);
|
||||
}
|
||||
}
|
||||
},
|
||||
enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
|
||||
disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BackendConfig {
|
||||
/// Parse the configuration passed in using `-Cllvm-args`.
|
||||
pub fn from_opts(opts: &[String]) -> Result<Self, String> {
|
||||
fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
|
||||
value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name))
|
||||
}
|
||||
let mut config = BackendConfig {
|
||||
codegen_mode: CodegenMode::Aot,
|
||||
jit_args: match std::env::var("CG_CLIF_JIT_ARGS") {
|
||||
Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(),
|
||||
Err(std::env::VarError::NotPresent) => vec![],
|
||||
Err(std::env::VarError::NotUnicode(s)) => {
|
||||
panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let mut config = BackendConfig::default();
|
||||
for opt in opts {
|
||||
if opt.starts_with("-import-instr-limit") {
|
||||
// Silently ignore -import-instr-limit. It is set by rust's build system even when
|
||||
|
@ -94,9 +45,14 @@ impl BackendConfig {
|
|||
}
|
||||
if let Some((name, value)) = opt.split_once('=') {
|
||||
match name {
|
||||
"mode" => config.codegen_mode = value.parse()?,
|
||||
"enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
|
||||
"disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
|
||||
"mode" => {
|
||||
config.codegen_mode = match value {
|
||||
"aot" => CodegenMode::Aot,
|
||||
"jit" => CodegenMode::Jit,
|
||||
"jit-lazy" => CodegenMode::JitLazy,
|
||||
_ => return Err(format!("Unknown codegen mode `{}`", value)),
|
||||
};
|
||||
}
|
||||
_ => return Err(format!("Unknown option `{}`", name)),
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -452,8 +452,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
let data_id = match reloc_target_alloc {
|
||||
GlobalAlloc::Function { instance, .. } => {
|
||||
assert_eq!(addend, 0);
|
||||
let func_id =
|
||||
crate::abi::import_function(tcx, module, instance.polymorphize(tcx));
|
||||
let func_id = crate::abi::import_function(tcx, module, instance);
|
||||
let local_func_id = module.declare_func_in_data(func_id, &mut data);
|
||||
data.write_function_addr(offset.bytes() as u32, local_func_id);
|
||||
continue;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
|
||||
//! standalone executable.
|
||||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::BufWriter;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -25,13 +26,18 @@ use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
|
|||
use rustc_session::Session;
|
||||
use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType};
|
||||
|
||||
use crate::BackendConfig;
|
||||
use crate::CodegenCx;
|
||||
use crate::base::CodegenedFunction;
|
||||
use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
|
||||
use crate::debuginfo::TypeDebugContext;
|
||||
use crate::global_asm::GlobalAsmConfig;
|
||||
use crate::prelude::*;
|
||||
use crate::unwind_module::UnwindModule;
|
||||
|
||||
fn disable_incr_cache() -> bool {
|
||||
env::var("CG_CLIF_DISABLE_INCR_CACHE").as_deref() == Ok("1")
|
||||
}
|
||||
|
||||
struct ModuleCodegenResult {
|
||||
module_regular: CompiledModule,
|
||||
module_global_asm: Option<CompiledModule>,
|
||||
|
@ -63,10 +69,10 @@ impl OngoingCodegen {
|
|||
self,
|
||||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
backend_config: &BackendConfig,
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let mut work_products = FxIndexMap::default();
|
||||
let mut modules = vec![];
|
||||
let disable_incr_cache = disable_incr_cache();
|
||||
|
||||
for module_codegen in self.modules {
|
||||
let module_codegen_result = match module_codegen {
|
||||
|
@ -87,7 +93,7 @@ impl OngoingCodegen {
|
|||
if let Some((work_product_id, work_product)) = existing_work_product {
|
||||
work_products.insert(work_product_id, work_product);
|
||||
} else {
|
||||
let work_product = if backend_config.disable_incr_cache {
|
||||
let work_product = if disable_incr_cache {
|
||||
None
|
||||
} else if let Some(module_global_asm) = &module_global_asm {
|
||||
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||
|
@ -322,12 +328,8 @@ fn produce_final_output_artifacts(
|
|||
// These are used in linking steps and will be cleaned up afterward.
|
||||
}
|
||||
|
||||
fn make_module(
|
||||
sess: &Session,
|
||||
backend_config: &BackendConfig,
|
||||
name: String,
|
||||
) -> UnwindModule<ObjectModule> {
|
||||
let isa = crate::build_isa(sess, backend_config);
|
||||
fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
|
||||
let isa = crate::build_isa(sess);
|
||||
|
||||
let mut builder =
|
||||
ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
|
||||
|
@ -412,7 +414,13 @@ fn emit_module(
|
|||
Err(err) => return Err(format!("error writing object file: {}", err)),
|
||||
};
|
||||
|
||||
prof.artifact_size("object_file", &*name, file.metadata().unwrap().len());
|
||||
if prof.enabled() {
|
||||
prof.artifact_size(
|
||||
"object_file",
|
||||
tmp_file.file_name().unwrap().to_string_lossy(),
|
||||
file.metadata().unwrap().len(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(CompiledModule {
|
||||
name,
|
||||
|
@ -486,91 +494,101 @@ fn reuse_workproduct_for_cgu(
|
|||
})
|
||||
}
|
||||
|
||||
fn codegen_cgu_content(
|
||||
tcx: TyCtxt<'_>,
|
||||
module: &mut dyn Module,
|
||||
cgu_name: rustc_span::Symbol,
|
||||
) -> (CodegenCx, Vec<CodegenedFunction>) {
|
||||
let _timer = tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str());
|
||||
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
let mono_items = cgu.items_in_deterministic_order(tcx);
|
||||
|
||||
let mut cx = crate::CodegenCx::new(
|
||||
tcx,
|
||||
module.isa(),
|
||||
tcx.sess.opts.debuginfo != DebugInfo::None,
|
||||
cgu_name,
|
||||
);
|
||||
let mut type_dbg = TypeDebugContext::default();
|
||||
super::predefine_mono_items(tcx, module, &mono_items);
|
||||
let mut codegened_functions = vec![];
|
||||
for (mono_item, _) in mono_items {
|
||||
match mono_item {
|
||||
MonoItem::Fn(inst) => {
|
||||
if let Some(codegened_function) = crate::base::codegen_fn(
|
||||
tcx,
|
||||
&mut cx,
|
||||
&mut type_dbg,
|
||||
Function::new(),
|
||||
module,
|
||||
inst,
|
||||
) {
|
||||
codegened_functions.push(codegened_function);
|
||||
}
|
||||
}
|
||||
MonoItem::Static(def_id) => {
|
||||
let data_id = crate::constant::codegen_static(tcx, module, def_id);
|
||||
if let Some(debug_context) = &mut cx.debug_context {
|
||||
debug_context.define_static(tcx, &mut type_dbg, def_id, data_id);
|
||||
}
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
crate::global_asm::codegen_global_asm_item(tcx, &mut cx.global_asm, item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::main_shim::maybe_create_entry_wrapper(tcx, module, false, cgu.is_primary());
|
||||
|
||||
(cx, codegened_functions)
|
||||
}
|
||||
|
||||
fn module_codegen(
|
||||
tcx: TyCtxt<'_>,
|
||||
(backend_config, global_asm_config, cgu_name, token): (
|
||||
BackendConfig,
|
||||
(global_asm_config, cgu_name, token): (
|
||||
Arc<GlobalAsmConfig>,
|
||||
rustc_span::Symbol,
|
||||
ConcurrencyLimiterToken,
|
||||
),
|
||||
) -> OngoingModuleCodegen {
|
||||
let (cgu_name, mut cx, mut module, codegened_functions) =
|
||||
tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str()).run(|| {
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
let mono_items = cgu.items_in_deterministic_order(tcx);
|
||||
let mut module = make_module(tcx.sess, cgu_name.as_str().to_string());
|
||||
|
||||
let mut module = make_module(tcx.sess, &backend_config, cgu_name.as_str().to_string());
|
||||
let (mut cx, codegened_functions) = codegen_cgu_content(tcx, &mut module, cgu_name);
|
||||
|
||||
let mut cx = crate::CodegenCx::new(
|
||||
tcx,
|
||||
module.isa(),
|
||||
tcx.sess.opts.debuginfo != DebugInfo::None,
|
||||
cgu_name,
|
||||
);
|
||||
let mut type_dbg = TypeDebugContext::default();
|
||||
super::predefine_mono_items(tcx, &mut module, &mono_items);
|
||||
let mut codegened_functions = vec![];
|
||||
for (mono_item, _) in mono_items {
|
||||
match mono_item {
|
||||
MonoItem::Fn(inst) => {
|
||||
if let Some(codegened_function) = crate::base::codegen_fn(
|
||||
tcx,
|
||||
&mut cx,
|
||||
&mut type_dbg,
|
||||
Function::new(),
|
||||
&mut module,
|
||||
inst,
|
||||
) {
|
||||
codegened_functions.push(codegened_function);
|
||||
}
|
||||
}
|
||||
MonoItem::Static(def_id) => {
|
||||
let data_id = crate::constant::codegen_static(tcx, &mut module, def_id);
|
||||
if let Some(debug_context) = &mut cx.debug_context {
|
||||
debug_context.define_static(tcx, &mut type_dbg, def_id, data_id);
|
||||
}
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
crate::global_asm::codegen_global_asm_item(
|
||||
tcx,
|
||||
&mut cx.global_asm,
|
||||
item_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, false, cgu.is_primary());
|
||||
|
||||
let cgu_name = cgu.name().as_str().to_owned();
|
||||
|
||||
(cgu_name, cx, module, codegened_functions)
|
||||
});
|
||||
let cgu_name = cgu_name.as_str().to_owned();
|
||||
|
||||
let producer = crate::debuginfo::producer(tcx.sess);
|
||||
|
||||
let profiler = tcx.prof.clone();
|
||||
|
||||
OngoingModuleCodegen::Async(std::thread::spawn(move || {
|
||||
cx.profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| {
|
||||
profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| {
|
||||
cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
|
||||
cx.profiler.clone(),
|
||||
profiler.clone(),
|
||||
)));
|
||||
|
||||
let mut cached_context = Context::new();
|
||||
for codegened_func in codegened_functions {
|
||||
crate::base::compile_fn(&mut cx, &mut cached_context, &mut module, codegened_func);
|
||||
crate::base::compile_fn(
|
||||
&mut cx,
|
||||
&profiler,
|
||||
&mut cached_context,
|
||||
&mut module,
|
||||
codegened_func,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let global_asm_object_file =
|
||||
cx.profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| {
|
||||
profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| {
|
||||
crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm)
|
||||
})?;
|
||||
|
||||
let codegen_result =
|
||||
cx.profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| {
|
||||
profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| {
|
||||
emit_cgu(
|
||||
&global_asm_config.output_filenames,
|
||||
&cx.profiler,
|
||||
&profiler,
|
||||
cgu_name,
|
||||
module,
|
||||
cx.debug_context,
|
||||
|
@ -583,9 +601,63 @@ fn module_codegen(
|
|||
}))
|
||||
}
|
||||
|
||||
fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> CompiledModule {
|
||||
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
|
||||
|
||||
let _timer = tcx.sess.timer("write compressed metadata");
|
||||
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
||||
let metadata_cgu_name = cgu_name_builder
|
||||
.build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata"))
|
||||
.as_str()
|
||||
.to_string();
|
||||
|
||||
let tmp_file =
|
||||
tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
|
||||
|
||||
let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx);
|
||||
let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name);
|
||||
|
||||
if let Err(err) = std::fs::write(&tmp_file, obj) {
|
||||
tcx.dcx().fatal(format!("error writing metadata object file: {}", err));
|
||||
}
|
||||
|
||||
CompiledModule {
|
||||
name: metadata_cgu_name,
|
||||
kind: ModuleKind::Metadata,
|
||||
object: Some(tmp_file),
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
assembly: None,
|
||||
llvm_ir: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> {
|
||||
let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string());
|
||||
let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module);
|
||||
|
||||
if created_alloc_shim {
|
||||
let product = allocator_module.finish();
|
||||
|
||||
match emit_module(
|
||||
tcx.output_filenames(()),
|
||||
&tcx.sess.prof,
|
||||
product.object,
|
||||
ModuleKind::Allocator,
|
||||
"allocator_shim".to_owned(),
|
||||
&crate::debuginfo::producer(tcx.sess),
|
||||
) {
|
||||
Ok(allocator_module) => Some(allocator_module),
|
||||
Err(err) => tcx.dcx().fatal(err),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_aot(
|
||||
tcx: TyCtxt<'_>,
|
||||
backend_config: BackendConfig,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<OngoingCodegen> {
|
||||
|
@ -631,9 +703,10 @@ pub(crate) fn run_aot(
|
|||
|
||||
let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx));
|
||||
|
||||
let disable_incr_cache = disable_incr_cache();
|
||||
let (todo_cgus, done_cgus) =
|
||||
cgus.into_iter().enumerate().partition::<Vec<_>, _>(|&(i, _)| match cgu_reuse[i] {
|
||||
_ if backend_config.disable_incr_cache => true,
|
||||
_ if disable_incr_cache => true,
|
||||
CguReuse::No => true,
|
||||
CguReuse::PreLto | CguReuse::PostLto => false,
|
||||
});
|
||||
|
@ -647,12 +720,7 @@ pub(crate) fn run_aot(
|
|||
.with_task(
|
||||
dep_node,
|
||||
tcx,
|
||||
(
|
||||
backend_config.clone(),
|
||||
global_asm_config.clone(),
|
||||
cgu.name(),
|
||||
concurrency_limiter.acquire(tcx.dcx()),
|
||||
),
|
||||
(global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())),
|
||||
module_codegen,
|
||||
Some(rustc_middle::dep_graph::hash_result),
|
||||
)
|
||||
|
@ -666,62 +734,10 @@ pub(crate) fn run_aot(
|
|||
modules
|
||||
});
|
||||
|
||||
let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
|
||||
let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module);
|
||||
let allocator_module = emit_allocator_module(tcx);
|
||||
|
||||
let allocator_module = if created_alloc_shim {
|
||||
let product = allocator_module.finish();
|
||||
|
||||
match emit_module(
|
||||
tcx.output_filenames(()),
|
||||
&tcx.sess.prof,
|
||||
product.object,
|
||||
ModuleKind::Allocator,
|
||||
"allocator_shim".to_owned(),
|
||||
&crate::debuginfo::producer(tcx.sess),
|
||||
) {
|
||||
Ok(allocator_module) => Some(allocator_module),
|
||||
Err(err) => tcx.dcx().fatal(err),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let metadata_module = if need_metadata_module {
|
||||
let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || {
|
||||
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
|
||||
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
||||
let metadata_cgu_name = cgu_name_builder
|
||||
.build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata"))
|
||||
.as_str()
|
||||
.to_string();
|
||||
|
||||
let tmp_file =
|
||||
tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
|
||||
|
||||
let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx);
|
||||
let obj = create_compressed_metadata_file(tcx.sess, &metadata, &symbol_name);
|
||||
|
||||
if let Err(err) = std::fs::write(&tmp_file, obj) {
|
||||
tcx.dcx().fatal(format!("error writing metadata object file: {}", err));
|
||||
}
|
||||
|
||||
(metadata_cgu_name, tmp_file)
|
||||
});
|
||||
|
||||
Some(CompiledModule {
|
||||
name: metadata_cgu_name,
|
||||
kind: ModuleKind::Metadata,
|
||||
object: Some(tmp_file),
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
assembly: None,
|
||||
llvm_ir: None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let metadata_module =
|
||||
if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None };
|
||||
|
||||
Box::new(OngoingCodegen {
|
||||
modules,
|
||||
|
|
|
@ -11,12 +11,12 @@ use cranelift_jit::{JITBuilder, JITModule};
|
|||
use rustc_codegen_ssa::CrateInfo;
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::debuginfo::TypeDebugContext;
|
||||
use crate::prelude::*;
|
||||
use crate::unwind_module::UnwindModule;
|
||||
use crate::{BackendConfig, CodegenCx, CodegenMode};
|
||||
use crate::{CodegenCx, CodegenMode};
|
||||
|
||||
struct JitState {
|
||||
jit_module: UnwindModule<JITModule>,
|
||||
|
@ -59,14 +59,10 @@ impl UnsafeMessage {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_jit_module(
|
||||
tcx: TyCtxt<'_>,
|
||||
backend_config: &BackendConfig,
|
||||
hotswap: bool,
|
||||
) -> (UnwindModule<JITModule>, CodegenCx) {
|
||||
fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule<JITModule>, CodegenCx) {
|
||||
let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
|
||||
|
||||
let isa = crate::build_isa(tcx.sess, backend_config);
|
||||
let isa = crate::build_isa(tcx.sess);
|
||||
let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
jit_builder.hotswap(hotswap);
|
||||
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
|
||||
|
@ -81,7 +77,7 @@ fn create_jit_module(
|
|||
(jit_module, cx)
|
||||
}
|
||||
|
||||
pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
||||
pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec<String>) -> ! {
|
||||
if !tcx.sess.opts.output_types.should_codegen() {
|
||||
tcx.dcx().fatal("JIT mode doesn't work with `cargo check`");
|
||||
}
|
||||
|
@ -90,11 +86,8 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
tcx.dcx().fatal("can't jit non-executable crate");
|
||||
}
|
||||
|
||||
let (mut jit_module, mut cx) = create_jit_module(
|
||||
tcx,
|
||||
&backend_config,
|
||||
matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
|
||||
);
|
||||
let (mut jit_module, mut cx) =
|
||||
create_jit_module(tcx, matches!(codegen_mode, CodegenMode::JitLazy));
|
||||
let mut cached_context = Context::new();
|
||||
|
||||
let (_, cgus) = tcx.collect_and_partition_mono_items(());
|
||||
|
@ -110,7 +103,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
super::predefine_mono_items(tcx, &mut jit_module, &mono_items);
|
||||
for (mono_item, _) in mono_items {
|
||||
match mono_item {
|
||||
MonoItem::Fn(inst) => match backend_config.codegen_mode {
|
||||
MonoItem::Fn(inst) => match codegen_mode {
|
||||
CodegenMode::Aot => unreachable!(),
|
||||
CodegenMode::Jit => {
|
||||
codegen_and_compile_fn(
|
||||
|
@ -151,7 +144,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
);
|
||||
|
||||
let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
|
||||
.chain(backend_config.jit_args.iter().map(|arg| &**arg))
|
||||
.chain(jit_args.iter().map(|arg| &**arg))
|
||||
.map(|arg| CString::new(arg).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -211,7 +204,7 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||
instance: Instance<'tcx>,
|
||||
) {
|
||||
cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
|
||||
cx.profiler.clone(),
|
||||
tcx.prof.clone(),
|
||||
)));
|
||||
|
||||
tcx.prof.generic_activity("codegen and compile fn").run(|| {
|
||||
|
@ -227,7 +220,7 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||
module,
|
||||
instance,
|
||||
) {
|
||||
crate::base::compile_fn(cx, cached_context, module, codegened_func);
|
||||
crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -102,13 +102,12 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
|
|||
// Pass a wrapper rather than the function itself as the function itself may not
|
||||
// be exported from the main codegen unit and may thus be unreachable from the
|
||||
// object file created by an external assembler.
|
||||
let inline_asm_index = fx.cx.inline_asm_index.get();
|
||||
fx.cx.inline_asm_index.set(inline_asm_index + 1);
|
||||
let wrapper_name = format!(
|
||||
"__inline_asm_{}_wrapper_n{}",
|
||||
fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
inline_asm_index
|
||||
fx.cx.inline_asm_index
|
||||
);
|
||||
fx.cx.inline_asm_index += 1;
|
||||
let sig =
|
||||
get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance);
|
||||
create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name);
|
||||
|
@ -167,13 +166,12 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>(
|
|||
asm_gen.allocate_registers();
|
||||
asm_gen.allocate_stack_slots();
|
||||
|
||||
let inline_asm_index = fx.cx.inline_asm_index.get();
|
||||
fx.cx.inline_asm_index.set(inline_asm_index + 1);
|
||||
let asm_name = format!(
|
||||
"__inline_asm_{}_n{}",
|
||||
fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
inline_asm_index
|
||||
fx.cx.inline_asm_index
|
||||
);
|
||||
fx.cx.inline_asm_index += 1;
|
||||
|
||||
let generated_asm = asm_gen.generate_asm_wrapper(&asm_name);
|
||||
fx.cx.global_asm.push_str(&generated_asm);
|
||||
|
@ -266,13 +264,12 @@ pub(crate) fn codegen_naked_asm<'tcx>(
|
|||
// Pass a wrapper rather than the function itself as the function itself may not
|
||||
// be exported from the main codegen unit and may thus be unreachable from the
|
||||
// object file created by an external assembler.
|
||||
let inline_asm_index = cx.inline_asm_index.get();
|
||||
cx.inline_asm_index.set(inline_asm_index + 1);
|
||||
let wrapper_name = format!(
|
||||
"__inline_asm_{}_wrapper_n{}",
|
||||
cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
inline_asm_index
|
||||
cx.inline_asm_index
|
||||
);
|
||||
cx.inline_asm_index += 1;
|
||||
let sig =
|
||||
get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
||||
create_wrapper_function(module, sig, &wrapper_name, symbol.name);
|
||||
|
|
|
@ -1270,8 +1270,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
}
|
||||
|
||||
sym::cold_path => {
|
||||
// This is a no-op. The intrinsic is just a hint to the optimizer.
|
||||
// We still have an impl here to avoid it being turned into a call.
|
||||
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
|
||||
}
|
||||
|
||||
// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
|
||||
|
|
|
@ -34,7 +34,7 @@ extern crate rustc_target;
|
|||
extern crate rustc_driver;
|
||||
|
||||
use std::any::Any;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
|
@ -42,7 +42,6 @@ use cranelift_codegen::settings::{self, Configurable};
|
|||
use rustc_codegen_ssa::CodegenResults;
|
||||
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_session::Session;
|
||||
|
@ -123,11 +122,10 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
|
|||
/// The codegen context holds any information shared between the codegen of individual functions
|
||||
/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
|
||||
struct CodegenCx {
|
||||
profiler: SelfProfilerRef,
|
||||
output_filenames: Arc<OutputFilenames>,
|
||||
should_write_ir: bool,
|
||||
global_asm: String,
|
||||
inline_asm_index: Cell<usize>,
|
||||
inline_asm_index: usize,
|
||||
debug_context: Option<DebugContext>,
|
||||
cgu_name: Symbol,
|
||||
}
|
||||
|
@ -142,11 +140,10 @@ impl CodegenCx {
|
|||
None
|
||||
};
|
||||
CodegenCx {
|
||||
profiler: tcx.prof.clone(),
|
||||
output_filenames: tcx.output_filenames(()).clone(),
|
||||
should_write_ir: crate::pretty_clif::should_write_ir(tcx),
|
||||
global_asm: String::new(),
|
||||
inline_asm_index: Cell::new(0),
|
||||
inline_asm_index: 0,
|
||||
debug_context,
|
||||
cgu_name,
|
||||
}
|
||||
|
@ -154,7 +151,7 @@ impl CodegenCx {
|
|||
}
|
||||
|
||||
pub struct CraneliftCodegenBackend {
|
||||
pub config: RefCell<Option<BackendConfig>>,
|
||||
pub config: Option<BackendConfig>,
|
||||
}
|
||||
|
||||
impl CodegenBackend for CraneliftCodegenBackend {
|
||||
|
@ -176,13 +173,6 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
sess.dcx()
|
||||
.fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift");
|
||||
}
|
||||
|
||||
let mut config = self.config.borrow_mut();
|
||||
if config.is_none() {
|
||||
let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args)
|
||||
.unwrap_or_else(|err| sess.dcx().fatal(err));
|
||||
*config = Some(new_config);
|
||||
}
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> {
|
||||
|
@ -215,12 +205,15 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
tcx.dcx().abort_if_errors();
|
||||
let config = self.config.borrow().clone().unwrap();
|
||||
let config = self.config.clone().unwrap_or_else(|| {
|
||||
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
|
||||
.unwrap_or_else(|err| tcx.sess.dcx().fatal(err))
|
||||
});
|
||||
match config.codegen_mode {
|
||||
CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
|
||||
CodegenMode::Aot => driver::aot::run_aot(tcx, metadata, need_metadata_module),
|
||||
CodegenMode::Jit | CodegenMode::JitLazy => {
|
||||
#[cfg(feature = "jit")]
|
||||
driver::jit::run_jit(tcx, config);
|
||||
driver::jit::run_jit(tcx, config.codegen_mode, config.jit_args);
|
||||
|
||||
#[cfg(not(feature = "jit"))]
|
||||
tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift");
|
||||
|
@ -236,14 +229,20 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let _timer = sess.timer("finish_ongoing_codegen");
|
||||
|
||||
ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(
|
||||
sess,
|
||||
outputs,
|
||||
self.config.borrow().as_ref().unwrap(),
|
||||
)
|
||||
ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(sess, outputs)
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine if the Cranelift ir verifier should run.
|
||||
///
|
||||
/// Returns true when `-Zverify-llvm-ir` is passed, the `CG_CLIF_ENABLE_VERIFIER` env var is set to
|
||||
/// 1 or when cg_clif is compiled with debug assertions enabled or false otherwise.
|
||||
fn enable_verifier(sess: &Session) -> bool {
|
||||
sess.verify_llvm_ir()
|
||||
|| cfg!(debug_assertions)
|
||||
|| env::var("CG_CLIF_ENABLE_VERIFIER").as_deref() == Ok("1")
|
||||
}
|
||||
|
||||
fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
||||
// FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS.
|
||||
// See <https://github.com/bytecodealliance/target-lexicon/pull/113>
|
||||
|
@ -253,14 +252,14 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIsa + 'static> {
|
||||
fn build_isa(sess: &Session) -> Arc<dyn TargetIsa + 'static> {
|
||||
use target_lexicon::BinaryFormat;
|
||||
|
||||
let target_triple = crate::target_triple(sess);
|
||||
|
||||
let mut flags_builder = settings::builder();
|
||||
flags_builder.enable("is_pic").unwrap();
|
||||
let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
|
||||
let enable_verifier = if enable_verifier(sess) { "true" } else { "false" };
|
||||
flags_builder.set("enable_verifier", enable_verifier).unwrap();
|
||||
flags_builder.set("regalloc_checker", enable_verifier).unwrap();
|
||||
|
||||
|
@ -295,6 +294,16 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIs
|
|||
}
|
||||
}
|
||||
|
||||
if let target_lexicon::OperatingSystem::Windows = target_triple.operating_system {
|
||||
// FIXME remove dependency on this from the Rust ABI. cc bytecodealliance/wasmtime#9510
|
||||
flags_builder.enable("enable_multi_ret_implicit_sret").unwrap();
|
||||
}
|
||||
|
||||
if let target_lexicon::Architecture::S390x = target_triple.architecture {
|
||||
// FIXME remove dependency on this from the Rust ABI. cc bytecodealliance/wasmtime#9510
|
||||
flags_builder.enable("enable_multi_ret_implicit_sret").unwrap();
|
||||
}
|
||||
|
||||
if let target_lexicon::Architecture::Aarch64(_)
|
||||
| target_lexicon::Architecture::Riscv64(_)
|
||||
| target_lexicon::Architecture::X86_64 = target_triple.architecture
|
||||
|
@ -347,5 +356,5 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIs
|
|||
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
|
||||
#[no_mangle]
|
||||
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
|
||||
Box::new(CraneliftCodegenBackend { config: RefCell::new(None) })
|
||||
Box::new(CraneliftCodegenBackend { config: None })
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
};
|
||||
|
||||
if main_def_id.is_local() {
|
||||
let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
|
||||
let instance = Instance::mono(tcx, main_def_id);
|
||||
if module.get_name(tcx.symbol_name(instance).name).is_none() {
|
||||
return;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
}
|
||||
};
|
||||
|
||||
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
|
||||
let instance = Instance::mono(tcx, rust_main_def_id);
|
||||
|
||||
let main_name = tcx.symbol_name(instance).name;
|
||||
let main_sig = get_function_sig(tcx, m.target_config().default_call_conv, instance);
|
||||
|
@ -117,8 +117,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
report.def_id,
|
||||
tcx.mk_args(&[GenericArg::from(main_ret_ty)]),
|
||||
DUMMY_SP,
|
||||
)
|
||||
.polymorphize(tcx);
|
||||
);
|
||||
|
||||
let report_name = tcx.symbol_name(report).name;
|
||||
let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report);
|
||||
|
@ -143,8 +142,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
start_def_id,
|
||||
tcx.mk_args(&[main_ret_ty.into()]),
|
||||
DUMMY_SP,
|
||||
)
|
||||
.polymorphize(tcx);
|
||||
);
|
||||
let start_func_id = import_function(tcx, m, start_instance);
|
||||
|
||||
let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
|
||||
|
|
|
@ -1005,9 +1005,6 @@ pub(crate) fn assert_assignable<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
(ty::Param(_), _) | (_, ty::Param(_)) if fx.tcx.sess.opts.unstable_opts.polymorphize => {
|
||||
// No way to check if it is correct or not with polymorphization enabled
|
||||
}
|
||||
_ => {
|
||||
assert_eq!(
|
||||
from_ty,
|
||||
|
|
|
@ -544,7 +544,10 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
|
|||
|
||||
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
|
||||
X86Abi {
|
||||
regparm: self.tcx.sess.opts.unstable_opts.regparm,
|
||||
reg_struct_return: self.tcx.sess.opts.unstable_opts.reg_struct_return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -302,10 +302,9 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
(value, AddressSpace::DATA)
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Function { instance, .. } => (
|
||||
self.get_fn_addr(instance.polymorphize(self.tcx)),
|
||||
self.data_layout().instruction_address_space,
|
||||
),
|
||||
GlobalAlloc::Function { instance, .. } => {
|
||||
(self.get_fn_addr(instance), self.data_layout().instruction_address_space)
|
||||
}
|
||||
GlobalAlloc::VTable(ty, dyn_ty) => {
|
||||
let alloc = self
|
||||
.tcx
|
||||
|
|
|
@ -471,8 +471,6 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
|
|||
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
|
||||
},
|
||||
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
|
||||
// Type parameters from polymorphized functions.
|
||||
ty::Param(_) => build_param_type_di_node(cx, t),
|
||||
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
|
||||
};
|
||||
|
||||
|
@ -871,26 +869,6 @@ fn build_foreign_type_di_node<'ll, 'tcx>(
|
|||
)
|
||||
}
|
||||
|
||||
fn build_param_type_di_node<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
debug!("build_param_type_di_node: {:?}", t);
|
||||
let name = format!("{t:?}");
|
||||
DINodeCreationResult {
|
||||
di_node: unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateBasicType(
|
||||
DIB(cx),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
Size::ZERO.bits(),
|
||||
DW_ATE_unsigned,
|
||||
)
|
||||
},
|
||||
already_stored_in_typemap: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
codegen_unit_name: &str,
|
||||
|
|
|
@ -10,6 +10,15 @@ use crate::type_::Type;
|
|||
use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
|
||||
fn round_up_to_alignment<'ll>(
|
||||
bx: &mut Builder<'_, 'll, '_>,
|
||||
mut value: &'ll Value,
|
||||
align: Align,
|
||||
) -> &'ll Value {
|
||||
value = bx.add(value, bx.cx().const_i32(align.bytes() as i32 - 1));
|
||||
return bx.and(value, bx.cx().const_i32(-(align.bytes() as i32)));
|
||||
}
|
||||
|
||||
fn round_pointer_up_to_alignment<'ll>(
|
||||
bx: &mut Builder<'_, 'll, '_>,
|
||||
addr: &'ll Value,
|
||||
|
@ -17,8 +26,7 @@ fn round_pointer_up_to_alignment<'ll>(
|
|||
ptr_ty: &'ll Type,
|
||||
) -> &'ll Value {
|
||||
let mut ptr_as_int = bx.ptrtoint(addr, bx.cx().type_isize());
|
||||
ptr_as_int = bx.add(ptr_as_int, bx.cx().const_i32(align.bytes() as i32 - 1));
|
||||
ptr_as_int = bx.and(ptr_as_int, bx.cx().const_i32(-(align.bytes() as i32)));
|
||||
ptr_as_int = round_up_to_alignment(bx, ptr_as_int, align);
|
||||
bx.inttoptr(ptr_as_int, ptr_ty)
|
||||
}
|
||||
|
||||
|
@ -270,6 +278,106 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
|
|||
bx.load(val_type, val_addr, layout.align.abi)
|
||||
}
|
||||
|
||||
fn emit_xtensa_va_arg<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
list: OperandRef<'tcx, &'ll Value>,
|
||||
target_ty: Ty<'tcx>,
|
||||
) -> &'ll Value {
|
||||
// Implementation of va_arg for Xtensa. There doesn't seem to be an authoritative source for
|
||||
// this, other than "what GCC does".
|
||||
//
|
||||
// The va_list type has three fields:
|
||||
// struct __va_list_tag {
|
||||
// int32_t *va_stk; // Arguments passed on the stack
|
||||
// int32_t *va_reg; // Arguments passed in registers, saved to memory by the prologue.
|
||||
// int32_t va_ndx; // Offset into the arguments, in bytes
|
||||
// };
|
||||
//
|
||||
// The first 24 bytes (equivalent to 6 registers) come from va_reg, the rest from va_stk.
|
||||
// Thus if va_ndx is less than 24, the next va_arg *may* read from va_reg,
|
||||
// otherwise it must come from va_stk.
|
||||
//
|
||||
// Primitive arguments are never split between registers and the stack. For example, if loading an 8 byte
|
||||
// primitive value and va_ndx = 20, we instead bump the offset and read everything from va_stk.
|
||||
let va_list_addr = list.immediate();
|
||||
// FIXME: handle multi-field structs that split across regsave/stack?
|
||||
let layout = bx.cx.layout_of(target_ty);
|
||||
let from_stack = bx.append_sibling_block("va_arg.from_stack");
|
||||
let from_regsave = bx.append_sibling_block("va_arg.from_regsave");
|
||||
let end = bx.append_sibling_block("va_arg.end");
|
||||
|
||||
// (*va).va_ndx
|
||||
let va_reg_offset = 4;
|
||||
let va_ndx_offset = va_reg_offset + 4;
|
||||
let offset_ptr =
|
||||
bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(va_ndx_offset)]);
|
||||
|
||||
let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align.abi);
|
||||
let offset = round_up_to_alignment(bx, offset, layout.align.abi);
|
||||
|
||||
let slot_size = layout.size.align_to(Align::from_bytes(4).unwrap()).bytes() as i32;
|
||||
|
||||
// Update the offset in va_list, by adding the slot's size.
|
||||
let offset_next = bx.add(offset, bx.const_i32(slot_size));
|
||||
|
||||
// Figure out where to look for our value. We do that by checking the end of our slot (offset_next).
|
||||
// If that is within the regsave area, then load from there. Otherwise load from the stack area.
|
||||
let regsave_size = bx.const_i32(24);
|
||||
let use_regsave = bx.icmp(IntPredicate::IntULE, offset_next, regsave_size);
|
||||
bx.cond_br(use_regsave, from_regsave, from_stack);
|
||||
|
||||
bx.switch_to_block(from_regsave);
|
||||
// update va_ndx
|
||||
bx.store(offset_next, offset_ptr, bx.tcx().data_layout.pointer_align.abi);
|
||||
|
||||
// (*va).va_reg
|
||||
let regsave_area_ptr =
|
||||
bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(va_reg_offset)]);
|
||||
let regsave_area =
|
||||
bx.load(bx.type_ptr(), regsave_area_ptr, bx.tcx().data_layout.pointer_align.abi);
|
||||
let regsave_value_ptr = bx.inbounds_gep(bx.type_i8(), regsave_area, &[offset]);
|
||||
bx.br(end);
|
||||
|
||||
bx.switch_to_block(from_stack);
|
||||
|
||||
// The first time we switch from regsave to stack we needs to adjust our offsets a bit.
|
||||
// va_stk is set up such that the first stack argument is always at va_stk + 32.
|
||||
// The corrected offset is written back into the va_list struct.
|
||||
|
||||
// let offset_corrected = cmp::max(offset, 32);
|
||||
let stack_offset_start = bx.const_i32(32);
|
||||
let needs_correction = bx.icmp(IntPredicate::IntULE, offset, stack_offset_start);
|
||||
let offset_corrected = bx.select(needs_correction, stack_offset_start, offset);
|
||||
|
||||
// let offset_next_corrected = offset_corrected + slot_size;
|
||||
// va_ndx = offset_next_corrected;
|
||||
let offset_next_corrected = bx.add(offset_next, bx.const_i32(slot_size));
|
||||
// update va_ndx
|
||||
bx.store(offset_next_corrected, offset_ptr, bx.tcx().data_layout.pointer_align.abi);
|
||||
|
||||
// let stack_value_ptr = unsafe { (*va).va_stk.byte_add(offset_corrected) };
|
||||
let stack_area_ptr = bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(0)]);
|
||||
let stack_area = bx.load(bx.type_ptr(), stack_area_ptr, bx.tcx().data_layout.pointer_align.abi);
|
||||
let stack_value_ptr = bx.inbounds_gep(bx.type_i8(), stack_area, &[offset_corrected]);
|
||||
bx.br(end);
|
||||
|
||||
bx.switch_to_block(end);
|
||||
|
||||
// On big-endian, for values smaller than the slot size we'd have to align the read to the end
|
||||
// of the slot rather than the start. While the ISA and GCC support big-endian, all the Xtensa
|
||||
// targets supported by rustc are litte-endian so don't worry about it.
|
||||
|
||||
// if from_regsave {
|
||||
// unsafe { *regsave_value_ptr }
|
||||
// } else {
|
||||
// unsafe { *stack_value_ptr }
|
||||
// }
|
||||
assert!(bx.tcx().sess.target.endian == Endian::Little);
|
||||
let value_ptr =
|
||||
bx.phi(bx.type_ptr(), &[regsave_value_ptr, stack_value_ptr], &[from_regsave, from_stack]);
|
||||
return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi);
|
||||
}
|
||||
|
||||
pub(super) fn emit_va_arg<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
addr: OperandRef<'tcx, &'ll Value>,
|
||||
|
@ -302,6 +410,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
|
|||
let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two();
|
||||
emit_ptr_va_arg(bx, addr, target_ty, indirect, Align::from_bytes(8).unwrap(), false)
|
||||
}
|
||||
"xtensa" => emit_xtensa_va_arg(bx, addr, target_ty),
|
||||
// For all other architecture/OS combinations fall back to using
|
||||
// the LLVM va_arg instruction.
|
||||
// https://llvm.org/docs/LangRef.html#va-arg-instruction
|
||||
|
|
|
@ -432,11 +432,8 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
|
||||
}
|
||||
}
|
||||
// Type parameters from polymorphized functions.
|
||||
ty::Param(_) => {
|
||||
write!(output, "{t:?}").unwrap();
|
||||
}
|
||||
ty::Error(_)
|
||||
ty::Param(_)
|
||||
| ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Alias(..)
|
||||
|
|
|
@ -847,10 +847,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
let (instance, mut llfn) = match *callee.layout.ty.kind() {
|
||||
ty::FnDef(def_id, args) => (
|
||||
Some(
|
||||
ty::Instance::expect_resolve(bx.tcx(), bx.typing_env(), def_id, args, fn_span)
|
||||
.polymorphize(bx.tcx()),
|
||||
),
|
||||
Some(ty::Instance::expect_resolve(
|
||||
bx.tcx(),
|
||||
bx.typing_env(),
|
||||
def_id,
|
||||
args,
|
||||
fn_span,
|
||||
)),
|
||||
None,
|
||||
),
|
||||
ty::FnPtr(..) => (None, Some(callee.immediate())),
|
||||
|
|
|
@ -478,8 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
def_id,
|
||||
args,
|
||||
)
|
||||
.unwrap()
|
||||
.polymorphize(bx.cx().tcx());
|
||||
.unwrap();
|
||||
OperandValue::Immediate(bx.get_fn_addr(instance))
|
||||
}
|
||||
_ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
|
||||
|
@ -493,8 +492,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
def_id,
|
||||
args,
|
||||
ty::ClosureKind::FnOnce,
|
||||
)
|
||||
.polymorphize(bx.cx().tcx());
|
||||
);
|
||||
OperandValue::Immediate(bx.cx().get_fn_addr(instance))
|
||||
}
|
||||
_ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
|
||||
|
|
|
@ -168,9 +168,9 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
|
|||
})
|
||||
}
|
||||
|
||||
fn expose_ptr(
|
||||
_ecx: &mut InterpCx<'tcx, Self>,
|
||||
_ptr: interpret::Pointer<Self::Provenance>,
|
||||
fn expose_provenance(
|
||||
_ecx: &InterpCx<'tcx, Self>,
|
||||
_provenance: Self::Provenance,
|
||||
) -> interpret::InterpResult<'tcx> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
|
@ -21,9 +21,8 @@ use crate::errors::{LongRunning, LongRunningWarn};
|
|||
use crate::fluent_generated as fluent;
|
||||
use crate::interpret::{
|
||||
self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy,
|
||||
InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, RangeSet, Scalar, compile_time_machine,
|
||||
interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup,
|
||||
throw_unsup_format,
|
||||
InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar, compile_time_machine, interp_ok,
|
||||
throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
};
|
||||
|
||||
/// When hitting this many interpreted terminators we emit a deny by default lint
|
||||
|
@ -586,7 +585,10 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn expose_ptr(_ecx: &mut InterpCx<'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> {
|
||||
fn expose_provenance(
|
||||
_ecx: &InterpCx<'tcx, Self>,
|
||||
_provenance: Self::Provenance,
|
||||
) -> InterpResult<'tcx> {
|
||||
// This is only reachable with -Zunleash-the-miri-inside-of-you.
|
||||
throw_unsup_format!("exposing pointers is not possible at compile-time")
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let scalar = src.to_scalar();
|
||||
let ptr = scalar.to_pointer(self)?;
|
||||
match ptr.into_pointer_or_addr() {
|
||||
Ok(ptr) => M::expose_ptr(self, ptr)?,
|
||||
Ok(ptr) => M::expose_provenance(self, ptr.provenance)?,
|
||||
Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
|
||||
};
|
||||
interp_ok(ImmTy::from_scalar(
|
||||
|
|
|
@ -327,11 +327,11 @@ pub trait Machine<'tcx>: Sized {
|
|||
addr: u64,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Self::Provenance>>>;
|
||||
|
||||
/// Marks a pointer as exposed, allowing it's provenance
|
||||
/// Marks a pointer as exposed, allowing its provenance
|
||||
/// to be recovered. "Pointer-to-int cast"
|
||||
fn expose_ptr(
|
||||
ecx: &mut InterpCx<'tcx, Self>,
|
||||
ptr: Pointer<Self::Provenance>,
|
||||
fn expose_provenance(
|
||||
ecx: &InterpCx<'tcx, Self>,
|
||||
provenance: Self::Provenance,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
/// Convert a pointer with provenance into an allocation-offset pair and extra provenance info.
|
||||
|
|
|
@ -944,6 +944,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
interp_ok(())
|
||||
}
|
||||
|
||||
/// Handle the effect an FFI call might have on the state of allocations.
|
||||
/// This overapproximates the modifications which external code might make to memory:
|
||||
/// We set all reachable allocations as initialized, mark all provenances as exposed
|
||||
/// and overwrite them with `Provenance::WILDCARD`.
|
||||
pub fn prepare_for_native_call(
|
||||
&mut self,
|
||||
id: AllocId,
|
||||
initial_prov: M::Provenance,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Expose provenance of the root allocation.
|
||||
M::expose_provenance(self, initial_prov)?;
|
||||
|
||||
let mut done = FxHashSet::default();
|
||||
let mut todo = vec![id];
|
||||
while let Some(id) = todo.pop() {
|
||||
if !done.insert(id) {
|
||||
// We already saw this allocation before, don't process it again.
|
||||
continue;
|
||||
}
|
||||
let info = self.get_alloc_info(id);
|
||||
|
||||
// If there is no data behind this pointer, skip this.
|
||||
if !matches!(info.kind, AllocKind::LiveData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Expose all provenances in this allocation, and add them to `todo`.
|
||||
let alloc = self.get_alloc_raw(id)?;
|
||||
for prov in alloc.provenance().provenances() {
|
||||
M::expose_provenance(self, prov)?;
|
||||
if let Some(id) = prov.get_alloc_id() {
|
||||
todo.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare for possible write from native code if mutable.
|
||||
if info.mutbl.is_mut() {
|
||||
self.get_alloc_raw_mut(id)?
|
||||
.0
|
||||
.prepare_for_native_write()
|
||||
.map_err(|e| e.to_interp_error(id))?;
|
||||
}
|
||||
}
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
/// Create a lazy debug printer that prints the given allocation and all allocations it points
|
||||
/// to, recursively.
|
||||
#[must_use]
|
||||
|
|
|
@ -14,10 +14,8 @@ use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationR
|
|||
|
||||
/// Checks whether a type contains generic parameters which must be instantiated.
|
||||
///
|
||||
/// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization
|
||||
/// types may be "concrete enough" even though they still contain generic parameters in
|
||||
/// case these parameters are unused.
|
||||
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
|
||||
/// In case it does, returns a `TooGeneric` const eval error.
|
||||
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(_tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
|
||||
where
|
||||
T: TypeVisitable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
@ -27,11 +25,9 @@ where
|
|||
}
|
||||
|
||||
struct FoundParam;
|
||||
struct UsedParamsNeedInstantiationVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
struct UsedParamsNeedInstantiationVisitor {}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor {
|
||||
type Result = ControlFlow<FoundParam>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
|
@ -41,25 +37,7 @@ where
|
|||
|
||||
match *ty.kind() {
|
||||
ty::Param(_) => ControlFlow::Break(FoundParam),
|
||||
ty::Closure(def_id, args)
|
||||
| ty::CoroutineClosure(def_id, args, ..)
|
||||
| ty::Coroutine(def_id, args, ..)
|
||||
| ty::FnDef(def_id, args) => {
|
||||
let instance = ty::InstanceKind::Item(def_id);
|
||||
let unused_params = self.tcx.unused_generic_params(instance);
|
||||
for (index, arg) in args.into_iter().enumerate() {
|
||||
let index = index
|
||||
.try_into()
|
||||
.expect("more generic parameters than can fit into a `u32`");
|
||||
// Only recurse when generic parameters in fns, closures and coroutines
|
||||
// are used and have to be instantiated.
|
||||
//
|
||||
// Just in case there are closures or coroutines within this arg,
|
||||
// recurse.
|
||||
if unused_params.is_used(index) && arg.has_param() {
|
||||
return arg.visit_with(self);
|
||||
}
|
||||
}
|
||||
ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::FnDef(..) => {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
|
@ -74,7 +52,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let mut vis = UsedParamsNeedInstantiationVisitor { tcx };
|
||||
let mut vis = UsedParamsNeedInstantiationVisitor {};
|
||||
if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
|
||||
throw_inval!(TooGeneric);
|
||||
} else {
|
||||
|
|
|
@ -1103,10 +1103,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
TEST, rustc_symbol_name, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_polymorphize_error, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_def_path, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
|
|
|
@ -29,10 +29,9 @@ use rustc_errors::codes::*;
|
|||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{GenericArg, GenericArgs, HirId};
|
||||
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
|
@ -2089,7 +2088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
qpath.span(),
|
||||
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
|
||||
),
|
||||
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon.def_id),
|
||||
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
|
||||
hir::ConstArgKind::Infer(span) => self.ct_infer(None, span),
|
||||
}
|
||||
}
|
||||
|
@ -2180,27 +2179,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
/// Literals and const generic parameters are eagerly converted to a constant, everything else
|
||||
/// becomes `Unevaluated`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn lower_anon_const(&self, def: LocalDefId) -> Const<'tcx> {
|
||||
fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let body_id = match tcx.hir_node_by_def_id(def) {
|
||||
hir::Node::AnonConst(ac) => ac.body,
|
||||
node => span_bug!(
|
||||
tcx.def_span(def.to_def_id()),
|
||||
"from_anon_const can only process anonymous constants, not {node:?}"
|
||||
),
|
||||
};
|
||||
|
||||
let expr = &tcx.hir().body(body_id).value;
|
||||
let expr = &tcx.hir().body(anon.body).value;
|
||||
debug!(?expr);
|
||||
|
||||
let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
|
||||
let ty = tcx
|
||||
.type_of(anon.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
|
||||
match self.try_lower_anon_const_lit(ty, expr) {
|
||||
Some(v) => v,
|
||||
None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst {
|
||||
def: def.to_def_id(),
|
||||
args: ty::GenericArgs::identity_for_item(tcx, def.to_def_id()),
|
||||
def: anon.def_id.to_def_id(),
|
||||
args: ty::GenericArgs::identity_for_item(tcx, anon.def_id.to_def_id()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// type in that case)
|
||||
let mut all_arms_diverge = Diverges::WarnedAlways;
|
||||
|
||||
let expected = orig_expected.adjust_for_branches(self);
|
||||
let expected =
|
||||
orig_expected.try_structurally_resolve_and_adjust_for_branches(self, expr.span);
|
||||
debug!(?expected);
|
||||
|
||||
let mut coercion = {
|
||||
|
|
|
@ -39,10 +39,14 @@ impl<'a, 'tcx> Expectation<'tcx> {
|
|||
// an expected type. Otherwise, we might write parts of the type
|
||||
// when checking the 'then' block which are incompatible with the
|
||||
// 'else' branch.
|
||||
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
|
||||
pub(super) fn try_structurally_resolve_and_adjust_for_branches(
|
||||
&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
) -> Expectation<'tcx> {
|
||||
match *self {
|
||||
ExpectHasType(ety) => {
|
||||
let ety = fcx.shallow_resolve(ety);
|
||||
let ety = fcx.try_structurally_resolve_type(span, ety);
|
||||
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
|
||||
}
|
||||
ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
|
||||
|
|
|
@ -628,7 +628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
|
||||
match ty.kind() {
|
||||
match self.try_structurally_resolve_type(expr.span, ty).kind() {
|
||||
ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
|
||||
if oprnd.is_syntactic_place_expr() {
|
||||
// Places may legitimately have unsized types.
|
||||
|
@ -1293,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let cond_diverges = self.diverges.get();
|
||||
self.diverges.set(Diverges::Maybe);
|
||||
|
||||
let expected = orig_expected.adjust_for_branches(self);
|
||||
let expected = orig_expected.try_structurally_resolve_and_adjust_for_branches(self, sp);
|
||||
let then_ty = self.check_expr_with_expectation(then_expr, expected);
|
||||
let then_diverges = self.diverges.get();
|
||||
self.diverges.set(Diverges::Maybe);
|
||||
|
@ -1354,8 +1354,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
rhs: &'tcx hir::Expr<'tcx>,
|
||||
span: Span,
|
||||
) -> Ty<'tcx> {
|
||||
let expected_ty = expected.coercion_target_type(self, expr.span);
|
||||
if expected_ty == self.tcx.types.bool {
|
||||
let expected_ty = expected.only_has_type(self);
|
||||
if expected_ty == Some(self.tcx.types.bool) {
|
||||
let guar = self.expr_assign_expected_bool_error(expr, lhs, rhs, span);
|
||||
return Ty::new_error(self.tcx, guar);
|
||||
}
|
||||
|
@ -1639,7 +1639,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let element_ty = if !args.is_empty() {
|
||||
let coerce_to = expected
|
||||
.to_option(self)
|
||||
.and_then(|uty| match *uty.kind() {
|
||||
.and_then(|uty| match *self.try_structurally_resolve_type(expr.span, uty).kind() {
|
||||
ty::Array(ty, _) | ty::Slice(ty) => Some(ty),
|
||||
_ => None,
|
||||
})
|
||||
|
|
|
@ -936,18 +936,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// can be collated pretty easily if needed.
|
||||
|
||||
// Next special case: if there is only one "Incompatible" error, just emit that
|
||||
if let [
|
||||
if let &[
|
||||
Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))),
|
||||
] = &errors[..]
|
||||
{
|
||||
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
|
||||
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
|
||||
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
|
||||
let (provided_ty, provided_arg_span) = provided_arg_tys[provided_idx];
|
||||
let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
|
||||
let mut err =
|
||||
self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *err);
|
||||
let mut err = self.err_ctxt().report_and_explain_type_error(trace, self.param_env, err);
|
||||
self.emit_coerce_suggestions(
|
||||
&mut err,
|
||||
provided_args[*provided_idx],
|
||||
provided_args[provided_idx],
|
||||
provided_ty,
|
||||
Expectation::rvalue_hint(self, expected_ty)
|
||||
.only_has_type(self)
|
||||
|
@ -982,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.suggest_ptr_null_mut(
|
||||
expected_ty,
|
||||
provided_ty,
|
||||
provided_args[*provided_idx],
|
||||
provided_args[provided_idx],
|
||||
&mut err,
|
||||
);
|
||||
|
||||
|
@ -992,7 +991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
call_ident,
|
||||
expected_ty,
|
||||
provided_ty,
|
||||
provided_args[*provided_idx],
|
||||
provided_args[provided_idx],
|
||||
is_method,
|
||||
);
|
||||
|
||||
|
|
|
@ -876,7 +876,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
|| tcx.hir().body_const_context(def_id).is_some()
|
||||
{
|
||||
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
|
||||
tcx.ensure().unused_generic_params(ty::InstanceKind::Item(def_id.to_def_id()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -895,8 +894,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
|
||||
// (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
|
||||
// in MIR optimizations that may only be reachable through codegen, or other codepaths
|
||||
// that requires the optimized/ctfe MIR, such as polymorphization, coroutine bodies,
|
||||
// or evaluating consts.
|
||||
// that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
|
||||
if tcx.sess.opts.unstable_opts.validate_mir {
|
||||
sess.time("ensuring_final_MIR_is_computable", || {
|
||||
tcx.hir().par_body_owners(|def_id| {
|
||||
|
|
|
@ -832,6 +832,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(precise_enum_drop_elaboration, false);
|
||||
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
|
||||
tracked!(profiler_runtime, "abc".to_string());
|
||||
tracked!(reg_struct_return, true);
|
||||
tracked!(regparm, Some(3));
|
||||
tracked!(relax_elf_relocations, Some(true));
|
||||
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
|
||||
|
|
|
@ -269,7 +269,6 @@ provide! { tcx, def_id, other, cdata,
|
|||
lookup_default_body_stability => { table }
|
||||
lookup_deprecation_entry => { table }
|
||||
params_in_repr => { table }
|
||||
unused_generic_params => { table_direct }
|
||||
def_kind => { cdata.def_kind(def_id.index) }
|
||||
impl_parent => { table }
|
||||
defaultness => { table_direct }
|
||||
|
|
|
@ -1767,10 +1767,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
{
|
||||
record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses);
|
||||
}
|
||||
|
||||
let instance = ty::InstanceKind::Item(def_id.to_def_id());
|
||||
let unused = tcx.unused_generic_params(instance);
|
||||
self.tables.unused_generic_params.set(def_id.local_def_index, unused);
|
||||
}
|
||||
|
||||
// Encode all the deduced parameter attributes for everything that has MIR, even for items
|
||||
|
|
|
@ -395,7 +395,6 @@ define_tables! {
|
|||
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
|
||||
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
|
||||
opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
|
||||
unused_generic_params: Table<DefIndex, UnusedGenericParams>,
|
||||
// Reexported names are not associated with individual `DefId`s,
|
||||
// e.g. a glob import can introduce a lot of names, all with the same `DefId`.
|
||||
// That's why the encoded list needs to contain `ModChild` structures describing all the names
|
||||
|
|
|
@ -643,6 +643,28 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize all previously uninitialized bytes in the entire allocation, and set
|
||||
/// provenance of everything to `Wildcard`. Before calling this, make sure all
|
||||
/// provenance in this allocation is exposed!
|
||||
pub fn prepare_for_native_write(&mut self) -> AllocResult {
|
||||
let full_range = AllocRange { start: Size::ZERO, size: Size::from_bytes(self.len()) };
|
||||
// Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be.
|
||||
for chunk in self.init_mask.range_as_init_chunks(full_range) {
|
||||
if !chunk.is_init() {
|
||||
let uninit_bytes = &mut self.bytes
|
||||
[chunk.range().start.bytes_usize()..chunk.range().end.bytes_usize()];
|
||||
uninit_bytes.fill(0);
|
||||
}
|
||||
}
|
||||
// Mark everything as initialized now.
|
||||
self.mark_init(full_range, true);
|
||||
|
||||
// Set provenance of all bytes to wildcard.
|
||||
self.provenance.write_wildcards(self.len());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove all provenance in the given memory range.
|
||||
pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
|
||||
self.provenance.clear(range, cx)?;
|
||||
|
|
|
@ -195,6 +195,25 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Overwrites all provenance in the allocation with wildcard provenance.
|
||||
///
|
||||
/// Provided for usage in Miri and panics otherwise.
|
||||
pub fn write_wildcards(&mut self, alloc_size: usize) {
|
||||
assert!(
|
||||
Prov::OFFSET_IS_ADDR,
|
||||
"writing wildcard provenance is not supported when `OFFSET_IS_ADDR` is false"
|
||||
);
|
||||
let wildcard = Prov::WILDCARD.unwrap();
|
||||
|
||||
// Remove all pointer provenances, then write wildcards into the whole byte range.
|
||||
self.ptrs.clear();
|
||||
let last = Size::from_bytes(alloc_size);
|
||||
let bytes = self.bytes.get_or_insert_with(Box::default);
|
||||
for offset in Size::ZERO..last {
|
||||
bytes.insert(offset, wildcard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A partial, owned list of provenance to transfer into another allocation.
|
||||
|
|
|
@ -66,6 +66,9 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
|
|||
/// pointer, and implement ptr-to-int transmutation by stripping provenance.
|
||||
const OFFSET_IS_ADDR: bool;
|
||||
|
||||
/// If wildcard provenance is implemented, contains the unique, general wildcard provenance variant.
|
||||
const WILDCARD: Option<Self>;
|
||||
|
||||
/// Determines how a pointer should be printed.
|
||||
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
|
||||
|
||||
|
@ -168,6 +171,9 @@ impl Provenance for CtfeProvenance {
|
|||
// so ptr-to-int casts are not possible (since we do not know the global physical offset).
|
||||
const OFFSET_IS_ADDR: bool = false;
|
||||
|
||||
// `CtfeProvenance` does not implement wildcard provenance.
|
||||
const WILDCARD: Option<Self> = None;
|
||||
|
||||
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Print AllocId.
|
||||
fmt::Debug::fmt(&ptr.provenance.alloc_id(), f)?; // propagates `alternate` flag
|
||||
|
@ -197,6 +203,9 @@ impl Provenance for AllocId {
|
|||
// so ptr-to-int casts are not possible (since we do not know the global physical offset).
|
||||
const OFFSET_IS_ADDR: bool = false;
|
||||
|
||||
// `AllocId` does not implement wildcard provenance.
|
||||
const WILDCARD: Option<Self> = None;
|
||||
|
||||
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Forward `alternate` flag to `alloc_id` printing.
|
||||
if f.alternate() {
|
||||
|
|
|
@ -82,7 +82,7 @@ use crate::ty::print::{PrintTraitRefExt, describe_as_module};
|
|||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::{
|
||||
self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt,
|
||||
TyCtxtFeed, UnusedGenericParams,
|
||||
TyCtxtFeed,
|
||||
};
|
||||
use crate::{dep_graph, mir, thir};
|
||||
|
||||
|
@ -916,6 +916,12 @@ rustc_queries! {
|
|||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
/// Checks well-formedness of tail calls (`become f()`).
|
||||
query check_tail_calls(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> {
|
||||
desc { |tcx| "tail-call-checking `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
/// Returns the types assumed to be well formed while "inside" of the given item.
|
||||
///
|
||||
/// Note that we've liberated the late bound regions of function signatures, so
|
||||
|
@ -2042,15 +2048,6 @@ rustc_queries! {
|
|||
desc { "getting codegen unit `{sym}`" }
|
||||
}
|
||||
|
||||
query unused_generic_params(key: ty::InstanceKind<'tcx>) -> UnusedGenericParams {
|
||||
cache_on_disk_if { key.def_id().is_local() }
|
||||
desc {
|
||||
|tcx| "determining which generic parameters are unused by `{}`",
|
||||
tcx.def_path_str(key.def_id())
|
||||
}
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
query backend_optimization_level(_: ()) -> OptLevel {
|
||||
desc { "optimization level used by backend" }
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ use crate::error;
|
|||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::ty::print::{FmtPrinter, Printer, shrunk_instance_name};
|
||||
use crate::ty::{
|
||||
self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
|
||||
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
|
||||
/// An `InstanceKind` along with the args that are needed to substitute the instance.
|
||||
|
@ -917,116 +917,6 @@ impl<'tcx> Instance<'tcx> {
|
|||
tcx.try_normalize_erasing_regions(typing_env, v.instantiate_identity())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new `Instance` where generic parameters in `instance.args` are replaced by
|
||||
/// identity parameters if they are determined to be unused in `instance.def`.
|
||||
pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
|
||||
debug!("polymorphize: running polymorphization analysis");
|
||||
if !tcx.sess.opts.unstable_opts.polymorphize {
|
||||
return self;
|
||||
}
|
||||
|
||||
let polymorphized_args = polymorphize(tcx, self.def, self.args);
|
||||
debug!("polymorphize: self={:?} polymorphized_args={:?}", self, polymorphized_args);
|
||||
Self { def: self.def, args: polymorphized_args }
|
||||
}
|
||||
}
|
||||
|
||||
fn polymorphize<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: ty::InstanceKind<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
debug!("polymorphize({:?}, {:?})", instance, args);
|
||||
let unused = tcx.unused_generic_params(instance);
|
||||
debug!("polymorphize: unused={:?}", unused);
|
||||
|
||||
// If this is a closure or coroutine then we need to handle the case where another closure
|
||||
// from the function is captured as an upvar and hasn't been polymorphized. In this case,
|
||||
// the unpolymorphized upvar closure would result in a polymorphized closure producing
|
||||
// multiple mono items (and eventually symbol clashes).
|
||||
let def_id = instance.def_id();
|
||||
let upvars_ty = match tcx.type_of(def_id).skip_binder().kind() {
|
||||
ty::Closure(..) => Some(args.as_closure().tupled_upvars_ty()),
|
||||
ty::Coroutine(..) => {
|
||||
assert_eq!(
|
||||
args.as_coroutine().kind_ty(),
|
||||
tcx.types.unit,
|
||||
"polymorphization does not support coroutines from async closures"
|
||||
);
|
||||
Some(args.as_coroutine().tupled_upvars_ty())
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let has_upvars = upvars_ty.is_some_and(|ty| !ty.tuple_fields().is_empty());
|
||||
debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
|
||||
|
||||
struct PolymorphizationFolder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for PolymorphizationFolder<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
debug!("fold_ty: ty={:?}", ty);
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, args) => {
|
||||
let polymorphized_args =
|
||||
polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args);
|
||||
if args == polymorphized_args {
|
||||
ty
|
||||
} else {
|
||||
Ty::new_closure(self.tcx, def_id, polymorphized_args)
|
||||
}
|
||||
}
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let polymorphized_args =
|
||||
polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args);
|
||||
if args == polymorphized_args {
|
||||
ty
|
||||
} else {
|
||||
Ty::new_coroutine(self.tcx, def_id, polymorphized_args)
|
||||
}
|
||||
}
|
||||
_ => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenericArgs::for_item(tcx, def_id, |param, _| {
|
||||
let is_unused = unused.is_unused(param.index);
|
||||
debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
|
||||
match param.kind {
|
||||
// Upvar case: If parameter is a type parameter..
|
||||
ty::GenericParamDefKind::Type { .. } if
|
||||
// ..and has upvars..
|
||||
has_upvars &&
|
||||
// ..and this param has the same type as the tupled upvars..
|
||||
upvars_ty == Some(args[param.index as usize].expect_ty()) => {
|
||||
// ..then double-check that polymorphization marked it used..
|
||||
debug_assert!(!is_unused);
|
||||
// ..and polymorphize any closures/coroutines captured as upvars.
|
||||
let upvars_ty = upvars_ty.unwrap();
|
||||
let polymorphized_upvars_ty = upvars_ty.fold_with(
|
||||
&mut PolymorphizationFolder { tcx });
|
||||
debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
|
||||
ty::GenericArg::from(polymorphized_upvars_ty)
|
||||
},
|
||||
|
||||
// Simple case: If parameter is a const or type parameter..
|
||||
ty::GenericParamDefKind::Const { .. } | ty::GenericParamDefKind::Type { .. } if
|
||||
// ..and is within range and unused..
|
||||
unused.is_unused(param.index) =>
|
||||
// ..then use the identity for this parameter.
|
||||
tcx.mk_param_from_def(param),
|
||||
|
||||
// Otherwise, use the parameter as before.
|
||||
_ => args[param.index as usize],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn needs_fn_once_adapter_shim(
|
||||
|
|
|
@ -552,7 +552,10 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
|
|||
|
||||
impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
X86Abi { regparm: self.sess.opts.unstable_opts.regparm }
|
||||
X86Abi {
|
||||
regparm: self.sess.opts.unstable_opts.regparm,
|
||||
reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -131,8 +131,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
|
|||
VtblEntry::Vacant => continue,
|
||||
VtblEntry::Method(instance) => {
|
||||
// Prepare the fn ptr we write into the vtable.
|
||||
let instance = instance.polymorphize(tcx);
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(*instance, CTFE_ALLOC_SALT);
|
||||
let fn_ptr = Pointer::from(fn_alloc_id);
|
||||
Scalar::from_pointer(fn_ptr, &tcx)
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
|
|||
return construct_error(tcx, def, e);
|
||||
}
|
||||
|
||||
if let Err(err) = tcx.check_tail_calls(def) {
|
||||
return construct_error(tcx, def, err);
|
||||
}
|
||||
|
||||
let body = match tcx.thir_body(def) {
|
||||
Err(error_reported) => construct_error(tcx, def, error_reported),
|
||||
Ok((thir, expr)) => {
|
||||
|
|
386
compiler/rustc_mir_build/src/check_tail_calls.rs
Normal file
386
compiler/rustc_mir_build/src/check_tail_calls.rs
Normal file
|
@ -0,0 +1,386 @@
|
|||
use rustc_abi::ExternAbi;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::thir::visit::{self, Visitor};
|
||||
use rustc_middle::thir::{BodyTy, Expr, ExprId, ExprKind, Thir};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
|
||||
|
||||
pub(crate) fn check_tail_calls(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), ErrorGuaranteed> {
|
||||
let (thir, expr) = tcx.thir_body(def)?;
|
||||
let thir = &thir.borrow();
|
||||
|
||||
// If `thir` is empty, a type error occurred, skip this body.
|
||||
if thir.exprs.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let is_closure = matches!(tcx.def_kind(def), DefKind::Closure);
|
||||
let caller_ty = tcx.type_of(def).skip_binder();
|
||||
|
||||
let mut visitor = TailCallCkVisitor {
|
||||
tcx,
|
||||
thir,
|
||||
found_errors: Ok(()),
|
||||
// FIXME(#132279): we're clearly in a body here.
|
||||
typing_env: ty::TypingEnv::non_body_analysis(tcx, def),
|
||||
is_closure,
|
||||
caller_ty,
|
||||
};
|
||||
|
||||
visitor.visit_expr(&thir[expr]);
|
||||
|
||||
visitor.found_errors
|
||||
}
|
||||
|
||||
struct TailCallCkVisitor<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
thir: &'a Thir<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
/// Whatever the currently checked body is one of a closure
|
||||
is_closure: bool,
|
||||
/// The result of the checks, `Err(_)` if there was a problem with some
|
||||
/// tail call, `Ok(())` if all of them were fine.
|
||||
found_errors: Result<(), ErrorGuaranteed>,
|
||||
/// Type of the caller function.
|
||||
caller_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
||||
fn check_tail_call(&mut self, call: &Expr<'_>, expr: &Expr<'_>) {
|
||||
if self.is_closure {
|
||||
self.report_in_closure(expr);
|
||||
return;
|
||||
}
|
||||
|
||||
let BodyTy::Fn(caller_sig) = self.thir.body_type else {
|
||||
span_bug!(
|
||||
call.span,
|
||||
"`become` outside of functions should have been disallowed by hit_typeck"
|
||||
)
|
||||
};
|
||||
|
||||
let ExprKind::Scope { value, .. } = call.kind else {
|
||||
span_bug!(call.span, "expected scope, found: {call:?}")
|
||||
};
|
||||
let value = &self.thir[value];
|
||||
|
||||
if matches!(
|
||||
value.kind,
|
||||
ExprKind::Binary { .. }
|
||||
| ExprKind::Unary { .. }
|
||||
| ExprKind::AssignOp { .. }
|
||||
| ExprKind::Index { .. }
|
||||
) {
|
||||
self.report_builtin_op(call, expr);
|
||||
return;
|
||||
}
|
||||
|
||||
let ExprKind::Call { ty, fun, ref args, from_hir_call, fn_span } = value.kind else {
|
||||
self.report_non_call(value, expr);
|
||||
return;
|
||||
};
|
||||
|
||||
if !from_hir_call {
|
||||
self.report_op(ty, args, fn_span, expr);
|
||||
}
|
||||
|
||||
// Closures in thir look something akin to
|
||||
// `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}`
|
||||
// So we have to check for them in this weird way...
|
||||
if let &ty::FnDef(did, args) = ty.kind() {
|
||||
let parent = self.tcx.parent(did);
|
||||
if self.tcx.fn_trait_kind_from_def_id(parent).is_some()
|
||||
&& args.first().and_then(|arg| arg.as_type()).is_some_and(Ty::is_closure)
|
||||
{
|
||||
self.report_calling_closure(&self.thir[fun], args[1].as_type().unwrap(), expr);
|
||||
|
||||
// Tail calling is likely to cause unrelated errors (ABI, argument mismatches),
|
||||
// skip them, producing an error about calling a closure is enough.
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
// Erase regions since tail calls don't care about lifetimes
|
||||
let callee_sig =
|
||||
self.tcx.normalize_erasing_late_bound_regions(self.typing_env, ty.fn_sig(self.tcx));
|
||||
|
||||
if caller_sig.abi != callee_sig.abi {
|
||||
self.report_abi_mismatch(expr.span, caller_sig.abi, callee_sig.abi);
|
||||
}
|
||||
|
||||
if caller_sig.inputs_and_output != callee_sig.inputs_and_output {
|
||||
if caller_sig.inputs() != callee_sig.inputs() {
|
||||
self.report_arguments_mismatch(expr.span, caller_sig, callee_sig);
|
||||
}
|
||||
|
||||
// FIXME(explicit_tail_calls): this currenly fails for cases where opaques are used.
|
||||
// e.g.
|
||||
// ```
|
||||
// fn a() -> impl Sized { become b() } // ICE
|
||||
// fn b() -> u8 { 0 }
|
||||
// ```
|
||||
// we should think what is the expected behavior here.
|
||||
// (we should probably just accept this by revealing opaques?)
|
||||
if caller_sig.output() != callee_sig.output() {
|
||||
span_bug!(expr.span, "hir typeck should have checked the return type already");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let caller_needs_location = self.needs_location(self.caller_ty);
|
||||
let callee_needs_location = self.needs_location(ty);
|
||||
|
||||
if caller_needs_location != callee_needs_location {
|
||||
self.report_track_caller_mismatch(expr.span, caller_needs_location);
|
||||
}
|
||||
}
|
||||
|
||||
if caller_sig.c_variadic {
|
||||
self.report_c_variadic_caller(expr.span);
|
||||
}
|
||||
|
||||
if callee_sig.c_variadic {
|
||||
self.report_c_variadic_callee(expr.span);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if function of type `ty` needs location argument
|
||||
/// (i.e. if a function is marked as `#[track_caller]`)
|
||||
fn needs_location(&self, ty: Ty<'tcx>) -> bool {
|
||||
if let &ty::FnDef(did, substs) = ty.kind() {
|
||||
let instance =
|
||||
ty::Instance::expect_resolve(self.tcx, self.typing_env, did, substs, DUMMY_SP);
|
||||
|
||||
instance.def.requires_caller_location(self.tcx)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn report_in_closure(&mut self, expr: &Expr<'_>) {
|
||||
let err = self.tcx.dcx().span_err(expr.span, "`become` is not allowed in closures");
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_builtin_op(&mut self, value: &Expr<'_>, expr: &Expr<'_>) {
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(value.span, "`become` does not support operators")
|
||||
.with_note("using `become` on a builtin operator is not useful")
|
||||
.with_span_suggestion(
|
||||
value.span.until(expr.span),
|
||||
"try using `return` instead",
|
||||
"return ",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_op(&mut self, fun_ty: Ty<'_>, args: &[ExprId], fn_span: Span, expr: &Expr<'_>) {
|
||||
let mut err =
|
||||
self.tcx.dcx().struct_span_err(fn_span, "`become` does not support operators");
|
||||
|
||||
if let &ty::FnDef(did, _substs) = fun_ty.kind()
|
||||
&& let parent = self.tcx.parent(did)
|
||||
&& matches!(self.tcx.def_kind(parent), DefKind::Trait)
|
||||
&& let Some(method) = op_trait_as_method_name(self.tcx, parent)
|
||||
{
|
||||
match args {
|
||||
&[arg] => {
|
||||
let arg = &self.thir[arg];
|
||||
|
||||
err.multipart_suggestion(
|
||||
"try using the method directly",
|
||||
vec![
|
||||
(fn_span.shrink_to_lo().until(arg.span), "(".to_owned()),
|
||||
(arg.span.shrink_to_hi(), format!(").{method}()")),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
&[lhs, rhs] => {
|
||||
let lhs = &self.thir[lhs];
|
||||
let rhs = &self.thir[rhs];
|
||||
|
||||
err.multipart_suggestion(
|
||||
"try using the method directly",
|
||||
vec![
|
||||
(lhs.span.shrink_to_lo(), format!("(")),
|
||||
(lhs.span.between(rhs.span), format!(").{method}(")),
|
||||
(rhs.span.between(expr.span.shrink_to_hi()), ")".to_owned()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => span_bug!(expr.span, "operator with more than 2 args? {args:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
self.found_errors = Err(err.emit());
|
||||
}
|
||||
|
||||
fn report_non_call(&mut self, value: &Expr<'_>, expr: &Expr<'_>) {
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(value.span, "`become` requires a function call")
|
||||
.with_span_note(value.span, "not a function call")
|
||||
.with_span_suggestion(
|
||||
value.span.until(expr.span),
|
||||
"try using `return` instead",
|
||||
"return ",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_calling_closure(&mut self, fun: &Expr<'_>, tupled_args: Ty<'_>, expr: &Expr<'_>) {
|
||||
let underscored_args = match tupled_args.kind() {
|
||||
ty::Tuple(tys) if tys.is_empty() => "".to_owned(),
|
||||
ty::Tuple(tys) => std::iter::repeat("_, ").take(tys.len() - 1).chain(["_"]).collect(),
|
||||
_ => "_".to_owned(),
|
||||
};
|
||||
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(expr.span, "tail calling closures directly is not allowed")
|
||||
.with_multipart_suggestion(
|
||||
"try casting the closure to a function pointer type",
|
||||
vec![
|
||||
(fun.span.shrink_to_lo(), "(".to_owned()),
|
||||
(fun.span.shrink_to_hi(), format!(" as fn({underscored_args}) -> _)")),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_abi_mismatch(&mut self, sp: Span, caller_abi: ExternAbi, callee_abi: ExternAbi) {
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(sp, "mismatched function ABIs")
|
||||
.with_note("`become` requires caller and callee to have the same ABI")
|
||||
.with_note(format!("caller ABI is `{caller_abi}`, while callee ABI is `{callee_abi}`"))
|
||||
.emit();
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_arguments_mismatch(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
caller_sig: ty::FnSig<'_>,
|
||||
callee_sig: ty::FnSig<'_>,
|
||||
) {
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(sp, "mismatched signatures")
|
||||
.with_note("`become` requires caller and callee to have matching signatures")
|
||||
.with_note(format!("caller signature: `{caller_sig}`"))
|
||||
.with_note(format!("callee signature: `{callee_sig}`"))
|
||||
.emit();
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_track_caller_mismatch(&mut self, sp: Span, caller_needs_location: bool) {
|
||||
let err = match caller_needs_location {
|
||||
true => self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
sp,
|
||||
"a function marked with `#[track_caller]` cannot tail-call one that is not",
|
||||
)
|
||||
.emit(),
|
||||
false => self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
sp,
|
||||
"a function mot marked with `#[track_caller]` cannot tail-call one that is",
|
||||
)
|
||||
.emit(),
|
||||
};
|
||||
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_c_variadic_caller(&mut self, sp: Span) {
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
// FIXME(explicit_tail_calls): highlight the `...`
|
||||
.struct_span_err(sp, "tail-calls are not allowed in c-variadic functions")
|
||||
.emit();
|
||||
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_c_variadic_callee(&mut self, sp: Span) {
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
// FIXME(explicit_tail_calls): highlight the function or something...
|
||||
.struct_span_err(sp, "c-variadic functions can't be tail-called")
|
||||
.emit();
|
||||
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'a, 'tcx> for TailCallCkVisitor<'a, 'tcx> {
|
||||
fn thir(&self) -> &'a Thir<'tcx> {
|
||||
&self.thir
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
|
||||
if let ExprKind::Become { value } = expr.kind {
|
||||
let call = &self.thir[value];
|
||||
self.check_tail_call(call, expr);
|
||||
}
|
||||
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn op_trait_as_method_name(tcx: TyCtxt<'_>, trait_did: DefId) -> Option<&'static str> {
|
||||
let m = match tcx.as_lang_item(trait_did)? {
|
||||
LangItem::Add => "add",
|
||||
LangItem::Sub => "sub",
|
||||
LangItem::Mul => "mul",
|
||||
LangItem::Div => "div",
|
||||
LangItem::Rem => "rem",
|
||||
LangItem::Neg => "neg",
|
||||
LangItem::Not => "not",
|
||||
LangItem::BitXor => "bitxor",
|
||||
LangItem::BitAnd => "bitand",
|
||||
LangItem::BitOr => "bitor",
|
||||
LangItem::Shl => "shl",
|
||||
LangItem::Shr => "shr",
|
||||
LangItem::AddAssign => "add_assign",
|
||||
LangItem::SubAssign => "sub_assign",
|
||||
LangItem::MulAssign => "mul_assign",
|
||||
LangItem::DivAssign => "div_assign",
|
||||
LangItem::RemAssign => "rem_assign",
|
||||
LangItem::BitXorAssign => "bitxor_assign",
|
||||
LangItem::BitAndAssign => "bitand_assign",
|
||||
LangItem::BitOrAssign => "bitor_assign",
|
||||
LangItem::ShlAssign => "shl_assign",
|
||||
LangItem::ShrAssign => "shr_assign",
|
||||
LangItem::Index => "index",
|
||||
LangItem::IndexMut => "index_mut",
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(m)
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
// tidy-alphabetical-end
|
||||
|
||||
mod build;
|
||||
mod check_tail_calls;
|
||||
mod check_unsafety;
|
||||
mod errors;
|
||||
pub mod lints;
|
||||
|
@ -28,6 +29,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
providers.closure_saved_names_of_captured_variables =
|
||||
build::closure_saved_names_of_captured_variables;
|
||||
providers.check_unsafety = check_unsafety::check_unsafety;
|
||||
providers.check_tail_calls = check_tail_calls::check_tail_calls;
|
||||
providers.thir_body = thir::cx::thir_body;
|
||||
providers.hooks.thir_tree = thir::print::thir_tree;
|
||||
providers.hooks.thir_flat = thir::print::thir_flat;
|
||||
|
|
|
@ -41,6 +41,4 @@ monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
|
|||
monomorphize_unknown_cgu_collection_mode =
|
||||
unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
|
||||
|
||||
monomorphize_unused_generic_params = item has unused generic parameters
|
||||
|
||||
monomorphize_written_to_path = the full type name has been written to '{$path}'
|
||||
|
|
|
@ -965,9 +965,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
|
|||
return true;
|
||||
}
|
||||
|
||||
if tcx.is_reachable_non_generic(def_id)
|
||||
|| instance.polymorphize(*tcx).upstream_monomorphization(*tcx).is_some()
|
||||
{
|
||||
if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(*tcx).is_some() {
|
||||
// We can link to the item in question, no instance needed in this crate.
|
||||
return false;
|
||||
}
|
||||
|
@ -1114,7 +1112,7 @@ fn create_fn_mono_item<'tcx>(
|
|||
crate::util::dump_closure_profile(tcx, instance);
|
||||
}
|
||||
|
||||
respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
|
||||
respan(source, MonoItem::Fn(instance))
|
||||
}
|
||||
|
||||
/// Creates a `MonoItem` for each method that is referenced by the vtable for
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(monomorphize_recursion_limit)]
|
||||
pub(crate) struct RecursionLimit {
|
||||
|
@ -28,28 +25,6 @@ pub(crate) struct NoOptimizedMir {
|
|||
pub crate_name: Symbol,
|
||||
}
|
||||
|
||||
pub(crate) struct UnusedGenericParamsHint {
|
||||
pub span: Span,
|
||||
pub param_spans: Vec<Span>,
|
||||
pub param_names: Vec<String>,
|
||||
}
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for UnusedGenericParamsHint {
|
||||
#[track_caller]
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
||||
let mut diag = Diag::new(dcx, level, fluent::monomorphize_unused_generic_params);
|
||||
diag.span(self.span);
|
||||
for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
|
||||
// FIXME: I can figure out how to do a label with a fluent string with a fixed message,
|
||||
// or a label with a dynamic value in a hard-coded string, but I haven't figured out
|
||||
// how to combine the two. 😢
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(span, format!("generic parameter `{name}` is unused"));
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(monomorphize_large_assignments)]
|
||||
#[note]
|
||||
|
|
|
@ -19,7 +19,6 @@ mod collector;
|
|||
mod errors;
|
||||
mod mono_checks;
|
||||
mod partitioning;
|
||||
mod polymorphize;
|
||||
mod util;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
@ -50,6 +49,5 @@ fn custom_coerce_unsize_info<'tcx>(
|
|||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
partitioning::provide(providers);
|
||||
polymorphize::provide(providers);
|
||||
mono_checks::provide(providers);
|
||||
}
|
||||
|
|
|
@ -113,7 +113,6 @@ use rustc_middle::mir::mono::{
|
|||
Visibility,
|
||||
};
|
||||
use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, InstanceKind, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_session::CodegenUnits;
|
||||
|
@ -661,18 +660,14 @@ fn characteristic_def_id_of_mono_item<'tcx>(
|
|||
return None;
|
||||
}
|
||||
|
||||
// When polymorphization is enabled, methods which do not depend on their generic
|
||||
// parameters, but the self-type of their impl block do will fail to normalize.
|
||||
if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() {
|
||||
// This is a method within an impl, find out what the self-type is:
|
||||
let impl_self_ty = tcx.instantiate_and_normalize_erasing_regions(
|
||||
instance.args,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
tcx.type_of(impl_def_id),
|
||||
);
|
||||
if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
|
||||
return Some(def_id);
|
||||
}
|
||||
// This is a method within an impl, find out what the self-type is:
|
||||
let impl_self_ty = tcx.instantiate_and_normalize_erasing_regions(
|
||||
instance.args,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
tcx.type_of(impl_def_id),
|
||||
);
|
||||
if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
|
||||
return Some(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,334 +0,0 @@
|
|||
//! Polymorphization Analysis
|
||||
//! =========================
|
||||
//!
|
||||
//! This module implements an analysis of functions, methods and closures to determine which
|
||||
//! generic parameters are unused (and eventually, in what ways generic parameters are used - only
|
||||
//! for their size, offset of a field, etc.).
|
||||
|
||||
use rustc_hir::ConstContext;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::visit::{TyContext, Visitor};
|
||||
use rustc_middle::mir::{self, Local, LocalDecl, Location};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, UnusedGenericParams};
|
||||
use rustc_span::symbol::sym;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::errors::UnusedGenericParamsHint;
|
||||
|
||||
/// Provide implementations of queries relating to polymorphization analysis.
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.unused_generic_params = unused_generic_params;
|
||||
}
|
||||
|
||||
/// Determine which generic parameters are used by the instance.
|
||||
///
|
||||
/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
|
||||
/// parameters are used).
|
||||
fn unused_generic_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: ty::InstanceKind<'tcx>,
|
||||
) -> UnusedGenericParams {
|
||||
assert!(instance.def_id().is_local());
|
||||
|
||||
if !tcx.sess.opts.unstable_opts.polymorphize {
|
||||
// If polymorphization disabled, then all parameters are used.
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
let def_id = instance.def_id();
|
||||
// Exit early if this instance should not be polymorphized.
|
||||
if !should_polymorphize(tcx, def_id, instance) {
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
debug!(?generics);
|
||||
|
||||
// Exit early when there are no parameters to be unused.
|
||||
if generics.is_empty() {
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
// Create a bitset with N rightmost ones for each parameter.
|
||||
let generics_count: u32 =
|
||||
generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
|
||||
let mut unused_parameters = UnusedGenericParams::new_all_unused(generics_count);
|
||||
debug!(?unused_parameters, "(start)");
|
||||
|
||||
mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
|
||||
debug!(?unused_parameters, "(after default)");
|
||||
|
||||
// Visit MIR and accumulate used generic parameters.
|
||||
let body = match tcx.hir().body_const_context(def_id.expect_local()) {
|
||||
// Const functions are actually called and should thus be considered for polymorphization
|
||||
// via their runtime MIR.
|
||||
Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id),
|
||||
Some(_) => tcx.mir_for_ctfe(def_id),
|
||||
};
|
||||
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
|
||||
vis.visit_body(body);
|
||||
debug!(?unused_parameters, "(end)");
|
||||
|
||||
// Emit errors for debugging and testing if enabled.
|
||||
if !unused_parameters.all_used() {
|
||||
emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters);
|
||||
}
|
||||
|
||||
unused_parameters
|
||||
}
|
||||
|
||||
/// Returns `true` if the instance should be polymorphized.
|
||||
fn should_polymorphize<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
instance: ty::InstanceKind<'tcx>,
|
||||
) -> bool {
|
||||
// If an instance's MIR body is not polymorphic then the modified generic parameters that are
|
||||
// derived from polymorphization's result won't make any difference.
|
||||
if !instance.has_polymorphic_mir_body() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic.
|
||||
if matches!(instance, ty::InstanceKind::Intrinsic(..) | ty::InstanceKind::Virtual(..)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Foreign items have no bodies to analyze.
|
||||
if tcx.is_foreign_item(def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure there is MIR available.
|
||||
match tcx.hir().body_const_context(def_id.expect_local()) {
|
||||
Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
|
||||
debug!("no mir available");
|
||||
return false;
|
||||
}
|
||||
Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
|
||||
debug!("no ctfe mir available");
|
||||
return false;
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
|
||||
/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
|
||||
/// be `true` if the item that `unused_generic_params` was invoked on is a closure.
|
||||
#[instrument(level = "debug", skip(tcx, def_id, generics, unused_parameters))]
|
||||
fn mark_used_by_default_parameters<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generics: &'tcx ty::Generics,
|
||||
unused_parameters: &mut UnusedGenericParams,
|
||||
) {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Closure | DefKind::SyntheticCoroutineBody => {
|
||||
for param in &generics.own_params {
|
||||
debug!(?param, "(closure/gen)");
|
||||
unused_parameters.mark_used(param.index);
|
||||
}
|
||||
}
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
| DefKind::Enum
|
||||
| DefKind::Variant
|
||||
| DefKind::Trait
|
||||
| DefKind::TyAlias
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::AssocTy
|
||||
| DefKind::TyParam
|
||||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(_, _)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Macro(_)
|
||||
| DefKind::ExternCrate
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl { .. } => {
|
||||
for param in &generics.own_params {
|
||||
debug!(?param, "(other)");
|
||||
if let ty::GenericParamDefKind::Lifetime = param.kind {
|
||||
unused_parameters.mark_used(param.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(parent) = generics.parent {
|
||||
mark_used_by_default_parameters(tcx, parent, tcx.generics_of(parent), unused_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
|
||||
/// parameter which was unused.
|
||||
#[instrument(level = "debug", skip(tcx, generics))]
|
||||
fn emit_unused_generic_params_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generics: &'tcx ty::Generics,
|
||||
unused_parameters: &UnusedGenericParams,
|
||||
) {
|
||||
let base_def_id = tcx.typeck_root_def_id(def_id);
|
||||
if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fn_span = match tcx.opt_item_ident(def_id) {
|
||||
Some(ident) => ident.span,
|
||||
_ => tcx.def_span(def_id),
|
||||
};
|
||||
|
||||
let mut param_spans = Vec::new();
|
||||
let mut param_names = Vec::new();
|
||||
let mut next_generics = Some(generics);
|
||||
while let Some(generics) = next_generics {
|
||||
for param in &generics.own_params {
|
||||
if unused_parameters.is_unused(param.index) {
|
||||
debug!(?param);
|
||||
let def_span = tcx.def_span(param.def_id);
|
||||
param_spans.push(def_span);
|
||||
param_names.push(param.name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
next_generics = generics.parent.map(|did| tcx.generics_of(did));
|
||||
}
|
||||
|
||||
tcx.dcx().emit_err(UnusedGenericParamsHint { span: fn_span, param_spans, param_names });
|
||||
}
|
||||
|
||||
/// Visitor used to aggregate generic parameter uses.
|
||||
struct MarkUsedGenericParams<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
unused_parameters: &'a mut UnusedGenericParams,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
|
||||
/// Invoke `unused_generic_params` on a body contained within the current item (e.g.
|
||||
/// a closure, coroutine or constant).
|
||||
#[instrument(level = "debug", skip(self, def_id, args))]
|
||||
fn visit_child_body(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) {
|
||||
let instance = ty::InstanceKind::Item(def_id);
|
||||
let unused = self.tcx.unused_generic_params(instance);
|
||||
debug!(?self.unused_parameters, ?unused);
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let i = i.try_into().unwrap();
|
||||
if unused.is_used(i) {
|
||||
arg.visit_with(self);
|
||||
}
|
||||
}
|
||||
debug!(?self.unused_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self, local))]
|
||||
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
if local == Local::from_usize(1) {
|
||||
let def_kind = self.tcx.def_kind(self.def_id);
|
||||
if matches!(def_kind, DefKind::Closure) {
|
||||
// Skip visiting the closure/coroutine that is currently being processed. This only
|
||||
// happens because the first argument to the closure is a reference to itself and
|
||||
// that will call `visit_args`, resulting in each generic parameter captured being
|
||||
// considered used by default.
|
||||
debug!("skipping closure args");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.super_local_decl(local, local_decl);
|
||||
}
|
||||
|
||||
fn visit_const_operand(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) {
|
||||
match ct.const_ {
|
||||
mir::Const::Ty(_, c) => {
|
||||
c.visit_with(self);
|
||||
}
|
||||
mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => {
|
||||
// Avoid considering `T` unused when constants are of the form:
|
||||
// `<Self as Foo<T>>::foo::promoted[p]`
|
||||
if let Some(p) = promoted {
|
||||
if self.def_id == def && !self.tcx.generics_of(def).has_self {
|
||||
// If there is a promoted, don't look at the args - since it will always contain
|
||||
// the generic parameters, instead, traverse the promoted MIR.
|
||||
let promoted = self.tcx.promoted_mir(def);
|
||||
self.visit_body(&promoted[p]);
|
||||
}
|
||||
}
|
||||
|
||||
Visitor::visit_ty(self, ty, TyContext::Location(location));
|
||||
}
|
||||
mir::Const::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) {
|
||||
ty.visit_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) {
|
||||
if !c.has_non_region_param() {
|
||||
return;
|
||||
}
|
||||
|
||||
match c.kind() {
|
||||
ty::ConstKind::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
}
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args })
|
||||
if matches!(self.tcx.def_kind(def), DefKind::AnonConst) =>
|
||||
{
|
||||
self.visit_child_body(def, args);
|
||||
}
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) {
|
||||
if !ty.has_non_region_param() {
|
||||
return;
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, args) | ty::Coroutine(def_id, args, ..) => {
|
||||
debug!(?def_id);
|
||||
// Avoid cycle errors with coroutines.
|
||||
if def_id == self.def_id {
|
||||
return;
|
||||
}
|
||||
|
||||
// Consider any generic parameters used by any closures/coroutines as used in the
|
||||
// parent.
|
||||
self.visit_child_body(def_id, args);
|
||||
}
|
||||
ty::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -135,5 +135,6 @@ session_unsupported_crate_type_for_target =
|
|||
|
||||
session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
|
||||
|
||||
session_unsupported_reg_struct_return_arch = `-Zreg-struct-return` is only supported on x86
|
||||
session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3)
|
||||
session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86
|
||||
|
|
|
@ -489,6 +489,10 @@ pub(crate) struct UnsupportedRegparm {
|
|||
#[diag(session_unsupported_regparm_arch)]
|
||||
pub(crate) struct UnsupportedRegparmArch;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_unsupported_reg_struct_return_arch)]
|
||||
pub(crate) struct UnsupportedRegStructReturnArch;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_failed_to_create_profiler)]
|
||||
pub(crate) struct FailedToCreateProfiler {
|
||||
|
|
|
@ -1950,8 +1950,6 @@ options! {
|
|||
(default: PLT is disabled if full relro is enabled on x86_64)"),
|
||||
polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED],
|
||||
"enable polonius-based borrow-checker (default: no)"),
|
||||
polymorphize: bool = (false, parse_bool, [TRACKED],
|
||||
"perform polymorphization analysis"),
|
||||
pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
|
||||
"a single extra argument to prepend the linker invocation (can be used several times)"),
|
||||
pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
|
||||
|
@ -1988,6 +1986,9 @@ options! {
|
|||
"enable queries of the dependency graph for regression testing (default: no)"),
|
||||
randomize_layout: bool = (false, parse_bool, [TRACKED],
|
||||
"randomize the layout of types (default: no)"),
|
||||
reg_struct_return: bool = (false, parse_bool, [TRACKED],
|
||||
"On x86-32 targets, it overrides the default ABI to return small structs in registers.
|
||||
It is UNSOUND to link together crates that use different values for this flag!"),
|
||||
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
|
||||
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
|
||||
in registers EAX, EDX, and ECX instead of on the stack for\
|
||||
|
|
|
@ -1305,6 +1305,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
sess.dcx().emit_err(errors::UnsupportedRegparmArch);
|
||||
}
|
||||
}
|
||||
if sess.opts.unstable_opts.reg_struct_return {
|
||||
if sess.target.arch != "x86" {
|
||||
sess.dcx().emit_err(errors::UnsupportedRegStructReturnArch);
|
||||
}
|
||||
}
|
||||
|
||||
// The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is
|
||||
// kept as a `match` to force a change if new ones are added, even if we currently only support
|
||||
|
|
|
@ -1746,7 +1746,6 @@ symbols! {
|
|||
rustc_peek_liveness,
|
||||
rustc_peek_maybe_init,
|
||||
rustc_peek_maybe_uninit,
|
||||
rustc_polymorphize_error,
|
||||
rustc_preserve_ub_checks,
|
||||
rustc_private,
|
||||
rustc_proc_macro_decls,
|
||||
|
|
|
@ -256,7 +256,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
});
|
||||
|
||||
// Encode impl generic params if the generic parameters contain non-region parameters
|
||||
// (implying polymorphization is enabled) and this isn't an inherent impl.
|
||||
// and this isn't an inherent impl.
|
||||
if impl_trait_ref.is_some() && args.iter().any(|a| a.has_non_region_param()) {
|
||||
self.path_generic_args(
|
||||
|this| {
|
||||
|
@ -330,9 +330,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
ty::Float(FloatTy::F128) => "C4f128",
|
||||
ty::Never => "z",
|
||||
|
||||
// Should only be encountered with polymorphization,
|
||||
// or within the identity-substituted impl header of an
|
||||
// item nested within an impl item.
|
||||
// Should only be encountered within the identity-substituted
|
||||
// impl header of an item nested within an impl item.
|
||||
ty::Param(_) => "p",
|
||||
|
||||
ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => bug!(),
|
||||
|
@ -558,9 +557,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
let (ct_ty, valtree) = match ct.kind() {
|
||||
ty::ConstKind::Value(ty, val) => (ty, val),
|
||||
|
||||
// Should only be encountered with polymorphization,
|
||||
// or within the identity-substituted impl header of an
|
||||
// item nested within an impl item.
|
||||
// Should only be encountered within the identity-substituted
|
||||
// impl header of an item nested within an impl item.
|
||||
ty::ConstKind::Param(_) => {
|
||||
// Never cached (single-character).
|
||||
self.push("p");
|
||||
|
|
|
@ -661,7 +661,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
|||
}
|
||||
_ => (x86::Flavor::General, None),
|
||||
};
|
||||
x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm });
|
||||
let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
|
||||
let opts = x86::X86Options { flavor, regparm, reg_struct_return };
|
||||
x86::compute_abi_info(cx, self, opts);
|
||||
}
|
||||
"x86_64" => match abi {
|
||||
spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
|
||||
|
|
|
@ -14,6 +14,7 @@ pub(crate) enum Flavor {
|
|||
pub(crate) struct X86Options {
|
||||
pub flavor: Flavor,
|
||||
pub regparm: Option<u32>,
|
||||
pub reg_struct_return: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
|
||||
|
@ -31,7 +32,7 @@ where
|
|||
// https://www.angelcode.com/dev/callconv/callconv.html
|
||||
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
|
||||
let t = cx.target_spec();
|
||||
if t.abi_return_struct_as_int {
|
||||
if t.abi_return_struct_as_int || opts.reg_struct_return {
|
||||
// According to Clang, everyone but MSVC returns single-element
|
||||
// float aggregates directly in a floating-point register.
|
||||
if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) {
|
||||
|
|
|
@ -2117,6 +2117,8 @@ pub struct X86Abi {
|
|||
/// On x86-32 targets, the regparm N causes the compiler to pass arguments
|
||||
/// in registers EAX, EDX, and ECX instead of on the stack.
|
||||
pub regparm: Option<u32>,
|
||||
/// Override the default ABI to return small structs in registers
|
||||
pub reg_struct_return: bool,
|
||||
}
|
||||
|
||||
pub trait HasX86AbiOpt {
|
||||
|
|
|
@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("Armv4T Linux".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
|
||||
|
|
|
@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("Armv5TE Linux with uClibc".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
|
||||
|
|
|
@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("Motorola 680x0 Linux".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16".into(),
|
||||
|
|
|
@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("MIPS64 for OpenWrt Linux musl 1.2.3".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
|
||||
|
|
|
@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("32-bit MIPS Release 6 Big Endian".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
|
||||
|
|
|
@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("32-bit MIPS Release 6 Little Endian".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
|
||||
|
|
|
@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("64-bit MIPS Release 6 Big Endian".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
|
||||
|
|
|
@ -14,7 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("64-bit PowerPC Linux with musl 1.2.3".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
|
||||
|
|
|
@ -12,8 +12,8 @@ pub(crate) fn target() -> Target {
|
|||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("PPC64LE FreeBSD".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(false),
|
||||
host_tools: Some(true),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-Fn32-i64:64-n32:64".into(),
|
||||
|
|
|
@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("64-bit PowerPC Linux with musl 1.2.3, Little Endian".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
|
||||
|
|
|
@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("PowerPC FreeBSD".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
|
||||
|
|
|
@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("PowerPC Linux with musl 1.2.3".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
|
||||
|
|
|
@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
|
|||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
|
||||
|
|
|
@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("RISC-V Linux (kernel 5.4, glibc 2.33)".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
|
||||
|
|
|
@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
|
|||
),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
|
||||
|
|
|
@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
|
|||
description: Some("RISC-V 64-bit Android".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue