From 75fce09751683f7177c4f0718f33d572a0278e8f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 19 Nov 2023 13:42:13 -0500 Subject: [PATCH 001/192] Merge commit '2e8386e9fb3506cef991d04f8b3bc78f9a0c2630' into subtree-update_cg_gcc_2023-11-17 --- .github/workflows/ci.yml | 9 ++++-- .github/workflows/failures.yml | 5 +++- .github/workflows/m68k.yml | 9 ++++-- .github/workflows/release.yml | 9 ++++-- .github/workflows/stdarch.yml | 12 +++++--- Cargo.lock | 4 +-- build_sysroot/build_sysroot.sh | 4 +++ build_system/src/build.rs | 6 ++++ failing-ui-tests12.txt | 2 ++ ...0001-core-Disable-portable-simd-test.patch | 14 +++++----- rust-toolchain | 2 +- src/base.rs | 16 +++++------ src/int.rs | 25 +++++++++++++++-- src/lib.rs | 28 +++++++++++++++---- 14 files changed, 104 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65e7a697ab0df..308bc55ead71e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,8 +99,10 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore - ./y.sh build - cargo test + # TODO: remove --features master when it is back to the default. + ./y.sh build --features master + # TODO: remove --features master when it is back to the default. + cargo test --features master ./clean_all.sh - name: Prepare dependencies @@ -121,7 +123,8 @@ jobs: - name: Run tests run: | - ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} + # TODO: remove --features master when it is back to the default. + ./test.sh --features master --release --clean --build-sysroot ${{ matrix.commands }} duplicates: runs-on: ubuntu-latest diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index 27864dcadd0fe..ae8de79b773db 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -21,11 +21,14 @@ jobs: libgccjit_version: - gcc: "libgccjit.so" artifacts_branch: "master" + # TODO: switch back to --no-default-features in the case of libgccjit 12 when the default is to enable + # master again. + extra: "--features master" - gcc: "libgccjit_without_int128.so" artifacts_branch: "master-without-128bit-integers" + extra: "--features master" - gcc: "libgccjit12.so" artifacts_branch: "gcc12" - extra: "--no-default-features" # FIXME(antoyo): we need to set GCC_EXEC_PREFIX so that the linker can find the linker plugin. # Not sure why it's not found otherwise. env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests' GCC_EXEC_PREFIX=/usr/lib/gcc/" diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 55ee0a212142e..4d9d7e23dc2b5 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -114,8 +114,10 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --target-triple m68k-unknown-linux-gnu - CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test + # TODO: remove --features master when it is back to the default. + ./y.sh build --target-triple m68k-unknown-linux-gnu --features master + # TODO: remove --features master when it is back to the default. + CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test --features master ./clean_all.sh - name: Prepare dependencies @@ -136,4 +138,5 @@ jobs: - name: Run tests run: | - ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} + # TODO: remove --features master when it is back to the default. + ./test.sh --release --features master --clean --build-sysroot ${{ matrix.commands }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ae1134177a77e..43b90fcec9337 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,8 +78,10 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore - EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot - cargo test + # TODO: remove --features master when it is back to the default. + EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot --features master + # TODO: remove --features master when it is back to the default. + cargo test --features master ./clean_all.sh - name: Prepare dependencies @@ -102,4 +104,5 @@ jobs: - name: Run tests run: | - EMBED_LTO_BITCODE=1 ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} + # TODO: remove --features master when it is back to the default. + EMBED_LTO_BITCODE=1 ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} --features master diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 28ac3cb65422f..42109ba3e0245 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -92,8 +92,10 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore - ./y.sh build --release --release-sysroot - cargo test + # TODO: remove `--features master` when it is back to the default. + ./y.sh build --release --release-sysroot --features master + # TODO: remove --features master when it is back to the default. + cargo test --features master - name: Clean if: ${{ !matrix.cargo_runner }} @@ -111,12 +113,14 @@ jobs: uses: actions-rs/cargo@v1.0.3 with: command: build - args: --release + # TODO: remove `--features master` when it is back to the default. + args: --release --features master - name: Run tests if: ${{ !matrix.cargo_runner }} run: | - ./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore + # TODO: remove `--features master` when it is back to the default. + ./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore --features master - name: Run stdarch tests if: ${{ !matrix.cargo_runner }} diff --git a/Cargo.lock b/Cargo.lock index b8e2e5d808044..7c18633692783 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#c52a218f5529321285b4489e5562a00e5428e033" +source = "git+https://github.com/antoyo/gccjit.rs#6e290f25b1d1edab5ae9ace486fd2dc8c08d6421" dependencies = [ "gccjit_sys", ] @@ -82,7 +82,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#c52a218f5529321285b4489e5562a00e5428e033" +source = "git+https://github.com/antoyo/gccjit.rs#6e290f25b1d1edab5ae9ace486fd2dc8c08d6421" dependencies = [ "libc", ] diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index 116fd36e7a7b3..ebc7dc375b125 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -28,3 +28,7 @@ fi # Copy files to sysroot mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +# Copy the source files to the sysroot (Rust for Linux needs this). +source_dir=sysroot/lib/rustlib/src/rust +mkdir -p $source_dir +cp -r sysroot_src/library/ $source_dir diff --git a/build_system/src/build.rs b/build_system/src/build.rs index eaca7a987d6b8..f1c3701a946ec 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -194,6 +194,12 @@ fn build_sysroot( copier, )?; + // Copy the source files to the sysroot (Rust for Linux needs this). + let sysroot_src_path = "sysroot/lib/rustlib/src/rust"; + fs::create_dir_all(&sysroot_src_path) + .map_err(|error| format!("Failed to create directory `{}`: {:?}", sysroot_src_path, error))?; + run_command(&[&"cp", &"-r", &"sysroot_src/library/", &sysroot_src_path], None)?; + Ok(()) } diff --git a/failing-ui-tests12.txt b/failing-ui-tests12.txt index f91aa92531848..4af93939b0642 100644 --- a/failing-ui-tests12.txt +++ b/failing-ui-tests12.txt @@ -38,3 +38,5 @@ tests/ui/target-feature/missing-plusminus.rs tests/ui/sse2.rs tests/ui/codegen/issue-79865-llvm-miscompile.rs tests/ui/intrinsics/intrinsics-integer.rs +tests/ui/std-backtrace.rs +tests/ui/mir/alignment/packed.rs diff --git a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch index 9520a5a39edcd..914ae986b50e7 100644 --- a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch +++ b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch @@ -1,6 +1,6 @@ -From 7bcd24ec6d4a96121874cb1ae5a23ea274aeff34 Mon Sep 17 00:00:00 2001 +From a5663265f797a43c502915c356fe7899c16cee92 Mon Sep 17 00:00:00 2001 From: None -Date: Thu, 19 Oct 2023 13:12:51 -0400 +Date: Sat, 18 Nov 2023 10:50:36 -0500 Subject: [PATCH] [core] Disable portable-simd test --- @@ -8,18 +8,18 @@ Subject: [PATCH] [core] Disable portable-simd test 1 file changed, 2 deletions(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs -index 5814ed4..194ad4c 100644 +index d0a119c..76fdece 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs -@@ -90,7 +90,6 @@ +@@ -89,7 +89,6 @@ + #![feature(never_type)] #![feature(unwrap_infallible)] - #![feature(pointer_byte_offsets)] #![feature(pointer_is_aligned)] -#![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(lazy_cell)] #![feature(unsized_tuple_coercion)] -@@ -157,7 +156,6 @@ mod pin; +@@ -155,7 +154,6 @@ mod pin; mod pin_macro; mod ptr; mod result; @@ -28,5 +28,5 @@ index 5814ed4..194ad4c 100644 mod str; mod str_lossy; -- -2.42.0 +2.42.1 diff --git a/rust-toolchain b/rust-toolchain index 205ec53b425bf..1962c217258a4 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-21" +channel = "nightly-2023-11-17" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/base.rs b/src/base.rs index 5073066c1383c..3ffdab8b16cab 100644 --- a/src/base.rs +++ b/src/base.rs @@ -3,7 +3,6 @@ use std::env; use std::time::Instant; use gccjit::{ - Context, FunctionType, GlobalKind, }; @@ -18,8 +17,9 @@ use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::DebugInfoMethods; use rustc_session::config::DebugInfo; use rustc_span::Symbol; +use rustc_target::spec::PanicStrategy; -use crate::{LockedTargetInfo, gcc_util}; +use crate::{LockedTargetInfo, gcc_util, new_context}; use crate::GccContext; use crate::builder::Builder; use crate::context::CodegenCx; @@ -88,20 +88,18 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); // Instantiate monomorphizations without filling out definitions yet... - let context = Context::default(); + let context = new_context(&tcx); - context.add_command_line_option("-fexceptions"); - context.add_driver_option("-fexceptions"); + if tcx.sess.panic_strategy() == PanicStrategy::Unwind { + context.add_command_line_option("-fexceptions"); + context.add_driver_option("-fexceptions"); + } let disabled_features: HashSet<_> = tcx.sess.opts.cg.target_feature.split(',') .filter(|feature| feature.starts_with('-')) .map(|string| &string[1..]) .collect(); - if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" { - context.add_command_line_option("-masm=intel"); - } - if !disabled_features.contains("avx") && tcx.sess.target.arch == "x86_64" { // NOTE: we always enable AVX because the equivalent of llvm.x86.sse2.cmp.pd in GCC for // SSE2 is multiple builtins, so we use the AVX __builtin_ia32_cmppd instead. diff --git a/src/int.rs b/src/int.rs index ea8550d20f362..9b9b3ea4f8704 100644 --- a/src/int.rs +++ b/src/int.rs @@ -76,6 +76,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { a >> b } } + else if a_type.is_vector() && a_type.is_vector() { + a >> b + } else if a_native && !b_native { self.gcc_lshr(a, self.gcc_int_cast(b, a_type)) } @@ -144,7 +147,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn additive_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); - if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { + if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { if a_type != b_type { if a_type.is_vector() { // Vector types need to be bitcast. @@ -158,6 +161,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.context.new_binary_op(None, operation, a_type, a, b) } else { + debug_assert!(a_type.dyncast_array().is_some()); + debug_assert!(b_type.dyncast_array().is_some()); let signed = a_type.is_compatible_with(self.i128_type); let func_name = match (operation, signed) { @@ -189,10 +194,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); - if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { + if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { self.context.new_binary_op(None, operation, a_type, a, b) } else { + debug_assert!(a_type.dyncast_array().is_some()); + debug_assert!(b_type.dyncast_array().is_some()); let sign = if signed { "" @@ -337,6 +344,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn operation_with_overflow(&self, func_name: &str, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { let a_type = lhs.get_type(); let b_type = rhs.get_type(); + debug_assert!(a_type.dyncast_array().is_some()); + debug_assert!(b_type.dyncast_array().is_some()); let param_a = self.context.new_parameter(None, a_type, "a"); let param_b = self.context.new_parameter(None, b_type, "b"); let result_field = self.context.new_field(None, a_type, "result"); @@ -496,7 +505,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); - if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { + if a_type.is_vector() && b_type.is_vector() { + let b = self.bitcast_if_needed(b, a_type); + a ^ b + } + else if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { a ^ b } else { @@ -527,6 +540,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { a << b } } + else if a_type.is_vector() && a_type.is_vector() { + a << b + } else if a_native && !b_native { self.gcc_shl(a, self.gcc_int_cast(b, a_type)) } @@ -690,6 +706,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let a_native = self.is_native_int_type_or_bool(a_type); let b_native = self.is_native_int_type_or_bool(b_type); if a_type.is_vector() && b_type.is_vector() { + let b = self.bitcast_if_needed(b, a_type); self.context.new_binary_op(None, operation, a_type, a, b) } else if a_native && b_native { @@ -748,6 +765,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { return self.context.new_cast(None, value, dest_typ); } + debug_assert!(value_type.dyncast_array().is_some()); let name_suffix = match self.type_kind(dest_typ) { TypeKind::Float => "tisf", @@ -781,6 +799,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { return self.context.new_cast(None, value, dest_typ); } + debug_assert!(value_type.dyncast_array().is_some()); let name_suffix = match self.type_kind(value_type) { TypeKind::Float => "sfti", diff --git a/src/lib.rs b/src/lib.rs index fd4af984bc039..fb60d7713324b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,8 @@ extern crate rustc_errors; extern crate rustc_fluent_macro; extern crate rustc_fs_util; extern crate rustc_hir; +#[cfg(feature="master")] +extern crate rustc_interface; extern crate rustc_macros; extern crate rustc_metadata; extern crate rustc_middle; @@ -86,7 +88,7 @@ use std::sync::atomic::Ordering; use gccjit::{Context, OptimizationLevel}; #[cfg(feature="master")] -use gccjit::TargetInfo; +use gccjit::{TargetInfo, Version}; #[cfg(not(feature="master"))] use gccjit::CType; use errors::LTONotSupported; @@ -244,17 +246,33 @@ impl CodegenBackend for GccCodegenBackend { } } +fn new_context<'gcc, 'tcx>(tcx: &TyCtxt<'tcx>) -> Context<'gcc> { + let context = Context::default(); + if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" { + context.add_command_line_option("-masm=intel"); + } + #[cfg(feature="master")] + { + let version = Version::get(); + let version = format!("{}.{}.{}", version.major, version.minor, version.patch); + context.set_output_ident(&format!("rustc version {} with libgccjit {}", + rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), + version, + )); + } + // TODO(antoyo): check if this should only be added when using -Cforce-unwind-tables=n. + context.add_command_line_option("-fno-asynchronous-unwind-tables"); + context +} + impl ExtraBackendMethods for GccCodegenBackend { fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { - context: Context::default(), + context: new_context(&tcx), should_combine_object_files: false, temp_dir: None, }; - if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" { - mods.context.add_command_line_option("-masm=intel"); - } unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } mods } From 456754c21a4a9e8889ac4c4ca645b5861febe1b8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 19 Nov 2023 13:51:56 -0500 Subject: [PATCH 002/192] Pass TyCtxt by value --- src/base.rs | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/base.rs b/src/base.rs index 3ffdab8b16cab..b0788718da4d1 100644 --- a/src/base.rs +++ b/src/base.rs @@ -88,7 +88,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); // Instantiate monomorphizations without filling out definitions yet... - let context = new_context(&tcx); + let context = new_context(tcx); if tcx.sess.panic_strategy() == PanicStrategy::Unwind { context.add_command_line_option("-fexceptions"); diff --git a/src/lib.rs b/src/lib.rs index fb60d7713324b..8c7bae0c8866d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -246,7 +246,7 @@ impl CodegenBackend for GccCodegenBackend { } } -fn new_context<'gcc, 'tcx>(tcx: &TyCtxt<'tcx>) -> Context<'gcc> { +fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { let context = Context::default(); if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" { context.add_command_line_option("-masm=intel"); @@ -268,7 +268,7 @@ fn new_context<'gcc, 'tcx>(tcx: &TyCtxt<'tcx>) -> Context<'gcc> { impl ExtraBackendMethods for GccCodegenBackend { fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { - context: new_context(&tcx), + context: new_context(tcx), should_combine_object_files: false, temp_dir: None, }; From a412e9c411ff13aaea0c88aeee0ad55690f2e2ce Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 22 Nov 2023 07:40:14 -0500 Subject: [PATCH 003/192] Update README --- Readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Readme.md b/Readme.md index 95fc6374c09ae..20871ceb814c3 100644 --- a/Readme.md +++ b/Readme.md @@ -295,6 +295,9 @@ git pull origin master git checkout -b subtree-update_cg_gcc_YYYY-MM-DD PATH="$HOME/bin:$PATH" ~/bin/git-subtree pull --prefix=compiler/rustc_codegen_gcc/ https://github.com/rust-lang/rustc_codegen_gcc.git master git push + +# Immediately merge the merge commit into cg_gcc to prevent merge conflicts when syncing from rust-lang/rust later. +PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name ``` TODO: write a script that does the above. From 4de5d372aab05f2c893ef83d08884e1ccfa72475 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Nov 2023 09:22:39 +1100 Subject: [PATCH 004/192] Avoid need for `{D,Subd}iagnosticMessage` imports. The `fluent_messages!` macro produces uses of `crate::{D,Subd}iagnosticMessage`, which means that every crate using the macro must have this import: ``` use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; ``` This commit changes the macro to instead use `rustc_errors::{D,Subd}iagnosticMessage`, which avoids the need for the imports. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 8c7bae0c8866d..dcf7a4124c279 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,7 @@ use rustc_codegen_ssa::target_features::supported_target_features; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; -use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; +use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; From 8e13be084a316883b4aadabbc9ff08aaaf676aa6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Nov 2023 09:53:07 +1100 Subject: [PATCH 005/192] Use `rustc_fluent_macro::fluent_messages!` directly. Currently we always do this: ``` use rustc_fluent_macro::fluent_messages; ... fluent_messages! { "./example.ftl" } ``` But there is no need, we can just do this everywhere: ``` rustc_fluent_macro::fluent_messages! { "./example.ftl" } ``` which is shorter. --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dcf7a4124c279..d54057615d2d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,7 +102,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_errors::{ErrorGuaranteed, Handler}; -use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::util::Providers; @@ -116,7 +115,7 @@ use tempfile::TempDir; use crate::back::lto::ModuleBuffer; use crate::gcc_util::target_cpu; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub struct PrintOnPanic String>(pub F); From cc7c9bea1546f9dc07b39feab2d1af776804ee84 Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Sat, 7 Oct 2023 23:59:58 -0500 Subject: [PATCH 006/192] implement simd_bswap intrinsic Implements lane-local byte swapping through vector shuffles. While this is more setup than non-vector shuffles, this implementation can shuffle multiple integers concurrently. Signed-off-by: Andy Sadler --- src/intrinsic/simd.rs | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 85d3e7234a0e6..3356d6f4a4b89 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -1,3 +1,5 @@ +use std::iter::FromIterator; + use gccjit::ToRValue; use gccjit::{BinaryOp, RValue, Type}; #[cfg(feature = "master")] @@ -156,6 +158,58 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(compare_simd_types(bx, arg1, arg2, in_elem, llret_ty, cmp_op)); } + if name == sym::simd_bswap { + let vector = args[0].immediate(); + let ret = match in_elem.kind() { + ty::Int(i) if i.bit_width() == Some(8) => vector, + ty::Uint(i) if i.bit_width() == Some(8) => vector, + ty::Int(_) | ty::Uint(_) => { + let v_type = vector.get_type(); + let vector_type = v_type.unqualified().dyncast_vector().expect("vector type"); + let elem_type = vector_type.get_element_type(); + let elem_size_bytes = elem_type.get_size(); + let type_size_bytes = elem_size_bytes as u64 * in_len; + + let shuffle_indices = Vec::from_iter(0..type_size_bytes); + let byte_vector_type = bx.context.new_vector_type(bx.type_u8(), type_size_bytes); + let byte_vector = bx.context.new_bitcast(None, args[0].immediate(), byte_vector_type); + + #[cfg(not(feature = "master"))] + let shuffled = { + let new_elements: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) + .flat_map(|x| x.iter().rev()) + .map(|&i| { + let index = bx.context.new_rvalue_from_long(bx.u64_type, i as _); + bx.extract_element(byte_vector, index) + }) + .collect(); + + bx.context.new_rvalue_from_vector(None, byte_vector_type, &new_elements) + }; + #[cfg(feature = "master")] + let shuffled = { + let indices: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) + .flat_map(|x| x.iter().rev()) + .map(|&i| bx.context.new_rvalue_from_int(bx.u8_type, i as _)) + .collect(); + + let mask = bx.context.new_rvalue_from_vector(None, byte_vector_type, &indices); + bx.context.new_rvalue_vector_perm(None, byte_vector, byte_vector, mask) + }; + bx.context.new_bitcast(None, shuffled, v_type) + } + _ => { + return_error!(InvalidMonomorphization::UnsupportedOperation { + span, + name, + in_ty, + in_elem, + }); + } + }; + return Ok(ret); + } + if name == sym::simd_shuffle { // Make sure this is actually an array, since typeck only checks the length-suffixed // version of this intrinsic. From 6d13f949ee67dbed3ee9a1da5533d3a55c03e774 Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Thu, 9 Nov 2023 19:49:06 -0600 Subject: [PATCH 007/192] remove generic-bswap-byte from failing test list Signed-off-by: Andy Sadler --- failing-ui-tests.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/failing-ui-tests.txt b/failing-ui-tests.txt index 22044eabe9697..4b2c3f64a176f 100644 --- a/failing-ui-tests.txt +++ b/failing-ui-tests.txt @@ -57,7 +57,6 @@ tests/ui/coroutine/panic-safe.rs tests/ui/issues/issue-14875.rs tests/ui/issues/issue-29948.rs tests/ui/panics/nested_panic_caught.rs -tests/ui/simd/intrinsic/generic-bswap-byte.rs tests/ui/const_prop/ice-issue-111353.rs tests/ui/process/println-with-broken-pipe.rs tests/ui/panic-runtime/lto-abort.rs From 70586a23a7fbe5b78752438587db86678f53ee2f Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Sun, 8 Oct 2023 00:13:10 -0500 Subject: [PATCH 008/192] fix simd_frem intrinsic implementation The simd intrinsic handler was delegating implementation of `simd_frem` to `Builder::frem`, which wasn't able to handle vector-typed inputs. To fix this, teach this method how to handle vector inputs. Signed-off-by: Andy Sadler --- src/builder.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index b8a8c144dc90b..4ae56a41e529a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -606,12 +606,29 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // ../../../gcc/gcc/cfgexpand.cc:6069 // 0x7f0101bf9194 execute // ../../../gcc/gcc/cfgexpand.cc:6795 - if a.get_type().is_compatible_with(self.cx.float_type) { + let a_type = a.get_type(); + let a_type_unqualified = a_type.unqualified(); + if a_type.is_compatible_with(self.cx.float_type) { let fmodf = self.context.get_builtin_function("fmodf"); // FIXME(antoyo): this seems to produce the wrong result. return self.context.new_call(None, fmodf, &[a, b]); } - assert_eq!(a.get_type().unqualified(), self.cx.double_type); + else if let Some(vector_type) = a_type_unqualified.dyncast_vector() { + assert_eq!(a_type_unqualified, b.get_type().unqualified()); + + let num_units = vector_type.get_num_units(); + let new_elements: Vec<_> = (0..num_units) + .map(|i| { + let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _); + let x = self.extract_element(a, index).to_rvalue(); + let y = self.extract_element(b, index).to_rvalue(); + self.frem(x, y) + }) + .collect(); + + return self.context.new_rvalue_from_vector(None, a_type, &new_elements) + } + assert_eq!(a_type_unqualified, self.cx.double_type); let fmod = self.context.get_builtin_function("fmod"); return self.context.new_call(None, fmod, &[a, b]); From 8d42a82b6e86b30e9a18cd12e2a89fd7b261bdd3 Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Sun, 8 Oct 2023 18:49:16 -0500 Subject: [PATCH 009/192] impl simd_bitreverse intrinsic If we're running against a patched libgccjit, use an algorithm similar to what LLVM uses for this intrinsic. Otherwise, fallback to a per-element bitreverse. Signed-off-by: Andy Sadler --- src/intrinsic/simd.rs | 213 +++++++++++++++++++++++++++++++++--------- 1 file changed, 168 insertions(+), 45 deletions(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 3356d6f4a4b89..2469e8d4c62ee 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -23,6 +23,8 @@ use rustc_target::abi::Align; use crate::builder::Builder; #[cfg(feature = "master")] use crate::context::CodegenCx; +#[cfg(not(feature = "master"))] +use crate::common::SignType; pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bx: &mut Builder<'a, 'gcc, 'tcx>, @@ -158,56 +160,177 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(compare_simd_types(bx, arg1, arg2, in_elem, llret_ty, cmp_op)); } + let simd_bswap = |bx: &mut Builder<'a, 'gcc, 'tcx>, vector: RValue<'gcc>| -> RValue<'gcc> { + let v_type = vector.get_type(); + let vector_type = v_type.unqualified().dyncast_vector().expect("vector type"); + let elem_type = vector_type.get_element_type(); + let elem_size_bytes = elem_type.get_size(); + if elem_size_bytes == 1 { + return vector; + } + + let type_size_bytes = elem_size_bytes as u64 * in_len; + let shuffle_indices = Vec::from_iter(0..type_size_bytes); + let byte_vector_type = bx.context.new_vector_type(bx.type_u8(), type_size_bytes); + let byte_vector = bx.context.new_bitcast(None, args[0].immediate(), byte_vector_type); + + #[cfg(not(feature = "master"))] + let shuffled = { + let new_elements: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) + .flat_map(|x| x.iter().rev()) + .map(|&i| { + let index = bx.context.new_rvalue_from_long(bx.u64_type, i as _); + bx.extract_element(byte_vector, index) + }) + .collect(); + + bx.context.new_rvalue_from_vector(None, byte_vector_type, &new_elements) + }; + #[cfg(feature = "master")] + let shuffled = { + let indices: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) + .flat_map(|x| x.iter().rev()) + .map(|&i| bx.context.new_rvalue_from_int(bx.u8_type, i as _)) + .collect(); + + let mask = bx.context.new_rvalue_from_vector(None, byte_vector_type, &indices); + bx.context.new_rvalue_vector_perm(None, byte_vector, byte_vector, mask) + }; + bx.context.new_bitcast(None, shuffled, v_type) + }; + + if name == sym::simd_bswap || name == sym::simd_bitreverse { + require!( + bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, + InvalidMonomorphization::UnsupportedOperation { + span, + name, + in_ty, + in_elem, + } + ); + } + if name == sym::simd_bswap { - let vector = args[0].immediate(); - let ret = match in_elem.kind() { - ty::Int(i) if i.bit_width() == Some(8) => vector, - ty::Uint(i) if i.bit_width() == Some(8) => vector, - ty::Int(_) | ty::Uint(_) => { - let v_type = vector.get_type(); - let vector_type = v_type.unqualified().dyncast_vector().expect("vector type"); - let elem_type = vector_type.get_element_type(); - let elem_size_bytes = elem_type.get_size(); - let type_size_bytes = elem_size_bytes as u64 * in_len; - - let shuffle_indices = Vec::from_iter(0..type_size_bytes); - let byte_vector_type = bx.context.new_vector_type(bx.type_u8(), type_size_bytes); - let byte_vector = bx.context.new_bitcast(None, args[0].immediate(), byte_vector_type); - - #[cfg(not(feature = "master"))] - let shuffled = { - let new_elements: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) - .flat_map(|x| x.iter().rev()) - .map(|&i| { - let index = bx.context.new_rvalue_from_long(bx.u64_type, i as _); - bx.extract_element(byte_vector, index) - }) - .collect(); + return Ok(simd_bswap(bx, args[0].immediate())); + } - bx.context.new_rvalue_from_vector(None, byte_vector_type, &new_elements) - }; - #[cfg(feature = "master")] - let shuffled = { - let indices: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) - .flat_map(|x| x.iter().rev()) - .map(|&i| bx.context.new_rvalue_from_int(bx.u8_type, i as _)) - .collect(); - - let mask = bx.context.new_rvalue_from_vector(None, byte_vector_type, &indices); - bx.context.new_rvalue_vector_perm(None, byte_vector, byte_vector, mask) - }; - bx.context.new_bitcast(None, shuffled, v_type) + // We use a different algorithm from non-vector bitreverse to take advantage of most + // processors' vector shuffle units. It works like this: + // 1. Generate pre-reversed low and high nibbles as a vector. + // 2. Byte-swap the input. + // 3. Mask off the low and high nibbles of each byte in the byte-swapped input. + // 4. Shuffle the pre-reversed low and high-nibbles using the masked nibbles as a shuffle mask. + // 5. Combine the results of the shuffle back together and cast back to the original type. + #[cfg(feature = "master")] + if name == sym::simd_bitreverse { + let vector = args[0].immediate(); + let v_type = vector.get_type(); + let vector_type = v_type.unqualified().dyncast_vector().expect("vector type"); + let elem_type = vector_type.get_element_type(); + let elem_size_bytes = elem_type.get_size(); + + let type_size_bytes = elem_size_bytes as u64 * in_len; + // We need to ensure at least 16 entries in our vector type, since the pre-reversed vectors + // we generate below have 16 entries in them. `new_rvalue_vector_perm` requires the mask + // vector to be of the same length as the source vectors. + let byte_vector_type_size = type_size_bytes.max(16); + + let byte_vector_type = bx.context.new_vector_type(bx.u8_type, type_size_bytes); + let long_byte_vector_type = bx.context.new_vector_type(bx.u8_type, byte_vector_type_size); + + // Step 1: Generate pre-reversed low and high nibbles as a vector. + let zero_byte = bx.context.new_rvalue_zero(bx.u8_type); + let hi_nibble_elements: Vec<_> = (0u8..16) + .map(|x| bx.context.new_rvalue_from_int(bx.u8_type, x.reverse_bits() as _)) + .chain((16..byte_vector_type_size).map(|_| zero_byte)) + .collect(); + let hi_nibble = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &hi_nibble_elements); + + let lo_nibble_elements: Vec<_> = (0u8..16) + .map(|x| bx.context.new_rvalue_from_int(bx.u8_type, (x.reverse_bits() >> 4) as _)) + .chain((16..byte_vector_type_size).map(|_| zero_byte)) + .collect(); + let lo_nibble = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &lo_nibble_elements); + + let mask = bx.context.new_rvalue_from_vector( + None, + long_byte_vector_type, + &vec![bx.context.new_rvalue_from_int(bx.u8_type, 0x0f); byte_vector_type_size as _]); + + let four_vec = bx.context.new_rvalue_from_vector( + None, + long_byte_vector_type, + &vec![bx.context.new_rvalue_from_int(bx.u8_type, 4); byte_vector_type_size as _]); + + // Step 2: Byte-swap the input. + let swapped = simd_bswap(bx, args[0].immediate()); + let byte_vector = bx.context.new_bitcast(None, swapped, byte_vector_type); + + // We're going to need to extend the vector with zeros to make sure that the types are the + // same, since that's what new_rvalue_vector_perm expects. + let byte_vector = if byte_vector_type_size > type_size_bytes { + let mut byte_vector_elements = Vec::with_capacity(byte_vector_type_size as _); + for i in 0..type_size_bytes { + let idx = bx.context.new_rvalue_from_int(bx.u32_type, i as _); + let val = bx.extract_element(byte_vector, idx); + byte_vector_elements.push(val); } - _ => { - return_error!(InvalidMonomorphization::UnsupportedOperation { - span, - name, - in_ty, - in_elem, - }); + for _ in type_size_bytes..byte_vector_type_size { + byte_vector_elements.push(zero_byte); } + bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &byte_vector_elements) + } else { + bx.context.new_bitcast(None, byte_vector, long_byte_vector_type) }; - return Ok(ret); + + // Step 3: Mask off the low and high nibbles of each byte in the byte-swapped input. + let masked_hi = (byte_vector >> four_vec) & mask; + let masked_lo = byte_vector & mask; + + // Step 4: Shuffle the pre-reversed low and high-nibbles using the masked nibbles as a shuffle mask. + let hi = bx.context.new_rvalue_vector_perm(None, hi_nibble, hi_nibble, masked_lo); + let lo = bx.context.new_rvalue_vector_perm(None, lo_nibble, lo_nibble, masked_hi); + + // Step 5: Combine the results of the shuffle back together and cast back to the original type. + let result = hi | lo; + let cast_ty = bx.context.new_vector_type(elem_type, byte_vector_type_size / (elem_size_bytes as u64)); + + // we might need to truncate if sizeof(v_type) < sizeof(cast_type) + if type_size_bytes < byte_vector_type_size { + let cast_result = bx.context.new_bitcast(None, result, cast_ty); + let elems: Vec<_> = (0..in_len) + .map(|i| { + let idx = bx.context.new_rvalue_from_int(bx.u32_type, i as _); + bx.extract_element(cast_result, idx) + }) + .collect(); + return Ok(bx.context.new_rvalue_from_vector(None, v_type, &elems)) + } else { + // avoid the unnecessary truncation as an optimization. + return Ok(bx.context.new_bitcast(None, result, v_type)); + } + } + // since gcc doesn't have vector shuffle methods available in non-patched builds, fallback to + // component-wise bitreverses if they're not available. + #[cfg(not(feature = "master"))] + if name == sym::simd_bitreverse { + let vector = args[0].immediate(); + let vector_ty = vector.get_type(); + let vector_type = vector_ty.unqualified().dyncast_vector().expect("vector type"); + let num_elements = vector_type.get_num_units(); + + let elem_type = vector_type.get_element_type(); + let elem_size_bytes = elem_type.get_size(); + let num_type = elem_type.to_unsigned(bx.cx); + let new_elements: Vec<_> = (0..num_elements) + .map(|idx| { + let index = bx.context.new_rvalue_from_long(num_type, idx as _); + let extracted_value = bx.extract_element(vector, index).to_rvalue(); + bx.bit_reverse(elem_size_bytes as u64 * 8, extracted_value) + }) + .collect(); + return Ok(bx.context.new_rvalue_from_vector(None, vector_ty, &new_elements)); } if name == sym::simd_shuffle { From 03e11a214e9b6295bb06a53f849b117e75986cf6 Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Thu, 19 Oct 2023 20:01:22 -0500 Subject: [PATCH 010/192] impl simd_ctlz/simd_cttz intrinsic Signed-off-by: Andy Sadler --- src/intrinsic/simd.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 2469e8d4c62ee..5991f061c10cc 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -333,6 +333,22 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(bx.context.new_rvalue_from_vector(None, vector_ty, &new_elements)); } + if name == sym::simd_ctlz || name == sym::simd_cttz { + let vector = args[0].immediate(); + let elements: Vec<_> = (0..in_len) + .map(|i| { + let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64); + let value = bx.extract_element(vector, index).to_rvalue(); + if name == sym::simd_ctlz { + bx.count_leading_zeroes(value.get_type().get_size() as u64 * 8, value) + } else { + bx.count_trailing_zeroes(value.get_type().get_size() as u64 * 8, value) + } + }) + .collect(); + return Ok(bx.context.new_rvalue_from_vector(None, vector.get_type(), &elements)); + } + if name == sym::simd_shuffle { // Make sure this is actually an array, since typeck only checks the length-suffixed // version of this intrinsic. From 3a221320eb49bf464fd332c2be244ca3a783d1ac Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Thu, 9 Nov 2023 19:07:44 -0600 Subject: [PATCH 011/192] fix simd_neg implementation for ints gcc_not would panic upon encountering a vector type, which is not what we want here. Signed-off-by: Andy Sadler --- src/int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/int.rs b/src/int.rs index 9b9b3ea4f8704..b69e073c4d94d 100644 --- a/src/int.rs +++ b/src/int.rs @@ -48,7 +48,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); - if self.is_native_int_type(a_type) { + if self.is_native_int_type(a_type) || a_type.is_vector() { self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) } else { From 17b2c46c8896adf07ae8f70b0d8b70227b5f4c71 Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Thu, 9 Nov 2023 19:49:34 -0600 Subject: [PATCH 012/192] remove generic-arithmetic-pass from failing tests This test now passes when tested with a patched libgccjit. However, due to [some compiler bugs][1], we can't enable this for non-patched libgccjit yet. [1]: https://github.com/sadlerap/rustc_codegen_gcc/actions/runs/6820180639/job/18548672444#step:15:4375 Signed-off-by: Andy Sadler --- failing-ui-tests.txt | 1 - failing-ui-tests12.txt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/failing-ui-tests.txt b/failing-ui-tests.txt index 4b2c3f64a176f..023fe9d7e8311 100644 --- a/failing-ui-tests.txt +++ b/failing-ui-tests.txt @@ -13,7 +13,6 @@ tests/ui/sepcomp/sepcomp-extern.rs tests/ui/sepcomp/sepcomp-fns-backwards.rs tests/ui/sepcomp/sepcomp-fns.rs tests/ui/sepcomp/sepcomp-statics.rs -tests/ui/simd/intrinsic/generic-arithmetic-pass.rs tests/ui/asm/x86_64/may_unwind.rs tests/ui/backtrace.rs tests/ui/catch-unwind-bang.rs diff --git a/failing-ui-tests12.txt b/failing-ui-tests12.txt index 24ef7bb8d709e..fef259c53f490 100644 --- a/failing-ui-tests12.txt +++ b/failing-ui-tests12.txt @@ -9,6 +9,7 @@ tests/ui/packed/packed-struct-vec.rs tests/ui/packed/packed-tuple-struct-layout.rs tests/ui/simd/array-type.rs tests/ui/simd/intrinsic/float-minmax-pass.rs +tests/ui/simd/intrinsic/generic-arithmetic-pass.rs tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs tests/ui/simd/intrinsic/generic-as.rs tests/ui/simd/intrinsic/generic-cast-pass.rs From bb4d0be014957067ea1386948fc1d691fff64918 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 2 Dec 2023 16:28:28 +0100 Subject: [PATCH 013/192] Fix build instructions --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 20871ceb814c3..9db1dec103232 100644 --- a/Readme.md +++ b/Readme.md @@ -59,13 +59,13 @@ Then you can run commands like this: ```bash $ ./y.sh prepare # download and patch sysroot src and install hyperfine for benchmarking -$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./y.sh build --release +$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./y.sh build --release --features master ``` To run the tests: ```bash -$ ./test.sh --release +$ ./test.sh --release --features master ``` ## Usage From f9a228df48f24f6596aeac5373efe9ee78e7f037 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 08:43:18 +1100 Subject: [PATCH 014/192] Rename some arguments. `sess` is a terribly misleading name for a `Handler`! This confused me for a bit. --- src/errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 4bf3b71f503d6..5fc4b12d7e699 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -111,8 +111,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.set_span(span); }; From 04f32f2016495ec8aabf6ba00b47a5665811eae6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 13 Nov 2023 16:05:35 +0100 Subject: [PATCH 015/192] Allow rustfmt to run on `build_system` --- .rustfmt.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index c7ad93bafe36c..87f034950e3b2 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1 +1 @@ -disable_all_formatting = true +ignore = ["/src", "/tests"] From 7b76ac4eb74f3cf8e0d616b82f8135fd7fd7ccab Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Nov 2023 17:31:56 +0100 Subject: [PATCH 016/192] Rustify `test.sh` --- build_system/src/build.rs | 128 ++-- build_system/src/config.rs | 332 ++++++---- build_system/src/prepare.rs | 18 +- build_system/src/test.rs | 1141 ++++++++++++++++++++++++++++++++++- build_system/src/utils.rs | 104 +++- 5 files changed, 1518 insertions(+), 205 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index f1c3701a946ec..6390458d4fd03 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -1,7 +1,5 @@ -use crate::config::{set_config, ConfigInfo}; -use crate::utils::{ - get_gcc_path, run_command, run_command_with_output_and_env, walk_dir, -}; +use crate::config::ConfigInfo; +use crate::utils::{get_gcc_path, run_command, run_command_with_output_and_env, walk_dir}; use std::collections::HashMap; use std::ffi::OsStr; use std::fs; @@ -10,10 +8,9 @@ use std::path::Path; #[derive(Default)] struct BuildArg { codegen_release_channel: bool, - sysroot_release_channel: bool, - sysroot_panic_abort: bool, flags: Vec, gcc_path: String, + config_info: ConfigInfo, } impl BuildArg { @@ -29,13 +26,9 @@ impl BuildArg { while let Some(arg) = args.next() { match arg.as_str() { "--release" => build_arg.codegen_release_channel = true, - "--release-sysroot" => build_arg.sysroot_release_channel = true, "--no-default-features" => { build_arg.flags.push("--no-default-features".to_string()); } - "--sysroot-panic-abort" => { - build_arg.sysroot_panic_abort = true; - }, "--features" => { if let Some(arg) = args.next() { build_arg.flags.push("--features".to_string()); @@ -63,12 +56,14 @@ impl BuildArg { if args.next().is_some() { // Handled in config.rs. } else { - return Err( - "Expected a value after `--target`, found nothing".to_string() - ); + return Err("Expected a value after `--target`, found nothing".to_string()); + } + } + arg => { + if !build_arg.config_info.parse_argument(arg, &mut args)? { + return Err(format!("Unknown argument `{}`", arg)); } } - arg => return Err(format!("Unknown argument `{}`", arg)), } } Ok(Some(build_arg)) @@ -80,28 +75,26 @@ impl BuildArg { `build` command help: --release : Build codegen in release mode - --release-sysroot : Build sysroot in release mode - --sysroot-panic-abort : Build the sysroot without unwinding support. --no-default-features : Add `--no-default-features` flag - --features [arg] : Add a new feature [arg] - --target-triple [arg] : Set the target triple to [arg] - --help : Show this help -"# - ) + --features [arg] : Add a new feature [arg]"# + ); + ConfigInfo::show_usage(); + println!(" --help : Show this help"); } } -fn build_sysroot( - env: &mut HashMap, - args: &BuildArg, +fn build_sysroot_inner( + env: &HashMap, + sysroot_panic_abort: bool, + sysroot_release_channel: bool, config: &ConfigInfo, + start_dir: Option<&Path>, ) -> Result<(), String> { - std::env::set_current_dir("build_sysroot") - .map_err(|error| format!("Failed to go to `build_sysroot` directory: {:?}", error))?; + let start_dir = start_dir.unwrap_or_else(|| Path::new(".")); // Cleanup for previous run // Clean target dir except for build scripts and incremental cache let _ = walk_dir( - "target", + start_dir.join("target"), |dir: &Path| { for top in &["debug", "release"] { let _ = fs::remove_dir_all(dir.join(top).join("build")); @@ -138,23 +131,22 @@ fn build_sysroot( |_| Ok(()), ); - let _ = fs::remove_file("Cargo.lock"); - let _ = fs::remove_file("test_target/Cargo.lock"); - let _ = fs::remove_dir_all("sysroot"); + let _ = fs::remove_file(start_dir.join("Cargo.lock")); + let _ = fs::remove_file(start_dir.join("test_target/Cargo.lock")); + let _ = fs::remove_dir_all(start_dir.join("sysroot")); // Builds libs - let mut rustflags = env - .get("RUSTFLAGS") - .cloned() - .unwrap_or_default(); - if args.sysroot_panic_abort { + let mut rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default(); + if sysroot_panic_abort { rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests"); } - env.insert( - "RUSTFLAGS".to_string(), - format!("{} -Zmir-opt-level=3", rustflags), - ); - let channel = if args.sysroot_release_channel { + rustflags.push_str(" -Z force-unstable-if-unmarked"); + let channel = if sysroot_release_channel { + let mut env = env.clone(); + env.insert( + "RUSTFLAGS".to_string(), + format!("{} -Zmir-opt-level=3", rustflags), + ); run_command_with_output_and_env( &[ &"cargo", @@ -163,33 +155,34 @@ fn build_sysroot( &config.target, &"--release", ], - None, + Some(start_dir), Some(&env), )?; "release" } else { run_command_with_output_and_env( - &[ - &"cargo", - &"build", - &"--target", - &config.target, - ], - None, + &[&"cargo", &"build", &"--target", &config.target], + Some(start_dir), Some(env), )?; "debug" }; // Copy files to sysroot - let sysroot_path = format!("sysroot/lib/rustlib/{}/lib/", config.target_triple); - fs::create_dir_all(&sysroot_path) - .map_err(|error| format!("Failed to create directory `{}`: {:?}", sysroot_path, error))?; + let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple)); + fs::create_dir_all(&sysroot_path).map_err(|error| { + format!( + "Failed to create directory `{}`: {:?}", + sysroot_path.display(), + error + ) + })?; let copier = |dir_to_copy: &Path| { + // FIXME: should not use shell command! run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ()) }; walk_dir( - &format!("target/{}/{}/deps", config.target_triple, channel), + start_dir.join(&format!("target/{}/{}/deps", config.target_triple, channel)), copier, copier, )?; @@ -203,7 +196,22 @@ fn build_sysroot( Ok(()) } -fn build_codegen(args: &BuildArg) -> Result<(), String> { +pub fn build_sysroot( + env: &HashMap, + sysroot_panic_abort: bool, + sysroot_release_channel: bool, + config: &ConfigInfo, +) -> Result<(), String> { + build_sysroot_inner( + env, + sysroot_panic_abort, + sysroot_release_channel, + config, + Some(Path::new("build_sysroot")), + ) +} + +fn build_codegen(args: &mut BuildArg) -> Result<(), String> { let mut env = HashMap::new(); env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone()); @@ -223,7 +231,8 @@ fn build_codegen(args: &BuildArg) -> Result<(), String> { } run_command_with_output_and_env(&command, None, Some(&env))?; - let config = set_config(&mut env, &[], Some(&args.gcc_path))?; + args.config_info + .setup(&mut env, &[], Some(&args.gcc_path))?; // We voluntarily ignore the error. let _ = fs::remove_dir_all("target/out"); @@ -237,18 +246,19 @@ fn build_codegen(args: &BuildArg) -> Result<(), String> { println!("[BUILD] sysroot"); build_sysroot( - &mut env, - args, - &config, + &env, + args.config_info.sysroot_panic_abort, + args.config_info.sysroot_release_channel, + &args.config_info, )?; Ok(()) } pub fn run() -> Result<(), String> { - let args = match BuildArg::new()? { + let mut args = match BuildArg::new()? { Some(args) => args, None => return Ok(()), }; - build_codegen(&args)?; + build_codegen(&mut args)?; Ok(()) } diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 64d9bd73e01a3..763cac8edb66b 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -1,149 +1,229 @@ -use crate::utils::{get_gcc_path, get_os_name, get_rustc_host_triple}; +use crate::utils::{get_gcc_path, get_os_name, rustc_version_info, split_args}; use std::collections::HashMap; use std::env as std_env; +#[derive(Default)] pub struct ConfigInfo { pub target: String, pub target_triple: String, + pub host_triple: String, pub rustc_command: Vec, + pub run_in_vm: bool, + pub cargo_target_dir: String, + pub dylib_ext: String, + pub sysroot_release_channel: bool, + pub sysroot_panic_abort: bool, } -// Returns the beginning for the command line of rustc. -pub fn set_config( - env: &mut HashMap, - test_flags: &[String], - gcc_path: Option<&str>, -) -> Result { - env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string()); - - let gcc_path = match gcc_path { - Some(path) => path.to_string(), - None => get_gcc_path()?, - }; - env.insert("GCC_PATH".to_string(), gcc_path.clone()); - - let os_name = get_os_name()?; - let dylib_ext = match os_name.as_str() { - "Linux" => "so", - "Darwin" => "dylib", - os => return Err(format!("unsupported OS `{}`", os)), - }; - let host_triple = get_rustc_host_triple()?; - let mut linker = None; - let mut target_triple = host_triple.clone(); - let mut target = target_triple.clone(); - - // We skip binary name and the command. - let mut args = std::env::args().skip(2); - - let mut set_target_triple = false; - let mut set_target = false; - while let Some(arg) = args.next() { - match arg.as_str() { - "--target-triple" => { - if let Some(arg) = args.next() { - target_triple = arg; - set_target_triple = true; - } else { +impl ConfigInfo { + /// Returns `true` if the argument was taken into account. + pub fn parse_argument( + &mut self, + arg: &str, + args: &mut impl Iterator, + ) -> Result { + match arg { + "--target-triple" => match args.next() { + Some(arg) if !arg.is_empty() => self.target_triple = arg.to_string(), + _ => { return Err( "Expected a value after `--target-triple`, found nothing".to_string() - ); + ) } }, - "--target" => { - if let Some(arg) = args.next() { - target = arg; - set_target = true; - } else { - return Err( - "Expected a value after `--target`, found nothing".to_string() - ); + "--target" => match args.next() { + Some(arg) if !arg.is_empty() => self.target = arg.to_string(), + _ => return Err("Expected a value after `--target`, found nothing".to_string()), + }, + "--out-dir" => match args.next() { + Some(arg) if !arg.is_empty() => { + // env.insert("CARGO_TARGET_DIR".to_string(), arg.to_string()); + self.cargo_target_dir = arg.to_string(); } + _ => return Err("Expected a value after `--out-dir`, found nothing".to_string()), }, - _ => (), + "--release-sysroot" => self.sysroot_release_channel = true, + "--sysroot-panic-abort" => self.sysroot_panic_abort = true, + _ => return Ok(false), } + Ok(true) } - if set_target_triple && !set_target { - target = target_triple.clone(); - } + pub fn setup( + &mut self, + env: &mut HashMap, + test_flags: &[String], + gcc_path: Option<&str>, + ) -> Result<(), String> { + env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string()); - if host_triple != target_triple { - linker = Some(format!("-Clinker={}-gcc", target_triple)); - } - let current_dir = - std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?; - let channel = if let Some(channel) = env.get("CHANNEL") { - channel.as_str() - } else { - "debug" - }; - let cg_backend_path = current_dir - .join("target") - .join(channel) - .join(&format!("librustc_codegen_gcc.{}", dylib_ext)); - let sysroot_path = current_dir.join("build_sysroot/sysroot"); - let mut rustflags = Vec::new(); - if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { - rustflags.push(cg_rustflags.clone()); - } - if let Some(linker) = linker { - rustflags.push(linker.to_string()); - } - rustflags.extend_from_slice(&[ - "-Csymbol-mangling-version=v0".to_string(), - "-Cdebuginfo=2".to_string(), - format!("-Zcodegen-backend={}", cg_backend_path.display()), - "--sysroot".to_string(), - sysroot_path.display().to_string(), - ]); - - // Since we don't support ThinLTO, disable LTO completely when not trying to do LTO. - // TODO(antoyo): remove when we can handle ThinLTO. - if !env.contains_key(&"FAT_LTO".to_string()) { - rustflags.push("-Clto=off".to_string()); - } - rustflags.extend_from_slice(test_flags); - // FIXME(antoyo): remove once the atomic shim is gone - if os_name == "Darwin" { + let gcc_path = match gcc_path { + Some(path) => path.to_string(), + None => get_gcc_path()?, + }; + env.insert("GCC_PATH".to_string(), gcc_path.clone()); + + if self.cargo_target_dir.is_empty() { + match env.get("CARGO_TARGET_DIR").filter(|dir| !dir.is_empty()) { + Some(cargo_target_dir) => self.cargo_target_dir = cargo_target_dir.clone(), + None => self.cargo_target_dir = "target/out".to_string(), + } + } + + let os_name = get_os_name()?; + self.dylib_ext = match os_name.as_str() { + "Linux" => "so", + "Darwin" => "dylib", + os => return Err(format!("unsupported OS `{}`", os)), + } + .to_string(); + let rustc = match env.get("RUSTC") { + Some(r) if !r.is_empty() => r.to_string(), + _ => "rustc".to_string(), + }; + self.host_triple = rustc_version_info(Some(&rustc))?.host.unwrap_or_default(); + + if !self.target_triple.is_empty() && self.target.is_empty() { + self.target = self.target_triple.clone(); + } + if self.target.is_empty() { + self.target = self.host_triple.clone(); + } + if self.target_triple.is_empty() { + self.target_triple = self.host_triple.clone(); + } + + let mut linker = None; + + if self.host_triple != self.target_triple { + if self.target_triple == "m68k-unknown-linux-gnu" { + linker = Some("-Clinker=m68k-unknown-linux-gnu-gcc".to_string()); + } else if self.target_triple == "aarch64-unknown-linux-gnu" { + // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + linker = Some("-Clinker=aarch64-linux-gnu-gcc".to_string()); + } else { + return Err("Unknown non-native platform".to_string()); + } + + self.run_in_vm = true; + } + + let current_dir = + std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?; + let channel = if let Some(channel) = env.get("CHANNEL") { + channel.as_str() + } else { + "debug" + }; + + let has_builtin_backend = env + .get("BUILTIN_BACKEND") + .map(|backend| !backend.is_empty()) + .unwrap_or(false); + let cg_backend_path; + + let mut rustflags = Vec::new(); + if has_builtin_backend { + // It means we're building inside the rustc testsuite, so some options need to be handled + // a bit differently. + cg_backend_path = "gcc".to_string(); + + match env.get("RUSTC_SYSROOT") { + Some(rustc_sysroot) if !rustc_sysroot.is_empty() => { + rustflags.extend_from_slice(&["--sysroot".to_string(), rustc_sysroot.clone()]); + } + _ => {} + } + rustflags.push("-Cpanic=abort".to_string()); + } else { + cg_backend_path = current_dir + .join("target") + .join(channel) + .join(&format!("librustc_codegen_gcc.{}", self.dylib_ext)) + .display() + .to_string(); + let sysroot_path = current_dir.join("build_sysroot/sysroot"); + rustflags + .extend_from_slice(&["--sysroot".to_string(), sysroot_path.display().to_string()]); + }; + + if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { + rustflags.extend_from_slice(&split_args(&cg_rustflags)); + } + if let Some(linker) = linker { + rustflags.push(linker.to_string()); + } rustflags.extend_from_slice(&[ - "-Clink-arg=-undefined".to_string(), - "-Clink-arg=dynamic_lookup".to_string(), + "-Csymbol-mangling-version=v0".to_string(), + "-Cdebuginfo=2".to_string(), + format!("-Zcodegen-backend={}", cg_backend_path), ]); + + // Since we don't support ThinLTO, disable LTO completely when not trying to do LTO. + // TODO(antoyo): remove when we can handle ThinLTO. + if !env.contains_key(&"FAT_LTO".to_string()) { + rustflags.push("-Clto=off".to_string()); + } + rustflags.extend_from_slice(test_flags); + // FIXME(antoyo): remove once the atomic shim is gone + if os_name == "Darwin" { + rustflags.extend_from_slice(&[ + "-Clink-arg=-undefined".to_string(), + "-Clink-arg=dynamic_lookup".to_string(), + ]); + } + env.insert("RUSTFLAGS".to_string(), rustflags.join(" ")); + // display metadata load errors + env.insert("RUSTC_LOG".to_string(), "warn".to_string()); + + let sysroot = current_dir.join(&format!( + "build_sysroot/sysroot/lib/rustlib/{}/lib", + self.target_triple, + )); + let ld_library_path = format!( + "{target}:{sysroot}:{gcc_path}", + target = current_dir.join("target/out").display(), + sysroot = sysroot.display(), + ); + env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone()); + env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path); + + // NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc. + // To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH. + // Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc + let path = std::env::var("PATH").unwrap_or_default(); + env.insert( + "PATH".to_string(), + format!( + "/opt/gcc/bin:/opt/m68k-unknown-linux-gnu/bin{}{}", + if path.is_empty() { "" } else { ":" }, + path + ), + ); + + self.rustc_command = vec![rustc]; + self.rustc_command.extend_from_slice(&rustflags); + self.rustc_command.extend_from_slice(&[ + "-L".to_string(), + "crate=target/out".to_string(), + "--out-dir".to_string(), + self.cargo_target_dir.clone(), + ]); + + if !env.contains_key("RUSTC_LOG") { + env.insert("RUSTC_LOG".to_string(), "warn".to_string()); + } + Ok(()) + } + + pub fn show_usage() { + println!( + "\ + --target [arg] : Set the target to [arg] + --target-triple [arg] : Set the target triple to [arg] + --out-dir : Location where the files will be generated + --release-sysroot : Build sysroot in release mode + --sysroot-panic-abort : Build the sysroot without unwinding support." + ); } - env.insert("RUSTFLAGS".to_string(), rustflags.join(" ")); - // display metadata load errors - env.insert("RUSTC_LOG".to_string(), "warn".to_string()); - - let sysroot = current_dir.join(&format!( - "build_sysroot/sysroot/lib/rustlib/{}/lib", - target_triple - )); - let ld_library_path = format!( - "{target}:{sysroot}:{gcc_path}", - target = current_dir.join("target/out").display(), - sysroot = sysroot.display(), - ); - env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone()); - env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path); - - // NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc. - // To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH. - // Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc - let path = std::env::var("PATH").unwrap_or_default(); - env.insert("PATH".to_string(), format!("/opt/gcc/bin:{}", path)); - - let mut rustc_command = vec!["rustc".to_string()]; - rustc_command.extend_from_slice(&rustflags); - rustc_command.extend_from_slice(&[ - "-L".to_string(), - "crate=target/out".to_string(), - "--out-dir".to_string(), - "target/out".to_string(), - ]); - Ok(ConfigInfo { - target, - target_triple, - rustc_command, - }) } diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index 6c7c858683456..da9f8953ec3cb 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -4,7 +4,11 @@ use crate::utils::{cargo_install, git_clone, run_command, run_command_with_outpu use std::fs; use std::path::Path; -fn prepare_libcore(sysroot_path: &Path, libgccjit12_patches: bool, cross_compile: bool) -> Result<(), String> { +fn prepare_libcore( + sysroot_path: &Path, + libgccjit12_patches: bool, + cross_compile: bool, +) -> Result<(), String> { let rustc_path = match get_rustc_path() { Some(path) => path, None => return Err("`rustc` path not found".to_string()), @@ -88,10 +92,14 @@ fn prepare_libcore(sysroot_path: &Path, libgccjit12_patches: bool, cross_compile }, )?; if cross_compile { - walk_dir("cross_patches", |_| Ok(()), |file_path: &Path| { - patches.push(file_path.to_path_buf()); - Ok(()) - })?; + walk_dir( + "cross_patches", + |_| Ok(()), + |file_path: &Path| { + patches.push(file_path.to_path_buf()); + Ok(()) + }, + )?; } if libgccjit12_patches { walk_dir( diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 4c8c63e59ab7c..fb2b24da9a233 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -1,15 +1,1138 @@ -use crate::utils::run_command_with_output; +use crate::build; +use crate::config::ConfigInfo; +use crate::utils::{ + get_gcc_path, get_toolchain, run_command, run_command_with_env, + run_command_with_output_and_env, rustc_version_info, split_args, walk_dir, +}; -fn get_args<'a>(args: &mut Vec<&'a dyn AsRef>, extra_args: &'a Vec) { - for extra_arg in extra_args { - args.push(extra_arg); +use std::collections::{BTreeSet, HashMap}; +use std::ffi::OsStr; +use std::fs::remove_dir_all; +use std::path::{Path, PathBuf}; +use std::str::FromStr; + +type Env = HashMap; +type Runner = &'static dyn Fn(&Env, &TestArg) -> Result<(), String>; +type Runners = HashMap<&'static str, (&'static str, Runner)>; + +fn get_runners() -> Runners { + let mut runners = HashMap::new(); + + runners.insert( + "--test-rustc", + ("Run all rustc tests", &test_rustc as Runner), + ); + runners.insert( + "--test-successful-rustc", + ("Run successful rustc tests", &test_successful_rustc), + ); + runners.insert( + "--test-failing-rustc", + ("Run failing rustc tests", &test_failing_rustc), + ); + runners.insert("--test-libcore", ("Run libcore tests", &test_libcore)); + runners.insert("--clean-ui-tests", ("Clean ui tests", &clean_ui_tests)); + runners.insert("--clean", ("Empty cargo target directory", &clean)); + runners.insert("--std-tests", ("Run std tests", &std_tests)); + runners.insert("--asm-tests", ("Run asm tests", &asm_tests)); + runners.insert( + "--extended-tests", + ("Run extended sysroot tests", &extended_sysroot_tests), + ); + runners.insert( + "--extended-rand-tests", + ("Run extended rand tests", &extended_rand_tests), + ); + runners.insert( + "--extended-regex-example-tests", + ( + "Run extended regex example tests", + &extended_regex_example_tests, + ), + ); + runners.insert( + "--extended-regex-tests", + ("Run extended regex tests", &extended_regex_tests), + ); + runners.insert("--mini-tests", ("Run mini tests", &mini_tests)); + + runners +} + +fn get_number_after_arg( + args: &mut impl Iterator, + option: &str, +) -> Result { + match args.next() { + Some(nb) if !nb.is_empty() => match usize::from_str(&nb) { + Ok(nb) => Ok(nb), + Err(_) => Err(format!( + "Expected a number after `{}`, found `{}`", + option, nb + )), + }, + _ => Err(format!( + "Expected a number after `{}`, found nothing", + option + )), + } +} + +fn show_usage() { + println!( + r#" +`test` command help: + + --release : Build codegen in release mode + --release-sysroot : Build sysroot in release mode + --sysroot-panic-abort : Build the sysroot without unwinding support. + --no-default-features : Add `--no-default-features` flag + --features [arg] : Add a new feature [arg] + --use-system-gcc : Use system installed libgccjit + --build-only : Only build rustc_codegen_gcc then exits + --use-backend : Useful only for rustc testsuite + --nb-parts : Used to split rustc_tests (for CI needs) + --current-part : Used with `--nb-parts`, allows you to specify which parts to test"# + ); + ConfigInfo::show_usage(); + for (option, (doc, _)) in get_runners() { + let needed_spaces = 23_usize.saturating_sub(option.len()); + let spaces: String = std::iter::repeat(' ').take(needed_spaces).collect(); + println!(" {}{}: {}", option, spaces, doc); } + println!(" --help : Show this help"); +} + +#[derive(Default, PartialEq, Eq, Clone, Copy)] +enum Channel { + #[default] + Debug, + Release, +} + +impl Channel { + pub fn as_str(self) -> &'static str { + match self { + Self::Debug => "debug", + Self::Release => "release", + } + } +} + +#[derive(Default)] +struct TestArg { + no_default_features: bool, + build_only: bool, + gcc_path: String, + channel: Channel, + sysroot_channel: Channel, + use_backend: bool, + runners: BTreeSet, + flags: Vec, + backend: Option, + nb_parts: Option, + current_part: Option, + sysroot_panic_abort: bool, + config_info: ConfigInfo, +} + +impl TestArg { + fn new() -> Result, String> { + let mut use_system_gcc = false; + let mut test_arg = Self::default(); + + // We skip binary name and the `test` command. + let mut args = std::env::args().skip(2); + let runners = get_runners(); + + while let Some(arg) = args.next() { + match arg.as_str() { + "--release" => test_arg.channel = Channel::Release, + "--release-sysroot" => test_arg.sysroot_channel = Channel::Release, + "--no-default-features" => { + // To prevent adding it more than once. + if !test_arg.no_default_features { + test_arg.flags.push("--no-default-features".into()); + } + test_arg.no_default_features = true; + } + "--features" => match args.next() { + Some(feature) if !feature.is_empty() => { + test_arg + .flags + .extend_from_slice(&["--features".into(), feature]); + } + _ => { + return Err("Expected an argument after `--features`, found nothing".into()) + } + }, + "--use-system-gcc" => use_system_gcc = true, + "--build-only" => test_arg.build_only = true, + "--use-backend" => match args.next() { + Some(backend) if !backend.is_empty() => test_arg.backend = Some(backend), + _ => { + return Err( + "Expected an argument after `--use-backend`, found nothing".into() + ) + } + }, + "--nb-parts" => { + test_arg.nb_parts = Some(get_number_after_arg(&mut args, "--nb-parts")?); + } + "--current-part" => { + test_arg.current_part = + Some(get_number_after_arg(&mut args, "--current-part")?); + } + "--sysroot-panic-abort" => { + test_arg.sysroot_panic_abort = true; + } + "--help" => { + show_usage(); + return Ok(None); + } + x if runners.contains_key(x) => { + test_arg.runners.insert(x.into()); + } + arg => { + if !test_arg.config_info.parse_argument(arg, &mut args)? { + return Err(format!("Unknown option {}", arg)); + } + } + } + + test_arg.gcc_path = if use_system_gcc { + println!("Using system GCC"); + "gcc".to_string() + } else { + get_gcc_path()? + }; + } + Ok(Some(test_arg)) + } +} + +fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> { + if args.use_backend { + return Ok(()); + } + let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; + if args.channel == Channel::Release { + let mut env = env.clone(); + env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string()); + command.push(&"--release"); + for flag in args.flags.iter() { + command.push(flag); + } + run_command_with_output_and_env(&command, None, Some(&env)) + } else { + for flag in args.flags.iter() { + command.push(flag); + } + run_command_with_output_and_env(&command, None, Some(&env)) + } +} + +fn clean(_env: &Env, args: &TestArg) -> Result<(), String> { + let _ = std::fs::remove_dir_all(&args.config_info.cargo_target_dir); + let path = Path::new(&args.config_info.cargo_target_dir).join("gccjit"); + std::fs::create_dir_all(&path) + .map_err(|error| format!("failed to create folder `{}`: {:?}", path.display(), error)) +} + +fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> { + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[BUILD] mini_core"); + let crate_types = if args.config_info.host_triple != args.config_info.target_triple { + "lib" + } else { + "lib,dylib" + } + .to_string(); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/mini_core.rs", + &"--crate-name", + &"mini_core", + &"--crate-type", + &crate_types, + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_output_and_env(&command, None, Some(&env))?; + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[BUILD] example"); + command.clear(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/example.rs", + &"--crate-type", + &"lib", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_output_and_env(&command, None, Some(&env))?; + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] mini_core_hello_world"); + command.clear(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/mini_core_hello_world.rs", + &"--crate-name", + &"mini_core_hello_world", + &"--crate-type", + &"bin", + &"-g", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_output_and_env(&command, None, Some(&env))?; + + let command: &[&dyn AsRef] = &[ + &Path::new(&args.config_info.cargo_target_dir).join("mini_core_hello_world"), + &"abc", + &"bcd", + ]; + run_command_in_vm(&command, env, args)?; + Ok(()) +} + +fn build_sysroot(env: &Env, args: &TestArg) -> Result<(), String> { + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[BUILD] sysroot"); + build::build_sysroot( + env, + args.config_info.sysroot_panic_abort, + args.config_info.sysroot_release_channel, + &args.config_info, + )?; + Ok(()) +} + +// TODO(GuillaumeGomez): when rewriting in Rust, refactor with the code in tests/lang_tests_common.rs if possible. +fn run_command_in_vm( + command: &[&dyn AsRef], + env: &Env, + args: &TestArg, +) -> Result<(), String> { + if !args.config_info.run_in_vm { + run_command_with_env(command, None, Some(env))?; + return Ok(()); + } + let vm_parent_dir = match env.get("CG_GCC_VM_DIR") { + Some(dir) if !dir.is_empty() => PathBuf::from(dir.clone()), + _ => std::env::current_dir().unwrap(), + }; + let vm_dir = "vm"; + let exe_to_run = command.first().unwrap(); + let exe = Path::new(&exe_to_run); + let exe_filename = exe.file_name().unwrap(); + let vm_home_dir = vm_parent_dir.join(vm_dir).join("home"); + let vm_exe_path = vm_home_dir.join(exe_filename); + let inside_vm_exe_path = Path::new("/home").join(exe_filename); + + let sudo_command: &[&dyn AsRef] = &[&"sudo", &"cp", &exe, &vm_exe_path]; + run_command_with_env(sudo_command, None, Some(env))?; + + let mut vm_command: Vec<&dyn AsRef> = + vec![&"sudo", &"chroot", &"qemu-m68k-static", &inside_vm_exe_path]; + vm_command.extend_from_slice(command); + run_command_with_env(&vm_command, Some(&vm_parent_dir), Some(env))?; + Ok(()) +} + +fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] arbitrary_self_types_pointers_and_wrappers"); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/arbitrary_self_types_pointers_and_wrappers.rs", + &"--crate-name", + &"arbitrary_self_types_pointers_and_wrappers", + &"--crate-type", + &"bin", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_env(&command, None, Some(env))?; + run_command_in_vm( + &[&Path::new(&args.config_info.cargo_target_dir) + .join("arbitrary_self_types_pointers_and_wrappers")], + env, + args, + )?; + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] alloc_system"); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/alloc_system.rs", + &"--crate-type", + &"lib", + &"--target", + &args.config_info.target_triple, + ]); + if !args.no_default_features { + command.push(&"--cfg feature=\"master\""); + } + run_command_with_env(&command, None, Some(env))?; + + // FIXME: doesn't work on m68k. + if args.config_info.host_triple != args.config_info.target_triple { + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] alloc_example"); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/alloc_example.rs", + &"--crate-type", + &"bin", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_env(&command, None, Some(env))?; + run_command_in_vm( + &[&Path::new(&args.config_info.cargo_target_dir).join("alloc_example")], + env, + args, + )?; + } + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] dst_field_align"); + // FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed. + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/dst-field-align.rs", + &"--crate-name", + &"dst_field_align", + &"--crate-type", + &"bin", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_env(&command, None, Some(env))?; + run_command_in_vm( + &[&Path::new(&args.config_info.cargo_target_dir).join("dst_field_align")], + env, + args, + )?; + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] std_example"); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/std_example.rs", + &"--crate-type", + &"bin", + &"--target", + &args.config_info.target_triple, + ]); + if !args.no_default_features { + command.push(&"--cfg feature=\"master\""); + } + run_command_with_env(&command, None, Some(env))?; + run_command_in_vm( + &[ + &Path::new(&args.config_info.cargo_target_dir).join("std_example"), + &"--target", + &args.config_info.target_triple, + ], + env, + args, + )?; + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] subslice-patterns-const-eval"); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/subslice-patterns-const-eval.rs", + &"--crate-type", + &"bin", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_env(&command, None, Some(env))?; + run_command_in_vm( + &[&Path::new(&args.config_info.cargo_target_dir).join("subslice-patterns-const-eval")], + env, + args, + )?; + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] track-caller-attribute"); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/track-caller-attribute.rs", + &"--crate-type", + &"bin", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_env(&command, None, Some(env))?; + run_command_in_vm( + &[&Path::new(&args.config_info.cargo_target_dir).join("track-caller-attribute")], + env, + args, + )?; + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[AOT] mod_bench"); + let mut command: Vec<&dyn AsRef> = Vec::new(); + for arg in args.config_info.rustc_command.iter() { + command.push(arg); + } + command.extend_from_slice(&[ + &"example/mod_bench.rs", + &"--crate-type", + &"bin", + &"--target", + &args.config_info.target_triple, + ]); + run_command_with_env(&command, None, Some(env))?; + // FIXME: the compiled binary is not run. Is it normal? + + Ok(()) +} + +fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { + let toolchain = get_toolchain()?; + + let rust_dir = Some(Path::new("rust")); + // If the repository was already cloned, command will fail, so doesn't matter. + let _ = run_command_with_output_and_env( + &[&"git", &"clone", &"https://github.com/rust-lang/rust.git"], + None, + Some(env), + ); + run_command_with_output_and_env(&[&"git", &"fetch"], rust_dir, Some(env))?; + let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash { + Some(commit_hash) => commit_hash, + None => return Err("Couldn't retrieve rustc commit hash".to_string()), + }; + run_command_with_output_and_env(&[&"git", &"checkout", &rustc_commit], rust_dir, Some(env))?; + env.insert("RUSTFLAGS".to_string(), String::new()); + let cargo = String::from_utf8( + run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, + ) + .map_err(|error| format!("Failed to retrieve cargo path: {:?}", error)) + .and_then(|cargo| { + let cargo = cargo.trim().to_owned(); + if cargo.is_empty() { + Err(format!("`cargo` path is empty")) + } else { + Ok(cargo) + } + })?; + let llvm_filecheck = String::from_utf8( + run_command_with_env( + &[ + &"bash", + &"-c", + &"which FileCheck-10 || \ + which FileCheck-11 || \ + which FileCheck-12 || \ + which FileCheck-13 || \ + which FileCheck-14", + ], + rust_dir, + Some(env), + )? + .stdout, + ) + .map_err(|error| format!("Failed to retrieve LLVM FileCheck: {:?}", error))?; + std::fs::write( + "rust/config.toml", + &format!( + r#"change-id = 115898 + +[rust] +codegen-backends = [] +deny-warnings = false +verbose-tests = true + +[build] +cargo = "{cargo}" +local-rebuild = true +rustc = "{home}/.rustup/toolchains/{toolchain}-{host_triple}/bin/rustc" + +[target.x86_64-unknown-linux-gnu] +llvm-filecheck = "{llvm_filecheck}" + +[llvm] +download-ci-llvm = false +"#, + cargo = cargo.trim(), + home = env.get("HOME").unwrap(), + toolchain = toolchain, + host_triple = args.config_info.host_triple, + llvm_filecheck = llvm_filecheck, + ), + ) + .map_err(|error| format!("Failed to write into `rust/config.toml`: {:?}", error))?; + + let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash { + Some(commit_hash) => commit_hash, + None => return Err("Couldn't retrieve rustc commit hash".to_string()), + }; + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("commit: {:?}", rustc_commit); + let command: &[&dyn AsRef] = &[&"git", &"checkout", &rustc_commit, &"tests"]; + run_command_with_output_and_env(command, rust_dir, Some(env))?; + Ok(()) +} + +fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { + let mut env = env.clone(); + setup_rustc(&mut env, args)?; + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[TEST] rustc asm test suite"); + + env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); + + run_command_with_env( + &[ + &"./x.py", + &"test", + &"--run", + &"always", + &"--stage", + &"0", + &"tests/assembly/asm", + &"--rustc-args", + &format!( + r#"-Zpanic-abort-tests -Csymbol-mangling-version=v0 \ + -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \ + --sysroot "{pwd}/build_sysroot/sysroot" -Cpanic=abort"#, + pwd = std::env::current_dir() + .map_err(|error| format!("`current_dir` failed: {:?}", error))? + .display(), + channel = args.channel.as_str(), + dylib_ext = args.config_info.dylib_ext, + ) + .as_str(), + ], + Some(Path::new("rust")), + Some(&env), + )?; + Ok(()) +} + +fn run_cargo_command( + command: &[&dyn AsRef], + cwd: Option<&Path>, + env: &Env, + args: &TestArg, +) -> Result<(), String> { + run_cargo_command_with_callback(command, cwd, env, args, |cargo_command, cwd, env| { + run_command_with_output_and_env(&cargo_command, cwd, Some(env))?; + Ok(()) + }) +} + +fn run_cargo_command_with_callback( + command: &[&dyn AsRef], + cwd: Option<&Path>, + env: &Env, + args: &TestArg, + callback: F, +) -> Result<(), String> +where + F: Fn(&[&dyn AsRef], Option<&Path>, &Env) -> Result<(), String>, +{ + let toolchain = get_toolchain()?; + let rustc_version = String::from_utf8( + run_command_with_env(&[&args.config_info.rustc_command[0], &"-V"], cwd, Some(env))?.stdout, + ) + .map_err(|error| format!("Failed to retrieve rustc version: {:?}", error))?; + let rustc_toolchain_version = String::from_utf8( + run_command_with_env( + &[ + &args.config_info.rustc_command[0], + &format!("+{}", toolchain), + &"-V", + ], + cwd, + Some(env), + )? + .stdout, + ) + .map_err(|error| format!("Failed to retrieve rustc +toolchain version: {:?}", error))?; + + if rustc_version != rustc_toolchain_version { + eprintln!( + "rustc_codegen_gcc is built for `{}` but the default rustc version is `{}`.", + rustc_toolchain_version, rustc_version, + ); + eprintln!("Using `{}`.", rustc_toolchain_version); + } + let mut cargo_command: Vec<&dyn AsRef> = vec![&"cargo", &toolchain]; + cargo_command.extend_from_slice(&command); + callback(&cargo_command, cwd, env) +} + +// FIXME(antoyo): linker gives multiple definitions error on Linux +// echo "[BUILD] sysroot in release mode" +// ./build_sysroot/build_sysroot.sh --release + +fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[TEST] libcore"); + let path = Path::new("build_sysroot/sysroot_src/library/core/tests"); + let _ = remove_dir_all(path.join("target")); + run_cargo_command(&[&"test"], Some(path), env, args)?; + Ok(()) +} + +// echo "[BENCH COMPILE] mod_bench" +// +// COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline" +// COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort" +// COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort" +// COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort" +// COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort" +// +// Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow +// hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3" +// echo "[BENCH RUN] mod_bench" +// hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_* + +fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { + if args.no_default_features { + return Ok(()); + } + let path = Path::new("rand"); + run_cargo_command(&[&"clean"], Some(path), env, args)?; + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[TEST] rust-random/rand"); + run_cargo_command(&[&"test", &"--workspace"], Some(path), env, args)?; + Ok(()) +} + +fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> { + if args.no_default_features { + return Ok(()); + } + let path = Path::new("regex"); + run_cargo_command(&[&"clean"], Some(path), env, args)?; + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[TEST] rust-lang/regex example shootout-regex-dna"); + let mut env = env.clone(); + // newer aho_corasick versions throw a deprecation warning + env.insert("CG_RUSTFLAGS".to_string(), "--cap-lints warn".to_string()); + // Make sure `[codegen mono items] start` doesn't poison the diff + run_cargo_command( + &[&"build", &"--example", &"shootout-regex-dna"], + Some(path), + &env, + args, + )?; + + run_cargo_command_with_callback( + &[&"run", &"--example", &"shootout-regex-dna"], + Some(path), + &env, + args, + |cargo_command, cwd, env| { + // FIXME: rewrite this with `child.stdin.write_all()` because + // `examples/regexdna-input.txt` is very small. + let mut command: Vec<&dyn AsRef> = vec![&"bash", &"-c"]; + let cargo_args = cargo_command + .iter() + .map(|s| s.as_ref().to_str().unwrap()) + .collect::>(); + let bash_command = format!( + "cat examples/regexdna-input.txt | {} | grep -v 'Spawned thread' > res.txt", + cargo_args.join(" "), + ); + command.push(&bash_command); + run_command_with_output_and_env(&command, cwd, Some(env))?; + run_command_with_output_and_env( + &[&"diff", &"-u", &"res.txt", &"examples/regexdna-output.txt"], + cwd, + Some(env), + )?; + Ok(()) + }, + )?; + + Ok(()) +} + +fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { + if args.no_default_features { + return Ok(()); + } + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[TEST] rust-lang/regex tests"); + let mut env = env.clone(); + env.insert("CG_RUSTFLAGS".to_string(), "--cap-lints warn".to_string()); + run_cargo_command( + &[ + &"test", + &"--tests", + &"--", + &"--exclude-should-panic", + &"--test-threads", + &"1", + &"-Zunstable-options", + &"-q", + ], + Some(Path::new("regex")), + &env, + args, + )?; + Ok(()) +} + +fn extended_sysroot_tests(env: &Env, args: &TestArg) -> Result<(), String> { + // pushd simple-raytracer + // echo "[BENCH COMPILE] ebobby/simple-raytracer" + // hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \ + // "RUSTC=rustc RUSTFLAGS='' cargo build" \ + // "../cargo.sh build" + + // echo "[BENCH RUN] ebobby/simple-raytracer" + // cp ./target/debug/main ./raytracer_cg_gcc + // hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_gcc + // popd + extended_rand_tests(env, args)?; + extended_regex_example_tests(env, args)?; + extended_regex_tests(env, args)?; + + Ok(()) +} + +fn should_remove_ui_test(content: &str) -> bool { + for line in content + .lines() + .map(|line| line.trim()) + .filter(|line| !line.is_empty()) + { + if [ + "// error-pattern:", + "// build-fail", + "// run-fail", + "-Cllvm-args", + "//~", + "// ~", + ] + .iter() + .any(|check| line.contains(check)) + { + return true; + } + } + false +} + +fn should_not_remove_test(file: &str) -> bool { + // contains //~ERROR, but shouldn't be removed + [ + "issues/auxiliary/issue-3136-a.rs", + "type-alias-impl-trait/auxiliary/cross_crate_ice.rs", + "type-alias-impl-trait/auxiliary/cross_crate_ice2.rs", + "macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs", + "imports/ambiguous-1.rs", + "imports/ambiguous-4-extern.rs", + "entry-point/auxiliary/bad_main_functions.rs", + ] + .iter() + .any(|to_ignore| file.ends_with(to_ignore)) +} + +fn should_remove_test(path: &Path, path_str: &str) -> bool { + // Tests generating errors. + path.file_name() + .and_then(|name| name.to_str()) + .map(|name| name.contains("thread")) + .unwrap_or(false) + || [ + "consts/issue-miri-1910.rs", + // Tests generating errors. + "consts/issue-94675.rs", + // this test is oom-killed in the CI. + "mir/mir_heavy/issue-miri-1910.rs", + ] + .iter() + .any(|to_ignore| path_str.ends_with(to_ignore)) +} + +fn test_rustc_inner(env: &Env, args: &TestArg, callback: F) -> Result<(), String> +where + F: Fn() -> Result, +{ + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[TEST] rust-lang/rust"); + walk_dir( + "rust/tests/ui", + |dir| { + let dir_name = dir.file_name().and_then(|name| name.to_str()).unwrap_or(""); + if [ + "abi", + "extern", + "unsized-locals", + "proc-macro", + "threads-sendsync", + "borrowck", + "test-attrs", + ] + .iter() + .any(|name| *name == dir_name) + { + std::fs::remove_dir_all(dir).map_err(|error| { + format!("Failed to remove folder `{}`: {:?}", dir.display(), error) + })?; + } + Ok(()) + }, + |_| Ok(()), + )?; + + fn dir_handling(dir: &Path) -> Result<(), String> { + walk_dir(dir, dir_handling, file_handling) + } + fn file_handling(file: &Path) -> Result<(), String> { + let path_str = file.display().to_string().replace("\\", "/"); + if should_not_remove_test(&path_str) { + return Ok(()); + } else if should_remove_test(file, &path_str) { + return std::fs::remove_file(file) + .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error)); + } + let file_content = std::fs::read_to_string(file) + .map_err(|error| format!("Failed to read `{}`: {:?}", file.display(), error))?; + if should_remove_ui_test(&file_content) { + std::fs::remove_file(file) + .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error))?; + } + Ok(()) + } + + walk_dir("rust/tests/ui", dir_handling, file_handling)?; + let file = "rust/tests/ui/consts/const_cmp_type_id.rs"; + std::fs::remove_file(file) + .map_err(|error| format!("Failed to remove `{}`: {:?}", file, error))?; + let file = "rust/tests/ui/consts/issue-73976-monomorphic.rs"; + std::fs::remove_file(file) + .map_err(|error| format!("Failed to remove `{}`: {:?}", file, error))?; + + let mut env = env.clone(); + setup_rustc(&mut env, args)?; + if !callback()? { + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("Keeping all UI tests"); + } + + let nb_parts = args.nb_parts.unwrap_or(0); + if nb_parts > 0 { + let current_part = args.current_part.unwrap_or(0); + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!( + "Splitting ui_test into {} parts (and running part {})", + nb_parts, current_part + ); + let out = String::from_utf8( + run_command( + &[ + &"find", + &"tests/ui", + &"-type", + &"f", + &"-name", + &"*.rs", + &"-not", + &"-path", + &"*/auxiliary/*", + ], + Some(Path::new("rust")), + )? + .stdout, + ) + .map_err(|error| format!("Failed to retrieve output of find command: {:?}", error))?; + let mut files = out + .split('\n') + .map(|line| line.trim()) + .filter(|line| !line.is_empty()) + .collect::>(); + // To ensure it'll be always the same sub files, we sort the content. + files.sort(); + // We increment the number of tests by one because if this is an odd number, we would skip + // one test. + let count = files.len() / nb_parts + 1; + let start = nb_parts * count; + let end = start + count; + for (pos, path) in files.iter().enumerate() { + if pos >= start && pos <= end { + continue; + } + std::fs::remove_file(path) + .map_err(|error| format!("Failed to remove `{}`: {:?}", path, error))?; + } + } + + // FIXME: create a function "display_if_not_quiet" or something along the line. + println!("[TEST] rustc test suite"); + env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); + let rustc_args = env + .get("RUSTFLAGS") + .expect("RUSTFLAGS should not be empty at this stage"); + run_command_with_output_and_env( + &[ + &"./x.py", + &"test", + &"--run", + &"always", + &"--stage", + &"0", + &"tests/ui", + &"--rustc-args", + &rustc_args, + ], + Some(Path::new("rust")), + Some(&env), + )?; + Ok(()) +} + +fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> { + test_rustc_inner(env, args, || Ok(false)) +} + +fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { + test_rustc_inner(env, args, || { + // Removing all tests. + run_command( + &[ + &"find", + &"tests/ui", + &"-type", + &"f", + &"-name", + &"*.rs", + &"-not", + &"-path", + &"*/auxiliary/*", + &"-delete", + ], + Some(Path::new("rust")), + )?; + // Putting back only the failing ones. + run_command( + &[ + &"xargs", + &"-a", + &"../failing-ui-tests.txt", + &"-d'\n'", + &"git", + &"checkout", + &"--", + ], + Some(Path::new("rust")), + )?; + Ok(true) + }) +} + +fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { + test_rustc_inner(env, args, || { + // Removing the failing tests. + run_command( + &[ + &"xargs", + &"-a", + &"../failing-ui-tests.txt", + &"-d'\n'", + &"rm", + ], + Some(Path::new("rust")), + )?; + Ok(true) + }) +} + +fn clean_ui_tests(_env: &Env, _args: &TestArg) -> Result<(), String> { + run_command( + &[ + &"find", + &"rust/build/x86_64-unknown-linux-gnu/test/ui/", + &"-name", + &"stamp", + &"-delete", + ], + None, + )?; + Ok(()) +} + +fn run_all(env: &Env, args: &TestArg) -> Result<(), String> { + clean(env, args)?; + mini_tests(env, args)?; + build_sysroot(env, args)?; + std_tests(env, args)?; + // asm_tests(env, args)?; + test_libcore(env, args)?; + extended_sysroot_tests(env, args)?; + test_rustc(env, args)?; + Ok(()) } pub fn run() -> Result<(), String> { - let mut args: Vec<&dyn AsRef> = vec![&"bash", &"test.sh"]; - let extra_args = std::env::args().skip(2).collect::>(); - get_args(&mut args, &extra_args); - let current_dir = std::env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?; - run_command_with_output(args.as_slice(), Some(¤t_dir)) + let mut args = match TestArg::new()? { + Some(args) => args, + None => return Ok(()), + }; + let mut env: HashMap = std::env::vars().collect(); + + env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone()); + env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone()); + + build_if_no_backend(&env, &args)?; + if args.build_only { + println!("Since it's build only, exiting..."); + return Ok(()); + } + + let test_flags = split_args(env.get("TEST_FLAGS").unwrap_or(&String::new())); + args.config_info + .setup(&mut env, &test_flags, Some(&args.gcc_path))?; + + if args.runners.is_empty() { + run_all(&env, &args)?; + } else { + let runners = get_runners(); + for runner in args.runners.iter() { + runners.get(runner.as_str()).unwrap().1(&env, &args)?; + } + } + + Ok(()) } diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 536f33a80293c..ba1e040cb20f9 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -143,17 +143,56 @@ pub fn get_os_name() -> Result { } } -pub fn get_rustc_host_triple() -> Result { - let output = run_command(&[&"rustc", &"-vV"], None)?; +#[derive(Default)] +pub struct RustcVersionInfo { + pub version: String, + pub host: Option, + pub commit_hash: Option, + pub commit_date: Option, +} + +pub fn rustc_version_info(rustc: Option<&str>) -> Result { + let output = run_command(&[&rustc.unwrap_or("rustc"), &"-vV"], None)?; let content = std::str::from_utf8(&output.stdout).unwrap_or(""); + let mut info = RustcVersionInfo::default(); + for line in content.split('\n').map(|line| line.trim()) { - if !line.starts_with("host:") { - continue; + match line.split_once(':') { + Some(("host", data)) => info.host = Some(data.trim().to_string()), + Some(("release", data)) => info.version = data.trim().to_string(), + Some(("commit-hash", data)) => info.commit_hash = Some(data.trim().to_string()), + Some(("commit-date", data)) => info.commit_date = Some(data.trim().to_string()), + _ => {} } - return Ok(line.split(':').nth(1).unwrap().trim().to_string()); } - Err("Cannot find host triple".to_string()) + if info.version.is_empty() { + Err("failed to retrieve rustc version".to_string()) + } else { + Ok(info) + } +} + +pub fn get_toolchain() -> Result { + let content = match fs::read_to_string("rust-toolchain") { + Ok(content) => content, + Err(_) => return Err("No `rust-toolchain` file found".to_string()), + }; + match content + .split('\n') + .map(|line| line.trim()) + .filter(|line| !line.is_empty()) + .filter_map(|line| { + if !line.starts_with("channel") { + return None; + } + line.split('"').skip(1).next() + }) + .next() + { + Some(toolchain) => Ok(toolchain.to_string()), + None => Err("Couldn't find `channel` in `rust-toolchain` file".to_string()), + } } pub fn get_gcc_path() -> Result { @@ -238,3 +277,56 @@ where } Ok(()) } + +pub fn split_args(args: &str) -> Vec { + let mut out = Vec::new(); + let mut start = 0; + let mut iter = args.char_indices().peekable(); + + while iter.peek().is_some() { + while let Some((pos, c)) = iter.next() { + if c == ' ' { + if pos != 0 { + out.push(args[start..pos].to_string()); + } + let mut found_start = false; + while let Some((pos, c)) = iter.peek() { + if *c != ' ' { + start = *pos; + found_start = true; + break; + } else { + iter.next(); + } + } + if !found_start { + return out; + } + } else if c == '"' || c == '\'' { + let end = c; + let mut found_end = false; + while let Some((_, c)) = iter.next() { + if c == end { + found_end = true; + break; + } else if c == '\\' { + // We skip the escaped character. + iter.next(); + } + } + if !found_end { + out.push(args[start..].to_string()); + return out; + } + } else if c == '\\' { + // We skip the escaped character. + iter.next(); + } + } + } + let s = args[start..].trim(); + if !s.is_empty() { + out.push(s.to_string()); + } + out +} From 84ca4f59c21425b02ba2042297187953d9aa283e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Nov 2023 22:51:51 +0100 Subject: [PATCH 017/192] Remove `test.sh`, `config.sh` and all calls and documentation pointing to it --- .github/workflows/ci.yml | 2 +- .github/workflows/failures.yml | 2 +- .github/workflows/gcc12.yml | 2 +- .github/workflows/m68k.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/stdarch.yml | 2 +- Readme.md | 4 +- config.sh | 85 ------ test.sh | 479 --------------------------------- 9 files changed, 8 insertions(+), 572 deletions(-) delete mode 100644 config.sh delete mode 100755 test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 308bc55ead71e..8e361bf617b1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,7 +124,7 @@ jobs: - name: Run tests run: | # TODO: remove --features master when it is back to the default. - ./test.sh --features master --release --clean --build-sysroot ${{ matrix.commands }} + ./y.sh test --features master --release --clean --build-sysroot ${{ matrix.commands }} duplicates: runs-on: ubuntu-latest diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index ae8de79b773db..b411b9a17846e 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -128,5 +128,5 @@ jobs: - name: Run tests id: tests run: | - ${{ matrix.libgccjit_version.env_extra }} ./test.sh --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} | tee output_log + ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} | tee output_log rg --text "test result" output_log >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index a0d363cf1fbda..1a17b936c743e 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -112,4 +112,4 @@ jobs: - name: Run tests run: | - ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features + ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 4d9d7e23dc2b5..ac141e0624793 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -139,4 +139,4 @@ jobs: - name: Run tests run: | # TODO: remove --features master when it is back to the default. - ./test.sh --release --features master --clean --build-sysroot ${{ matrix.commands }} + ./y.sh test --release --features master --clean --build-sysroot ${{ matrix.commands }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43b90fcec9337..9798bc338f3d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,4 +105,4 @@ jobs: - name: Run tests run: | # TODO: remove --features master when it is back to the default. - EMBED_LTO_BITCODE=1 ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} --features master + EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} --features master diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 42109ba3e0245..d290f1d056288 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -120,7 +120,7 @@ jobs: if: ${{ !matrix.cargo_runner }} run: | # TODO: remove `--features master` when it is back to the default. - ./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore --features master + ./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore --features master - name: Run stdarch tests if: ${{ !matrix.cargo_runner }} diff --git a/Readme.md b/Readme.md index 9db1dec103232..68effb2bf78f9 100644 --- a/Readme.md +++ b/Readme.md @@ -65,7 +65,7 @@ $ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./y.sh build --re To run the tests: ```bash -$ ./test.sh --release --features master +$ ./y.sh test --release --features master ``` ## Usage @@ -82,7 +82,7 @@ export CG_GCCJIT_DIR=[the full path to rustc_codegen_gcc] $ CHANNEL="release" $CG_GCCJIT_DIR/cargo.sh run ``` -If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely. +If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./y.sh test`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely. ### LTO diff --git a/config.sh b/config.sh deleted file mode 100644 index 7ae2175d41de7..0000000000000 --- a/config.sh +++ /dev/null @@ -1,85 +0,0 @@ -set -e - -export CARGO_INCREMENTAL=0 - -if [ -f ./gcc_path ]; then - export GCC_PATH=$(cat gcc_path) -elif (( $use_system_gcc == 1 )); then - echo 'Using system GCC' -else - echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' - exit 1 -fi - -if [[ -z "$RUSTC" ]]; then - export RUSTC="rustc" -fi - -unamestr=`uname` -if [[ "$unamestr" == 'Linux' ]]; then - dylib_ext='so' -elif [[ "$unamestr" == 'Darwin' ]]; then - dylib_ext='dylib' -else - echo "Unsupported os" - exit 1 -fi - -HOST_TRIPLE=$($RUSTC -vV | grep host | cut -d: -f2 | tr -d " ") -# TODO: remove $OVERWRITE_TARGET_TRIPLE when config.sh is removed. -TARGET_TRIPLE="${OVERWRITE_TARGET_TRIPLE:-$HOST_TRIPLE}" - -linker='' -RUN_WRAPPER='' -if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then - RUN_WRAPPER=run_in_vm - if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then - linker='-Clinker=m68k-unknown-linux-gnu-gcc' - elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then - # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - linker='-Clinker=aarch64-linux-gnu-gcc' - else - echo "Unknown non-native platform" - fi -fi - -# Since we don't support ThinLTO, disable LTO completely when not trying to do LTO. -# TODO(antoyo): remove when we can handle ThinLTO. -disable_lto_flags='' -if [[ ! -v FAT_LTO ]]; then - disable_lto_flags='-Clto=off' -fi - -if [[ -z "$BUILTIN_BACKEND" ]]; then - export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS" -else - export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=gcc $TEST_FLAGS -Cpanic=abort" - - if [[ ! -z "$RUSTC_SYSROOT" ]]; then - export RUSTFLAGS="$RUSTFLAGS --sysroot $RUSTC_SYSROOT" - fi -fi - -# FIXME(antoyo): remove once the atomic shim is gone -if [[ unamestr == 'Darwin' ]]; then - export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" -fi - -if [[ -z "$cargo_target_dir" ]]; then - RUST_CMD="$RUSTC $RUSTFLAGS -L crate=target/out --out-dir target/out" - cargo_target_dir="target/out" -else - RUST_CMD="$RUSTC $RUSTFLAGS -L crate=$cargo_target_dir --out-dir $cargo_target_dir" -fi -export RUSTC_LOG=warn # display metadata load errors - -export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib" -if [[ ! -z "$:$GCC_PATH" ]]; then - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$GCC_PATH" -fi - -export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH -# NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc. -# To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH. -# Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc -export PATH="/opt/gcc/bin:/opt/m68k-unknown-linux-gnu/bin:$PATH" diff --git a/test.sh b/test.sh deleted file mode 100755 index e896237a1ea4a..0000000000000 --- a/test.sh +++ /dev/null @@ -1,479 +0,0 @@ -#!/usr/bin/env bash - -# TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed? - -set -e -#set -x - -flags= -gcc_master_branch=1 -channel="debug" -funcs=() -build_only=0 -nb_parts=0 -current_part=0 -use_system_gcc=0 -use_backend=0 -cargo_target_dir="" - -export CHANNEL='debug' - -while [[ $# -gt 0 ]]; do - case $1 in - --release) - codegen_channel=release - channel="release" - export CHANNEL='release' - shift - ;; - --release-sysroot) - sysroot_channel="--release" - shift - ;; - --no-default-features) - gcc_master_branch=0 - flags="$flags --no-default-features" - shift - ;; - --features) - shift - flags="$flags --features $1" - shift - ;; - "--test-rustc") - funcs+=(test_rustc) - shift - ;; - "--test-successful-rustc") - funcs+=(test_successful_rustc) - shift - ;; - "--test-failing-rustc") - funcs+=(test_failing_rustc) - shift - ;; - - "--test-libcore") - funcs+=(test_libcore) - shift - ;; - - "--clean-ui-tests") - funcs+=(clean_ui_tests) - shift - ;; - "--clean") - funcs+=(clean) - shift - ;; - - "--std-tests") - funcs+=(std_tests) - shift - ;; - - "--asm-tests") - funcs+=(asm_tests) - shift - ;; - - "--extended-tests") - funcs+=(extended_sysroot_tests) - shift - ;; - "--extended-rand-tests") - funcs+=(extended_rand_tests) - shift - ;; - "--extended-regex-example-tests") - funcs+=(extended_regex_example_tests) - shift - ;; - "--extended-regex-tests") - funcs+=(extended_regex_tests) - shift - ;; - - "--mini-tests") - funcs+=(mini_tests) - shift - ;; - - "--build-sysroot") - funcs+=(build_sysroot) - shift - ;; - "--build") - build_only=1 - shift - ;; - "--use-system-gcc") - use_system_gcc=1 - shift - ;; - "--use-backend") - use_backend=1 - shift - export BUILTIN_BACKEND=$1 - shift - ;; - "--out-dir") - shift - export CARGO_TARGET_DIR=$1 - cargo_target_dir=$1 - shift - ;; - "--nb-parts") - shift - nb_parts=$1 - shift - ;; - "--current-part") - shift - current_part=$1 - shift - ;; - *) - echo "Unknown option $1" - exit 1 - ;; - esac -done - -if [ -f ./gcc_path ]; then - export GCC_PATH=$(cat gcc_path) -elif (( $use_system_gcc == 1 )); then - echo 'Using system GCC' -else - echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' - exit 1 -fi - -export LD_LIBRARY_PATH="$GCC_PATH" -export LIBRARY_PATH="$GCC_PATH" - -if [[ $use_backend == 0 ]]; then - if [[ $channel == "release" ]]; then - CARGO_INCREMENTAL=1 cargo rustc --release $flags - else - echo $LD_LIBRARY_PATH - cargo rustc $flags - fi -fi - -if (( $build_only == 1 )); then - echo "Since it's 'build-only', exiting..." - exit -fi - -source config.sh - -function clean() { - rm -r $cargo_target_dir || true - mkdir -p $cargo_target_dir/gccjit -} - -function mini_tests() { - echo "[BUILD] mini_core" - crate_types="lib,dylib" - - if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then - crate_types="lib" - fi - - $RUST_CMD example/mini_core.rs --crate-name mini_core --crate-type $crate_types --target $TARGET_TRIPLE - - echo "[BUILD] example" - $RUST_CMD example/example.rs --crate-type lib --target $TARGET_TRIPLE - - echo "[AOT] mini_core_hello_world" - $RUST_CMD example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE - $RUN_WRAPPER $cargo_target_dir/mini_core_hello_world abc bcd -} - -function build_sysroot() { - echo "[BUILD] sysroot" - time ./build_sysroot/build_sysroot.sh $sysroot_channel -} - -# TODO(GuillaumeGomez): when rewriting in Rust, refactor with the code in tests/lang_tests_common.rs if possible. -function run_in_vm() { - vm_parent_dir=${CG_GCC_VM_DIR:-$(pwd)} - vm_dir=vm - exe=$1 - exe_filename=$(basename $exe) - vm_home_dir=$vm_parent_dir/$vm_dir/home - vm_exe_path=$vm_home_dir/$exe_filename - inside_vm_exe_path=/home/$exe_filename - sudo cp $exe $vm_exe_path - - shift - pushd $vm_parent_dir - sudo chroot $vm_dir qemu-m68k-static $inside_vm_exe_path $@ - popd -} - -function std_tests() { - echo "[AOT] arbitrary_self_types_pointers_and_wrappers" - $RUST_CMD example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE - $RUN_WRAPPER $cargo_target_dir/arbitrary_self_types_pointers_and_wrappers - - echo "[AOT] alloc_system" - $RUST_CMD example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE" - - # FIXME: doesn't work on m68k. - if [[ "$HOST_TRIPLE" == "$TARGET_TRIPLE" ]]; then - echo "[AOT] alloc_example" - $RUST_CMD example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE - $RUN_WRAPPER $cargo_target_dir/alloc_example - fi - - echo "[AOT] dst_field_align" - # FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed. - $RUST_CMD example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE - $RUN_WRAPPER $cargo_target_dir/dst_field_align || (echo $?; false) - - echo "[AOT] std_example" - std_flags="--cfg feature=\"master\"" - if (( $gcc_master_branch == 0 )); then - std_flags="" - fi - $RUST_CMD example/std_example.rs --crate-type bin --target $TARGET_TRIPLE $std_flags - $RUN_WRAPPER $cargo_target_dir/std_example --target $TARGET_TRIPLE - - echo "[AOT] subslice-patterns-const-eval" - $RUST_CMD example/subslice-patterns-const-eval.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE - $RUN_WRAPPER $cargo_target_dir/subslice-patterns-const-eval - - echo "[AOT] track-caller-attribute" - $RUST_CMD example/track-caller-attribute.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE - $RUN_WRAPPER $cargo_target_dir/track-caller-attribute - - echo "[BUILD] mod_bench" - $RUST_CMD example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE -} - -function setup_rustc() { - rust_toolchain=$(cat rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') - - git clone https://github.com/rust-lang/rust.git || true - cd rust - git fetch - git checkout $($RUSTC -V | cut -d' ' -f3 | tr -d '(') - export RUSTFLAGS= - - rm config.toml || true - - cat > config.toml < res.txt - diff -u res.txt examples/regexdna-output.txt - popd -} - -function extended_regex_tests() { - if (( $gcc_master_branch == 0 )); then - return - fi - - pushd regex - echo "[TEST] rust-lang/regex tests" - export CG_RUSTFLAGS="--cap-lints warn" # newer aho_corasick versions throw a deprecation warning - ../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q - popd -} - -function extended_sysroot_tests() { - #pushd simple-raytracer - #echo "[BENCH COMPILE] ebobby/simple-raytracer" - #hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \ - #"RUSTC=rustc RUSTFLAGS='' cargo build" \ - #"../cargo.sh build" - - #echo "[BENCH RUN] ebobby/simple-raytracer" - #cp ./target/debug/main ./raytracer_cg_gcc - #hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_gcc - #popd - - extended_rand_tests - extended_regex_example_tests - extended_regex_tests -} - -function test_rustc() { - echo - echo "[TEST] rust-lang/rust" - - setup_rustc - - for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do - rm $test - done - rm tests/ui/consts/const_cmp_type_id.rs - rm tests/ui/consts/issue-73976-monomorphic.rs - - git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed - - rm -r tests/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,borrowck/,test*,consts/issue-miri-1910.rs} || true - rm tests/ui/mir/mir_heavy_promoted.rs # this test is oom-killed in the CI. - # Tests generating errors. - rm tests/ui/consts/issue-94675.rs - for test in $(rg --files-with-matches "thread" tests/ui); do - rm $test - done - git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs - git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs - git checkout tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs - git checkout tests/ui/imports/ambiguous-1.rs - git checkout tests/ui/imports/ambiguous-4-extern.rs - git checkout tests/ui/entry-point/auxiliary/bad_main_functions.rs - - RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot" - - if [ $# -eq 0 ]; then - # No argument supplied to the function. Doing nothing. - echo "No argument provided. Keeping all UI tests" - elif [ $1 = "0" ]; then - # Removing the failing tests. - xargs -a ../failing-ui-tests.txt -d'\n' rm - else - # Removing all tests. - find tests/ui -type f -name '*.rs' -not -path '*/auxiliary/*' -delete - # Putting back only the failing ones. - xargs -a ../failing-ui-tests.txt -d'\n' git checkout -- - fi - - if [ $nb_parts -gt 0 ]; then - echo "Splitting ui_test into $nb_parts parts (and running part $current_part)" - find tests/ui -type f -name '*.rs' -not -path "*/auxiliary/*" > ui_tests - # To ensure it'll be always the same sub files, we sort the content. - sort ui_tests -o ui_tests - count=$((`wc -l < ui_tests` / $nb_parts)) - # We increment the number of tests by one because if this is an odd number, we would skip - # one test. - count=$((count + 1)) - split -d -l $count -a 1 ui_tests ui_tests.split - # Removing all tests. - find tests/ui -type f -name '*.rs' -not -path "*/auxiliary/*" -delete - # Putting back only the ones we want to test. - xargs -a "ui_tests.split$current_part" -d'\n' git checkout -- - fi - - echo "[TEST] rustc test suite" - COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui/ --rustc-args "$RUSTC_ARGS" # --target $TARGET_TRIPLE -} - -function test_failing_rustc() { - test_rustc "1" -} - -function test_successful_rustc() { - test_rustc "0" -} - -function clean_ui_tests() { - find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -delete -} - -function all() { - clean - mini_tests - build_sysroot - std_tests - #asm_tests - test_libcore - extended_sysroot_tests - test_rustc -} - -if [ ${#funcs[@]} -eq 0 ]; then - echo "No command passed, running '--all'..." - all -else - for t in ${funcs[@]}; do - $t - done -fi From d3e14a49c9710a93ebd315b1b54a596496531de7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Nov 2023 16:29:32 +0100 Subject: [PATCH 018/192] Display stdout and stderr if a command failed to run --- build_system/src/build.rs | 13 ++++++++--- build_system/src/main.rs | 2 +- build_system/src/utils.rs | 47 ++++++++++++++++++++++++++------------- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 6390458d4fd03..43fa442bf5b24 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -189,9 +189,16 @@ fn build_sysroot_inner( // Copy the source files to the sysroot (Rust for Linux needs this). let sysroot_src_path = "sysroot/lib/rustlib/src/rust"; - fs::create_dir_all(&sysroot_src_path) - .map_err(|error| format!("Failed to create directory `{}`: {:?}", sysroot_src_path, error))?; - run_command(&[&"cp", &"-r", &"sysroot_src/library/", &sysroot_src_path], None)?; + fs::create_dir_all(&sysroot_src_path).map_err(|error| { + format!( + "Failed to create directory `{}`: {:?}", + sysroot_src_path, error + ) + })?; + run_command( + &[&"cp", &"-r", &"sysroot_src/library/", &sysroot_src_path], + None, + )?; Ok(()) } diff --git a/build_system/src/main.rs b/build_system/src/main.rs index bff82b6e3e57d..e0091ff697733 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -61,7 +61,7 @@ fn main() { Command::Build => build::run(), Command::Test => test::run(), } { - eprintln!("Command failed to run: {e:?}"); + eprintln!("Command failed to run: {e}"); process::exit(1); } } diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index ba1e040cb20f9..6dfc6a6506aa4 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -29,22 +29,37 @@ fn check_exit_status( input: &[&dyn AsRef], cwd: Option<&Path>, exit_status: ExitStatus, + output: Option<&Output>, ) -> Result<(), String> { if exit_status.success() { - Ok(()) - } else { - Err(format!( - "Command `{}`{} exited with status {:?}", - input - .iter() - .map(|s| s.as_ref().to_str().unwrap()) - .collect::>() - .join(" "), - cwd.map(|cwd| format!(" (running in folder `{}`)", cwd.display())) - .unwrap_or_default(), - exit_status.code(), - )) + return Ok(()); + } + let mut error = format!( + "Command `{}`{} exited with status {:?}", + input + .iter() + .map(|s| s.as_ref().to_str().unwrap()) + .collect::>() + .join(" "), + cwd.map(|cwd| format!(" (running in folder `{}`)", cwd.display())) + .unwrap_or_default(), + exit_status.code() + ); + if let Some(output) = output { + unsafe { + let stdout = std::str::from_utf8_unchecked(&output.stdout); + if !stdout.is_empty() { + error.push_str("\n==== STDOUT ====\n"); + error.push_str(stdout); + } + let stderr = std::str::from_utf8_unchecked(&output.stderr); + if !stderr.is_empty() { + error.push_str("\n==== STDERR ====\n"); + error.push_str(stderr); + } + } } + Err(error) } fn command_error(input: &[&dyn AsRef], cwd: &Option<&Path>, error: D) -> String { @@ -73,7 +88,7 @@ pub fn run_command_with_env( let output = get_command_inner(input, cwd, env) .output() .map_err(|e| command_error(input, &cwd, e))?; - check_exit_status(input, cwd, output.status)?; + check_exit_status(input, cwd, output.status, Some(&output))?; Ok(output) } @@ -86,7 +101,7 @@ pub fn run_command_with_output( .map_err(|e| command_error(input, &cwd, e))? .wait() .map_err(|e| command_error(input, &cwd, e))?; - check_exit_status(input, cwd, exit_status)?; + check_exit_status(input, cwd, exit_status, None)?; Ok(()) } @@ -100,7 +115,7 @@ pub fn run_command_with_output_and_env( .map_err(|e| command_error(input, &cwd, e))? .wait() .map_err(|e| command_error(input, &cwd, e))?; - check_exit_status(input, cwd, exit_status)?; + check_exit_status(input, cwd, exit_status, None)?; Ok(()) } From 8cc024c84dc76cb081bbaf8ae2eef4647ed8d78b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Nov 2023 18:38:30 +0100 Subject: [PATCH 019/192] Fix invalid path in `build_sysroot_inner` --- build_system/src/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 43fa442bf5b24..8f5c113fe319a 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -196,7 +196,7 @@ fn build_sysroot_inner( ) })?; run_command( - &[&"cp", &"-r", &"sysroot_src/library/", &sysroot_src_path], + &[&"cp", &"-r", &start_dir.join("sysroot_src/library/"), &sysroot_src_path], None, )?; From 694a80d3724cdf7138df550d64fcaceb5d1404b0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Nov 2023 21:38:16 +0100 Subject: [PATCH 020/192] Add missing `--build-sysroot` option --- build_system/src/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index fb2b24da9a233..2619fbc2f646a 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -33,6 +33,7 @@ fn get_runners() -> Runners { runners.insert("--test-libcore", ("Run libcore tests", &test_libcore)); runners.insert("--clean-ui-tests", ("Clean ui tests", &clean_ui_tests)); runners.insert("--clean", ("Empty cargo target directory", &clean)); + runners.insert("--build-sysroot", ("Build sysroot", &build_sysroot)); runners.insert("--std-tests", ("Run std tests", &std_tests)); runners.insert("--asm-tests", ("Run asm tests", &asm_tests)); runners.insert( From c27fe3e0366313933daf6f9a6b3df578bde2682b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Nov 2023 15:17:48 +0100 Subject: [PATCH 021/192] Correctly handle channel in config --- build_system/src/config.rs | 4 +++- build_system/src/test.rs | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 763cac8edb66b..8bab64f121ac0 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -110,7 +110,9 @@ impl ConfigInfo { let current_dir = std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?; - let channel = if let Some(channel) = env.get("CHANNEL") { + let channel = if self.sysroot_release_channel { + "release" + } else if let Some(channel) = env.get("CHANNEL") { channel.as_str() } else { "debug" diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 2619fbc2f646a..06a5c3157bb2f 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -126,7 +126,6 @@ struct TestArg { build_only: bool, gcc_path: String, channel: Channel, - sysroot_channel: Channel, use_backend: bool, runners: BTreeSet, flags: Vec, @@ -148,8 +147,11 @@ impl TestArg { while let Some(arg) = args.next() { match arg.as_str() { - "--release" => test_arg.channel = Channel::Release, - "--release-sysroot" => test_arg.sysroot_channel = Channel::Release, + "--release" => { + test_arg.channel = Channel::Release; + test_arg.config_info.sysroot_release_channel = true; + } + "--release-sysroot" => test_arg.config_info.sysroot_release_channel = true, "--no-default-features" => { // To prevent adding it more than once. if !test_arg.no_default_features { From 9d104a0cbf0abbf5d2f5176298373510392e5a36 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Nov 2023 17:01:05 +0100 Subject: [PATCH 022/192] Clone rust repository before modifying it --- build_system/src/test.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 06a5c3157bb2f..7785957541f5b 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -895,6 +895,9 @@ where { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rust-lang/rust"); + let mut env = env.clone(); + setup_rustc(&mut env, args)?; + walk_dir( "rust/tests/ui", |dir| { @@ -948,8 +951,6 @@ where std::fs::remove_file(file) .map_err(|error| format!("Failed to remove `{}`: {:?}", file, error))?; - let mut env = env.clone(); - setup_rustc(&mut env, args)?; if !callback()? { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("Keeping all UI tests"); From 87c284c9bc05e290cb0ee577717a94de9e853c89 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Nov 2023 17:20:14 +0100 Subject: [PATCH 023/192] Only read rust test files --- build_system/src/test.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 7785957541f5b..bbe2322f93d3e 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -928,7 +928,9 @@ where } fn file_handling(file: &Path) -> Result<(), String> { let path_str = file.display().to_string().replace("\\", "/"); - if should_not_remove_test(&path_str) { + if !path_str.ends_with(".rs") { + return Ok(()) + } else if should_not_remove_test(&path_str) { return Ok(()); } else if should_remove_test(file, &path_str) { return std::fs::remove_file(file) From 23c97b545dd7d8dbee80e491269f95308707c750 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Nov 2023 17:35:49 +0100 Subject: [PATCH 024/192] Replace `xargs` command with pure Rust --- build_system/src/build.rs | 7 ++++- build_system/src/test.rs | 59 ++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 8f5c113fe319a..3087a5d79e01b 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -196,7 +196,12 @@ fn build_sysroot_inner( ) })?; run_command( - &[&"cp", &"-r", &start_dir.join("sysroot_src/library/"), &sysroot_src_path], + &[ + &"cp", + &"-r", + &start_dir.join("sysroot_src/library/"), + &sysroot_src_path, + ], None, )?; diff --git a/build_system/src/test.rs b/build_system/src/test.rs index bbe2322f93d3e..12927c5d13cab 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -929,7 +929,7 @@ where fn file_handling(file: &Path) -> Result<(), String> { let path_str = file.display().to_string().replace("\\", "/"); if !path_str.ends_with(".rs") { - return Ok(()) + return Ok(()); } else if should_not_remove_test(&path_str) { return Ok(()); } else if should_remove_test(file, &path_str) { @@ -1052,18 +1052,24 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { Some(Path::new("rust")), )?; // Putting back only the failing ones. - run_command( - &[ - &"xargs", - &"-a", - &"../failing-ui-tests.txt", - &"-d'\n'", - &"git", - &"checkout", - &"--", - ], - Some(Path::new("rust")), - )?; + let path = "failing-ui-tests.txt"; + if let Ok(files) = std::fs::read_to_string(path) { + for file in files + .split('\n') + .map(|line| line.trim()) + .filter(|line| !line.is_empty()) + { + run_command( + &[&"git", &"checkout", &"--", &file], + Some(Path::new("rust")), + )?; + } + } else { + println!( + "Failed to read `{}`, not putting back failing ui tests", + path + ); + } Ok(true) }) } @@ -1071,16 +1077,23 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { test_rustc_inner(env, args, || { // Removing the failing tests. - run_command( - &[ - &"xargs", - &"-a", - &"../failing-ui-tests.txt", - &"-d'\n'", - &"rm", - ], - Some(Path::new("rust")), - )?; + let path = "failing-ui-tests.txt"; + if let Ok(files) = std::fs::read_to_string(path) { + for file in files + .split('\n') + .map(|line| line.trim()) + .filter(|line| !line.is_empty()) + { + let path = Path::new("rust").join(file); + std::fs::remove_file(&path) + .map_err(|error| format!("failed to remove `{}`: {:?}", path.display(), error))?; + } + } else { + println!( + "Failed to read `{}`, not putting back failing ui tests", + path + ); + } Ok(true) }) } From 673661db8b35fbbdc71b91af9b122a7eaf7f7bf3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Nov 2023 17:54:58 +0100 Subject: [PATCH 025/192] Remove newline for llvm FileCheck binary path --- build_system/src/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 12927c5d13cab..e175b62625cb8 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -597,7 +597,7 @@ download-ci-llvm = false home = env.get("HOME").unwrap(), toolchain = toolchain, host_triple = args.config_info.host_triple, - llvm_filecheck = llvm_filecheck, + llvm_filecheck = llvm_filecheck.trim(), ), ) .map_err(|error| format!("Failed to write into `rust/config.toml`: {:?}", error))?; From d793f80bd4ceb85c032e18c1d0badac9a8664bba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Nov 2023 16:09:11 +0100 Subject: [PATCH 026/192] Correctly pass `cfg` option --- build_system/src/test.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index e175b62625cb8..614042b36c20d 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -390,7 +390,7 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); if !args.no_default_features { - command.push(&"--cfg feature=\"master\""); + command.extend_from_slice(&[&"--cfg", &"feature=\"master\""]); } run_command_with_env(&command, None, Some(env))?; @@ -454,7 +454,7 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); if !args.no_default_features { - command.push(&"--cfg feature=\"master\""); + command.extend_from_slice(&[&"--cfg", &"feature=\"master\""]); } run_command_with_env(&command, None, Some(env))?; run_command_in_vm( @@ -1085,8 +1085,9 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { .filter(|line| !line.is_empty()) { let path = Path::new("rust").join(file); - std::fs::remove_file(&path) - .map_err(|error| format!("failed to remove `{}`: {:?}", path.display(), error))?; + std::fs::remove_file(&path).map_err(|error| { + format!("failed to remove `{}`: {:?}", path.display(), error) + })?; } } else { println!( From 4bed89f79bfd40fdfe615334c38e2427319db34f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Nov 2023 16:25:52 +0100 Subject: [PATCH 027/192] Correctly pass toolchain to cargo command --- build_system/src/test.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 614042b36c20d..114aa6dc72071 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -672,17 +672,14 @@ where F: Fn(&[&dyn AsRef], Option<&Path>, &Env) -> Result<(), String>, { let toolchain = get_toolchain()?; + let toolchain_arg = format!("+{}", toolchain); let rustc_version = String::from_utf8( run_command_with_env(&[&args.config_info.rustc_command[0], &"-V"], cwd, Some(env))?.stdout, ) .map_err(|error| format!("Failed to retrieve rustc version: {:?}", error))?; let rustc_toolchain_version = String::from_utf8( run_command_with_env( - &[ - &args.config_info.rustc_command[0], - &format!("+{}", toolchain), - &"-V", - ], + &[&args.config_info.rustc_command[0], &toolchain_arg, &"-V"], cwd, Some(env), )? @@ -697,7 +694,7 @@ where ); eprintln!("Using `{}`.", rustc_toolchain_version); } - let mut cargo_command: Vec<&dyn AsRef> = vec![&"cargo", &toolchain]; + let mut cargo_command: Vec<&dyn AsRef> = vec![&"cargo", &toolchain_arg]; cargo_command.extend_from_slice(&command); callback(&cargo_command, cwd, env) } From 3c6bae7fa88d700a34b57f43e55749c510c57b72 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Nov 2023 16:41:16 +0100 Subject: [PATCH 028/192] Use the correct folder when deleting rust UI tests --- build_system/src/test.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 114aa6dc72071..16f01a1ba2def 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -942,13 +942,15 @@ where Ok(()) } - walk_dir("rust/tests/ui", dir_handling, file_handling)?; - let file = "rust/tests/ui/consts/const_cmp_type_id.rs"; - std::fs::remove_file(file) - .map_err(|error| format!("Failed to remove `{}`: {:?}", file, error))?; - let file = "rust/tests/ui/consts/issue-73976-monomorphic.rs"; - std::fs::remove_file(file) - .map_err(|error| format!("Failed to remove `{}`: {:?}", file, error))?; + let rust_path = Path::new("rust"); + + walk_dir(rust_path.join("tests/ui"), dir_handling, file_handling)?; + let file = rust_path.join("tests/ui/consts/const_cmp_type_id.rs"); + std::fs::remove_file(&file) + .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error))?; + let file = rust_path.join("tests/ui/consts/issue-73976-monomorphic.rs"); + std::fs::remove_file(&file) + .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error))?; if !callback()? { // FIXME: create a function "display_if_not_quiet" or something along the line. @@ -976,7 +978,7 @@ where &"-path", &"*/auxiliary/*", ], - Some(Path::new("rust")), + Some(rust_path), )? .stdout, ) @@ -997,8 +999,10 @@ where if pos >= start && pos <= end { continue; } - std::fs::remove_file(path) - .map_err(|error| format!("Failed to remove `{}`: {:?}", path, error))?; + let test_path = rust_path.join(path); + std::fs::remove_file(&test_path).map_err(|error| { + format!("Failed to remove `{}`: {:?}", test_path.display(), error) + })?; } } @@ -1020,7 +1024,7 @@ where &"--rustc-args", &rustc_args, ], - Some(Path::new("rust")), + Some(rust_path), Some(&env), )?; Ok(()) From 7013eccc052228044faa0103ca596ed75ea2a70e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Nov 2023 17:05:33 +0100 Subject: [PATCH 029/192] Add missing code comment --- build_system/src/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 16f01a1ba2def..7ab4767e405d1 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -794,6 +794,7 @@ fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rust-lang/regex tests"); let mut env = env.clone(); + // newer aho_corasick versions throw a deprecation warning env.insert("CG_RUSTFLAGS".to_string(), "--cap-lints warn".to_string()); run_cargo_command( &[ From ad1d5417e705c8d915b718b8fc29e58c49b8defa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Nov 2023 17:11:07 +0100 Subject: [PATCH 030/192] Set RUSTDOCFLAGS environment variable in `run_cargo_command_with_callback` function --- build_system/src/test.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 7ab4767e405d1..02e6309bd338d 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -694,9 +694,12 @@ where ); eprintln!("Using `{}`.", rustc_toolchain_version); } + let mut env = env.clone(); + let rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default(); + env.insert("RUSTDOCFLAGS".to_string(), rustflags); let mut cargo_command: Vec<&dyn AsRef> = vec![&"cargo", &toolchain_arg]; cargo_command.extend_from_slice(&command); - callback(&cargo_command, cwd, env) + callback(&cargo_command, cwd, &env) } // FIXME(antoyo): linker gives multiple definitions error on Linux From 7d71b87691c22d54a1119a491647db63d28b55d3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Nov 2023 18:10:01 +0100 Subject: [PATCH 031/192] Correctly set `--cap-lints` when running regex tests --- build_system/src/config.rs | 2 ++ build_system/src/test.rs | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 8bab64f121ac0..b31a728c68075 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -149,9 +149,11 @@ impl ConfigInfo { .extend_from_slice(&["--sysroot".to_string(), sysroot_path.display().to_string()]); }; + // This environment variable is useful in case we want to change options of rustc commands. if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { rustflags.extend_from_slice(&split_args(&cg_rustflags)); } + if let Some(linker) = linker { rustflags.push(linker.to_string()); } diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 02e6309bd338d..4e8c176db7379 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -750,7 +750,8 @@ fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> println!("[TEST] rust-lang/regex example shootout-regex-dna"); let mut env = env.clone(); // newer aho_corasick versions throw a deprecation warning - env.insert("CG_RUSTFLAGS".to_string(), "--cap-lints warn".to_string()); + let rustflags = format!("{} --cap-lints warn", env.get("RUSTFLAGS").cloned().unwrap_or_default()); + env.insert("RUSTFLAGS".to_string(), rustflags); // Make sure `[codegen mono items] start` doesn't poison the diff run_cargo_command( &[&"build", &"--example", &"shootout-regex-dna"], @@ -798,7 +799,8 @@ fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { println!("[TEST] rust-lang/regex tests"); let mut env = env.clone(); // newer aho_corasick versions throw a deprecation warning - env.insert("CG_RUSTFLAGS".to_string(), "--cap-lints warn".to_string()); + let rustflags = format!("{} --cap-lints warn", env.get("RUSTFLAGS").cloned().unwrap_or_default()); + env.insert("RUSTFLAGS".to_string(), rustflags); run_cargo_command( &[ &"test", From 970b2c770010c044abe5e3a8433fffc4ab3b8d52 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Nov 2023 21:34:29 +0100 Subject: [PATCH 032/192] Fix `build_sysroot` by adding missing `RUSTFLAGS` environment variable --- build_system/src/build.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 3087a5d79e01b..da29e87c33cbe 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -141,8 +141,8 @@ fn build_sysroot_inner( rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests"); } rustflags.push_str(" -Z force-unstable-if-unmarked"); + let mut env = env.clone(); let channel = if sysroot_release_channel { - let mut env = env.clone(); env.insert( "RUSTFLAGS".to_string(), format!("{} -Zmir-opt-level=3", rustflags), @@ -160,10 +160,15 @@ fn build_sysroot_inner( )?; "release" } else { + env.insert( + "RUSTFLAGS".to_string(), + rustflags, + ); + run_command_with_output_and_env( &[&"cargo", &"build", &"--target", &config.target], Some(start_dir), - Some(env), + Some(&env), )?; "debug" }; From ff043162432a33fb7d2c675f05aef2803b39d387 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Nov 2023 22:05:08 +0100 Subject: [PATCH 033/192] Remove `--target` option --- build_system/src/build.rs | 25 +++---------------------- build_system/src/config.rs | 12 ------------ build_system/src/test.rs | 10 ++++++++-- 3 files changed, 11 insertions(+), 36 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index da29e87c33cbe..189c393019fd4 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -43,22 +43,6 @@ impl BuildArg { Self::usage(); return Ok(None); } - "--target-triple" => { - if args.next().is_some() { - // Handled in config.rs. - } else { - return Err( - "Expected a value after `--target-triple`, found nothing".to_string() - ); - } - } - "--target" => { - if args.next().is_some() { - // Handled in config.rs. - } else { - return Err("Expected a value after `--target`, found nothing".to_string()); - } - } arg => { if !build_arg.config_info.parse_argument(arg, &mut args)? { return Err(format!("Unknown argument `{}`", arg)); @@ -152,7 +136,7 @@ fn build_sysroot_inner( &"cargo", &"build", &"--target", - &config.target, + &config.target_triple, &"--release", ], Some(start_dir), @@ -160,13 +144,10 @@ fn build_sysroot_inner( )?; "release" } else { - env.insert( - "RUSTFLAGS".to_string(), - rustflags, - ); + env.insert("RUSTFLAGS".to_string(), rustflags); run_command_with_output_and_env( - &[&"cargo", &"build", &"--target", &config.target], + &[&"cargo", &"build", &"--target", &config.target_triple], Some(start_dir), Some(&env), )?; diff --git a/build_system/src/config.rs b/build_system/src/config.rs index b31a728c68075..267f454644236 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -4,7 +4,6 @@ use std::env as std_env; #[derive(Default)] pub struct ConfigInfo { - pub target: String, pub target_triple: String, pub host_triple: String, pub rustc_command: Vec, @@ -31,10 +30,6 @@ impl ConfigInfo { ) } }, - "--target" => match args.next() { - Some(arg) if !arg.is_empty() => self.target = arg.to_string(), - _ => return Err("Expected a value after `--target`, found nothing".to_string()), - }, "--out-dir" => match args.next() { Some(arg) if !arg.is_empty() => { // env.insert("CARGO_TARGET_DIR".to_string(), arg.to_string()); @@ -83,12 +78,6 @@ impl ConfigInfo { }; self.host_triple = rustc_version_info(Some(&rustc))?.host.unwrap_or_default(); - if !self.target_triple.is_empty() && self.target.is_empty() { - self.target = self.target_triple.clone(); - } - if self.target.is_empty() { - self.target = self.host_triple.clone(); - } if self.target_triple.is_empty() { self.target_triple = self.host_triple.clone(); } @@ -223,7 +212,6 @@ impl ConfigInfo { pub fn show_usage() { println!( "\ - --target [arg] : Set the target to [arg] --target-triple [arg] : Set the target triple to [arg] --out-dir : Location where the files will be generated --release-sysroot : Build sysroot in release mode diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 4e8c176db7379..1e012798cba1e 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -750,7 +750,10 @@ fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> println!("[TEST] rust-lang/regex example shootout-regex-dna"); let mut env = env.clone(); // newer aho_corasick versions throw a deprecation warning - let rustflags = format!("{} --cap-lints warn", env.get("RUSTFLAGS").cloned().unwrap_or_default()); + let rustflags = format!( + "{} --cap-lints warn", + env.get("RUSTFLAGS").cloned().unwrap_or_default() + ); env.insert("RUSTFLAGS".to_string(), rustflags); // Make sure `[codegen mono items] start` doesn't poison the diff run_cargo_command( @@ -799,7 +802,10 @@ fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { println!("[TEST] rust-lang/regex tests"); let mut env = env.clone(); // newer aho_corasick versions throw a deprecation warning - let rustflags = format!("{} --cap-lints warn", env.get("RUSTFLAGS").cloned().unwrap_or_default()); + let rustflags = format!( + "{} --cap-lints warn", + env.get("RUSTFLAGS").cloned().unwrap_or_default() + ); env.insert("RUSTFLAGS".to_string(), rustflags); run_cargo_command( &[ From 53b2759bef791bad51bfcef022f2da432e6a4269 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Nov 2023 22:23:08 +0100 Subject: [PATCH 034/192] Show command which failed --- build_system/src/utils.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 6dfc6a6506aa4..88fce2fcbce18 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -45,6 +45,8 @@ fn check_exit_status( .unwrap_or_default(), exit_status.code() ); + let input = input.iter().map(|i| i.as_ref()).collect::>(); + eprintln!("Command `{:?}` failed", input); if let Some(output) = output { unsafe { let stdout = std::str::from_utf8_unchecked(&output.stdout); From 2ec8d46dd1b6adc116a5efba46b7aad4a5315f86 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Nov 2023 23:54:18 +0100 Subject: [PATCH 035/192] Correctly handle `OVERWRITE_TARGET_TRIPLE` env variable --- build_system/src/config.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 267f454644236..d602cec9f9f58 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -78,6 +78,11 @@ impl ConfigInfo { }; self.host_triple = rustc_version_info(Some(&rustc))?.host.unwrap_or_default(); + if self.target_triple.is_empty() { + if let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") { + self.target_triple = overwrite.clone(); + } + } if self.target_triple.is_empty() { self.target_triple = self.host_triple.clone(); } From 996635bad689a90ba90a8dbf887611f6fa287bab Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Nov 2023 00:04:08 +0100 Subject: [PATCH 036/192] Fix chroot command --- build_system/src/test.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 1e012798cba1e..db3e4d9894d8c 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -345,8 +345,13 @@ fn run_command_in_vm( let sudo_command: &[&dyn AsRef] = &[&"sudo", &"cp", &exe, &vm_exe_path]; run_command_with_env(sudo_command, None, Some(env))?; - let mut vm_command: Vec<&dyn AsRef> = - vec![&"sudo", &"chroot", &"qemu-m68k-static", &inside_vm_exe_path]; + let mut vm_command: Vec<&dyn AsRef> = vec![ + &"sudo", + &"chroot", + &vm_dir, + &"qemu-m68k-static", + &inside_vm_exe_path, + ]; vm_command.extend_from_slice(command); run_command_with_env(&vm_command, Some(&vm_parent_dir), Some(env))?; Ok(()) From ebb7aa0b8575a27e2768c42f1472d3523925357c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 Dec 2023 23:57:16 +0100 Subject: [PATCH 037/192] Apply suggestions --- build_system/src/build.rs | 40 +------ build_system/src/config.rs | 25 ++-- build_system/src/prepare.rs | 7 +- build_system/src/test.rs | 227 ++++++++++++++++-------------------- build_system/src/utils.rs | 47 +++++--- 5 files changed, 156 insertions(+), 190 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 189c393019fd4..618e74be2c0c9 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -67,14 +67,8 @@ impl BuildArg { } } -fn build_sysroot_inner( - env: &HashMap, - sysroot_panic_abort: bool, - sysroot_release_channel: bool, - config: &ConfigInfo, - start_dir: Option<&Path>, -) -> Result<(), String> { - let start_dir = start_dir.unwrap_or_else(|| Path::new(".")); +pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Result<(), String> { + let start_dir = Path::new("build_sysroot"); // Cleanup for previous run // Clean target dir except for build scripts and incremental cache let _ = walk_dir( @@ -121,12 +115,11 @@ fn build_sysroot_inner( // Builds libs let mut rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default(); - if sysroot_panic_abort { + if config.sysroot_panic_abort { rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests"); } - rustflags.push_str(" -Z force-unstable-if-unmarked"); let mut env = env.clone(); - let channel = if sysroot_release_channel { + let channel = if config.sysroot_release_channel { env.insert( "RUSTFLAGS".to_string(), format!("{} -Zmir-opt-level=3", rustflags), @@ -194,21 +187,6 @@ fn build_sysroot_inner( Ok(()) } -pub fn build_sysroot( - env: &HashMap, - sysroot_panic_abort: bool, - sysroot_release_channel: bool, - config: &ConfigInfo, -) -> Result<(), String> { - build_sysroot_inner( - env, - sysroot_panic_abort, - sysroot_release_channel, - config, - Some(Path::new("build_sysroot")), - ) -} - fn build_codegen(args: &mut BuildArg) -> Result<(), String> { let mut env = HashMap::new(); @@ -229,8 +207,7 @@ fn build_codegen(args: &mut BuildArg) -> Result<(), String> { } run_command_with_output_and_env(&command, None, Some(&env))?; - args.config_info - .setup(&mut env, &[], Some(&args.gcc_path))?; + args.config_info.setup(&mut env, Some(&args.gcc_path))?; // We voluntarily ignore the error. let _ = fs::remove_dir_all("target/out"); @@ -243,12 +220,7 @@ fn build_codegen(args: &mut BuildArg) -> Result<(), String> { })?; println!("[BUILD] sysroot"); - build_sysroot( - &env, - args.config_info.sysroot_panic_abort, - args.config_info.sysroot_release_channel, - &args.config_info, - )?; + build_sysroot(&env, &args.config_info)?; Ok(()) } diff --git a/build_system/src/config.rs b/build_system/src/config.rs index d602cec9f9f58..8396681b292a4 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -1,8 +1,9 @@ use crate::utils::{get_gcc_path, get_os_name, rustc_version_info, split_args}; use std::collections::HashMap; use std::env as std_env; +use std::ffi::OsStr; -#[derive(Default)] +#[derive(Default, Debug)] pub struct ConfigInfo { pub target_triple: String, pub host_triple: String, @@ -32,7 +33,6 @@ impl ConfigInfo { }, "--out-dir" => match args.next() { Some(arg) if !arg.is_empty() => { - // env.insert("CARGO_TARGET_DIR".to_string(), arg.to_string()); self.cargo_target_dir = arg.to_string(); } _ => return Err("Expected a value after `--out-dir`, found nothing".to_string()), @@ -44,10 +44,17 @@ impl ConfigInfo { Ok(true) } + pub fn rustc_command_vec(&self) -> Vec<&dyn AsRef> { + let mut command: Vec<&dyn AsRef> = Vec::with_capacity(self.rustc_command.len()); + for arg in self.rustc_command.iter() { + command.push(arg); + } + command + } + pub fn setup( &mut self, env: &mut HashMap, - test_flags: &[String], gcc_path: Option<&str>, ) -> Result<(), String> { env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string()); @@ -90,15 +97,10 @@ impl ConfigInfo { let mut linker = None; if self.host_triple != self.target_triple { - if self.target_triple == "m68k-unknown-linux-gnu" { - linker = Some("-Clinker=m68k-unknown-linux-gnu-gcc".to_string()); - } else if self.target_triple == "aarch64-unknown-linux-gnu" { - // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - linker = Some("-Clinker=aarch64-linux-gnu-gcc".to_string()); - } else { + if self.target_triple.is_empty() { return Err("Unknown non-native platform".to_string()); } - + linker = Some(format!("-Clinker={}-gcc", self.target_triple)); self.run_in_vm = true; } @@ -145,7 +147,7 @@ impl ConfigInfo { // This environment variable is useful in case we want to change options of rustc commands. if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { - rustflags.extend_from_slice(&split_args(&cg_rustflags)); + rustflags.extend_from_slice(&split_args(&cg_rustflags)?); } if let Some(linker) = linker { @@ -162,7 +164,6 @@ impl ConfigInfo { if !env.contains_key(&"FAT_LTO".to_string()) { rustflags.push("-Clto=off".to_string()); } - rustflags.extend_from_slice(test_flags); // FIXME(antoyo): remove once the atomic shim is gone if os_name == "Darwin" { rustflags.extend_from_slice(&[ diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index da9f8953ec3cb..ce9b440be053a 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -1,5 +1,7 @@ use crate::rustc_info::get_rustc_path; -use crate::utils::{cargo_install, git_clone, run_command, run_command_with_output, walk_dir}; +use crate::utils::{ + cargo_install, git_clone, remove_file, run_command, run_command_with_output, walk_dir, +}; use std::fs; use std::path::Path; @@ -137,8 +139,7 @@ fn build_raytracer(repo_dir: &Path) -> Result<(), String> { run_command(&[&"cargo", &"build"], Some(repo_dir))?; let mv_target = repo_dir.join("raytracer_cg_llvm"); if mv_target.is_file() { - std::fs::remove_file(&mv_target) - .map_err(|e| format!("Failed to remove file `{}`: {e:?}", mv_target.display()))?; + remove_file(&mv_target)?; } run_command( &[&"mv", &"target/debug/main", &"raytracer_cg_llvm"], diff --git a/build_system/src/test.rs b/build_system/src/test.rs index db3e4d9894d8c..af2367e668ebb 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -3,11 +3,13 @@ use crate::config::ConfigInfo; use crate::utils::{ get_gcc_path, get_toolchain, run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, split_args, walk_dir, + remove_file, }; use std::collections::{BTreeSet, HashMap}; use std::ffi::OsStr; -use std::fs::remove_dir_all; +use std::fs::{File, remove_dir_all}; +use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -85,7 +87,6 @@ fn show_usage() { `test` command help: --release : Build codegen in release mode - --release-sysroot : Build sysroot in release mode --sysroot-panic-abort : Build the sysroot without unwinding support. --no-default-features : Add `--no-default-features` flag --features [arg] : Add a new feature [arg] @@ -104,7 +105,7 @@ fn show_usage() { println!(" --help : Show this help"); } -#[derive(Default, PartialEq, Eq, Clone, Copy)] +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug)] enum Channel { #[default] Debug, @@ -120,7 +121,7 @@ impl Channel { } } -#[derive(Default)] +#[derive(Default, Debug)] struct TestArg { no_default_features: bool, build_only: bool, @@ -151,7 +152,6 @@ impl TestArg { test_arg.channel = Channel::Release; test_arg.config_info.sysroot_release_channel = true; } - "--release-sysroot" => test_arg.config_info.sysroot_release_channel = true, "--no-default-features" => { // To prevent adding it more than once. if !test_arg.no_default_features { @@ -210,8 +210,19 @@ impl TestArg { get_gcc_path()? }; } + match (test_arg.current_part, test_arg.nb_parts) { + (Some(_), Some(_)) | (None, None) => {} + _ => { + return Err("If either `--current-part` or `--nb-parts` is specified, the other one \ + needs to be specified as well!".to_string()); + } + } Ok(Some(test_arg)) } + + pub fn is_using_gcc_master_branch(&self) -> bool { + !self.no_default_features + } } fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> { @@ -251,10 +262,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> { "lib,dylib" } .to_string(); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/mini_core.rs", &"--crate-name", @@ -268,10 +276,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[BUILD] example"); - command.clear(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/example.rs", &"--crate-type", @@ -283,10 +288,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] mini_core_hello_world"); - command.clear(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/mini_core_hello_world.rs", &"--crate-name", @@ -304,24 +306,19 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"abc", &"bcd", ]; - run_command_in_vm(&command, env, args)?; + maybe_run_command_in_vm(&command, env, args)?; Ok(()) } fn build_sysroot(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[BUILD] sysroot"); - build::build_sysroot( - env, - args.config_info.sysroot_panic_abort, - args.config_info.sysroot_release_channel, - &args.config_info, - )?; + build::build_sysroot(env, &args.config_info)?; Ok(()) } // TODO(GuillaumeGomez): when rewriting in Rust, refactor with the code in tests/lang_tests_common.rs if possible. -fn run_command_in_vm( +fn maybe_run_command_in_vm( command: &[&dyn AsRef], env: &Env, args: &TestArg, @@ -358,12 +355,10 @@ fn run_command_in_vm( } fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { + let cargo_target_dir = Path::new(&args.config_info.cargo_target_dir); // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] arbitrary_self_types_pointers_and_wrappers"); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/arbitrary_self_types_pointers_and_wrappers.rs", &"--crate-name", @@ -374,19 +369,15 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); run_command_with_env(&command, None, Some(env))?; - run_command_in_vm( - &[&Path::new(&args.config_info.cargo_target_dir) - .join("arbitrary_self_types_pointers_and_wrappers")], + maybe_run_command_in_vm( + &[&cargo_target_dir.join("arbitrary_self_types_pointers_and_wrappers")], env, args, )?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] alloc_system"); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/alloc_system.rs", &"--crate-type", @@ -394,19 +385,16 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"--target", &args.config_info.target_triple, ]); - if !args.no_default_features { + if args.is_using_gcc_master_branch() { command.extend_from_slice(&[&"--cfg", &"feature=\"master\""]); } run_command_with_env(&command, None, Some(env))?; // FIXME: doesn't work on m68k. - if args.config_info.host_triple != args.config_info.target_triple { + if args.config_info.host_triple == args.config_info.target_triple { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] alloc_example"); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/alloc_example.rs", &"--crate-type", @@ -415,8 +403,8 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); run_command_with_env(&command, None, Some(env))?; - run_command_in_vm( - &[&Path::new(&args.config_info.cargo_target_dir).join("alloc_example")], + maybe_run_command_in_vm( + &[&cargo_target_dir.join("alloc_example")], env, args, )?; @@ -425,10 +413,7 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] dst_field_align"); // FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed. - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/dst-field-align.rs", &"--crate-name", @@ -439,18 +424,15 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); run_command_with_env(&command, None, Some(env))?; - run_command_in_vm( - &[&Path::new(&args.config_info.cargo_target_dir).join("dst_field_align")], + maybe_run_command_in_vm( + &[&cargo_target_dir.join("dst_field_align")], env, args, )?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] std_example"); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/std_example.rs", &"--crate-type", @@ -458,13 +440,13 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"--target", &args.config_info.target_triple, ]); - if !args.no_default_features { + if args.is_using_gcc_master_branch() { command.extend_from_slice(&[&"--cfg", &"feature=\"master\""]); } run_command_with_env(&command, None, Some(env))?; - run_command_in_vm( + maybe_run_command_in_vm( &[ - &Path::new(&args.config_info.cargo_target_dir).join("std_example"), + &cargo_target_dir.join("std_example"), &"--target", &args.config_info.target_triple, ], @@ -472,12 +454,14 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { args, )?; + let test_flags = if let Some(test_flags) = env.get("TEST_FLAGS") { + split_args(test_flags)? + } else { + Vec::new() + }; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] subslice-patterns-const-eval"); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/subslice-patterns-const-eval.rs", &"--crate-type", @@ -485,19 +469,19 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"--target", &args.config_info.target_triple, ]); + for test_flag in &test_flags { + command.push(test_flag); + } run_command_with_env(&command, None, Some(env))?; - run_command_in_vm( - &[&Path::new(&args.config_info.cargo_target_dir).join("subslice-patterns-const-eval")], + maybe_run_command_in_vm( + &[&cargo_target_dir.join("subslice-patterns-const-eval")], env, args, )?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] track-caller-attribute"); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/track-caller-attribute.rs", &"--crate-type", @@ -505,19 +489,19 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"--target", &args.config_info.target_triple, ]); + for test_flag in &test_flags { + command.push(test_flag); + } run_command_with_env(&command, None, Some(env))?; - run_command_in_vm( - &[&Path::new(&args.config_info.cargo_target_dir).join("track-caller-attribute")], + maybe_run_command_in_vm( + &[&cargo_target_dir.join("track-caller-attribute")], env, args, )?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] mod_bench"); - let mut command: Vec<&dyn AsRef> = Vec::new(); - for arg in args.config_info.rustc_command.iter() { - command.push(arg); - } + let mut command = args.config_info.rustc_command_vec(); command.extend_from_slice(&[ &"example/mod_bench.rs", &"--crate-type", @@ -547,6 +531,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { None => return Err("Couldn't retrieve rustc commit hash".to_string()), }; run_command_with_output_and_env(&[&"git", &"checkout", &rustc_commit], rust_dir, Some(env))?; + // FIXME: Is it really needed to empty `RUSTFLAGS` here? env.insert("RUSTFLAGS".to_string(), String::new()); let cargo = String::from_utf8( run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, @@ -661,7 +646,7 @@ fn run_cargo_command( args: &TestArg, ) -> Result<(), String> { run_cargo_command_with_callback(command, cwd, env, args, |cargo_command, cwd, env| { - run_command_with_output_and_env(&cargo_command, cwd, Some(env))?; + run_command_with_output_and_env(cargo_command, cwd, Some(env))?; Ok(()) }) } @@ -734,7 +719,7 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { // hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_* fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { - if args.no_default_features { + if !args.is_using_gcc_master_branch() { return Ok(()); } let path = Path::new("rand"); @@ -746,7 +731,7 @@ fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { } fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> { - if args.no_default_features { + if !args.is_using_gcc_master_branch() { return Ok(()); } let path = Path::new("regex"); @@ -800,7 +785,7 @@ fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> } fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { - if args.no_default_features { + if !args.is_using_gcc_master_branch() { return Ok(()); } // FIXME: create a function "display_if_not_quiet" or something along the line. @@ -817,6 +802,7 @@ fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"test", &"--tests", &"--", + // FIXME: try removing `--exclude-should-panic` argument &"--exclude-should-panic", &"--test-threads", &"1", @@ -848,24 +834,22 @@ fn extended_sysroot_tests(env: &Env, args: &TestArg) -> Result<(), String> { Ok(()) } -fn should_remove_ui_test(content: &str) -> bool { - for line in content - .lines() - .map(|line| line.trim()) - .filter(|line| !line.is_empty()) - { - if [ - "// error-pattern:", - "// build-fail", - "// run-fail", - "-Cllvm-args", - "//~", - "// ~", - ] - .iter() - .any(|check| line.contains(check)) - { - return true; +fn should_remove_ui_test(file: File) -> bool { + for line in BufReader::new(file).lines() { + if let Ok(line) = line { + if [ + "// error-pattern:", + "// build-fail", + "// run-fail", + "-Cllvm-args", + "//~", + "// ~", + ] + .iter() + .any(|check| line.contains(check)) + { + return true; + } } } false @@ -903,7 +887,7 @@ fn should_remove_test(path: &Path, path_str: &str) -> bool { .any(|to_ignore| path_str.ends_with(to_ignore)) } -fn test_rustc_inner(env: &Env, args: &TestArg, callback: F) -> Result<(), String> +fn test_rustc_inner(env: &Env, args: &TestArg, prepare_files_callback: F) -> Result<(), String> where F: Fn() -> Result, { @@ -937,24 +921,24 @@ where |_| Ok(()), )?; + // These two functions are used to remove files that are known to not be working currently + // with the GCC backend to reduce noise. fn dir_handling(dir: &Path) -> Result<(), String> { walk_dir(dir, dir_handling, file_handling) } - fn file_handling(file: &Path) -> Result<(), String> { - let path_str = file.display().to_string().replace("\\", "/"); + fn file_handling(file_path: &Path) -> Result<(), String> { + let path_str = file_path.display().to_string().replace("\\", "/"); if !path_str.ends_with(".rs") { return Ok(()); } else if should_not_remove_test(&path_str) { return Ok(()); - } else if should_remove_test(file, &path_str) { - return std::fs::remove_file(file) - .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error)); + } else if should_remove_test(file_path, &path_str) { + return remove_file(&file_path); } - let file_content = std::fs::read_to_string(file) - .map_err(|error| format!("Failed to read `{}`: {:?}", file.display(), error))?; - if should_remove_ui_test(&file_content) { - std::fs::remove_file(file) - .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error))?; + let file = File::open(file_path) + .map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?; + if should_remove_ui_test(file) { + remove_file(&file_path)?; } Ok(()) } @@ -963,20 +947,18 @@ where walk_dir(rust_path.join("tests/ui"), dir_handling, file_handling)?; let file = rust_path.join("tests/ui/consts/const_cmp_type_id.rs"); - std::fs::remove_file(&file) - .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error))?; + remove_file(&file)?; let file = rust_path.join("tests/ui/consts/issue-73976-monomorphic.rs"); - std::fs::remove_file(&file) - .map_err(|error| format!("Failed to remove `{}`: {:?}", file.display(), error))?; + remove_file(&file)?; - if !callback()? { + if !prepare_files_callback()? { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("Keeping all UI tests"); } let nb_parts = args.nb_parts.unwrap_or(0); if nb_parts > 0 { - let current_part = args.current_part.unwrap_or(0); + let current_part = args.current_part.unwrap(); // FIXME: create a function "display_if_not_quiet" or something along the line. println!( "Splitting ui_test into {} parts (and running part {})", @@ -1017,18 +999,19 @@ where continue; } let test_path = rust_path.join(path); - std::fs::remove_file(&test_path).map_err(|error| { - format!("Failed to remove `{}`: {:?}", test_path.display(), error) - })?; + remove_file(&test_path)?; } } // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rustc test suite"); env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); - let rustc_args = env - .get("RUSTFLAGS") - .expect("RUSTFLAGS should not be empty at this stage"); + let rustc_args = format!( + "{} {}", + env.get("RUSTFLAGS") + .expect("RUSTFLAGS should not be empty at this stage"), + env.get("TEST_FLAGS").unwrap_or(&String::new()), + ); run_command_with_output_and_env( &[ &"./x.py", @@ -1103,9 +1086,7 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { .filter(|line| !line.is_empty()) { let path = Path::new("rust").join(file); - std::fs::remove_file(&path).map_err(|error| { - format!("failed to remove `{}`: {:?}", path.display(), error) - })?; + remove_file(&path)?; } } else { println!( @@ -1159,9 +1140,7 @@ pub fn run() -> Result<(), String> { return Ok(()); } - let test_flags = split_args(env.get("TEST_FLAGS").unwrap_or(&String::new())); - args.config_info - .setup(&mut env, &test_flags, Some(&args.gcc_path))?; + args.config_info.setup(&mut env, Some(&args.gcc_path))?; if args.runners.is_empty() { run_all(&env, &args)?; diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 88fce2fcbce18..59863fcfd90a1 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::collections::HashMap; use std::ffi::OsStr; use std::fmt::Debug; @@ -48,16 +49,20 @@ fn check_exit_status( let input = input.iter().map(|i| i.as_ref()).collect::>(); eprintln!("Command `{:?}` failed", input); if let Some(output) = output { - unsafe { - let stdout = std::str::from_utf8_unchecked(&output.stdout); - if !stdout.is_empty() { - error.push_str("\n==== STDOUT ====\n"); - error.push_str(stdout); + let stdout = String::from_utf8_lossy(&output.stdout); + if !stdout.is_empty() { + error.push_str("\n==== STDOUT ====\n"); + match stdout { + Cow::Owned(s) => error.push_str(&s), + Cow::Borrowed(s) => error.push_str(s), } - let stderr = std::str::from_utf8_unchecked(&output.stderr); - if !stderr.is_empty() { - error.push_str("\n==== STDERR ====\n"); - error.push_str(stderr); + } + let stderr = String::from_utf8_lossy(&output.stderr); + if !stderr.is_empty() { + error.push_str("\n==== STDERR ====\n"); + match stderr { + Cow::Owned(s) => error.push_str(&s), + Cow::Borrowed(s) => error.push_str(s), } } } @@ -295,17 +300,16 @@ where Ok(()) } -pub fn split_args(args: &str) -> Vec { +pub fn split_args(args: &str) -> Result, String> { let mut out = Vec::new(); let mut start = 0; + let args = args.trim(); let mut iter = args.char_indices().peekable(); while iter.peek().is_some() { while let Some((pos, c)) = iter.next() { if c == ' ' { - if pos != 0 { - out.push(args[start..pos].to_string()); - } + out.push(args[start..pos].to_string()); let mut found_start = false; while let Some((pos, c)) = iter.peek() { if *c != ' ' { @@ -317,7 +321,7 @@ pub fn split_args(args: &str) -> Vec { } } if !found_start { - return out; + return Ok(out); } } else if c == '"' || c == '\'' { let end = c; @@ -332,8 +336,7 @@ pub fn split_args(args: &str) -> Vec { } } if !found_end { - out.push(args[start..].to_string()); - return out; + return Err(format!("Didn't find `{}` at the end of `{}`", end, &args[start..])); } } else if c == '\\' { // We skip the escaped character. @@ -345,5 +348,15 @@ pub fn split_args(args: &str) -> Vec { if !s.is_empty() { out.push(s.to_string()); } - out + Ok(out) +} + +pub fn remove_file>(file_path: &P) -> Result<(), String> { + std::fs::remove_file(file_path).map_err(|error| { + format!( + "Failed to remove `{}`: {:?}", + file_path.as_ref().display(), + error + ) + }) } From 2baa073fb1dc1a3556d174b58e5bc94b28682119 Mon Sep 17 00:00:00 2001 From: quininer Date: Mon, 13 Nov 2023 20:48:23 +0800 Subject: [PATCH 038/192] Add emulated TLS support Currently LLVM uses emutls by default for some targets (such as android, openbsd), but rust does not use it, because `has_thread_local` is false. This commit has some changes to allow users to enable emutls: 1. add `-Zhas-thread-local` flag to specify that std uses `#[thread_local]` instead of pthread key. 2. when using emutls, decorate symbol names to find thread local symbol correctly. 3. change `-Zforce-emulated-tls` to `-Ztls-model=emulated` to explicitly specify whether to generate emutls. --- src/context.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/context.rs b/src/context.rs index a043660ea632b..893cad0516182 100644 --- a/src/context.rs +++ b/src/context.rs @@ -569,5 +569,6 @@ fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel { TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic, TlsModel::InitialExec => gccjit::TlsModel::InitialExec, TlsModel::LocalExec => gccjit::TlsModel::LocalExec, + TlsModel::Emulated => gccjit::TlsModel::GlobalDynamic, } } From 19e11760ab8c2694875f4fdbeb4063706ceae009 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 7 Dec 2023 14:59:37 +0100 Subject: [PATCH 039/192] Update rustc_codegen_gcc libc --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c18633692783..ddfce5d59bde8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" From 3cfff05ac7c880e24c4e89f4e9518e8715d2ef29 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 7 Dec 2023 15:25:46 +0100 Subject: [PATCH 040/192] Allow internal_features in rustc_codegen_gcc examples --- example/std_example.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/example/std_example.rs b/example/std_example.rs index 0f6325c8980e7..ad69409eb6590 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -1,3 +1,4 @@ +#![allow(internal_features)] #![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted)] #[cfg(feature="master")] From cb32ffd8da5831c7052362fa58d27b36558b3b78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Nov 2023 18:41:53 +0100 Subject: [PATCH 041/192] ctfe interpreter: extend provenance so that it can track whether a pointer is immutable --- src/common.rs | 3 ++- src/consts.rs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/common.rs b/src/common.rs index 93fe27e547aef..b7ddc410315c3 100644 --- a/src/common.rs +++ b/src/common.rs @@ -199,7 +199,8 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (alloc_id, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let alloc_id = prov.alloc_id(); let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { diff --git a/src/consts.rs b/src/consts.rs index d8a1fd315c0a5..f06416b9bb5fe 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -285,7 +285,8 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; - for &(offset, alloc_id) in alloc.provenance().ptrs().iter() { + for &(offset, prov) in alloc.provenance().ptrs().iter() { + let alloc_id = prov.alloc_id(); let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; @@ -313,7 +314,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl llvals.push(cx.scalar_to_backend( InterpScalar::from_pointer( - interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), + interpret::Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx, ), abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) }, From 92de9d4210a7e81fd8db558c54367026a68bec62 Mon Sep 17 00:00:00 2001 From: r0cky Date: Mon, 11 Dec 2023 23:12:49 +0800 Subject: [PATCH 042/192] Remove dead codes --- src/common.rs | 11 ----------- src/context.rs | 6 ------ 2 files changed, 17 deletions(-) diff --git a/src/common.rs b/src/common.rs index b7ddc410315c3..c6edd52d1e416 100644 --- a/src/common.rs +++ b/src/common.rs @@ -377,9 +377,6 @@ pub trait TypeReflection<'gcc, 'tcx> { fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; - fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; - fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; - fn is_vector(&self) -> bool; } @@ -464,14 +461,6 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> { self.unqualified() == cx.u128_type.unqualified() } - fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { - self.unqualified() == cx.context.new_type::() - } - - fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { - self.unqualified() == cx.context.new_type::() - } - fn is_vector(&self) -> bool { let mut typ = self.clone(); loop { diff --git a/src/context.rs b/src/context.rs index 893cad0516182..ab9c703db37da 100644 --- a/src/context.rs +++ b/src/context.rs @@ -22,12 +22,6 @@ use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; use crate::callee::get_fn; use crate::common::SignType; -#[derive(Clone)] -pub struct FuncSig<'gcc> { - pub params: Vec>, - pub return_type: Type<'gcc>, -} - pub struct CodegenCx<'gcc, 'tcx> { pub check_overflow: bool, pub codegen_unit: &'tcx CodegenUnit<'tcx>, From a72e20d77378420af6c02daebb9c6b1f3fe9757a Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 11 Dec 2023 18:48:49 +0100 Subject: [PATCH 043/192] Fix rustc codegen gcc tests --- example/mini_core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 3432852034325..db94bc1c86af9 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -4,7 +4,7 @@ thread_local )] #![no_core] -#![allow(dead_code, internal_features)] +#![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)] #[no_mangle] unsafe extern "C" fn _Unwind_Resume() { From 867ea124884cabf81462e152fcfa2cdccd3ed1aa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 5 Dec 2023 21:09:13 +0100 Subject: [PATCH 044/192] Fix non-running rustc ui tests --- build_system/src/build.rs | 2 +- build_system/src/config.rs | 17 ++-- build_system/src/test.rs | 186 ++++++++++++++++++------------------- build_system/src/utils.rs | 6 +- 4 files changed, 108 insertions(+), 103 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 618e74be2c0c9..370d8436e3de1 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -128,9 +128,9 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu &[ &"cargo", &"build", + &"--release", &"--target", &config.target_triple, - &"--release", ], Some(start_dir), Some(&env), diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 8396681b292a4..091186b90660c 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -13,6 +13,8 @@ pub struct ConfigInfo { pub dylib_ext: String, pub sysroot_release_channel: bool, pub sysroot_panic_abort: bool, + pub cg_backend_path: String, + pub sysroot_path: String, } impl ConfigInfo { @@ -118,13 +120,12 @@ impl ConfigInfo { .get("BUILTIN_BACKEND") .map(|backend| !backend.is_empty()) .unwrap_or(false); - let cg_backend_path; let mut rustflags = Vec::new(); if has_builtin_backend { // It means we're building inside the rustc testsuite, so some options need to be handled // a bit differently. - cg_backend_path = "gcc".to_string(); + self.cg_backend_path = "gcc".to_string(); match env.get("RUSTC_SYSROOT") { Some(rustc_sysroot) if !rustc_sysroot.is_empty() => { @@ -134,15 +135,17 @@ impl ConfigInfo { } rustflags.push("-Cpanic=abort".to_string()); } else { - cg_backend_path = current_dir + self.cg_backend_path = current_dir .join("target") .join(channel) .join(&format!("librustc_codegen_gcc.{}", self.dylib_ext)) .display() .to_string(); - let sysroot_path = current_dir.join("build_sysroot/sysroot"); - rustflags - .extend_from_slice(&["--sysroot".to_string(), sysroot_path.display().to_string()]); + self.sysroot_path = current_dir + .join("build_sysroot/sysroot") + .display() + .to_string(); + rustflags.extend_from_slice(&["--sysroot".to_string(), self.sysroot_path.clone()]); }; // This environment variable is useful in case we want to change options of rustc commands. @@ -156,7 +159,7 @@ impl ConfigInfo { rustflags.extend_from_slice(&[ "-Csymbol-mangling-version=v0".to_string(), "-Cdebuginfo=2".to_string(), - format!("-Zcodegen-backend={}", cg_backend_path), + format!("-Zcodegen-backend={}", self.cg_backend_path), ]); // Since we don't support ThinLTO, disable LTO completely when not trying to do LTO. diff --git a/build_system/src/test.rs b/build_system/src/test.rs index af2367e668ebb..efd8ebdd52d91 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -1,14 +1,13 @@ use crate::build; use crate::config::ConfigInfo; use crate::utils::{ - get_gcc_path, get_toolchain, run_command, run_command_with_env, + get_gcc_path, get_toolchain, remove_file, run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, split_args, walk_dir, - remove_file, }; use std::collections::{BTreeSet, HashMap}; use std::ffi::OsStr; -use std::fs::{File, remove_dir_all}; +use std::fs::{remove_dir_all, File}; use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -213,8 +212,11 @@ impl TestArg { match (test_arg.current_part, test_arg.nb_parts) { (Some(_), Some(_)) | (None, None) => {} _ => { - return Err("If either `--current-part` or `--nb-parts` is specified, the other one \ - needs to be specified as well!".to_string()); + return Err( + "If either `--current-part` or `--nb-parts` is specified, the other one \ + needs to be specified as well!" + .to_string(), + ); } } Ok(Some(test_arg)) @@ -230,20 +232,19 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> { return Ok(()); } let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; - if args.channel == Channel::Release { - let mut env = env.clone(); - env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string()); + let mut tmp_env; + let env = if args.channel == Channel::Release { + tmp_env = env.clone(); + tmp_env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string()); command.push(&"--release"); - for flag in args.flags.iter() { - command.push(flag); - } - run_command_with_output_and_env(&command, None, Some(&env)) + &tmp_env } else { - for flag in args.flags.iter() { - command.push(flag); - } - run_command_with_output_and_env(&command, None, Some(&env)) + &env + }; + for flag in args.flags.iter() { + command.push(flag); } + run_command_with_output_and_env(&command, None, Some(env)) } fn clean(_env: &Env, args: &TestArg) -> Result<(), String> { @@ -403,11 +404,7 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); run_command_with_env(&command, None, Some(env))?; - maybe_run_command_in_vm( - &[&cargo_target_dir.join("alloc_example")], - env, - args, - )?; + maybe_run_command_in_vm(&[&cargo_target_dir.join("alloc_example")], env, args)?; } // FIXME: create a function "display_if_not_quiet" or something along the line. @@ -424,11 +421,7 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); run_command_with_env(&command, None, Some(env))?; - maybe_run_command_in_vm( - &[&cargo_target_dir.join("dst_field_align")], - env, - args, - )?; + maybe_run_command_in_vm(&[&cargo_target_dir.join("dst_field_align")], env, args)?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[AOT] std_example"); @@ -525,6 +518,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { None, Some(env), ); + run_command(&[&"git", &"checkout", &"--", &"tests/"], rust_dir)?; run_command_with_output_and_env(&[&"git", &"fetch"], rust_dir, Some(env))?; let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash { Some(commit_hash) => commit_hash, @@ -532,7 +526,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { }; run_command_with_output_and_env(&[&"git", &"checkout", &rustc_commit], rust_dir, Some(env))?; // FIXME: Is it really needed to empty `RUSTFLAGS` here? - env.insert("RUSTFLAGS".to_string(), String::new()); + // env.insert("RUSTFLAGS".to_string(), String::new()); let cargo = String::from_utf8( run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, ) @@ -591,15 +585,6 @@ download-ci-llvm = false ), ) .map_err(|error| format!("Failed to write into `rust/config.toml`: {:?}", error))?; - - let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash { - Some(commit_hash) => commit_hash, - None => return Err("Couldn't retrieve rustc commit hash".to_string()), - }; - // FIXME: create a function "display_if_not_quiet" or something along the line. - println!("commit: {:?}", rustc_commit); - let command: &[&dyn AsRef] = &[&"git", &"checkout", &rustc_commit, &"tests"]; - run_command_with_output_and_env(command, rust_dir, Some(env))?; Ok(()) } @@ -834,27 +819,6 @@ fn extended_sysroot_tests(env: &Env, args: &TestArg) -> Result<(), String> { Ok(()) } -fn should_remove_ui_test(file: File) -> bool { - for line in BufReader::new(file).lines() { - if let Ok(line) = line { - if [ - "// error-pattern:", - "// build-fail", - "// run-fail", - "-Cllvm-args", - "//~", - "// ~", - ] - .iter() - .any(|check| line.contains(check)) - { - return true; - } - } - } - false -} - fn should_not_remove_test(file: &str) -> bool { // contains //~ERROR, but shouldn't be removed [ @@ -870,21 +834,40 @@ fn should_not_remove_test(file: &str) -> bool { .any(|to_ignore| file.ends_with(to_ignore)) } -fn should_remove_test(path: &Path, path_str: &str) -> bool { +fn should_remove_test(file_path: &Path) -> Result { // Tests generating errors. - path.file_name() - .and_then(|name| name.to_str()) - .map(|name| name.contains("thread")) - .unwrap_or(false) - || [ - "consts/issue-miri-1910.rs", - // Tests generating errors. - "consts/issue-94675.rs", - // this test is oom-killed in the CI. - "mir/mir_heavy/issue-miri-1910.rs", + let file = File::open(file_path) + .map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?; + for line in BufReader::new(file).lines().filter_map(|line| line.ok()) { + let line = line.trim(); + if line.is_empty() { + continue; + } + if [ + "// error-pattern:", + "// build-fail", + "// run-fail", + "-Cllvm-args", + "//~", + "thread", ] .iter() - .any(|to_ignore| path_str.ends_with(to_ignore)) + .any(|check| line.contains(check)) + { + return Ok(true); + } + if line.contains("//[") && line.contains("]~") { + return Ok(true); + } + } + if file_path + .display() + .to_string() + .contains("ambiguous-4-extern.rs") + { + eprintln!("nothing found for {file_path:?}"); + } + Ok(false) } fn test_rustc_inner(env: &Env, args: &TestArg, prepare_files_callback: F) -> Result<(), String> @@ -896,6 +879,8 @@ where let mut env = env.clone(); setup_rustc(&mut env, args)?; + let rust_path = Path::new("rust"); + walk_dir( "rust/tests/ui", |dir| { @@ -924,32 +909,41 @@ where // These two functions are used to remove files that are known to not be working currently // with the GCC backend to reduce noise. fn dir_handling(dir: &Path) -> Result<(), String> { + if dir + .file_name() + .map(|name| name == "auxiliary") + .unwrap_or(true) + { + return Ok(()); + } walk_dir(dir, dir_handling, file_handling) } fn file_handling(file_path: &Path) -> Result<(), String> { - let path_str = file_path.display().to_string().replace("\\", "/"); - if !path_str.ends_with(".rs") { + if !file_path + .extension() + .map(|extension| extension == "rs") + .unwrap_or(false) + { return Ok(()); - } else if should_not_remove_test(&path_str) { + } + let path_str = file_path.display().to_string().replace("\\", "/"); + if should_not_remove_test(&path_str) { return Ok(()); - } else if should_remove_test(file_path, &path_str) { + } else if should_remove_test(file_path)? { return remove_file(&file_path); } - let file = File::open(file_path) - .map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?; - if should_remove_ui_test(file) { - remove_file(&file_path)?; - } Ok(()) } - let rust_path = Path::new("rust"); + remove_file(&rust_path.join("tests/ui/consts/const_cmp_type_id.rs"))?; + remove_file(&rust_path.join("tests/ui/consts/issue-73976-monomorphic.rs"))?; + // this test is oom-killed in the CI. + remove_file(&rust_path.join("tests/ui/consts/issue-miri-1910.rs"))?; + // Tests generating errors. + remove_file(&rust_path.join("tests/ui/consts/issue-94675.rs"))?; + remove_file(&rust_path.join("tests/ui/mir/mir_heavy_promoted.rs"))?; walk_dir(rust_path.join("tests/ui"), dir_handling, file_handling)?; - let file = rust_path.join("tests/ui/consts/const_cmp_type_id.rs"); - remove_file(&file)?; - let file = rust_path.join("tests/ui/consts/issue-73976-monomorphic.rs"); - remove_file(&file)?; if !prepare_files_callback()? { // FIXME: create a function "display_if_not_quiet" or something along the line. @@ -992,14 +986,16 @@ where // We increment the number of tests by one because if this is an odd number, we would skip // one test. let count = files.len() / nb_parts + 1; - let start = nb_parts * count; - let end = start + count; - for (pos, path) in files.iter().enumerate() { - if pos >= start && pos <= end { - continue; - } - let test_path = rust_path.join(path); - remove_file(&test_path)?; + let start = current_part * count; + let end = current_part * count + count; + // We remove the files we don't want to test. + for path in files + .iter() + .enumerate() + .filter(|(pos, _)| *pos < start || *pos >= end) + .map(|(_, path)| path) + { + remove_file(&rust_path.join(path))?; } } @@ -1007,11 +1003,13 @@ where println!("[TEST] rustc test suite"); env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); let rustc_args = format!( - "{} {}", - env.get("RUSTFLAGS") - .expect("RUSTFLAGS should not be empty at this stage"), + "{} -Csymbol-mangling-version=v0 -Zcodegen-backend={} --sysroot {}", env.get("TEST_FLAGS").unwrap_or(&String::new()), + args.config_info.cg_backend_path, + args.config_info.sysroot_path, ); + + env.get_mut("RUSTFLAGS").unwrap().clear(); run_command_with_output_and_env( &[ &"./x.py", diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 59863fcfd90a1..9d785e7f57cf4 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -336,7 +336,11 @@ pub fn split_args(args: &str) -> Result, String> { } } if !found_end { - return Err(format!("Didn't find `{}` at the end of `{}`", end, &args[start..])); + return Err(format!( + "Didn't find `{}` at the end of `{}`", + end, + &args[start..] + )); } } else if c == '\\' { // We skip the escaped character. From e1f039f5628f665dead2c9a13b4c32ffe92336ac Mon Sep 17 00:00:00 2001 From: Lukasz Anforowicz Date: Wed, 13 Dec 2023 21:14:18 +0000 Subject: [PATCH 045/192] Add unstable `-Zdefault-hidden-visibility` cmdline flag for `rustc`. The new flag has been described in the Major Change Proposal at https://github.com/rust-lang/compiler-team/issues/656 --- src/allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allocator.rs b/src/allocator.rs index c8c098e2973f0..7c7044830f3d4 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -90,7 +90,7 @@ fn create_wrapper_function( .collect(); let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, from_name, false); - if tcx.sess.target.options.default_hidden_visibility { + if tcx.sess.default_hidden_visibility() { #[cfg(feature="master")] func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); } From b1affb9321442f378ee06fbaf0ebdc3317e5c9fe Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 12 Dec 2023 21:47:20 +0100 Subject: [PATCH 046/192] Move rustc_codegen_ssa target features to rustc_target --- src/gcc_util.rs | 8 +++----- src/lib.rs | 5 +++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/gcc_util.rs b/src/gcc_util.rs index 1248fdcd2599c..2aa84f26797c3 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -2,12 +2,10 @@ use gccjit::Context; use smallvec::{smallvec, SmallVec}; -use rustc_codegen_ssa::target_features::{ - supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES, -}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; use rustc_session::Session; +use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use crate::errors::{PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; @@ -44,7 +42,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> // Given a map from target_features to whether they are enabled or disabled, // ensure only valid combinations are allowed. pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> { - for tied in tied_target_features(sess) { + for tied in sess.target.tied_target_features() { // Tied features must be set to the same value, or not set at all let mut tied_iter = tied.iter(); let enabled = features.get(tied_iter.next().unwrap()); diff --git a/src/lib.rs b/src/lib.rs index d54057615d2d8..0ececc5dda0a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,7 +97,6 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; -use rustc_codegen_ssa::target_features::supported_target_features; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; @@ -397,7 +396,9 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { } pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &LockedTargetInfo) -> Vec { - supported_target_features(sess) + sess + .target + .supported_target_features() .iter() .filter_map( |&(feature, gate)| { From db9b932314023318f49b0b5941d09f034a12b31e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 13 Dec 2023 21:35:05 +0100 Subject: [PATCH 047/192] Fix sysroot build --- build_system/src/build.rs | 8 +++----- build_system/src/config.rs | 24 +++++++++++++++++++++++- build_system/src/test.rs | 27 +++------------------------ 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 370d8436e3de1..9fb47195aeed7 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -1,4 +1,4 @@ -use crate::config::ConfigInfo; +use crate::config::{Channel, ConfigInfo}; use crate::utils::{get_gcc_path, run_command, run_command_with_output_and_env, walk_dir}; use std::collections::HashMap; use std::ffi::OsStr; @@ -7,7 +7,6 @@ use std::path::Path; #[derive(Default)] struct BuildArg { - codegen_release_channel: bool, flags: Vec, gcc_path: String, config_info: ConfigInfo, @@ -25,7 +24,6 @@ impl BuildArg { while let Some(arg) = args.next() { match arg.as_str() { - "--release" => build_arg.codegen_release_channel = true, "--no-default-features" => { build_arg.flags.push("--no-default-features".to_string()); } @@ -58,7 +56,6 @@ impl BuildArg { r#" `build` command help: - --release : Build codegen in release mode --no-default-features : Add `--no-default-features` flag --features [arg] : Add a new feature [arg]"# ); @@ -118,6 +115,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu if config.sysroot_panic_abort { rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests"); } + rustflags.push_str(" -Z force-unstable-if-unmarked"); let mut env = env.clone(); let channel = if config.sysroot_release_channel { env.insert( @@ -194,7 +192,7 @@ fn build_codegen(args: &mut BuildArg) -> Result<(), String> { env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone()); let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; - if args.codegen_release_channel { + if args.config_info.channel == Channel::Release { command.push(&"--release"); env.insert("CHANNEL".to_string(), "release".to_string()); env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string()); diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 091186b90660c..09375791aa314 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -3,6 +3,22 @@ use std::collections::HashMap; use std::env as std_env; use std::ffi::OsStr; +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug)] +pub enum Channel { + #[default] + Debug, + Release, +} + +impl Channel { + pub fn as_str(self) -> &'static str { + match self { + Self::Debug => "debug", + Self::Release => "release", + } + } +} + #[derive(Default, Debug)] pub struct ConfigInfo { pub target_triple: String, @@ -12,6 +28,7 @@ pub struct ConfigInfo { pub cargo_target_dir: String, pub dylib_ext: String, pub sysroot_release_channel: bool, + pub channel: Channel, pub sysroot_panic_abort: bool, pub cg_backend_path: String, pub sysroot_path: String, @@ -40,6 +57,7 @@ impl ConfigInfo { _ => return Err("Expected a value after `--out-dir`, found nothing".to_string()), }, "--release-sysroot" => self.sysroot_release_channel = true, + "--release" => self.channel = Channel::Release, "--sysroot-panic-abort" => self.sysroot_panic_abort = true, _ => return Ok(false), } @@ -108,7 +126,7 @@ impl ConfigInfo { let current_dir = std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?; - let channel = if self.sysroot_release_channel { + let channel = if self.channel == Channel::Release { "release" } else if let Some(channel) = env.get("CHANNEL") { channel.as_str() @@ -152,6 +170,9 @@ impl ConfigInfo { if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { rustflags.extend_from_slice(&split_args(&cg_rustflags)?); } + if let Some(test_flags) = env.get("TEST_FLAGS") { + rustflags.extend_from_slice(&split_args(&test_flags)?); + } if let Some(linker) = linker { rustflags.push(linker.to_string()); @@ -223,6 +244,7 @@ impl ConfigInfo { "\ --target-triple [arg] : Set the target triple to [arg] --out-dir : Location where the files will be generated + --release : Build in release mode --release-sysroot : Build sysroot in release mode --sysroot-panic-abort : Build the sysroot without unwinding support." ); diff --git a/build_system/src/test.rs b/build_system/src/test.rs index efd8ebdd52d91..1e9652d282200 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -1,5 +1,5 @@ use crate::build; -use crate::config::ConfigInfo; +use crate::config::{Channel, ConfigInfo}; use crate::utils::{ get_gcc_path, get_toolchain, remove_file, run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, split_args, walk_dir, @@ -104,28 +104,11 @@ fn show_usage() { println!(" --help : Show this help"); } -#[derive(Default, PartialEq, Eq, Clone, Copy, Debug)] -enum Channel { - #[default] - Debug, - Release, -} - -impl Channel { - pub fn as_str(self) -> &'static str { - match self { - Self::Debug => "debug", - Self::Release => "release", - } - } -} - #[derive(Default, Debug)] struct TestArg { no_default_features: bool, build_only: bool, gcc_path: String, - channel: Channel, use_backend: bool, runners: BTreeSet, flags: Vec, @@ -147,10 +130,6 @@ impl TestArg { while let Some(arg) = args.next() { match arg.as_str() { - "--release" => { - test_arg.channel = Channel::Release; - test_arg.config_info.sysroot_release_channel = true; - } "--no-default-features" => { // To prevent adding it more than once. if !test_arg.no_default_features { @@ -233,7 +212,7 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> { } let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; let mut tmp_env; - let env = if args.channel == Channel::Release { + let env = if args.config_info.channel == Channel::Release { tmp_env = env.clone(); tmp_env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string()); command.push(&"--release"); @@ -613,7 +592,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { pwd = std::env::current_dir() .map_err(|error| format!("`current_dir` failed: {:?}", error))? .display(), - channel = args.channel.as_str(), + channel = args.config_info.channel.as_str(), dylib_ext = args.config_info.dylib_ext, ) .as_str(), From 95dfe5ec9040bcba53a8dd61d3593d182defab71 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 16 Dec 2023 17:39:58 +0100 Subject: [PATCH 048/192] Simplify `split_args` code, add a unit test for it and run it into CI --- .github/workflows/ci.yml | 9 ++++ build_system/src/utils.rs | 95 ++++++++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e361bf617b1f..b04ea1550ba2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,3 +131,12 @@ jobs: steps: - uses: actions/checkout@v3 - run: python tools/check_intrinsics_duplicates.py + + build_system: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Test build system + run: | + cd build_system + cargo test diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 9d785e7f57cf4..ebfa41c761cee 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -306,46 +306,44 @@ pub fn split_args(args: &str) -> Result, String> { let args = args.trim(); let mut iter = args.char_indices().peekable(); - while iter.peek().is_some() { - while let Some((pos, c)) = iter.next() { - if c == ' ' { - out.push(args[start..pos].to_string()); - let mut found_start = false; - while let Some((pos, c)) = iter.peek() { - if *c != ' ' { - start = *pos; - found_start = true; - break; - } else { - iter.next(); - } + while let Some((pos, c)) = iter.next() { + if c == ' ' { + out.push(args[start..pos].to_string()); + let mut found_start = false; + while let Some((pos, c)) = iter.peek() { + if *c != ' ' { + start = *pos; + found_start = true; + break; + } else { + iter.next(); } - if !found_start { - return Ok(out); - } - } else if c == '"' || c == '\'' { - let end = c; - let mut found_end = false; - while let Some((_, c)) = iter.next() { - if c == end { - found_end = true; - break; - } else if c == '\\' { - // We skip the escaped character. - iter.next(); - } - } - if !found_end { - return Err(format!( - "Didn't find `{}` at the end of `{}`", - end, - &args[start..] - )); + } + if !found_start { + return Ok(out); + } + } else if c == '"' || c == '\'' { + let end = c; + let mut found_end = false; + while let Some((_, c)) = iter.next() { + if c == end { + found_end = true; + break; + } else if c == '\\' { + // We skip the escaped character. + iter.next(); } - } else if c == '\\' { - // We skip the escaped character. - iter.next(); } + if !found_end { + return Err(format!( + "Didn't find `{}` at the end of `{}`", + end, + &args[start..] + )); + } + } else if c == '\\' { + // We skip the escaped character. + iter.next(); } } let s = args[start..].trim(); @@ -364,3 +362,26 @@ pub fn remove_file>(file_path: &P) -> Result<(), String> { ) }) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_split_args() { + // Missing `"` at the end. + assert!(split_args("\"tada").is_err()); + // Missing `'` at the end. + assert!(split_args("\'tada").is_err()); + + assert_eq!( + split_args("a \"b\" c"), + Ok(vec!["a".to_string(), "\"b\"".to_string(), "c".to_string()]) + ); + // Trailing whitespace characters. + assert_eq!( + split_args(" a \"b\" c "), + Ok(vec!["a".to_string(), "\"b\"".to_string(), "c".to_string()]) + ); + } +} From 9882d7c511fcfed404c547a64cbc42b6cf3fc17c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 16 Dec 2023 17:55:53 +0100 Subject: [PATCH 049/192] Apply suggestions --- build_system/src/build.rs | 4 ++-- build_system/src/config.rs | 12 ++++++++++++ build_system/src/test.rs | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 9fb47195aeed7..d264aac7effbd 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -128,7 +128,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu &"build", &"--release", &"--target", - &config.target_triple, + &config.target, ], Some(start_dir), Some(&env), @@ -138,7 +138,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu env.insert("RUSTFLAGS".to_string(), rustflags); run_command_with_output_and_env( - &[&"cargo", &"build", &"--target", &config.target_triple], + &[&"cargo", &"build", &"--target", &config.target], Some(start_dir), Some(&env), )?; diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 09375791aa314..d948572bda567 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -21,6 +21,7 @@ impl Channel { #[derive(Default, Debug)] pub struct ConfigInfo { + pub target: String, pub target_triple: String, pub host_triple: String, pub rustc_command: Vec, @@ -42,6 +43,13 @@ impl ConfigInfo { args: &mut impl Iterator, ) -> Result { match arg { + "--target" => { + if let Some(arg) = args.next() { + self.target = arg; + } else { + return Err("Expected a value after `--target`, found nothing".to_string()); + } + } "--target-triple" => match args.next() { Some(arg) if !arg.is_empty() => self.target_triple = arg.to_string(), _ => { @@ -113,6 +121,9 @@ impl ConfigInfo { if self.target_triple.is_empty() { self.target_triple = self.host_triple.clone(); } + if self.target.is_empty() && !self.target_triple.is_empty() { + self.target = self.target_triple.clone(); + } let mut linker = None; @@ -243,6 +254,7 @@ impl ConfigInfo { println!( "\ --target-triple [arg] : Set the target triple to [arg] + --target [arg] : Set the target to [arg] --out-dir : Location where the files will be generated --release : Build in release mode --release-sysroot : Build sysroot in release mode diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 1e9652d282200..a926ee4c79ebd 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -482,7 +482,7 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { &args.config_info.target_triple, ]); run_command_with_env(&command, None, Some(env))?; - // FIXME: the compiled binary is not run. Is it normal? + // FIXME: the compiled binary is not run. Ok(()) } From 590e0d9573bcde7637b9c0a00c96a6e18d887b70 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 17 Dec 2023 21:48:57 +1100 Subject: [PATCH 050/192] Rename `Handler` as `DiagCtxt`. --- src/back/lto.rs | 6 +++--- src/back/write.rs | 6 +++--- src/errors.rs | 5 +++-- src/lib.rs | 8 ++++---- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index 529454b119e86..289b93fab876a 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -30,7 +30,7 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{FatalError, Handler}; +use rustc_errors::{FatalError, DiagCtxt}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; @@ -61,7 +61,7 @@ struct LtoData { tmp_path: TempDir, } -fn prepare_lto(cgcx: &CodegenContext, diag_handler: &Handler) -> Result { +fn prepare_lto(cgcx: &CodegenContext, diag_handler: &DiagCtxt) -> Result { let export_threshold = match cgcx.lto { // We're just doing LTO for our one crate Lto::ThinLocal => SymbolExportLevel::Rust, @@ -192,7 +192,7 @@ pub(crate) fn run_fat( ) } -fn fat_lto(cgcx: &CodegenContext, _diag_handler: &Handler, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, +fn fat_lto(cgcx: &CodegenContext, _diag_handler: &DiagCtxt, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[*const libc::c_char], ) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); diff --git a/src/back/write.rs b/src/back/write.rs index 04772d7707abd..c2438d7ca36fd 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -4,7 +4,7 @@ use gccjit::OutputKind; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; -use rustc_errors::Handler; +use rustc_errors::DiagCtxt; use rustc_fs_util::link_or_copy; use rustc_session::config::OutputType; use rustc_span::fatal_error::FatalError; @@ -13,7 +13,7 @@ use rustc_target::spec::SplitDebuginfo; use crate::{GccCodegenBackend, GccContext}; use crate::errors::CopyBitcode; -pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig) -> Result { +pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; @@ -148,7 +148,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_hand )) } -pub(crate) fn link(_cgcx: &CodegenContext, _diag_handler: &Handler, mut _modules: Vec>) -> Result, FatalError> { +pub(crate) fn link(_cgcx: &CodegenContext, _diag_handler: &DiagCtxt, mut _modules: Vec>) -> Result, FatalError> { unimplemented!(); } diff --git a/src/errors.rs b/src/errors.rs index 5fc4b12d7e699..0261d5cd59044 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,6 @@ use rustc_errors::{ - DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, IntoDiagnosticArg, + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, + IntoDiagnosticArg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -111,7 +112,7 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + fn into_diagnostic(self, handler: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.set_span(span); diff --git a/src/lib.rs b/src/lib.rs index 0ececc5dda0a9..cbe03f4051ed3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; -use rustc_errors::{ErrorGuaranteed, Handler}; +use rustc_errors::{ErrorGuaranteed, DiagCtxt}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::util::Providers; @@ -330,7 +330,7 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!() } - unsafe fn optimize(_cgcx: &CodegenContext, _diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig) -> Result<(), FatalError> { + unsafe fn optimize(_cgcx: &CodegenContext, _diag_handler: &DiagCtxt, module: &ModuleCodegen, config: &ModuleConfig) -> Result<(), FatalError> { module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); Ok(()) } @@ -344,7 +344,7 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!(); } - unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig) -> Result { + unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { back::write::codegen(cgcx, diag_handler, module, config) } @@ -356,7 +356,7 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!(); } - fn run_link(cgcx: &CodegenContext, diag_handler: &Handler, modules: Vec>) -> Result, FatalError> { + fn run_link(cgcx: &CodegenContext, diag_handler: &DiagCtxt, modules: Vec>) -> Result, FatalError> { back::write::link(cgcx, diag_handler, modules) } } From a5c63ae13b8e5f37bb5e58ce44fd6d3a6fb503e1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 08:43:59 +1100 Subject: [PATCH 051/192] Rename `CodegenContext::create_diag_handler` as `CodegenContext::create_dcx`. --- src/back/lto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index 289b93fab876a..ee8da7c6cb736 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -183,7 +183,7 @@ pub(crate) fn run_fat( modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result, FatalError> { - let diag_handler = cgcx.create_diag_handler(); + let diag_handler = cgcx.create_dcx(); let lto_data = prepare_lto(cgcx, &diag_handler)?; /*let symbols_below_threshold = lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>();*/ From 5ea71c1150a7ef7a35be240c0e0d40525a94afe0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 10:15:45 +1100 Subject: [PATCH 052/192] Rename many `DiagCtxt` arguments. --- src/back/lto.rs | 20 ++++++++++---------- src/back/write.rs | 8 ++++---- src/errors.rs | 4 ++-- src/lib.rs | 10 +++++----- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index ee8da7c6cb736..c21b768682399 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -61,7 +61,7 @@ struct LtoData { tmp_path: TempDir, } -fn prepare_lto(cgcx: &CodegenContext, diag_handler: &DiagCtxt) -> Result { +fn prepare_lto(cgcx: &CodegenContext, dcx: &DiagCtxt) -> Result { let export_threshold = match cgcx.lto { // We're just doing LTO for our one crate Lto::ThinLocal => SymbolExportLevel::Rust, @@ -106,18 +106,18 @@ fn prepare_lto(cgcx: &CodegenContext, diag_handler: &DiagCtxt // Make sure we actually can run LTO for crate_type in cgcx.crate_types.iter() { if !crate_type_allows_lto(*crate_type) { - diag_handler.emit_err(LtoDisallowed); + dcx.emit_err(LtoDisallowed); return Err(FatalError); } else if *crate_type == CrateType::Dylib { if !cgcx.opts.unstable_opts.dylib_lto { - diag_handler.emit_err(LtoDylib); + dcx.emit_err(LtoDylib); return Err(FatalError); } } } if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto { - diag_handler.emit_err(DynamicLinkingWithLTO); + dcx.emit_err(DynamicLinkingWithLTO); return Err(FatalError); } @@ -154,7 +154,7 @@ fn prepare_lto(cgcx: &CodegenContext, diag_handler: &DiagCtxt upstream_modules.push((module, CString::new(name).unwrap())); } Err(e) => { - diag_handler.emit_err(e); + dcx.emit_err(e); return Err(FatalError); } } @@ -183,16 +183,16 @@ pub(crate) fn run_fat( modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result, FatalError> { - let diag_handler = cgcx.create_dcx(); - let lto_data = prepare_lto(cgcx, &diag_handler)?; + let dcx = cgcx.create_dcx(); + let lto_data = prepare_lto(cgcx, &dcx)?; /*let symbols_below_threshold = lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>();*/ - fat_lto(cgcx, &diag_handler, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path, + fat_lto(cgcx, &dcx, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path, //&symbols_below_threshold, ) } -fn fat_lto(cgcx: &CodegenContext, _diag_handler: &DiagCtxt, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, +fn fat_lto(cgcx: &CodegenContext, _dcx: &DiagCtxt, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[*const libc::c_char], ) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); @@ -257,7 +257,7 @@ fn fat_lto(cgcx: &CodegenContext, _diag_handler: &DiagCtxt, m let (buffer, name) = serialized_modules.remove(0); info!("no in-memory regular modules to choose from, parsing {:?}", name); ModuleCodegen { - module_llvm: GccContext::parse(cgcx, &name, buffer.data(), diag_handler)?, + module_llvm: GccContext::parse(cgcx, &name, buffer.data(), dcx)?, name: name.into_string().unwrap(), kind: ModuleKind::Regular, }*/ diff --git a/src/back/write.rs b/src/back/write.rs index c2438d7ca36fd..2f8a54f529cc5 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -13,7 +13,7 @@ use rustc_target::spec::SplitDebuginfo; use crate::{GccCodegenBackend, GccContext}; use crate::errors::CopyBitcode; -pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { +pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; @@ -127,12 +127,12 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_hand EmitObj::Bitcode => { debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); if let Err(err) = link_or_copy(&bc_out, &obj_out) { - diag_handler.emit_err(CopyBitcode { err }); + dcx.emit_err(CopyBitcode { err }); } if !config.emit_bc { debug!("removing_bitcode {:?}", bc_out); - ensure_removed(diag_handler, &bc_out); + ensure_removed(dcx, &bc_out); } } @@ -148,7 +148,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_hand )) } -pub(crate) fn link(_cgcx: &CodegenContext, _diag_handler: &DiagCtxt, mut _modules: Vec>) -> Result, FatalError> { +pub(crate) fn link(_cgcx: &CodegenContext, _dcx: &DiagCtxt, mut _modules: Vec>) -> Result, FatalError> { unimplemented!(); } diff --git a/src/errors.rs b/src/errors.rs index 0261d5cd59044..766d90cf72407 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -112,8 +112,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, handler: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); + fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = dcx.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.set_span(span); }; diff --git a/src/lib.rs b/src/lib.rs index cbe03f4051ed3..1f3f909d8b4f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,7 +330,7 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!() } - unsafe fn optimize(_cgcx: &CodegenContext, _diag_handler: &DiagCtxt, module: &ModuleCodegen, config: &ModuleConfig) -> Result<(), FatalError> { + unsafe fn optimize(_cgcx: &CodegenContext, _dcx: &DiagCtxt, module: &ModuleCodegen, config: &ModuleConfig) -> Result<(), FatalError> { module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); Ok(()) } @@ -344,8 +344,8 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!(); } - unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { - back::write::codegen(cgcx, diag_handler, module, config) + unsafe fn codegen(cgcx: &CodegenContext, dcx: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { + back::write::codegen(cgcx, dcx, module, config) } fn prepare_thin(_module: ModuleCodegen) -> (String, Self::ThinBuffer) { @@ -356,8 +356,8 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!(); } - fn run_link(cgcx: &CodegenContext, diag_handler: &DiagCtxt, modules: Vec>) -> Result, FatalError> { - back::write::link(cgcx, diag_handler, modules) + fn run_link(cgcx: &CodegenContext, dcx: &DiagCtxt, modules: Vec>) -> Result, FatalError> { + back::write::link(cgcx, dcx, modules) } } From 472ea06999ce6ecfb78554a74b14dec9dae97f38 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 14:12:39 +1100 Subject: [PATCH 053/192] Add `level` arg to `into_diagnostic`. And make all hand-written `IntoDiagnostic` impls generic, by using `DiagnosticBuilder::new(dcx, level, ...)` instead of e.g. `dcx.struct_err(...)`. This means the `create_*` functions are the source of the error level. This change will let us remove `struct_diagnostic`. Note: `#[rustc_lint_diagnostics]` is added to `DiagnosticBuilder::new`, it's necessary to pass diagnostics tests now that it's used in `into_diagnostic` functions. --- src/errors.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 766d90cf72407..1b1ed0b411c71 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, - IntoDiagnosticArg, + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + IntoDiagnosticArg, Level, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -111,9 +111,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { #[help(codegen_gcc_missing_features)] pub(crate) struct MissingFeatures; -impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); +impl IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new( + dcx, + level, + fluent::codegen_gcc_target_feature_disable_or_enable + ); if let Some(span) = self.span { diag.set_span(span); }; From a8b0e30a8b5c9b97b83bdabd700c0f6e92e0f96d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 18 Dec 2023 23:25:23 +0100 Subject: [PATCH 054/192] Error earlier if the rustc host cannot be found --- build_system/src/config.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index d948572bda567..b61c65f7b0220 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -111,7 +111,10 @@ impl ConfigInfo { Some(r) if !r.is_empty() => r.to_string(), _ => "rustc".to_string(), }; - self.host_triple = rustc_version_info(Some(&rustc))?.host.unwrap_or_default(); + self.host_triple = match rustc_version_info(Some(&rustc))?.host { + Some(host) => host, + None => return Err("no host found".to_string()), + }; if self.target_triple.is_empty() { if let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") { @@ -216,6 +219,8 @@ impl ConfigInfo { )); let ld_library_path = format!( "{target}:{sysroot}:{gcc_path}", + // FIXME: It's possible to pick another out directory. Would be nice to have a command + // line option to change it. target = current_dir.join("target/out").display(), sysroot = sysroot.display(), ); From f516c9681133788c6ff20932e443226ffef98d5c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Dec 2023 01:07:01 +0100 Subject: [PATCH 055/192] Add comment about why `-Cpanic=abort` option is needed --- build_system/src/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index b61c65f7b0220..1824bdd292ffa 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -165,6 +165,8 @@ impl ConfigInfo { } _ => {} } + // This should not be needed, but is necessary for the CI in the rust repository. + // FIXME: Remove when the rust CI switches to the master version of libgccjit. rustflags.push("-Cpanic=abort".to_string()); } else { self.cg_backend_path = current_dir From bb4fd2c638fa31c0121255e8548488381ab39041 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Dec 2023 01:16:29 +0100 Subject: [PATCH 056/192] Simplify code by removing unneeded pattern matching --- build_system/src/utils.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index ebfa41c761cee..9c3a86ad68a2a 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::collections::HashMap; use std::ffi::OsStr; use std::fmt::Debug; @@ -52,18 +51,12 @@ fn check_exit_status( let stdout = String::from_utf8_lossy(&output.stdout); if !stdout.is_empty() { error.push_str("\n==== STDOUT ====\n"); - match stdout { - Cow::Owned(s) => error.push_str(&s), - Cow::Borrowed(s) => error.push_str(s), - } + error.push_str(&*stdout); } let stderr = String::from_utf8_lossy(&output.stderr); if !stderr.is_empty() { error.push_str("\n==== STDERR ====\n"); - match stderr { - Cow::Owned(s) => error.push_str(&s), - Cow::Borrowed(s) => error.push_str(s), - } + error.push_str(&*stderr); } } Err(error) From 984e045848ff28294d86471478286307942680da Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Dec 2023 16:54:02 +0100 Subject: [PATCH 057/192] Show output of `--mini-tests` and `--std-tests` commands --- build_system/src/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index a926ee4c79ebd..13828e461913b 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -304,7 +304,7 @@ fn maybe_run_command_in_vm( args: &TestArg, ) -> Result<(), String> { if !args.config_info.run_in_vm { - run_command_with_env(command, None, Some(env))?; + run_command_with_output_and_env(command, None, Some(env))?; return Ok(()); } let vm_parent_dir = match env.get("CG_GCC_VM_DIR") { @@ -330,7 +330,7 @@ fn maybe_run_command_in_vm( &inside_vm_exe_path, ]; vm_command.extend_from_slice(command); - run_command_with_env(&vm_command, Some(&vm_parent_dir), Some(env))?; + run_command_with_output_and_env(&vm_command, Some(&vm_parent_dir), Some(env))?; Ok(()) } From a46066ca230a421ef40bf1136ec030cc10afab84 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Dec 2023 16:55:22 +0100 Subject: [PATCH 058/192] Remove ignored commands from gcc12 CI --- .github/workflows/gcc12.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index 1a17b936c743e..a27ef913c21d6 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -28,9 +28,6 @@ jobs: # FIXME: re-enable asm tests when GCC can emit in the right syntax. # "--asm-tests", "--test-libcore", - "--extended-rand-tests", - "--extended-regex-example-tests", - "--extended-regex-tests", "--test-successful-rustc --nb-parts 2 --current-part 0", "--test-successful-rustc --nb-parts 2 --current-part 1", ] From 6e53832eda190141516e0faeb4651eecfe3710be Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Dec 2023 21:15:28 +0100 Subject: [PATCH 059/192] Simplify `Runner` type alias --- build_system/src/test.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 13828e461913b..f368e5b420e6f 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; type Env = HashMap; -type Runner = &'static dyn Fn(&Env, &TestArg) -> Result<(), String>; +type Runner = fn(&Env, &TestArg) -> Result<(), String>; type Runners = HashMap<&'static str, (&'static str, Runner)>; fn get_runners() -> Runners { @@ -21,42 +21,42 @@ fn get_runners() -> Runners { runners.insert( "--test-rustc", - ("Run all rustc tests", &test_rustc as Runner), + ("Run all rustc tests", test_rustc as Runner), ); runners.insert( "--test-successful-rustc", - ("Run successful rustc tests", &test_successful_rustc), + ("Run successful rustc tests", test_successful_rustc), ); runners.insert( "--test-failing-rustc", - ("Run failing rustc tests", &test_failing_rustc), + ("Run failing rustc tests", test_failing_rustc), ); - runners.insert("--test-libcore", ("Run libcore tests", &test_libcore)); - runners.insert("--clean-ui-tests", ("Clean ui tests", &clean_ui_tests)); - runners.insert("--clean", ("Empty cargo target directory", &clean)); - runners.insert("--build-sysroot", ("Build sysroot", &build_sysroot)); - runners.insert("--std-tests", ("Run std tests", &std_tests)); - runners.insert("--asm-tests", ("Run asm tests", &asm_tests)); + runners.insert("--test-libcore", ("Run libcore tests", test_libcore)); + runners.insert("--clean-ui-tests", ("Clean ui tests", clean_ui_tests)); + runners.insert("--clean", ("Empty cargo target directory", clean)); + runners.insert("--build-sysroot", ("Build sysroot", build_sysroot)); + runners.insert("--std-tests", ("Run std tests", std_tests)); + runners.insert("--asm-tests", ("Run asm tests", asm_tests)); runners.insert( "--extended-tests", - ("Run extended sysroot tests", &extended_sysroot_tests), + ("Run extended sysroot tests", extended_sysroot_tests), ); runners.insert( "--extended-rand-tests", - ("Run extended rand tests", &extended_rand_tests), + ("Run extended rand tests", extended_rand_tests), ); runners.insert( "--extended-regex-example-tests", ( "Run extended regex example tests", - &extended_regex_example_tests, + extended_regex_example_tests, ), ); runners.insert( "--extended-regex-tests", - ("Run extended regex tests", &extended_regex_tests), + ("Run extended regex tests", extended_regex_tests), ); - runners.insert("--mini-tests", ("Run mini tests", &mini_tests)); + runners.insert("--mini-tests", ("Run mini tests", mini_tests)); runners } From 8e870c75d991b06a19a6ae8af45cef39a70ffae9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Dec 2023 21:22:32 +0100 Subject: [PATCH 060/192] Remove unused `TestArgs::use_backend` and display messages in case a test is not run --- build_system/src/test.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index f368e5b420e6f..f66b16c31496e 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -97,6 +97,7 @@ fn show_usage() { ); ConfigInfo::show_usage(); for (option, (doc, _)) in get_runners() { + // FIXME: Instead of using the hard-coded `23` value, better to compute it instead. let needed_spaces = 23_usize.saturating_sub(option.len()); let spaces: String = std::iter::repeat(' ').take(needed_spaces).collect(); println!(" {}{}: {}", option, spaces, doc); @@ -109,7 +110,6 @@ struct TestArg { no_default_features: bool, build_only: bool, gcc_path: String, - use_backend: bool, runners: BTreeSet, flags: Vec, backend: Option, @@ -207,7 +207,7 @@ impl TestArg { } fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> { - if args.use_backend { + if args.backend.is_some() { return Ok(()); } let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; @@ -504,8 +504,6 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { None => return Err("Couldn't retrieve rustc commit hash".to_string()), }; run_command_with_output_and_env(&[&"git", &"checkout", &rustc_commit], rust_dir, Some(env))?; - // FIXME: Is it really needed to empty `RUSTFLAGS` here? - // env.insert("RUSTFLAGS".to_string(), String::new()); let cargo = String::from_utf8( run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, ) @@ -684,6 +682,7 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { if !args.is_using_gcc_master_branch() { + println!("Not using GCC master branch. Skipping `extended_rand_tests`."); return Ok(()); } let path = Path::new("rand"); @@ -696,6 +695,7 @@ fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> { if !args.is_using_gcc_master_branch() { + println!("Not using GCC master branch. Skipping `extended_regex_example_tests`."); return Ok(()); } let path = Path::new("regex"); @@ -750,6 +750,7 @@ fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { if !args.is_using_gcc_master_branch() { + println!("Not using GCC master branch. Skipping `extended_regex_tests`."); return Ok(()); } // FIXME: create a function "display_if_not_quiet" or something along the line. From 05ef68961b0375cca8ddf7e842d6dbba9d46db11 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Dec 2023 14:47:42 +0100 Subject: [PATCH 061/192] Remove unused `build_sysroot.sh` file --- build_sysroot/build_sysroot.sh | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100755 build_sysroot/build_sysroot.sh diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh deleted file mode 100755 index ebc7dc375b125..0000000000000 --- a/build_sysroot/build_sysroot.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -# Requires the CHANNEL env var to be set to `debug` or `release.` - -set -e -cd $(dirname "$0") - -pushd ../ -source ./config.sh -popd - -# Cleanup for previous run -# v Clean target dir except for build scripts and incremental cache -rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true -rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true -rm -r sysroot/ 2>/dev/null || true - -# Build libs -export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked" -if [[ "$1" == "--release" ]]; then - sysroot_channel='release' - RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release -else - sysroot_channel='debug' - cargo build --target $TARGET_TRIPLE -fi - -# Copy files to sysroot -mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ -cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ -# Copy the source files to the sysroot (Rust for Linux needs this). -source_dir=sysroot/lib/rustlib/src/rust -mkdir -p $source_dir -cp -r sysroot_src/library/ $source_dir From e26e074261c841508cf4114645291c92ab552be2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Dec 2023 14:58:43 +0100 Subject: [PATCH 062/192] Rustify `clean_all.sh` --- .github/workflows/ci.yml | 2 +- .github/workflows/gcc12.yml | 2 +- .github/workflows/m68k.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/stdarch.yml | 2 +- build_system/src/clean.rs | 73 +++++++++++++++++++++++++++++++++++ build_system/src/main.rs | 5 +++ build_system/src/utils.rs | 2 +- clean_all.sh | 6 --- rustup.sh | 2 +- 10 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 build_system/src/clean.rs delete mode 100755 clean_all.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b04ea1550ba2b..d14f30338b01a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: ./y.sh build --features master # TODO: remove --features master when it is back to the default. cargo test --features master - ./clean_all.sh + ./y.sh clean all - name: Prepare dependencies run: | diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index a27ef913c21d6..eef26f01789f1 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -86,7 +86,7 @@ jobs: ./y.sh prepare --only-libcore --libgccjit12-patches ./y.sh build --no-default-features --sysroot-panic-abort cargo test --no-default-features - ./clean_all.sh + ./y.sh clean all - name: Prepare dependencies run: | diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index ac141e0624793..a7489b10744f4 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -118,7 +118,7 @@ jobs: ./y.sh build --target-triple m68k-unknown-linux-gnu --features master # TODO: remove --features master when it is back to the default. CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test --features master - ./clean_all.sh + ./y.sh clean all - name: Prepare dependencies run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9798bc338f3d5..6dc950f88a23b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,7 +82,7 @@ jobs: EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot --features master # TODO: remove --features master when it is back to the default. cargo test --features master - ./clean_all.sh + ./y.sh clean all - name: Prepare dependencies run: | diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index d290f1d056288..dc670c5701c8d 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -100,7 +100,7 @@ jobs: - name: Clean if: ${{ !matrix.cargo_runner }} run: | - ./clean_all.sh + ./y.sh clean all - name: Prepare dependencies run: | diff --git a/build_system/src/clean.rs b/build_system/src/clean.rs new file mode 100644 index 0000000000000..56cc19d255f96 --- /dev/null +++ b/build_system/src/clean.rs @@ -0,0 +1,73 @@ +use crate::utils::remove_file; + +use std::fs::remove_dir_all; + +#[derive(Default)] +struct CleanArg { + all: bool, +} + +impl CleanArg { + fn new() -> Result, String> { + let mut args = CleanArg::default(); + + // We skip the binary and the "clean" option. + for arg in std::env::args().skip(2) { + match arg.as_str() { + "all" => args.all = true, + "--help" => { + Self::usage(); + return Ok(None); + } + a => return Err(format!("Unknown argument `{}`", a)), + } + } + Ok(Some(args)) + } + + fn usage() { + println!( + r#" + `clean` command help: + + all : Clean all data + --help : Show this help + "# + ) + } +} + +fn clean_all() -> Result<(), String> { + let dirs_to_remove = [ + "target", + "build_sysroot/sysroot", + "build_sysroot/sysroot_src", + "build_sysroot/target", + "regex", + "simple-raytracer", + ]; + for dir in dirs_to_remove { + let _ = remove_dir_all(dir); + } + + let files_to_remove = ["build_sysroot/Cargo.lock", "perf.data", "perf.data.old"]; + + for file in files_to_remove { + let _ = remove_file(file); + } + + println!("Successfully ran `clean all`"); + Ok(()) +} + +pub fn run() -> Result<(), String> { + let args = match CleanArg::new()? { + Some(a) => a, + None => return Ok(()), + }; + + if args.all { + clean_all()?; + } + Ok(()) +} diff --git a/build_system/src/main.rs b/build_system/src/main.rs index e0091ff697733..1ed44b22a9538 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -2,6 +2,7 @@ use std::env; use std::process; mod build; +mod clean; mod config; mod prepare; mod rustc_info; @@ -22,6 +23,7 @@ fn usage() { "\ Available commands for build_system: + clean : Run clean command prepare : Run prepare command build : Run build command test : Run test command @@ -30,6 +32,7 @@ Available commands for build_system: } pub enum Command { + Clean, Prepare, Build, Test, @@ -41,6 +44,7 @@ fn main() { } let command = match env::args().nth(1).as_deref() { + Some("clean") => Command::Clean, Some("prepare") => Command::Prepare, Some("build") => Command::Build, Some("test") => Command::Test, @@ -57,6 +61,7 @@ fn main() { }; if let Err(e) = match command { + Command::Clean => clean::run(), Command::Prepare => prepare::run(), Command::Build => build::run(), Command::Test => test::run(), diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 9c3a86ad68a2a..276f4f2d989b2 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -346,7 +346,7 @@ pub fn split_args(args: &str) -> Result, String> { Ok(out) } -pub fn remove_file>(file_path: &P) -> Result<(), String> { +pub fn remove_file + ?Sized>(file_path: &P) -> Result<(), String> { std::fs::remove_file(file_path).map_err(|error| { format!( "Failed to remove `{}`: {:?}", diff --git a/clean_all.sh b/clean_all.sh deleted file mode 100755 index 782bd3e5058c4..0000000000000 --- a/clean_all.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -set -e -set -v - -rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/,Cargo.lock} perf.data{,.old} -rm -rf regex/ simple-raytracer/ diff --git a/rustup.sh b/rustup.sh index a4f938e4b5b76..3cdc07ca5207a 100755 --- a/rustup.sh +++ b/rustup.sh @@ -15,7 +15,7 @@ case $1 in rustup toolchain uninstall $nightly done - ./clean_all.sh + ./y.sh clean all ./y.sh prepare ;; "commit") From 9a8245fed83d55a5bdcd72cf126107a11cc676e1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Dec 2023 16:19:03 +0100 Subject: [PATCH 063/192] Remove unused `rustup.sh` script --- rustup.sh | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100755 rustup.sh diff --git a/rustup.sh b/rustup.sh deleted file mode 100755 index 3cdc07ca5207a..0000000000000 --- a/rustup.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -set -e - -case $1 in - "prepare") - TOOLCHAIN=$(date +%Y-%m-%d) - - echo "=> Installing new nightly" - rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists - echo nightly-${TOOLCHAIN} > rust-toolchain - - echo "=> Uninstalling all old nightlies" - for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do - rustup toolchain uninstall $nightly - done - - ./y.sh clean all - ./y.sh prepare - ;; - "commit") - git add rust-toolchain - git commit -m "Rustup to $(rustc -V)" - ;; - *) - echo "Unknown command '$1'" - echo "Usage: ./rustup.sh prepare|commit" - ;; -esac From 87a704a2278882d4d8717e83c62879dc540ad87d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Dec 2023 21:33:21 +0100 Subject: [PATCH 064/192] If the rustc commit cannot be retrieve, just checkout the repository --- build_system/src/test.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index f66b16c31496e..c98be8dcaccdb 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -503,7 +503,15 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { Some(commit_hash) => commit_hash, None => return Err("Couldn't retrieve rustc commit hash".to_string()), }; - run_command_with_output_and_env(&[&"git", &"checkout", &rustc_commit], rust_dir, Some(env))?; + if rustc_commit != "unknown" { + run_command_with_output_and_env( + &[&"git", &"checkout", &rustc_commit], + rust_dir, + Some(env), + )?; + } else { + run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?; + } let cargo = String::from_utf8( run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, ) From 6631dd9dd27b63bf89d3ace5dbce02ea240c5a44 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Dec 2023 21:44:12 +0100 Subject: [PATCH 065/192] Don't stop test if llvm FileCheck cannot be found --- build_system/src/test.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index c98be8dcaccdb..1a9bb4ea94eb8 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -524,23 +524,25 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { Ok(cargo) } })?; - let llvm_filecheck = String::from_utf8( - run_command_with_env( - &[ - &"bash", - &"-c", - &"which FileCheck-10 || \ + let llvm_filecheck = match run_command_with_env( + &[ + &"bash", + &"-c", + &"which FileCheck-10 || \ which FileCheck-11 || \ which FileCheck-12 || \ which FileCheck-13 || \ which FileCheck-14", - ], - rust_dir, - Some(env), - )? - .stdout, - ) - .map_err(|error| format!("Failed to retrieve LLVM FileCheck: {:?}", error))?; + ], + rust_dir, + Some(env), + ) { + Ok(cmd) => String::from_utf8_lossy(&cmd.stdout).to_string(), + Err(_) => { + eprintln!("Failed to retrieve LLVM FileCheck, ignoring..."); + String::new() + } + }; std::fs::write( "rust/config.toml", &format!( From a53495ab45a1d7773561431eb2fb753aee102d44 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 21 Dec 2023 11:18:11 -0500 Subject: [PATCH 066/192] Add comment --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 8c7bae0c8866d..5f8d00bb455e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ * TODO(antoyo): support LTO (gcc's equivalent to Full LTO is -flto -flto-partition=one — https://documentation.suse.com/sbp/all/html/SBP-GCC-10/index.html). * For Thin LTO, this might be helpful: * In gcc 4.6 -fwhopr was removed and became default with -flto. The non-whopr path can still be executed via -flto-partition=none. + * Or the new incremental LTO? * * Maybe some missing optizations enabled by rustc's LTO is in there: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html * Like -fipa-icf (should be already enabled) and maybe -fdevirtualize-at-ltrans. @@ -29,6 +30,7 @@ #![warn(unused_lifetimes)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![deny(clippy::pattern_type_mismatch)] extern crate rustc_apfloat; extern crate rustc_ast; From 2e52b08800d5213e6cc7d75559f62584e8e0eede Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 21 Dec 2023 23:46:41 +0100 Subject: [PATCH 067/192] Rustify `cargo.sh` --- .github/workflows/stdarch.yml | 4 +- Readme.md | 10 ++-- build_system/src/cargo.rs | 98 +++++++++++++++++++++++++++++++++++ build_system/src/main.rs | 5 ++ build_system/src/test.rs | 2 +- build_system/src/utils.rs | 27 ++++++++-- cargo.sh | 23 -------- 7 files changed, 135 insertions(+), 34 deletions(-) create mode 100644 build_system/src/cargo.rs delete mode 100755 cargo.sh diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index dc670c5701c8d..d8336fe991b63 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -126,11 +126,11 @@ jobs: if: ${{ !matrix.cargo_runner }} run: | cd build_sysroot/sysroot_src/library/stdarch/ - CHANNEL=release TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../cargo.sh test + CHANNEL=release TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../y.sh cargo test - name: Run stdarch tests if: ${{ matrix.cargo_runner }} run: | cd build_sysroot/sysroot_src/library/stdarch/ # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. - STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a + STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../y.sh cargo test -- --skip rtm --skip tbm --skip sse4a diff --git a/Readme.md b/Readme.md index 68effb2bf78f9..f31b5c17969e3 100644 --- a/Readme.md +++ b/Readme.md @@ -79,7 +79,7 @@ export CG_GCCJIT_DIR=[the full path to rustc_codegen_gcc] ### Cargo ```bash -$ CHANNEL="release" $CG_GCCJIT_DIR/cargo.sh run +$ CHANNEL="release" $CG_GCCJIT_DIR/y.sh cargo run ``` If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./y.sh test`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely. @@ -230,13 +230,13 @@ Run do the command with `-v -save-temps` and then extract the `lto1` line from t ### How to send arguments to the GCC linker ``` -CG_RUSTFLAGS="-Clink-args=-save-temps -v" ../cargo.sh build +CG_RUSTFLAGS="-Clink-args=-save-temps -v" ../y.sh cargo build ``` ### How to see the personality functions in the asm dump ``` -CG_RUSTFLAGS="-Clink-arg=-save-temps -v -Clink-arg=-dA" ../cargo.sh build +CG_RUSTFLAGS="-Clink-arg=-save-temps -v -Clink-arg=-dA" ../y.sh cargo build ``` ### How to see the LLVM IR for a sysroot crate @@ -324,13 +324,13 @@ generate it in [gimple.md](./doc/gimple.md). * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case. * Set the path to the cross-compiling libgccjit in `gcc_path`. * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu`. - * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../cargo.sh build --target m68k-unknown-linux-gnu`. + * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target m68k-unknown-linux-gnu`. If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler). Then, you can use it the following way: * Add the target specification file using `--target` as an **absolute** path to build the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu --target $(pwd)/m68k-unknown-linux-gnu.json` - * Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../cargo.sh build --target path/to/m68k-unknown-linux-gnu.json`. + * Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`. If you get the following error: diff --git a/build_system/src/cargo.rs b/build_system/src/cargo.rs new file mode 100644 index 0000000000000..06b543a6cad65 --- /dev/null +++ b/build_system/src/cargo.rs @@ -0,0 +1,98 @@ +use crate::config::ConfigInfo; +use crate::utils::{ + get_toolchain, run_command_with_output_and_env, rustc_toolchain_version_info, + rustc_version_info, +}; + +use std::collections::HashMap; +use std::ffi::OsStr; + +fn args() -> Result>, String> { + // We skip the binary and the "cargo" option. + if let Some("--help") = std::env::args().skip(2).next().as_deref() { + usage(); + return Ok(None); + } + let args = std::env::args().skip(2).collect::>(); + if args.is_empty() { + return Err( + "Expected at least one argument for `cargo` subcommand, found none".to_string(), + ); + } + Ok(Some(args)) +} + +fn usage() { + println!( + r#" +`cargo` command help: + + [args] : Arguments to be passed to the cargo command + --help : Show this help +"# + ) +} + +pub fn run() -> Result<(), String> { + let args = match args()? { + Some(a) => a, + None => return Ok(()), + }; + + // We first need to go to the original location to ensure that the config setup will go as + // expected. + let current_dir = std::env::current_dir() + .map_err(|error| format!("Failed to get current directory path: {:?}", error))?; + let current_exe = std::env::current_exe() + .map_err(|error| format!("Failed to get current exe path: {:?}", error))?; + let parent_dir = match current_exe.parent() { + Some(parent) => parent, + None => { + return Err(format!( + "Cannot get parent of current executable path `{}`", + current_exe.display() + )); + } + }; + std::env::set_current_dir(&parent_dir).map_err(|error| { + format!( + "Failed to go to `{}` folder: {:?}", + parent_dir.display(), + error + ) + })?; + + let mut env: HashMap = std::env::vars().collect(); + ConfigInfo::default().setup(&mut env, None)?; + let toolchain = get_toolchain()?; + + let toolchain_version = rustc_toolchain_version_info(&toolchain)?; + let default_version = rustc_version_info(None)?; + if toolchain_version != default_version { + println!( + "rustc_codegen_gcc is built for {} but the default rustc version is {}.", + toolchain_version.short, default_version.short, + ); + println!("Using {}.", toolchain_version.short); + } + + // We go back to the original folder since we now have set up everything we needed. + std::env::set_current_dir(¤t_dir).map_err(|error| { + format!( + "Failed to go back to `{}` folder: {:?}", + current_dir.display(), + error + ) + })?; + + let rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default(); + env.insert("RUSTDOCFLAGS".to_string(), rustflags); + let toolchain = format!("+{}", toolchain); + let mut command: Vec<&dyn AsRef> = vec![&"cargo", &toolchain]; + for arg in &args { + command.push(arg); + } + run_command_with_output_and_env(&command, None, Some(&env))?; + + Ok(()) +} diff --git a/build_system/src/main.rs b/build_system/src/main.rs index 1ed44b22a9538..102c5486a75e4 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -2,6 +2,7 @@ use std::env; use std::process; mod build; +mod cargo; mod clean; mod config; mod prepare; @@ -23,6 +24,7 @@ fn usage() { "\ Available commands for build_system: + cargo : Run cargo command clean : Run clean command prepare : Run prepare command build : Run build command @@ -32,6 +34,7 @@ Available commands for build_system: } pub enum Command { + Cargo, Clean, Prepare, Build, @@ -44,6 +47,7 @@ fn main() { } let command = match env::args().nth(1).as_deref() { + Some("cargo") => Command::Cargo, Some("clean") => Command::Clean, Some("prepare") => Command::Prepare, Some("build") => Command::Build, @@ -61,6 +65,7 @@ fn main() { }; if let Err(e) = match command { + Command::Cargo => cargo::run(), Command::Clean => clean::run(), Command::Prepare => prepare::run(), Command::Build => build::run(), diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 1a9bb4ea94eb8..1577cbf2b53ed 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -796,7 +796,7 @@ fn extended_sysroot_tests(env: &Env, args: &TestArg) -> Result<(), String> { // echo "[BENCH COMPILE] ebobby/simple-raytracer" // hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \ // "RUSTC=rustc RUSTFLAGS='' cargo build" \ - // "../cargo.sh build" + // "../y.sh cargo build" // echo "[BENCH RUN] ebobby/simple-raytracer" // cp ./target/debug/main ./raytracer_cg_gcc diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 276f4f2d989b2..fdd8bd8f4c4d7 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -158,21 +158,42 @@ pub fn get_os_name() -> Result { } } -#[derive(Default)] +#[derive(Default, PartialEq)] pub struct RustcVersionInfo { + pub short: String, pub version: String, pub host: Option, pub commit_hash: Option, pub commit_date: Option, } +pub fn rustc_toolchain_version_info(toolchain: &str) -> Result { + rustc_version_info_inner(None, Some(toolchain)) +} + pub fn rustc_version_info(rustc: Option<&str>) -> Result { - let output = run_command(&[&rustc.unwrap_or("rustc"), &"-vV"], None)?; + rustc_version_info_inner(rustc, None) +} + +fn rustc_version_info_inner( + rustc: Option<&str>, + toolchain: Option<&str>, +) -> Result { + let output = if let Some(toolchain) = toolchain { + run_command(&[&rustc.unwrap_or("rustc"), &toolchain, &"-vV"], None) + } else { + run_command(&[&rustc.unwrap_or("rustc"), &"-vV"], None) + }?; let content = std::str::from_utf8(&output.stdout).unwrap_or(""); let mut info = RustcVersionInfo::default(); + let mut lines = content.split('\n'); + info.short = match lines.next() { + Some(s) => s.to_string(), + None => return Err("failed to retrieve rustc version".to_string()), + }; - for line in content.split('\n').map(|line| line.trim()) { + for line in lines.map(|line| line.trim()) { match line.split_once(':') { Some(("host", data)) => info.host = Some(data.trim().to_string()), Some(("release", data)) => info.version = data.trim().to_string(), diff --git a/cargo.sh b/cargo.sh deleted file mode 100755 index b68a08ee88f80..0000000000000 --- a/cargo.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -if [ -z $CHANNEL ]; then -export CHANNEL='debug' -fi - -pushd $(dirname "$0") >/dev/null -source config.sh - -# read nightly compiler from rust-toolchain file -TOOLCHAIN=$(cat rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') - -popd >/dev/null - -if [[ $(${RUSTC} -V) != $(${RUSTC} +${TOOLCHAIN} -V) ]]; then - echo "rustc_codegen_gcc is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)." - echo "Using $(rustc +${TOOLCHAIN} -V)." -fi - -cmd=$1 -shift - -RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd $@ From ec940748175eca4e476ed29fa537319eb090356a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 22 Dec 2023 00:47:01 +0100 Subject: [PATCH 068/192] Correctly take into account potential position of cargo command in `y.sh` --- build_system/src/cargo.rs | 26 ++++++++++++++++++++------ y.sh | 6 +++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/build_system/src/cargo.rs b/build_system/src/cargo.rs index 06b543a6cad65..5f9de5e2eb658 100644 --- a/build_system/src/cargo.rs +++ b/build_system/src/cargo.rs @@ -6,6 +6,7 @@ use crate::utils::{ use std::collections::HashMap; use std::ffi::OsStr; +use std::path::PathBuf; fn args() -> Result>, String> { // We skip the binary and the "cargo" option. @@ -42,18 +43,31 @@ pub fn run() -> Result<(), String> { // We first need to go to the original location to ensure that the config setup will go as // expected. let current_dir = std::env::current_dir() + .and_then(|path| path.canonicalize()) .map_err(|error| format!("Failed to get current directory path: {:?}", error))?; let current_exe = std::env::current_exe() + .and_then(|path| path.canonicalize()) .map_err(|error| format!("Failed to get current exe path: {:?}", error))?; - let parent_dir = match current_exe.parent() { - Some(parent) => parent, - None => { + let mut parent_dir = current_exe + .components() + .map(|comp| comp.as_os_str()) + .collect::>(); + // We run this script from "build_system/target/release/y", so we need to remove these elements. + for to_remove in &["y", "release", "target", "build_system"] { + if parent_dir + .last() + .map(|part| part == to_remove) + .unwrap_or(false) + { + parent_dir.pop(); + } else { return Err(format!( - "Cannot get parent of current executable path `{}`", - current_exe.display() + "Build script not executed from `build_system/target/release/y` (in path {})", + current_exe.display(), )); } - }; + } + let parent_dir = PathBuf::from(parent_dir.join(&OsStr::new("/"))); std::env::set_current_dir(&parent_dir).map_err(|error| { format!( "Failed to go to `{}` folder: {:?}", diff --git a/y.sh b/y.sh index 188109743e3db..69d7917dd7779 100755 --- a/y.sh +++ b/y.sh @@ -2,7 +2,7 @@ set -e echo "[BUILD] build system" 1>&2 -cd build_system +pushd $(dirname "$0")/build_system > /dev/null cargo build --release -cd .. -./build_system/target/release/y $@ +popd > /dev/null +$(dirname "$0")/build_system/target/release/y $@ From 02ed79063171e4214d4139e651b477487c517108 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 22:21:37 +1100 Subject: [PATCH 069/192] Remove `Session` methods that duplicate `DiagCtxt` methods. Also add some `dcx` methods to types that wrap `TyCtxt`, for easier access. --- src/asm.rs | 2 +- src/attributes.rs | 2 +- src/consts.rs | 2 +- src/context.rs | 6 +++--- src/gcc_util.rs | 6 +++--- src/intrinsic/mod.rs | 2 +- src/intrinsic/simd.rs | 4 ++-- src/lib.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/asm.rs b/src/asm.rs index f3a9ca77a67b1..ddd67a994c942 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -109,7 +109,7 @@ enum ConstraintOrRegister { impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) { if options.contains(InlineAsmOptions::MAY_UNWIND) { - self.sess() + self.sess().dcx() .create_err(UnwindingInlineAsm { span: span[0] }) .emit(); return; diff --git a/src/attributes.rs b/src/attributes.rs index 6159971cfaa8d..9f361d3688695 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -80,7 +80,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( let span = cx.tcx .get_attr(instance.def_id(), sym::target_feature) .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); - cx.tcx.sess.create_err(TiedTargetFeatures { + cx.tcx.dcx().create_err(TiedTargetFeatures { features: features.join(", "), span, }) diff --git a/src/consts.rs b/src/consts.rs index f06416b9bb5fe..70d8db02247ce 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -24,7 +24,7 @@ fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc> match Align::from_bits(min) { Ok(min) => align = align.max(min), Err(err) => { - cx.sess().emit_err(InvalidMinimumAlignment { err: err.to_string() }); + cx.sess().dcx().emit_err(InvalidMinimumAlignment { err: err.to_string() }); } } } diff --git a/src/context.rs b/src/context.rs index ab9c703db37da..053f759329fb1 100644 --- a/src/context.rs +++ b/src/context.rs @@ -500,9 +500,9 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { - self.sess().emit_fatal(respan(span, err.into_diagnostic())) + self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic())) } else { - self.tcx.sess.emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) + self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) } } } @@ -518,7 +518,7 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { - self.sess().emit_fatal(respan(span, err)) + self.tcx.dcx().emit_fatal(respan(span, err)) } else { match fn_abi_request { FnAbiRequest::OfFnPtr { sig, extra_args } => { diff --git a/src/gcc_util.rs b/src/gcc_util.rs index 2aa84f26797c3..df917d527ced8 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -52,7 +52,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec c, Some(_) => { if diagnostics { - sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s }); + sess.dcx().emit_warning(UnknownCTargetFeaturePrefix { feature: s }); } return None; } @@ -79,7 +79,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Vec IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { _ => bug!(), }, None => { - tcx.sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); + tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); return; } } diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 85d3e7234a0e6..9fa978cd2ef7a 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -34,7 +34,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // macros for error handling: macro_rules! return_error { ($err:expr) => {{ - bx.sess().emit_err($err); + bx.tcx.dcx().emit_err($err); return Err(()); }}; } @@ -390,7 +390,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( ) -> Result, ()> { macro_rules! return_error { ($err:expr) => {{ - bx.sess().emit_err($err); + bx.tcx.dcx().emit_err($err); return Err(()); }}; } diff --git a/src/lib.rs b/src/lib.rs index 1f3f909d8b4f0..f69f850c1d4a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,7 +191,7 @@ impl CodegenBackend for GccCodegenBackend { #[cfg(feature="master")] gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); if sess.lto() == Lto::Thin { - sess.emit_warning(LTONotSupported {}); + sess.dcx().emit_warning(LTONotSupported {}); } #[cfg(not(feature="master"))] From 69b5a9f2eb8b7d16091b76a2a5b84cd4889eefe2 Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Thu, 30 Nov 2023 14:54:27 +0100 Subject: [PATCH 070/192] Change `rustc_codegen_ssa`'s `atomic_cmpxchg` interface to return a pair of values --- src/builder.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index b8a8c144dc90b..42e61b3ccb5ad 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1296,7 +1296,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } // Atomic Operations - fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { + fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> (RValue<'gcc>, RValue<'gcc>) { let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); self.llbb().add_assignment(None, expected, cmp); // NOTE: gcc doesn't support a failure memory model that is stronger than the success @@ -1310,20 +1310,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; let success = self.compare_exchange(dst, expected, src, order, failure_order, weak); - let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false); - let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result"); - let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align. + // NOTE: since success contains the call to the intrinsic, it must be added to the basic block before + // expected so that we store expected after the call. + let success_var = self.current_func().new_local(None, self.bool_type, "success"); + self.llbb().add_assignment(None, success_var, success); - let value_type = result.to_rvalue().get_type(); - if let Some(struct_type) = value_type.is_struct() { - self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align); - // NOTE: since success contains the call to the intrinsic, it must be stored before - // expected so that we store expected after the call. - self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align); - } - // TODO(antoyo): handle when value is not a struct. - - result.to_rvalue() + (expected.to_rvalue(), success_var.to_rvalue()) } fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> { From eca05c6cb06ca059bf13bd7f2b53066d217edaa2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 21 Dec 2023 01:52:10 +0000 Subject: [PATCH 071/192] Remove movability from TyKind::Coroutine --- src/type_of.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type_of.rs b/src/type_of.rs index 479a814788a54..e5c0b2de4ca46 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -98,7 +98,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout write!(&mut name, "::{}", def.variant(index).name).unwrap(); } } - if let (&ty::Coroutine(_, _, _), &Variants::Single { index }) = + if let (&ty::Coroutine(_, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) { write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap(); From c122376493e40dd494dac45614205c340141f005 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 29 Dec 2023 21:27:36 +0100 Subject: [PATCH 072/192] Don't show `cargo` command errors --- build_system/src/cargo.rs | 6 ++++-- build_system/src/utils.rs | 25 +++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/build_system/src/cargo.rs b/build_system/src/cargo.rs index 5f9de5e2eb658..67b301d9aa646 100644 --- a/build_system/src/cargo.rs +++ b/build_system/src/cargo.rs @@ -1,6 +1,6 @@ use crate::config::ConfigInfo; use crate::utils::{ - get_toolchain, run_command_with_output_and_env, rustc_toolchain_version_info, + get_toolchain, run_command_with_output_and_env_no_err, rustc_toolchain_version_info, rustc_version_info, }; @@ -106,7 +106,9 @@ pub fn run() -> Result<(), String> { for arg in &args { command.push(arg); } - run_command_with_output_and_env(&command, None, Some(&env))?; + if run_command_with_output_and_env_no_err(&command, None, Some(&env)).is_err() { + std::process::exit(1); + } Ok(()) } diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index fdd8bd8f4c4d7..f0a07b597a0f4 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -30,6 +30,7 @@ fn check_exit_status( cwd: Option<&Path>, exit_status: ExitStatus, output: Option<&Output>, + show_err: bool, ) -> Result<(), String> { if exit_status.success() { return Ok(()); @@ -46,7 +47,9 @@ fn check_exit_status( exit_status.code() ); let input = input.iter().map(|i| i.as_ref()).collect::>(); - eprintln!("Command `{:?}` failed", input); + if show_err { + eprintln!("Command `{:?}` failed", input); + } if let Some(output) = output { let stdout = String::from_utf8_lossy(&output.stdout); if !stdout.is_empty() { @@ -88,7 +91,7 @@ pub fn run_command_with_env( let output = get_command_inner(input, cwd, env) .output() .map_err(|e| command_error(input, &cwd, e))?; - check_exit_status(input, cwd, output.status, Some(&output))?; + check_exit_status(input, cwd, output.status, Some(&output), true)?; Ok(output) } @@ -101,7 +104,7 @@ pub fn run_command_with_output( .map_err(|e| command_error(input, &cwd, e))? .wait() .map_err(|e| command_error(input, &cwd, e))?; - check_exit_status(input, cwd, exit_status, None)?; + check_exit_status(input, cwd, exit_status, None, true)?; Ok(()) } @@ -115,7 +118,21 @@ pub fn run_command_with_output_and_env( .map_err(|e| command_error(input, &cwd, e))? .wait() .map_err(|e| command_error(input, &cwd, e))?; - check_exit_status(input, cwd, exit_status, None)?; + check_exit_status(input, cwd, exit_status, None, true)?; + Ok(()) +} + +pub fn run_command_with_output_and_env_no_err( + input: &[&dyn AsRef], + cwd: Option<&Path>, + env: Option<&HashMap>, +) -> Result<(), String> { + let exit_status = get_command_inner(input, cwd, env) + .spawn() + .map_err(|e| command_error(input, &cwd, e))? + .wait() + .map_err(|e| command_error(input, &cwd, e))?; + check_exit_status(input, cwd, exit_status, None, false)?; Ok(()) } From a56eff2b4152a9846027f03c6bab35a653f958c4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 24 Dec 2023 09:08:41 +1100 Subject: [PATCH 073/192] Rename some `Diagnostic` setters. `Diagnostic` has 40 methods that return `&mut Self` and could be considered setters. Four of them have a `set_` prefix. This doesn't seem necessary for a type that implements the builder pattern. This commit removes the `set_` prefixes on those four methods. --- src/errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 1b1ed0b411c71..e9283b1989453 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -119,12 +119,12 @@ impl IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl fluent::codegen_gcc_target_feature_disable_or_enable ); if let Some(span) = self.span { - diag.set_span(span); + diag.span(span); }; if let Some(missing_features) = self.missing_features { diag.subdiagnostic(missing_features); } - diag.set_arg("features", self.features.join(", ")); + diag.arg("features", self.features.join(", ")); diag } } From f93e985664ad56be1286b9cbe3a14cfe499be239 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 3 Jan 2024 18:00:37 +0900 Subject: [PATCH 074/192] Support reg_addr register class in s390x inline assembly --- src/asm.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/asm.rs b/src/asm.rs index ddd67a994c942..78e8e32b97299 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -634,6 +634,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { } InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Err => unreachable!(), } @@ -704,7 +705,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") }, - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::S390x( + S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr + ) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::Err => unreachable!(), } From b5681ca4aa818e10debd99020327af9c01c43ed2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Jan 2024 15:27:19 +0100 Subject: [PATCH 075/192] Update intrinsics conversion --- src/intrinsic/archs.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index 15d67385c3e98..c4ae1751fa05a 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -151,8 +151,10 @@ match name { "llvm.amdgcn.msad.u8" => "__builtin_amdgcn_msad_u8", "llvm.amdgcn.perm" => "__builtin_amdgcn_perm", "llvm.amdgcn.permlane16" => "__builtin_amdgcn_permlane16", + "llvm.amdgcn.permlane16.var" => "__builtin_amdgcn_permlane16_var", "llvm.amdgcn.permlane64" => "__builtin_amdgcn_permlane64", "llvm.amdgcn.permlanex16" => "__builtin_amdgcn_permlanex16", + "llvm.amdgcn.permlanex16.var" => "__builtin_amdgcn_permlanex16_var", "llvm.amdgcn.qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8", "llvm.amdgcn.queue.ptr" => "__builtin_amdgcn_queue_ptr", "llvm.amdgcn.rcp.legacy" => "__builtin_amdgcn_rcp_legacy", @@ -160,11 +162,20 @@ match name { "llvm.amdgcn.readlane" => "__builtin_amdgcn_readlane", "llvm.amdgcn.rsq.legacy" => "__builtin_amdgcn_rsq_legacy", "llvm.amdgcn.s.barrier" => "__builtin_amdgcn_s_barrier", + "llvm.amdgcn.s.barrier.init" => "__builtin_amdgcn_s_barrier_init", + "llvm.amdgcn.s.barrier.join" => "__builtin_amdgcn_s_barrier_join", + "llvm.amdgcn.s.barrier.leave" => "__builtin_amdgcn_s_barrier_leave", + "llvm.amdgcn.s.barrier.signal" => "__builtin_amdgcn_s_barrier_signal", + "llvm.amdgcn.s.barrier.signal.isfirst" => "__builtin_amdgcn_s_barrier_signal_isfirst", + "llvm.amdgcn.s.barrier.signal.isfirst.var" => "__builtin_amdgcn_s_barrier_signal_isfirst_var", + "llvm.amdgcn.s.barrier.signal.var" => "__builtin_amdgcn_s_barrier_signal_var", + "llvm.amdgcn.s.barrier.wait" => "__builtin_amdgcn_s_barrier_wait", "llvm.amdgcn.s.dcache.inv" => "__builtin_amdgcn_s_dcache_inv", "llvm.amdgcn.s.dcache.inv.vol" => "__builtin_amdgcn_s_dcache_inv_vol", "llvm.amdgcn.s.dcache.wb" => "__builtin_amdgcn_s_dcache_wb", "llvm.amdgcn.s.dcache.wb.vol" => "__builtin_amdgcn_s_dcache_wb_vol", "llvm.amdgcn.s.decperflevel" => "__builtin_amdgcn_s_decperflevel", + "llvm.amdgcn.s.get.barrier.state" => "__builtin_amdgcn_s_get_barrier_state", "llvm.amdgcn.s.get.waveid.in.workgroup" => "__builtin_amdgcn_s_get_waveid_in_workgroup", "llvm.amdgcn.s.getpc" => "__builtin_amdgcn_s_getpc", "llvm.amdgcn.s.getreg" => "__builtin_amdgcn_s_getreg", @@ -176,8 +187,10 @@ match name { "llvm.amdgcn.s.setprio" => "__builtin_amdgcn_s_setprio", "llvm.amdgcn.s.setreg" => "__builtin_amdgcn_s_setreg", "llvm.amdgcn.s.sleep" => "__builtin_amdgcn_s_sleep", + "llvm.amdgcn.s.sleep.var" => "__builtin_amdgcn_s_sleep_var", "llvm.amdgcn.s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", "llvm.amdgcn.s.waitcnt" => "__builtin_amdgcn_s_waitcnt", + "llvm.amdgcn.s.wakeup.barrier" => "__builtin_amdgcn_s_wakeup_barrier", "llvm.amdgcn.sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8", "llvm.amdgcn.sad.u16" => "__builtin_amdgcn_sad_u16", "llvm.amdgcn.sad.u8" => "__builtin_amdgcn_sad_u8", @@ -314,6 +327,8 @@ match name { // bpf "llvm.bpf.btf.type.id" => "__builtin_bpf_btf_type_id", "llvm.bpf.compare" => "__builtin_bpf_compare", + "llvm.bpf.getelementptr.and.load" => "__builtin_bpf_getelementptr_and_load", + "llvm.bpf.getelementptr.and.store" => "__builtin_bpf_getelementptr_and_store", "llvm.bpf.load.byte" => "__builtin_bpf_load_byte", "llvm.bpf.load.half" => "__builtin_bpf_load_half", "llvm.bpf.load.word" => "__builtin_bpf_load_word", @@ -5776,14 +5791,6 @@ match name { "llvm.s390.verimf" => "__builtin_s390_verimf", "llvm.s390.verimg" => "__builtin_s390_verimg", "llvm.s390.verimh" => "__builtin_s390_verimh", - "llvm.s390.verllb" => "__builtin_s390_verllb", - "llvm.s390.verllf" => "__builtin_s390_verllf", - "llvm.s390.verllg" => "__builtin_s390_verllg", - "llvm.s390.verllh" => "__builtin_s390_verllh", - "llvm.s390.verllvb" => "__builtin_s390_verllvb", - "llvm.s390.verllvf" => "__builtin_s390_verllvf", - "llvm.s390.verllvg" => "__builtin_s390_verllvg", - "llvm.s390.verllvh" => "__builtin_s390_verllvh", "llvm.s390.vfaeb" => "__builtin_s390_vfaeb", "llvm.s390.vfaef" => "__builtin_s390_vfaef", "llvm.s390.vfaeh" => "__builtin_s390_vfaeh", @@ -5815,7 +5822,7 @@ match name { "llvm.s390.vistrh" => "__builtin_s390_vistrh", "llvm.s390.vlbb" => "__builtin_s390_vlbb", "llvm.s390.vll" => "__builtin_s390_vll", - "llvm.s390.vlrl" => "__builtin_s390_vlrl", + "llvm.s390.vlrl" => "__builtin_s390_vlrlr", "llvm.s390.vmaeb" => "__builtin_s390_vmaeb", "llvm.s390.vmaef" => "__builtin_s390_vmaef", "llvm.s390.vmaeh" => "__builtin_s390_vmaeh", @@ -5885,7 +5892,7 @@ match name { "llvm.s390.vstrczb" => "__builtin_s390_vstrczb", "llvm.s390.vstrczf" => "__builtin_s390_vstrczf", "llvm.s390.vstrczh" => "__builtin_s390_vstrczh", - "llvm.s390.vstrl" => "__builtin_s390_vstrl", + "llvm.s390.vstrl" => "__builtin_s390_vstrlr", "llvm.s390.vsumb" => "__builtin_s390_vsumb", "llvm.s390.vsumgf" => "__builtin_s390_vsumgf", "llvm.s390.vsumgh" => "__builtin_s390_vsumgh", From 47b06069b3e63df4d850479084d5543b24a92302 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Fri, 22 Dec 2023 15:12:01 +0300 Subject: [PATCH 076/192] Update test for `E0796` and `static_mut_ref` lint --- example/mini_core_hello_world.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 40a1ad22c0e13..9827e299f2a31 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -98,6 +98,9 @@ fn start( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { From b10f5dd3b9f33093030bda58b470d727128fa3ea Mon Sep 17 00:00:00 2001 From: vuittont60 <81072379+vuittont60@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:52:52 +0800 Subject: [PATCH 077/192] Fix typo Readme.md --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index f31b5c17969e3..39ff41acf84ae 100644 --- a/Readme.md +++ b/Readme.md @@ -181,7 +181,7 @@ debug_tree(expr); (defined in print-tree.h) -To print a debug reprensentation of a gimple struct: +To print a debug representation of a gimple struct: ```c debug_gimple_stmt(gimple_struct) From 4e8627cf8982e16c000f5b36e0cf505337ce467f Mon Sep 17 00:00:00 2001 From: vuittont60 <81072379+vuittont60@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:53:00 +0800 Subject: [PATCH 078/192] Fix typo src/base.rs --- src/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base.rs b/src/base.rs index b0788718da4d1..773e234150d1b 100644 --- a/src/base.rs +++ b/src/base.rs @@ -164,7 +164,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock context.add_driver_option("-v"); } - // NOTE: The codegen generates unrechable blocks. + // NOTE: The codegen generates unreachable blocks. context.set_allow_unreachable_blocks(true); { From f8e079a1714c43d81b96bfa2af67833eeec6eae6 Mon Sep 17 00:00:00 2001 From: vuittont60 <81072379+vuittont60@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:53:11 +0800 Subject: [PATCH 079/192] Fix typo src/intrinsic/llvm.rs --- src/intrinsic/llvm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 35eb4a11005b9..0d2ce20c654cf 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -262,7 +262,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc }, // NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors. // FIXME: the intrinsics like _mm_mask_fmadd_sd should probably directly call the GCC - // instrinsic to avoid this. + // intrinsic to avoid this. "__builtin_ia32_vfmaddss3_round" => { let new_args = args.to_vec(); let arg1_type = gcc_func.get_param_type(0); From 558d051b1d956dc9db8fd7c437f2a624fd86e751 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jan 2024 11:28:14 +1100 Subject: [PATCH 080/192] Rename `{create,emit}_warning` as `{create,emit}_warn`. For consistency with `warn`/`struct_warn`, and also `{create,emit}_err`, all of which use an abbreviated form. --- src/gcc_util.rs | 4 ++-- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gcc_util.rs b/src/gcc_util.rs index df917d527ced8..4babe5bfb813f 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -52,7 +52,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec c, Some(_) => { if diagnostics { - sess.dcx().emit_warning(UnknownCTargetFeaturePrefix { feature: s }); + sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s }); } return None; } @@ -79,7 +79,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Date: Thu, 11 Jan 2024 17:41:37 -0500 Subject: [PATCH 081/192] Fix the destination path of the sysroot copy --- build_system/src/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index d264aac7effbd..3149560b458a8 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -165,11 +165,11 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu )?; // Copy the source files to the sysroot (Rust for Linux needs this). - let sysroot_src_path = "sysroot/lib/rustlib/src/rust"; + let sysroot_src_path = start_dir.join("sysroot/lib/rustlib/src/rust"); fs::create_dir_all(&sysroot_src_path).map_err(|error| { format!( "Failed to create directory `{}`: {:?}", - sysroot_src_path, error + sysroot_src_path.display(), error ) })?; run_command( From 0fe5c7fee387d8440b99227ec17587863434b6b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 11 Jan 2024 20:42:00 -0500 Subject: [PATCH 082/192] Switch from actions-rs to preinstalled rustup actions-rs is deprecated. Switch to using the preinstalled rustup to install the toolchain, and https://github.com/Swatinem/rust-cache to configure cacheing. --- .github/workflows/ci.yml | 38 ++++++------------------------ .github/workflows/failures.yml | 38 ++++++------------------------ .github/workflows/gcc12.yml | 38 ++++++------------------------ .github/workflows/m68k.yml | 42 ++++++++-------------------------- .github/workflows/release.yml | 38 ++++++------------------------ .github/workflows/stdarch.yml | 39 ++++++------------------------- 6 files changed, 44 insertions(+), 189 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d14f30338b01a..d063f39293960 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,13 @@ jobs: steps: - uses: actions/checkout@v3 + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + - name: Install packages # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. run: sudo apt-get install ninja-build ripgrep llvm-14-tools @@ -63,30 +70,6 @@ jobs: echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: cargo-installed-crates2-ubuntu-latest - - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} - #- name: Cache rust repository ## We only clone the rust repository for rustc tests #if: ${{ contains(matrix.commands, 'rustc') }} @@ -111,13 +94,6 @@ jobs: git config --global user.name "User" ./y.sh prepare - # Compile is a separate step, as the actions-rs/cargo action supports error annotations - - name: Compile - uses: actions-rs/cargo@v1.0.3 - with: - command: build - args: --release - - name: Add more failing tests because the sysroot is not compiled with LTO run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index b411b9a17846e..b768918a014ee 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -36,6 +36,13 @@ jobs: steps: - uses: actions/checkout@v3 + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + - name: Install packages run: sudo apt-get install ninja-build ripgrep @@ -71,30 +78,6 @@ jobs: echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: cargo-installed-crates2-ubuntu-latest - - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} - #- name: Cache rust repository #uses: actions/cache@v3 #id: cache-rust-repository @@ -115,13 +98,6 @@ jobs: if: matrix.libgccjit_version.gcc != 'libgccjit12.so' run: ./y.sh prepare - # Compile is a separate step, as the actions-rs/cargo action supports error annotations - - name: Compile - uses: actions-rs/cargo@v1.0.3 - with: - command: build - args: --release - - name: Add more failing tests because the sysroot is not compiled with LTO run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index eef26f01789f1..a522423f36cc5 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -35,6 +35,13 @@ jobs: steps: - uses: actions/checkout@v3 + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + - name: Install packages # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. run: sudo apt-get install ninja-build ripgrep llvm-14-tools libgccjit-12-dev @@ -48,30 +55,6 @@ jobs: echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: cargo-installed-crates2-ubuntu-latest - - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} - #- name: Cache rust repository ## We only clone the rust repository for rustc tests #if: ${{ contains(matrix.commands, 'rustc') }} @@ -94,13 +77,6 @@ jobs: git config --global user.name "User" ./y.sh prepare --libgccjit12-patches - # Compile is a separate step, as the actions-rs/cargo action supports error annotations - - name: Compile - uses: actions-rs/cargo@v1.0.3 - with: - command: build - args: --release - - name: Add more failing tests for GCC 12 run: cat failing-ui-tests12.txt >> failing-ui-tests.txt diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index a7489b10744f4..af46650219852 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -36,13 +36,20 @@ jobs: ] steps: + - uses: actions/checkout@v3 + + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + - name: Install packages run: | sudo apt-get update sudo apt-get install qemu qemu-user-static - - uses: actions/checkout@v3 - - name: Download GCC artifact uses: dawidd6/action-download-artifact@v2 with: @@ -72,30 +79,6 @@ jobs: echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: cargo-installed-crates2-ubuntu-latest - - #- name: Cache cargo registry - #uses: actions/cache@v3 - #with: - #path: ~/.cargo/registry - #key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} - - #- name: Cache cargo index - #uses: actions/cache@v3 - #with: - #path: ~/.cargo/git - #key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} - #- name: Cache rust repository ## We only clone the rust repository for rustc tests #if: ${{ contains(matrix.commands, 'rustc') }} @@ -126,13 +109,6 @@ jobs: git config --global user.name "User" ./y.sh prepare --cross - # Compile is a separate step, as the actions-rs/cargo action supports error annotations - - name: Compile - uses: actions-rs/cargo@v1.0.3 - with: - command: build - args: --release - - name: Add more failing tests because the sysroot is not compiled with LTO run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6dc950f88a23b..071c21d5f7bb3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,6 +26,13 @@ jobs: steps: - uses: actions/checkout@v3 + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + - name: Install packages run: sudo apt-get install ninja-build ripgrep @@ -51,30 +58,6 @@ jobs: echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: cargo-installed-crates2-ubuntu-latest - - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} - - name: Build run: | ./y.sh prepare --only-libcore @@ -92,13 +75,6 @@ jobs: # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros. echo -n 'lto = "fat"' >> build_sysroot/Cargo.toml - # Compile is a separate step, as the actions-rs/cargo action supports error annotations - - name: Compile - uses: actions-rs/cargo@v1.0.3 - with: - command: build - args: --release - - name: Add more failing tests because of undefined symbol errors (FIXME) run: cat failing-lto-tests.txt >> failing-ui-tests.txt diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index d8336fe991b63..7c3ad6281e9fb 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -26,6 +26,13 @@ jobs: steps: - uses: actions/checkout@v3 + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + - name: Install packages run: sudo apt-get install ninja-build ripgrep @@ -65,30 +72,6 @@ jobs: echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: cargo-installed-crates2-ubuntu-latest - - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} - - name: Build run: | ./y.sh prepare --only-libcore @@ -108,14 +91,6 @@ jobs: git config --global user.name "User" ./y.sh prepare - # Compile is a separate step, as the actions-rs/cargo action supports error annotations - - name: Compile - uses: actions-rs/cargo@v1.0.3 - with: - command: build - # TODO: remove `--features master` when it is back to the default. - args: --release --features master - - name: Run tests if: ${{ !matrix.cargo_runner }} run: | From 0783d4505737fc2dff395065af7af0e0e3ad5962 Mon Sep 17 00:00:00 2001 From: usamoi Date: Wed, 3 Jan 2024 20:24:24 +0800 Subject: [PATCH 083/192] add avx512fp16 to x86 target features --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 03f8f43ff1643..f8f054db65ede 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -408,7 +408,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &Locke .filter(|_feature| { target_info.cpu_supports(_feature) /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma, + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves From 52946377dc9dfbeb3c2ebc31f9263d308c0af2ab Mon Sep 17 00:00:00 2001 From: Nicholas Thompson Date: Sun, 14 Jan 2024 11:52:06 -0500 Subject: [PATCH 084/192] Honor $RUSTUP_HOME --- build_system/src/test.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 1577cbf2b53ed..dc1dc82736efb 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -556,7 +556,7 @@ verbose-tests = true [build] cargo = "{cargo}" local-rebuild = true -rustc = "{home}/.rustup/toolchains/{toolchain}-{host_triple}/bin/rustc" +rustc = "{rustup_home}/toolchains/{toolchain}-{host_triple}/bin/rustc" [target.x86_64-unknown-linux-gnu] llvm-filecheck = "{llvm_filecheck}" @@ -565,7 +565,10 @@ llvm-filecheck = "{llvm_filecheck}" download-ci-llvm = false "#, cargo = cargo.trim(), - home = env.get("HOME").unwrap(), + rustup_home = match env.get("RUSTUP_HOME") { + Some(rustup_dir) => rustup_dir.clone(), + None => env.get("HOME").unwrap().to_owned() + "/.rustup", + }, toolchain = toolchain, host_triple = args.config_info.host_triple, llvm_filecheck = llvm_filecheck.trim(), From 7dd3f6fffbefcd8acb142cd2d0d166b08619e62f Mon Sep 17 00:00:00 2001 From: Nicholas Thompson Date: Sun, 14 Jan 2024 14:19:40 -0500 Subject: [PATCH 085/192] call rustup which --- build_system/src/test.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index dc1dc82736efb..11622026994d1 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -488,8 +488,10 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { } fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { - let toolchain = get_toolchain()?; - + let toolchain = format!("+{channel}-{host}", + channel = get_toolchain()?, // May also include date + host = args.config_info.host_triple + ); let rust_dir = Some(Path::new("rust")); // If the repository was already cloned, command will fail, so doesn't matter. let _ = run_command_with_output_and_env( @@ -524,6 +526,18 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { Ok(cargo) } })?; + let rustc = String::from_utf8( + run_command_with_env(&[&"rustup", &OsStr::new(&*toolchain), &"which", &"rustc"], rust_dir, Some(env))?.stdout, + ) + .map_err(|error| format!("Failed to retrieve rustc path: {:?}", error)) + .and_then(|rustc| { + let rustc = rustc.trim().to_owned(); + if rustc.is_empty() { + Err(format!("`rustc` path is empty")) + } else { + Ok(rustc) + } + })?; let llvm_filecheck = match run_command_with_env( &[ &"bash", @@ -556,7 +570,7 @@ verbose-tests = true [build] cargo = "{cargo}" local-rebuild = true -rustc = "{rustup_home}/toolchains/{toolchain}-{host_triple}/bin/rustc" +rustc = "{rustc}" [target.x86_64-unknown-linux-gnu] llvm-filecheck = "{llvm_filecheck}" @@ -564,13 +578,8 @@ llvm-filecheck = "{llvm_filecheck}" [llvm] download-ci-llvm = false "#, - cargo = cargo.trim(), - rustup_home = match env.get("RUSTUP_HOME") { - Some(rustup_dir) => rustup_dir.clone(), - None => env.get("HOME").unwrap().to_owned() + "/.rustup", - }, - toolchain = toolchain, - host_triple = args.config_info.host_triple, + cargo = cargo, + rustc = rustc, llvm_filecheck = llvm_filecheck.trim(), ), ) From dcb531f13042c5d335ce689555aae2230c3db778 Mon Sep 17 00:00:00 2001 From: Nic Date: Tue, 16 Jan 2024 12:57:34 -0500 Subject: [PATCH 086/192] Update build_system/src/test.rs Co-authored-by: antoyo --- build_system/src/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 11622026994d1..e098e3702b890 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -527,7 +527,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { } })?; let rustc = String::from_utf8( - run_command_with_env(&[&"rustup", &OsStr::new(&*toolchain), &"which", &"rustc"], rust_dir, Some(env))?.stdout, + run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))?.stdout, ) .map_err(|error| format!("Failed to retrieve rustc path: {:?}", error)) .and_then(|rustc| { From 94ed9d16cff42752e2fdd95ca131fa8288cb513f Mon Sep 17 00:00:00 2001 From: Rowan S-L Date: Thu, 18 Jan 2024 12:41:25 -0500 Subject: [PATCH 087/192] rename `y.sh test --clean-ui-tests` to `y.sh clean ui-tests` --- build_system/src/clean.rs | 76 +++++++++++++++++++++++---------------- build_system/src/test.rs | 15 -------- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/build_system/src/clean.rs b/build_system/src/clean.rs index 56cc19d255f96..929a878113d69 100644 --- a/build_system/src/clean.rs +++ b/build_system/src/clean.rs @@ -1,40 +1,43 @@ -use crate::utils::remove_file; +use crate::utils::{remove_file, run_command}; use std::fs::remove_dir_all; #[derive(Default)] -struct CleanArg { - all: bool, +enum CleanArg { + /// `clean all` + All, + /// `clean ui-tests` + UiTests, + /// `clean --help` + #[default] + Help, } impl CleanArg { - fn new() -> Result, String> { - let mut args = CleanArg::default(); - + fn new() -> Result { // We skip the binary and the "clean" option. for arg in std::env::args().skip(2) { - match arg.as_str() { - "all" => args.all = true, - "--help" => { - Self::usage(); - return Ok(None); - } - a => return Err(format!("Unknown argument `{}`", a)), - } + return match arg.as_str() { + "all" => Ok(Self::All), + "ui-tests" => Ok(Self::UiTests), + "--help" => Ok(Self::Help), + a => Err(format!("Unknown argument `{}`", a)), + }; } - Ok(Some(args)) + Ok(Self::default()) } +} - fn usage() { - println!( - r#" - `clean` command help: +fn usage() { + println!( + r#" +`clean` command help: - all : Clean all data - --help : Show this help - "# - ) - } + all : Clean all data + ui-tests : Clean ui tests + --help : Show this help +"# + ) } fn clean_all() -> Result<(), String> { @@ -60,14 +63,25 @@ fn clean_all() -> Result<(), String> { Ok(()) } -pub fn run() -> Result<(), String> { - let args = match CleanArg::new()? { - Some(a) => a, - None => return Ok(()), - }; +fn clean_ui_tests() -> Result<(), String> { + run_command( + &[ + &"find", + &"rust/build/x86_64-unknown-linux-gnu/test/ui/", + &"-name", + &"stamp", + &"-delete", + ], + None, + )?; + Ok(()) +} - if args.all { - clean_all()?; +pub fn run() -> Result<(), String> { + match CleanArg::new()? { + CleanArg::All => clean_all()?, + CleanArg::UiTests => clean_ui_tests()?, + CleanArg::Help => usage(), } Ok(()) } diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 1577cbf2b53ed..f3d0d38499cbb 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -32,7 +32,6 @@ fn get_runners() -> Runners { ("Run failing rustc tests", test_failing_rustc), ); runners.insert("--test-libcore", ("Run libcore tests", test_libcore)); - runners.insert("--clean-ui-tests", ("Clean ui tests", clean_ui_tests)); runners.insert("--clean", ("Empty cargo target directory", clean)); runners.insert("--build-sysroot", ("Build sysroot", build_sysroot)); runners.insert("--std-tests", ("Run std tests", std_tests)); @@ -1086,20 +1085,6 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { }) } -fn clean_ui_tests(_env: &Env, _args: &TestArg) -> Result<(), String> { - run_command( - &[ - &"find", - &"rust/build/x86_64-unknown-linux-gnu/test/ui/", - &"-name", - &"stamp", - &"-delete", - ], - None, - )?; - Ok(()) -} - fn run_all(env: &Env, args: &TestArg) -> Result<(), String> { clean(env, args)?; mini_tests(env, args)?; From d34789f5d2bb31b76b8775a695ba8b559ac93303 Mon Sep 17 00:00:00 2001 From: Rowan S-L Date: Fri, 19 Jan 2024 11:18:40 -0500 Subject: [PATCH 088/192] update Intel Software Development Emulator --- .github/workflows/stdarch.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 7c3ad6281e9fb..8ffb82518efa5 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -41,9 +41,9 @@ jobs: run: | mkdir intel-sde cd intel-sde - dir=sde-external-9.14.0-2022-10-25-lin + dir=sde-external-9.33.0-2024-01-07-lin file=$dir.tar.xz - wget https://downloadmirror.intel.com/751535/$file + wget https://downloadmirror.intel.com/813591/$file tar xvf $file sudo mkdir /usr/share/intel-sde sudo cp -r $dir/* /usr/share/intel-sde From 599492a3d594312f59d051240e573176bd1df2ab Mon Sep 17 00:00:00 2001 From: liewyec Date: Sat, 20 Jan 2024 13:30:51 +0100 Subject: [PATCH 089/192] replace filter with skip and take --- build_system/src/test.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 1577cbf2b53ed..e7325d5e71fe8 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -979,12 +979,7 @@ where let start = current_part * count; let end = current_part * count + count; // We remove the files we don't want to test. - for path in files - .iter() - .enumerate() - .filter(|(pos, _)| *pos < start || *pos >= end) - .map(|(_, path)| path) - { + for path in files.iter().skip(start).take(count) { remove_file(&rust_path.join(path))?; } } From b2a7afd898b06b8d575563caebb43b32b3a149ec Mon Sep 17 00:00:00 2001 From: Nicholas Thompson Date: Tue, 23 Jan 2024 12:02:31 -0500 Subject: [PATCH 090/192] Further Implement `is_val_statically_known` --- src/context.rs | 7 ++++--- src/intrinsic/mod.rs | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/context.rs b/src/context.rs index 053f759329fb1..5760d96165ddf 100644 --- a/src/context.rs +++ b/src/context.rs @@ -196,15 +196,16 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let mut functions = FxHashMap::default(); let builtins = [ - "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow", - "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ + "__builtin_unreachable", "abort", "__builtin_expect", /*"__builtin_expect_with_probability",*/ + "__builtin_constant_p", "__builtin_add_overflow", "__builtin_mul_overflow", "__builtin_saddll_overflow", + /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow", "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow", "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos", "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf", "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf", "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round", - "__builtin_expect_with_probability", + ]; for builtin in builtins.iter() { diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 85b891fce3e42..eac8cb437794b 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -123,6 +123,12 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { sym::unlikely => { self.expect(args[0].immediate(), false) } + sym::is_val_statically_known => { + let a = args[0].immediate(); + let builtin = self.context.get_builtin_function("__builtin_constant_p"); + let res = self.context.new_call(None, builtin, &[a]); + self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) + } kw::Try => { try_intrinsic( self, From 215284a490a382cf9c1e2bde12484d7daa72e9aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Sep 2023 09:39:41 +0200 Subject: [PATCH 091/192] remove StructuralEq trait --- example/mini_core.rs | 3 --- tests/run/static.rs | 3 --- 2 files changed, 6 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index db94bc1c86af9..230009741dc41 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -100,9 +100,6 @@ unsafe impl Freeze for &mut T {} #[lang = "structural_peq"] pub trait StructuralPartialEq {} -#[lang = "structural_teq"] -pub trait StructuralEq {} - #[lang = "not"] pub trait Not { type Output; diff --git a/tests/run/static.rs b/tests/run/static.rs index 0b933754c2937..e7c46ae3fcc81 100644 --- a/tests/run/static.rs +++ b/tests/run/static.rs @@ -61,9 +61,6 @@ mod libc { #[lang = "structural_peq"] pub trait StructuralPartialEq {} -#[lang = "structural_teq"] -pub trait StructuralEq {} - #[lang = "drop_in_place"] #[allow(unconditional_recursion)] pub unsafe fn drop_in_place(to_drop: *mut T) { From b9d44eef7ad1fc21d3c6fed7f0ca5401ae59f5f8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Jan 2024 15:27:16 +1100 Subject: [PATCH 092/192] Remove the lifetime from `DiagnosticArgValue`. Because it's almost always static. This makes `impl IntoDiagnosticArg for DiagnosticArgValue` trivial, which is nice. There are a few diagnostics constructed in `compiler/rustc_mir_build/src/check_unsafety.rs` and `compiler/rustc_mir_transform/src/errors.rs` that now need symbols converted to `String` with `to_string` instead of `&str` with `as_str`, but that' no big deal, and worth it for the simplifications elsewhere. --- src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/errors.rs b/src/errors.rs index e9283b1989453..cc0fbe46dcc11 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -35,7 +35,7 @@ pub(crate) enum PossibleFeature<'a> { struct ExitCode(Option); impl IntoDiagnosticArg for ExitCode { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { let ExitCode(exit_code) = self; match exit_code { Some(t) => t.into_diagnostic_arg(), From 04e4c5ddbc7ab8e60a9481698d97e805b81fa59a Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 30 Jan 2024 20:55:56 +0000 Subject: [PATCH 093/192] Remove `ffi_returns_twice` feature --- src/attributes.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/attributes.rs b/src/attributes.rs index 9f361d3688695..142f86b003ddb 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -62,9 +62,6 @@ pub fn from_fn_attrs<'gcc, 'tcx>( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { func.add_attribute(FnAttribute::Cold); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) { - func.add_attribute(FnAttribute::ReturnsTwice); - } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) { func.add_attribute(FnAttribute::Pure); } From ad8e8201395b0c2a9dbacfde2c5aa7580a1cdb82 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 25 Jan 2024 21:20:12 -0400 Subject: [PATCH 094/192] Update for rebased gcc --- .github/workflows/ci.yml | 14 +++----------- .github/workflows/failures.yml | 14 +++----------- .github/workflows/gcc12.yml | 4 ++-- .github/workflows/m68k.yml | 12 +++--------- .github/workflows/release.yml | 14 +++----------- .github/workflows/stdarch.yml | 12 ++---------- .gitignore | 2 ++ Cargo.lock | 4 ++-- build_system/src/test.rs | 5 ++--- src/consts.rs | 2 +- src/mono_item.rs | 2 +- .../failing-lto-tests.txt | 0 .../failing-non-lto-tests.txt | 0 failing-ui-tests.txt => tests/failing-ui-tests.txt | 1 + .../failing-ui-tests12.txt | 1 - 15 files changed, 25 insertions(+), 62 deletions(-) rename failing-lto-tests.txt => tests/failing-lto-tests.txt (100%) rename failing-non-lto-tests.txt => tests/failing-non-lto-tests.txt (100%) rename failing-ui-tests.txt => tests/failing-ui-tests.txt (98%) rename failing-ui-tests12.txt => tests/failing-ui-tests12.txt (97%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d063f39293960..0d84926fddfec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,19 +49,11 @@ jobs: run: sudo apt-get install ninja-build ripgrep llvm-14-tools - name: Download artifact - uses: dawidd6/action-download-artifact@v2 - with: - workflow: main.yml - name: gcc-13 - path: gcc-13 - repo: antoyo/gcc - branch: ${{ matrix.libgccjit_version.artifacts_branch }} - event: push - search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. + run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/gcc-13.deb - name: Setup path to libgccjit run: | - sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb + sudo dpkg --force-overwrite -i gcc-13.deb echo /usr/lib/ > gcc_path - name: Set env @@ -95,7 +87,7 @@ jobs: ./y.sh prepare - name: Add more failing tests because the sysroot is not compiled with LTO - run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt + run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt - name: Run tests run: | diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index b768918a014ee..7aaf47facd87f 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -56,20 +56,12 @@ jobs: - name: Download artifact if: matrix.libgccjit_version.gcc != 'libgccjit12.so' - uses: dawidd6/action-download-artifact@v2 - with: - workflow: main.yml - name: gcc-13 - path: gcc-13 - repo: antoyo/gcc - branch: ${{ matrix.libgccjit_version.artifacts_branch }} - event: push - search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. + run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/gcc-13.deb - name: Setup path to libgccjit if: matrix.libgccjit_version.gcc != 'libgccjit12.so' run: | - sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb + sudo dpkg --force-overwrite -i gcc-13.deb echo /usr/lib/ > gcc_path - name: Set env @@ -99,7 +91,7 @@ jobs: run: ./y.sh prepare - name: Add more failing tests because the sysroot is not compiled with LTO - run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt + run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt - name: Run tests id: tests diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index a522423f36cc5..8d4f88ea7b1a4 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -78,10 +78,10 @@ jobs: ./y.sh prepare --libgccjit12-patches - name: Add more failing tests for GCC 12 - run: cat failing-ui-tests12.txt >> failing-ui-tests.txt + run: cat tests/failing-ui-tests12.txt >> tests/failing-ui-tests.txt - name: Add more failing tests because the sysroot is not compiled with LTO - run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt + run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt - name: Run tests run: | diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index af46650219852..b0866bafb8e31 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -50,14 +50,8 @@ jobs: sudo apt-get update sudo apt-get install qemu qemu-user-static - - name: Download GCC artifact - uses: dawidd6/action-download-artifact@v2 - with: - workflow: m68k.yml - name: gcc-m68k-13 - repo: cross-cg-gcc-tools/cross-gcc - branch: master - event: push + - name: Download artifact + run: curl -LO https://github.com/cross-cg-gcc-tools/cross-gcc/releases/latest/download/gcc-m68k-13.deb - name: Download VM artifact uses: dawidd6/action-download-artifact@v2 @@ -110,7 +104,7 @@ jobs: ./y.sh prepare --cross - name: Add more failing tests because the sysroot is not compiled with LTO - run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt + run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt - name: Run tests run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 071c21d5f7bb3..7628fd6557166 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,19 +37,11 @@ jobs: run: sudo apt-get install ninja-build ripgrep - name: Download artifact - uses: dawidd6/action-download-artifact@v2 - with: - workflow: main.yml - name: gcc-13 - path: gcc-13 - repo: antoyo/gcc - branch: "master" - event: push - search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. + run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/gcc-13.deb - name: Setup path to libgccjit run: | - sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb + sudo dpkg --force-overwrite -i gcc-13.deb echo /usr/lib/ > gcc_path - name: Set env @@ -76,7 +68,7 @@ jobs: echo -n 'lto = "fat"' >> build_sysroot/Cargo.toml - name: Add more failing tests because of undefined symbol errors (FIXME) - run: cat failing-lto-tests.txt >> failing-ui-tests.txt + run: cat tests/failing-lto-tests.txt >> tests/failing-ui-tests.txt - name: Run tests run: | diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 8ffb82518efa5..a5c3a5456bd7f 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -51,19 +51,11 @@ jobs: sudo ln -s /usr/share/intel-sde/sde64 /usr/bin/sde64 - name: Download artifact - uses: dawidd6/action-download-artifact@v2 - with: - workflow: main.yml - name: gcc-13 - path: gcc-13 - repo: antoyo/gcc - branch: "master" - event: push - search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. + run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/gcc-13.deb - name: Setup path to libgccjit run: | - sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb + sudo dpkg --force-overwrite -i gcc-13.deb echo /usr/lib/ > gcc_path - name: Set env diff --git a/.gitignore b/.gitignore index b44d1aa78c2e6..c865386dad306 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ gimple* res test-backend gcc_path +cross_gcc_path +projects benchmarks tools/llvm-project tools/llvmint diff --git a/Cargo.lock b/Cargo.lock index 7c18633692783..26dc7c535f854 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#6e290f25b1d1edab5ae9ace486fd2dc8c08d6421" +source = "git+https://github.com/antoyo/gccjit.rs#e6109eb8b7ced60b5191e65b34954d04d4abeaec" dependencies = [ "gccjit_sys", ] @@ -82,7 +82,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#6e290f25b1d1edab5ae9ace486fd2dc8c08d6421" +source = "git+https://github.com/antoyo/gccjit.rs#e6109eb8b7ced60b5191e65b34954d04d4abeaec" dependencies = [ "libc", ] diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 44c003d8f75e5..5e8a5ebe94960 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -988,7 +988,6 @@ where // one test. let count = files.len() / nb_parts + 1; let start = current_part * count; - let end = current_part * count + count; // We remove the files we don't want to test. for path in files.iter().skip(start).take(count) { remove_file(&rust_path.join(path))?; @@ -1047,7 +1046,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { Some(Path::new("rust")), )?; // Putting back only the failing ones. - let path = "failing-ui-tests.txt"; + let path = "tests/failing-ui-tests.txt"; if let Ok(files) = std::fs::read_to_string(path) { for file in files .split('\n') @@ -1072,7 +1071,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { test_rustc_inner(env, args, || { // Removing the failing tests. - let path = "failing-ui-tests.txt"; + let path = "tests/failing-ui-tests.txt"; if let Ok(files) = std::fs::read_to_string(path) { for file in files .split('\n') diff --git a/src/consts.rs b/src/consts.rs index d8a1fd315c0a5..2501c126faf2f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -235,7 +235,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { if !self.tcx.is_reachable_non_generic(def_id) { #[cfg(feature = "master")] - global.add_attribute(VarAttribute::Visibility(Visibility::Hidden)); + global.add_string_attribute(VarAttribute::Visibility(Visibility::Hidden)); } global diff --git a/src/mono_item.rs b/src/mono_item.rs index 3322d56513bbe..fdeb2f96fe2c9 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -23,7 +23,7 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section); #[cfg(feature="master")] - global.add_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); + global.add_string_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); // TODO(antoyo): set linkage. self.instances.borrow_mut().insert(instance, global); diff --git a/failing-lto-tests.txt b/tests/failing-lto-tests.txt similarity index 100% rename from failing-lto-tests.txt rename to tests/failing-lto-tests.txt diff --git a/failing-non-lto-tests.txt b/tests/failing-non-lto-tests.txt similarity index 100% rename from failing-non-lto-tests.txt rename to tests/failing-non-lto-tests.txt diff --git a/failing-ui-tests.txt b/tests/failing-ui-tests.txt similarity index 98% rename from failing-ui-tests.txt rename to tests/failing-ui-tests.txt index 023fe9d7e8311..13d79cd23e336 100644 --- a/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -70,3 +70,4 @@ tests/ui/async-await/deep-futures-are-freeze.rs tests/ui/closures/capture-unsized-by-ref.rs tests/ui/coroutine/resume-after-return.rs tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +tests/ui/intrinsics/intrinsics-integer.rs diff --git a/failing-ui-tests12.txt b/tests/failing-ui-tests12.txt similarity index 97% rename from failing-ui-tests12.txt rename to tests/failing-ui-tests12.txt index 3ef2bc3ebf894..857c158e42f0e 100644 --- a/failing-ui-tests12.txt +++ b/tests/failing-ui-tests12.txt @@ -38,6 +38,5 @@ tests/ui/rust-2018/proc-macro-crate-in-paths.rs tests/ui/target-feature/missing-plusminus.rs tests/ui/sse2.rs tests/ui/codegen/issue-79865-llvm-miscompile.rs -tests/ui/intrinsics/intrinsics-integer.rs tests/ui/std-backtrace.rs tests/ui/mir/alignment/packed.rs From 0a38748d8a49b21d5060b6b274a4b87cd5a7c53e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 3 Feb 2024 13:26:06 -0500 Subject: [PATCH 095/192] Renable intrinsics-integer.rs test --- tests/failing-ui-tests.txt | 1 - tests/failing-ui-tests12.txt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 13d79cd23e336..023fe9d7e8311 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -70,4 +70,3 @@ tests/ui/async-await/deep-futures-are-freeze.rs tests/ui/closures/capture-unsized-by-ref.rs tests/ui/coroutine/resume-after-return.rs tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs -tests/ui/intrinsics/intrinsics-integer.rs diff --git a/tests/failing-ui-tests12.txt b/tests/failing-ui-tests12.txt index 857c158e42f0e..b4615b26852d8 100644 --- a/tests/failing-ui-tests12.txt +++ b/tests/failing-ui-tests12.txt @@ -40,3 +40,4 @@ tests/ui/sse2.rs tests/ui/codegen/issue-79865-llvm-miscompile.rs tests/ui/std-backtrace.rs tests/ui/mir/alignment/packed.rs +tests/ui/intrinsics/intrinsics-integer.rs From 007cea323884bc8f61effcbf625bcb1d7368a7ec Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 6 Feb 2024 09:51:39 +1100 Subject: [PATCH 096/192] Invert diagnostic lints. That is, change `diagnostic_outside_of_impl` and `untranslatable_diagnostic` from `allow` to `deny`, because more than half of the compiler has be converted to use translated diagnostics. This commit removes more `deny` attributes than it adds `allow` attributes, which proves that this change is warranted. --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f8f054db65ede..863b6333bcc29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,8 +27,6 @@ #![recursion_limit="256"] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] extern crate rustc_apfloat; extern crate rustc_ast; From 31f7f03c2a08396f518d7732a5dc86f9c13de106 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 24 Jan 2024 18:01:56 +0000 Subject: [PATCH 097/192] Add CoroutineClosure to TyKind, AggregateKind, UpvarArgs --- src/type_of.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type_of.rs b/src/type_of.rs index e5c0b2de4ca46..25149b8020162 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -87,7 +87,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str if !cx.sess().fewer_names() => { let mut name = with_no_trimmed_paths!(layout.ty.to_string()); From 6b05753cb3c7373b151774540476ae04365fd898 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 8 Feb 2024 12:17:41 -0500 Subject: [PATCH 098/192] Run the tests of popular crates in the CI --- .github/workflows/ci.yml | 1 + build_system/src/prepare.rs | 2 +- build_system/src/test.rs | 56 +++++++++++++++++++++++++++++++++++-- build_system/src/utils.rs | 12 ++++++-- 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d84926fddfec..426eabdd176b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,7 @@ jobs: "--extended-regex-tests", "--test-successful-rustc --nb-parts 2 --current-part 0", "--test-successful-rustc --nb-parts 2 --current-part 1", + "--projects", ] steps: diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index ce9b440be053a..7f1401e594c4c 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -152,7 +152,7 @@ fn clone_and_setup(repo_url: &str, checkout_commit: &str, extra: Option) - where F: Fn(&Path) -> Result<(), String>, { - let clone_result = git_clone(repo_url, None)?; + let clone_result = git_clone(repo_url, None, false)?; if !clone_result.ran_clone { println!("`{}` has already been cloned", clone_result.repo_name); } diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 5e8a5ebe94960..6564322924318 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -1,13 +1,13 @@ use crate::build; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ - get_gcc_path, get_toolchain, remove_file, run_command, run_command_with_env, + get_gcc_path, get_toolchain, git_clone, remove_file, run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, split_args, walk_dir, }; use std::collections::{BTreeSet, HashMap}; use std::ffi::OsStr; -use std::fs::{remove_dir_all, File}; +use std::fs::{create_dir_all, remove_dir_all, File}; use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -31,6 +31,7 @@ fn get_runners() -> Runners { "--test-failing-rustc", ("Run failing rustc tests", test_failing_rustc), ); + runners.insert("--projects", ("Run the tests of popular crates", test_projects)); runners.insert("--test-libcore", ("Run libcore tests", test_libcore)); runners.insert("--clean", ("Empty cargo target directory", clean)); runners.insert("--build-sysroot", ("Build sysroot", build_sysroot)); @@ -679,6 +680,57 @@ where // echo "[BUILD] sysroot in release mode" // ./build_sysroot/build_sysroot.sh --release +fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { + let projects = [ + //"https://gitlab.gnome.org/GNOME/librsvg", // FIXME: doesn't compile in the CI since the + // version of cairo and other libraries is too old. + "https://github.com/rust-random/getrandom", + "https://github.com/BurntSushi/memchr", + "https://github.com/dtolnay/itoa", + "https://github.com/rust-lang/cfg-if", + "https://github.com/rust-lang-nursery/lazy-static.rs", + //"https://github.com/marshallpierce/rust-base64", // FIXME: one test is OOM-killed. + // TODO: ignore the base64 test that is OOM-killed. + "https://github.com/time-rs/time", + "https://github.com/rust-lang/log", + "https://github.com/bitflags/bitflags", + //"https://github.com/serde-rs/serde", // FIXME: one test fails. + //"https://github.com/rayon-rs/rayon", // TODO: very slow, only run on master? + //"https://github.com/rust-lang/cargo", // TODO: very slow, only run on master? + ]; + + let run_tests = |projects_path, iter: &mut dyn Iterator| -> Result<(), String> { + for project in iter { + let clone_result = git_clone(project, Some(projects_path), true)?; + let repo_path = Path::new(&clone_result.repo_dir); + run_cargo_command(&[&"build", &"--release"], Some(repo_path), env, args)?; + run_cargo_command(&[&"test"], Some(repo_path), env, args)?; + } + + Ok(()) + }; + + let projects_path = Path::new("projects"); + create_dir_all(projects_path) + .map_err(|err| format!("Failed to create directory `projects`: {}", err))?; + + let nb_parts = args.nb_parts.unwrap_or(0); + if nb_parts > 0 { + // We increment the number of tests by one because if this is an odd number, we would skip + // one test. + let count = projects.len() / nb_parts + 1; + let current_part = args.current_part.unwrap(); + let start = current_part * count; + // We remove the projects we don't want to test. + run_tests(projects_path, &mut projects.iter().skip(start).take(count))?; + } + else { + run_tests(projects_path, &mut projects.iter())?; + } + + Ok(()) +} + fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] libcore"); diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index f0a07b597a0f4..85f1e18006caf 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -283,9 +283,10 @@ pub fn get_gcc_path() -> Result { pub struct CloneResult { pub ran_clone: bool, pub repo_name: String, + pub repo_dir: String, } -pub fn git_clone(to_clone: &str, dest: Option<&Path>) -> Result { +pub fn git_clone(to_clone: &str, dest: Option<&Path>, shallow_clone: bool) -> Result { let repo_name = to_clone.split('/').last().unwrap(); let repo_name = match repo_name.strip_suffix(".git") { Some(n) => n.to_string(), @@ -299,13 +300,20 @@ pub fn git_clone(to_clone: &str, dest: Option<&Path>) -> Result> = vec![&"git", &"clone", &to_clone, &dest]; + if shallow_clone { + command.push(&"--depth"); + command.push(&"1"); + } + run_command_with_output(&command, None)?; Ok(CloneResult { ran_clone: true, repo_name, + repo_dir: dest.display().to_string(), }) } From 2640b316e2e64dd1c4a79ba81bd2da809ad47d41 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Feb 2024 15:26:44 +0100 Subject: [PATCH 099/192] Switch to `config.toml` instead of `gcc-path` --- .gitignore | 1 + Readme.md | 22 ++++++-- build_system/Cargo.lock | 9 +++ build_system/Cargo.toml | 3 + build_system/src/build.rs | 25 +++++---- build_system/src/config.rs | 112 ++++++++++++++++++++++++++++++++++--- build_system/src/test.rs | 35 ++++++++---- build_system/src/utils.rs | 32 ----------- config.example.toml | 2 + 9 files changed, 173 insertions(+), 68 deletions(-) create mode 100644 config.example.toml diff --git a/.gitignore b/.gitignore index c865386dad306..687c3a6797af1 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ tools/llvmint-2 # The `llvm` folder is generated by the `tools/generate_intrinsics.py` script to update intrinsics. llvm build_system/target +config.toml diff --git a/Readme.md b/Readme.md index 39ff41acf84ae..a380d0d5be6d1 100644 --- a/Readme.md +++ b/Readme.md @@ -49,17 +49,27 @@ $ make check-jit $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-asm.cc" ``` -**Put the path to your custom build of libgccjit in the file `gcc_path`.** +**Put the path to your custom build of libgccjit in the file `config.toml`.** + +If you followed the instructions exactly as written (ie, you have created a `gcc-build` folder +where gcc is built), the only thing you need to do is: + +```bash +$ cp config.example.toml config.toml +``` + +But if you did something different, you also need to set the `gcc-path` value in `config.toml` with +the result of this command: ```bash -$ dirname $(readlink -f `find . -name libgccjit.so`) > gcc_path +$ dirname $(readlink -f `find . -name libgccjit.so`) ``` Then you can run commands like this: ```bash $ ./y.sh prepare # download and patch sysroot src and install hyperfine for benchmarking -$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./y.sh build --release --features master +$ ./y.sh build --release --features master ``` To run the tests: @@ -100,7 +110,7 @@ error: failed to copy bitcode to object file: No such file or directory (os erro > You should prefer using the Cargo method. ```bash -$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) rustc +$(cat $CG_GCCJIT_DIR/rust-toolchain | grep 'channel' | cut -d '=' -f 2 | sed 's/"//g' | sed 's/ //g') -Cpanic=abort -Zcodegen-backend=$CG_GCCJIT_DIR/target/release/librustc_codegen_gcc.so --sysroot $CG_GCCJIT_DIR/build_sysroot/sysroot my_crate.rs +$ LIBRARY_PATH="[gcc-path value]" LD_LIBRARY_PATH="[gcc-path value]" rustc +$(cat $CG_GCCJIT_DIR/rust-toolchain | grep 'channel' | cut -d '=' -f 2 | sed 's/"//g' | sed 's/ //g') -Cpanic=abort -Zcodegen-backend=$CG_GCCJIT_DIR/target/release/librustc_codegen_gcc.so --sysroot $CG_GCCJIT_DIR/build_sysroot/sysroot my_crate.rs ``` ## Env vars @@ -322,7 +332,7 @@ generate it in [gimple.md](./doc/gimple.md). #### Configuring rustc_codegen_gcc * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case. - * Set the path to the cross-compiling libgccjit in `gcc_path`. + * Set the path to the cross-compiling libgccjit in `gcc-path` (in `config.toml`). * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu`. * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target m68k-unknown-linux-gnu`. @@ -338,4 +348,4 @@ If you get the following error: /usr/bin/ld: unrecognised emulation mode: m68kelf ``` -Make sure you set `gcc_path` to the install directory. +Make sure you set `gcc-path` (in `config.toml`) to the install directory. diff --git a/build_system/Cargo.lock b/build_system/Cargo.lock index 86268e1916030..e727561a2bfba 100644 --- a/build_system/Cargo.lock +++ b/build_system/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "boml" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5" + [[package]] name = "y" version = "0.1.0" +dependencies = [ + "boml", +] diff --git a/build_system/Cargo.toml b/build_system/Cargo.toml index f36709ea03605..d2600ed5a0314 100644 --- a/build_system/Cargo.toml +++ b/build_system/Cargo.toml @@ -3,6 +3,9 @@ name = "y" version = "0.1.0" edition = "2021" +[dependencies] +boml = "0.3.1" + [[bin]] name = "y" path = "src/main.rs" diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 3149560b458a8..efae5a46b04f9 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -1,5 +1,5 @@ use crate::config::{Channel, ConfigInfo}; -use crate::utils::{get_gcc_path, run_command, run_command_with_output_and_env, walk_dir}; +use crate::utils::{run_command, run_command_with_output_and_env, walk_dir}; use std::collections::HashMap; use std::ffi::OsStr; use std::fs; @@ -8,17 +8,12 @@ use std::path::Path; #[derive(Default)] struct BuildArg { flags: Vec, - gcc_path: String, config_info: ConfigInfo, } impl BuildArg { fn new() -> Result, String> { - let gcc_path = get_gcc_path()?; - let mut build_arg = Self { - gcc_path, - ..Default::default() - }; + let mut build_arg = Self::default(); // We skip binary name and the `build` command. let mut args = std::env::args().skip(2); @@ -169,7 +164,8 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu fs::create_dir_all(&sysroot_src_path).map_err(|error| { format!( "Failed to create directory `{}`: {:?}", - sysroot_src_path.display(), error + sysroot_src_path.display(), + error ) })?; run_command( @@ -188,8 +184,14 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu fn build_codegen(args: &mut BuildArg) -> Result<(), String> { let mut env = HashMap::new(); - env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone()); - env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone()); + env.insert( + "LD_LIBRARY_PATH".to_string(), + args.config_info.gcc_path.clone(), + ); + env.insert( + "LIBRARY_PATH".to_string(), + args.config_info.gcc_path.clone(), + ); let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; if args.config_info.channel == Channel::Release { @@ -205,7 +207,7 @@ fn build_codegen(args: &mut BuildArg) -> Result<(), String> { } run_command_with_output_and_env(&command, None, Some(&env))?; - args.config_info.setup(&mut env, Some(&args.gcc_path))?; + args.config_info.setup(&mut env, None)?; // We voluntarily ignore the error. let _ = fs::remove_dir_all("target/out"); @@ -227,6 +229,7 @@ pub fn run() -> Result<(), String> { Some(args) => args, None => return Ok(()), }; + args.config_info.setup_gcc_path(None)?; build_codegen(&mut args)?; Ok(()) } diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 1824bdd292ffa..09fa3ee9d3b9c 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -1,7 +1,11 @@ -use crate::utils::{get_gcc_path, get_os_name, rustc_version_info, split_args}; +use crate::utils::{get_os_name, rustc_version_info, split_args}; use std::collections::HashMap; use std::env as std_env; use std::ffi::OsStr; +use std::fs; +use std::path::Path; + +use boml::{types::TomlValue, Toml}; #[derive(Default, PartialEq, Eq, Clone, Copy, Debug)] pub enum Channel { @@ -19,6 +23,72 @@ impl Channel { } } +fn failed_config_parsing(err: &str) -> Result { + Err(format!( + "Failed to parse `{}`: {}", + ConfigFile::CONFIG_FILE, + err + )) +} + +#[derive(Default)] +pub struct ConfigFile { + gcc_path: Option, + download_gccjit: Option, +} + +impl ConfigFile { + pub const CONFIG_FILE: &'static str = "config.toml"; + + pub fn new() -> Result { + let content = fs::read_to_string(Self::CONFIG_FILE).map_err(|_| { + format!( + "Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project", + Self::CONFIG_FILE, + ) + })?; + let toml = Toml::parse(&content).map_err(|err| { + format!( + "Error occurred around `{}`: {:?}", + &content[err.start..=err.end], + err.kind + ) + })?; + let mut config = Self::default(); + for (key, value) in toml.iter() { + match (key, value) { + ("gcc-path", TomlValue::String(value)) => { + config.gcc_path = Some(value.as_str().to_string()) + } + ("gcc-path", _) => { + return failed_config_parsing("Expected a string for `gcc-path`") + } + ("download-gccjit", TomlValue::Boolean(value)) => { + config.download_gccjit = Some(*value) + } + ("download-gccjit", _) => { + return failed_config_parsing("Expected a boolean for `download-gccjit`") + } + _ => return failed_config_parsing(&format!("Unknown key `{}`", key)), + } + } + if config.gcc_path.is_none() && config.download_gccjit.is_none() { + return failed_config_parsing( + "At least one of `gcc-path` or `download-gccjit` value must be set", + ); + } + if let Some(gcc_path) = config.gcc_path.as_mut() { + let path = Path::new(gcc_path); + *gcc_path = path + .canonicalize() + .map_err(|err| format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err))? + .display() + .to_string(); + } + Ok(config) + } +} + #[derive(Default, Debug)] pub struct ConfigInfo { pub target: String, @@ -33,6 +103,7 @@ pub struct ConfigInfo { pub sysroot_panic_abort: bool, pub cg_backend_path: String, pub sysroot_path: String, + pub gcc_path: String, } impl ConfigInfo { @@ -80,18 +151,43 @@ impl ConfigInfo { command } + pub fn setup_gcc_path(&mut self, override_gcc_path: Option<&str>) -> Result<(), String> { + let ConfigFile { gcc_path, .. } = ConfigFile::new()?; + + self.gcc_path = match override_gcc_path { + Some(path) => { + if gcc_path.is_some() { + println!("overriding setting from `{}`", ConfigFile::CONFIG_FILE); + } + path.to_string() + } + None => { + match gcc_path { + Some(path) => path, + // FIXME: Once we support "download", rewrite this. + None => { + return Err(format!( + "missing `gcc-path` value from `{}`", + ConfigFile::CONFIG_FILE + )) + } + } + } + }; + Ok(()) + } + pub fn setup( &mut self, env: &mut HashMap, - gcc_path: Option<&str>, + override_gcc_path: Option<&str>, ) -> Result<(), String> { env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string()); - let gcc_path = match gcc_path { - Some(path) => path.to_string(), - None => get_gcc_path()?, - }; - env.insert("GCC_PATH".to_string(), gcc_path.clone()); + if self.gcc_path.is_empty() || override_gcc_path.is_some() { + self.setup_gcc_path(override_gcc_path)?; + } + env.insert("GCC_PATH".to_string(), self.gcc_path.clone()); if self.cargo_target_dir.is_empty() { match env.get("CARGO_TARGET_DIR").filter(|dir| !dir.is_empty()) { @@ -225,7 +321,9 @@ impl ConfigInfo { // line option to change it. target = current_dir.join("target/out").display(), sysroot = sysroot.display(), + gcc_path = self.gcc_path, ); + env.insert("LIBRARY_PATH".to_string(), ld_library_path.clone()); env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone()); env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path); diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 6564322924318..1cacd6efc7fee 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -1,7 +1,7 @@ use crate::build; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ - get_gcc_path, get_toolchain, git_clone, remove_file, run_command, run_command_with_env, + get_toolchain, git_clone, remove_file, run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, split_args, walk_dir, }; @@ -109,7 +109,7 @@ fn show_usage() { struct TestArg { no_default_features: bool, build_only: bool, - gcc_path: String, + gcc_path: Option, runners: BTreeSet, flags: Vec, backend: Option, @@ -181,12 +181,10 @@ impl TestArg { } } - test_arg.gcc_path = if use_system_gcc { + if use_system_gcc { println!("Using system GCC"); - "gcc".to_string() - } else { - get_gcc_path()? - }; + test_arg.gcc_path = Some("gcc".to_string()); + } } match (test_arg.current_part, test_arg.nb_parts) { (Some(_), Some(_)) | (None, None) => {} @@ -488,7 +486,8 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { } fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { - let toolchain = format!("+{channel}-{host}", + let toolchain = format!( + "+{channel}-{host}", channel = get_toolchain()?, // May also include date host = args.config_info.host_triple ); @@ -527,7 +526,12 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { } })?; let rustc = String::from_utf8( - run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))?.stdout, + run_command_with_env( + &[&"rustup", &toolchain, &"which", &"rustc"], + rust_dir, + Some(env), + )? + .stdout, ) .map_err(|error| format!("Failed to retrieve rustc path: {:?}", error)) .and_then(|rustc| { @@ -1162,8 +1166,15 @@ pub fn run() -> Result<(), String> { }; let mut env: HashMap = std::env::vars().collect(); - env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone()); - env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone()); + args.config_info.setup_gcc_path(None)?; + env.insert( + "LIBRARY_PATH".to_string(), + args.config_info.gcc_path.clone(), + ); + env.insert( + "LD_LIBRARY_PATH".to_string(), + args.config_info.gcc_path.clone(), + ); build_if_no_backend(&env, &args)?; if args.build_only { @@ -1171,7 +1182,7 @@ pub fn run() -> Result<(), String> { return Ok(()); } - args.config_info.setup(&mut env, Some(&args.gcc_path))?; + args.config_info.setup(&mut env, args.gcc_path.as_deref())?; if args.runners.is_empty() { run_all(&env, &args)?; diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 85f1e18006caf..b288eff94a5d4 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -248,38 +248,6 @@ pub fn get_toolchain() -> Result { } } -pub fn get_gcc_path() -> Result { - let content = match fs::read_to_string("gcc_path") { - Ok(content) => content, - Err(_) => { - return Err( - "Please put the path to your custom build of libgccjit in the file \ - `gcc_path`, see Readme.md for details" - .into(), - ) - } - }; - match content - .split('\n') - .map(|line| line.trim()) - .filter(|line| !line.is_empty()) - .next() - { - Some(gcc_path) => { - let path = Path::new(gcc_path); - if !path.exists() { - Err(format!( - "Path `{}` contained in the `gcc_path` file doesn't exist", - gcc_path, - )) - } else { - Ok(gcc_path.into()) - } - } - None => Err("No path found in `gcc_path` file".into()), - } -} - pub struct CloneResult { pub ran_clone: bool, pub repo_name: String, diff --git a/config.example.toml b/config.example.toml new file mode 100644 index 0000000000000..dcc414b731001 --- /dev/null +++ b/config.example.toml @@ -0,0 +1,2 @@ +gcc-path = "gcc-build/gcc" +# download-gccjit = true From 0b2402fdfcf0f126abb3c2f2ce11fd8ac79f5c38 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Feb 2024 16:47:28 +0100 Subject: [PATCH 100/192] Update CI scripts to work with `config.toml` --- .github/workflows/ci.yml | 6 +++--- .github/workflows/failures.yml | 11 +++++++---- .github/workflows/gcc12.yml | 6 +++--- .github/workflows/m68k.yml | 6 +++--- .github/workflows/release.yml | 6 +++--- .github/workflows/stdarch.yml | 6 +++--- 6 files changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 426eabdd176b9..ba64f40acc4ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,13 +55,13 @@ jobs: - name: Setup path to libgccjit run: | sudo dpkg --force-overwrite -i gcc-13.deb - echo /usr/lib/ > gcc_path + echo 'gcc-path = "/usr/lib/"' > config.toml - name: Set env run: | - echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV #- name: Cache rust repository ## We only clone the rust repository for rustc tests diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index 7aaf47facd87f..ae00a257e2486 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -52,7 +52,10 @@ jobs: - name: Setup path to libgccjit if: matrix.libgccjit_version.gcc == 'libgccjit12.so' - run: echo /usr/lib/gcc/x86_64-linux-gnu/12 > gcc_path + run: | + echo 'gcc-path = "/usr/lib/gcc/x86_64-linux-gnu/12"' > config.toml + echo "LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV - name: Download artifact if: matrix.libgccjit_version.gcc != 'libgccjit12.so' @@ -62,12 +65,12 @@ jobs: if: matrix.libgccjit_version.gcc != 'libgccjit12.so' run: | sudo dpkg --force-overwrite -i gcc-13.deb - echo /usr/lib/ > gcc_path + echo 'gcc-path = "/usr/lib"' > config.toml + echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV - name: Set env run: | - echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV #- name: Cache rust repository diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index 8d4f88ea7b1a4..f7bb156049233 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -47,13 +47,13 @@ jobs: run: sudo apt-get install ninja-build ripgrep llvm-14-tools libgccjit-12-dev - name: Setup path to libgccjit - run: echo /usr/lib/gcc/x86_64-linux-gnu/12 > gcc_path + run: echo 'gcc-path = "/usr/lib/gcc/x86_64-linux-gnu/12"' > config.toml - name: Set env run: | - echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + echo "LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV #- name: Cache rust repository ## We only clone the rust repository for rustc tests diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index b0866bafb8e31..2428125483bdd 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -65,13 +65,13 @@ jobs: - name: Setup path to libgccjit run: | sudo dpkg -i gcc-m68k-13.deb - echo /usr/lib/ > gcc_path + echo 'gcc-path = "/usr/lib/"' > config.toml - name: Set env run: | - echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV #- name: Cache rust repository ## We only clone the rust repository for rustc tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7628fd6557166..729a76e80bf90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,13 +42,13 @@ jobs: - name: Setup path to libgccjit run: | sudo dpkg --force-overwrite -i gcc-13.deb - echo /usr/lib/ > gcc_path + echo 'gcc-path = "/usr/lib/"' > config.toml - name: Set env run: | - echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV - name: Build run: | diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index a5c3a5456bd7f..65687756cd4eb 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -56,13 +56,13 @@ jobs: - name: Setup path to libgccjit run: | sudo dpkg --force-overwrite -i gcc-13.deb - echo /usr/lib/ > gcc_path + echo 'gcc-path = "/usr/lib/"' > config.toml - name: Set env run: | - echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV - name: Build run: | From 79241b8a4e511a4e59761477c0bdffea24bd7201 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Feb 2024 17:00:37 +0100 Subject: [PATCH 101/192] Update tests to use `config.toml` instead --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + tests/lang_tests_common.rs | 13 +++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26dc7c535f854..a19de10d0d29b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "boml" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5" + [[package]] name = "cc" version = "1.0.79" @@ -185,6 +191,7 @@ checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" name = "rustc_codegen_gcc" version = "0.1.0" dependencies = [ + "boml", "gccjit", "lang_tester", "object", diff --git a/Cargo.toml b/Cargo.toml index b0b3aeecdbdfd..a280ac73de093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ tempfile = "3.7.1" [dev-dependencies] lang_tester = "0.3.9" tempfile = "3.1.0" +boml = "0.3.1" [profile.dev] # By compiling dependencies with optimizations, performing tests gets much faster. diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index af0133aad461d..029a3b98ff23a 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -7,6 +7,7 @@ use std::{ use lang_tester::LangTester; use tempfile::TempDir; +use boml::Toml; /// Controls the compile options (e.g., optimization level) used to compile /// test code. @@ -20,8 +21,16 @@ pub fn main_inner(profile: Profile) { let tempdir = TempDir::new().expect("temp dir"); let current_dir = current_dir().expect("current dir"); let current_dir = current_dir.to_str().expect("current dir").to_string(); - let gcc_path = include_str!("../gcc_path"); - let gcc_path = gcc_path.trim(); + let gcc_path = Toml::parse(include_str!("../config.toml")) + .expect("Failed to parse `config.toml`") + .get_string("gcc-path") + .expect("Missing `gcc-path` key in `config.toml`") + .to_string(); + let gcc_path = Path::new(&gcc_path) + .canonicalize() + .expect("failed to get absolute path of `gcc-path`") + .display() + .to_string(); env::set_var("LD_LIBRARY_PATH", gcc_path); fn rust_filter(filename: &Path) -> bool { From de9d1b63b4b1bde72baee556c833fb9fe73e013b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Feb 2024 17:37:56 +0100 Subject: [PATCH 102/192] Add `--config-file` option to override default location of `config.toml` --- build_system/src/config.rs | 48 ++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 09fa3ee9d3b9c..5ba6233617ec5 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -23,12 +23,8 @@ impl Channel { } } -fn failed_config_parsing(err: &str) -> Result { - Err(format!( - "Failed to parse `{}`: {}", - ConfigFile::CONFIG_FILE, - err - )) +fn failed_config_parsing(config_file: &str, err: &str) -> Result { + Err(format!("Failed to parse `{}`: {}", config_file, err)) } #[derive(Default)] @@ -38,13 +34,12 @@ pub struct ConfigFile { } impl ConfigFile { - pub const CONFIG_FILE: &'static str = "config.toml"; - - pub fn new() -> Result { - let content = fs::read_to_string(Self::CONFIG_FILE).map_err(|_| { + pub fn new(config_file: Option<&str>) -> Result { + let config_file = config_file.unwrap_or("config.toml"); + let content = fs::read_to_string(config_file).map_err(|_| { format!( "Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project", - Self::CONFIG_FILE, + config_file, ) })?; let toml = Toml::parse(&content).map_err(|err| { @@ -61,19 +56,23 @@ impl ConfigFile { config.gcc_path = Some(value.as_str().to_string()) } ("gcc-path", _) => { - return failed_config_parsing("Expected a string for `gcc-path`") + return failed_config_parsing(config_file, "Expected a string for `gcc-path`") } ("download-gccjit", TomlValue::Boolean(value)) => { config.download_gccjit = Some(*value) } ("download-gccjit", _) => { - return failed_config_parsing("Expected a boolean for `download-gccjit`") + return failed_config_parsing( + config_file, + "Expected a boolean for `download-gccjit`", + ) } - _ => return failed_config_parsing(&format!("Unknown key `{}`", key)), + _ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)), } } if config.gcc_path.is_none() && config.download_gccjit.is_none() { return failed_config_parsing( + config_file, "At least one of `gcc-path` or `download-gccjit` value must be set", ); } @@ -104,6 +103,7 @@ pub struct ConfigInfo { pub cg_backend_path: String, pub sysroot_path: String, pub gcc_path: String, + config_file: Option, } impl ConfigInfo { @@ -135,6 +135,14 @@ impl ConfigInfo { } _ => return Err("Expected a value after `--out-dir`, found nothing".to_string()), }, + "--config-file" => match args.next() { + Some(arg) if !arg.is_empty() => { + self.config_file = Some(arg.to_string()); + } + _ => { + return Err("Expected a value after `--config-file`, found nothing".to_string()) + } + }, "--release-sysroot" => self.sysroot_release_channel = true, "--release" => self.channel = Channel::Release, "--sysroot-panic-abort" => self.sysroot_panic_abort = true, @@ -152,12 +160,15 @@ impl ConfigInfo { } pub fn setup_gcc_path(&mut self, override_gcc_path: Option<&str>) -> Result<(), String> { - let ConfigFile { gcc_path, .. } = ConfigFile::new()?; + let ConfigFile { gcc_path, .. } = ConfigFile::new(self.config_file.as_deref())?; self.gcc_path = match override_gcc_path { Some(path) => { if gcc_path.is_some() { - println!("overriding setting from `{}`", ConfigFile::CONFIG_FILE); + println!( + "overriding setting from `{}`", + self.config_file.as_deref().unwrap_or("config.toml") + ); } path.to_string() } @@ -168,7 +179,7 @@ impl ConfigInfo { None => { return Err(format!( "missing `gcc-path` value from `{}`", - ConfigFile::CONFIG_FILE + self.config_file.as_deref().unwrap_or("config.toml"), )) } } @@ -363,7 +374,8 @@ impl ConfigInfo { --out-dir : Location where the files will be generated --release : Build in release mode --release-sysroot : Build sysroot in release mode - --sysroot-panic-abort : Build the sysroot without unwinding support." + --sysroot-panic-abort : Build the sysroot without unwinding support + --config-file : Location of the config file to be used" ); } } From 588db24344dc2b626bb050067e9e6cda2de3bc59 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Feb 2024 14:41:18 +0100 Subject: [PATCH 103/192] Correctly handle `--use-system-gcc` --- build_system/src/build.rs | 4 ++-- build_system/src/cargo.rs | 2 +- build_system/src/config.rs | 35 ++++++++++------------------- build_system/src/test.rs | 45 +++++++++++++++++++------------------- build_system/src/utils.rs | 6 ++++- 5 files changed, 42 insertions(+), 50 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index efae5a46b04f9..308ad34654941 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -207,7 +207,7 @@ fn build_codegen(args: &mut BuildArg) -> Result<(), String> { } run_command_with_output_and_env(&command, None, Some(&env))?; - args.config_info.setup(&mut env, None)?; + args.config_info.setup(&mut env, false)?; // We voluntarily ignore the error. let _ = fs::remove_dir_all("target/out"); @@ -229,7 +229,7 @@ pub fn run() -> Result<(), String> { Some(args) => args, None => return Ok(()), }; - args.config_info.setup_gcc_path(None)?; + args.config_info.setup_gcc_path()?; build_codegen(&mut args)?; Ok(()) } diff --git a/build_system/src/cargo.rs b/build_system/src/cargo.rs index 67b301d9aa646..1cfcdba6b1cd1 100644 --- a/build_system/src/cargo.rs +++ b/build_system/src/cargo.rs @@ -77,7 +77,7 @@ pub fn run() -> Result<(), String> { })?; let mut env: HashMap = std::env::vars().collect(); - ConfigInfo::default().setup(&mut env, None)?; + ConfigInfo::default().setup(&mut env, false)?; let toolchain = get_toolchain()?; let toolchain_version = rustc_toolchain_version_info(&toolchain)?; diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 5ba6233617ec5..49782fc64ef70 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -159,30 +159,17 @@ impl ConfigInfo { command } - pub fn setup_gcc_path(&mut self, override_gcc_path: Option<&str>) -> Result<(), String> { + pub fn setup_gcc_path(&mut self) -> Result<(), String> { let ConfigFile { gcc_path, .. } = ConfigFile::new(self.config_file.as_deref())?; - self.gcc_path = match override_gcc_path { - Some(path) => { - if gcc_path.is_some() { - println!( - "overriding setting from `{}`", - self.config_file.as_deref().unwrap_or("config.toml") - ); - } - path.to_string() - } + self.gcc_path = match gcc_path { + Some(path) => path, + // FIXME: Once we support "download", rewrite this. None => { - match gcc_path { - Some(path) => path, - // FIXME: Once we support "download", rewrite this. - None => { - return Err(format!( - "missing `gcc-path` value from `{}`", - self.config_file.as_deref().unwrap_or("config.toml"), - )) - } - } + return Err(format!( + "missing `gcc-path` value from `{}`", + self.config_file.as_deref().unwrap_or("config.toml"), + )) } }; Ok(()) @@ -191,12 +178,12 @@ impl ConfigInfo { pub fn setup( &mut self, env: &mut HashMap, - override_gcc_path: Option<&str>, + use_system_gcc: bool, ) -> Result<(), String> { env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string()); - if self.gcc_path.is_empty() || override_gcc_path.is_some() { - self.setup_gcc_path(override_gcc_path)?; + if self.gcc_path.is_empty() && !use_system_gcc { + self.setup_gcc_path()?; } env.insert("GCC_PATH".to_string(), self.gcc_path.clone()); diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 1cacd6efc7fee..806e18431c46d 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -31,7 +31,10 @@ fn get_runners() -> Runners { "--test-failing-rustc", ("Run failing rustc tests", test_failing_rustc), ); - runners.insert("--projects", ("Run the tests of popular crates", test_projects)); + runners.insert( + "--projects", + ("Run the tests of popular crates", test_projects), + ); runners.insert("--test-libcore", ("Run libcore tests", test_libcore)); runners.insert("--clean", ("Empty cargo target directory", clean)); runners.insert("--build-sysroot", ("Build sysroot", build_sysroot)); @@ -109,7 +112,7 @@ fn show_usage() { struct TestArg { no_default_features: bool, build_only: bool, - gcc_path: Option, + use_system_gcc: bool, runners: BTreeSet, flags: Vec, backend: Option, @@ -121,7 +124,6 @@ struct TestArg { impl TestArg { fn new() -> Result, String> { - let mut use_system_gcc = false; let mut test_arg = Self::default(); // We skip binary name and the `test` command. @@ -147,7 +149,10 @@ impl TestArg { return Err("Expected an argument after `--features`, found nothing".into()) } }, - "--use-system-gcc" => use_system_gcc = true, + "--use-system-gcc" => { + println!("Using system GCC"); + test_arg.use_system_gcc = true; + } "--build-only" => test_arg.build_only = true, "--use-backend" => match args.next() { Some(backend) if !backend.is_empty() => test_arg.backend = Some(backend), @@ -180,11 +185,6 @@ impl TestArg { } } } - - if use_system_gcc { - println!("Using system GCC"); - test_arg.gcc_path = Some("gcc".to_string()); - } } match (test_arg.current_part, test_arg.nb_parts) { (Some(_), Some(_)) | (None, None) => {} @@ -703,7 +703,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { //"https://github.com/rust-lang/cargo", // TODO: very slow, only run on master? ]; - let run_tests = |projects_path, iter: &mut dyn Iterator| -> Result<(), String> { + let run_tests = |projects_path, iter: &mut dyn Iterator| -> Result<(), String> { for project in iter { let clone_result = git_clone(project, Some(projects_path), true)?; let repo_path = Path::new(&clone_result.repo_dir); @@ -727,8 +727,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { let start = current_part * count; // We remove the projects we don't want to test. run_tests(projects_path, &mut projects.iter().skip(start).take(count))?; - } - else { + } else { run_tests(projects_path, &mut projects.iter())?; } @@ -1166,15 +1165,17 @@ pub fn run() -> Result<(), String> { }; let mut env: HashMap = std::env::vars().collect(); - args.config_info.setup_gcc_path(None)?; - env.insert( - "LIBRARY_PATH".to_string(), - args.config_info.gcc_path.clone(), - ); - env.insert( - "LD_LIBRARY_PATH".to_string(), - args.config_info.gcc_path.clone(), - ); + if !args.use_system_gcc { + args.config_info.setup_gcc_path()?; + env.insert( + "LIBRARY_PATH".to_string(), + args.config_info.gcc_path.clone(), + ); + env.insert( + "LD_LIBRARY_PATH".to_string(), + args.config_info.gcc_path.clone(), + ); + } build_if_no_backend(&env, &args)?; if args.build_only { @@ -1182,7 +1183,7 @@ pub fn run() -> Result<(), String> { return Ok(()); } - args.config_info.setup(&mut env, args.gcc_path.as_deref())?; + args.config_info.setup(&mut env, args.use_system_gcc)?; if args.runners.is_empty() { run_all(&env, &args)?; diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index b288eff94a5d4..046008ae1a247 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -254,7 +254,11 @@ pub struct CloneResult { pub repo_dir: String, } -pub fn git_clone(to_clone: &str, dest: Option<&Path>, shallow_clone: bool) -> Result { +pub fn git_clone( + to_clone: &str, + dest: Option<&Path>, + shallow_clone: bool, +) -> Result { let repo_name = to_clone.split('/').last().unwrap(); let repo_name = match repo_name.strip_suffix(".git") { Some(n) => n.to_string(), From 64dfa4f455ed72e1c17a82fa67a577b869ed5992 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Jan 2024 20:39:59 +0000 Subject: [PATCH 104/192] Teach llvm backend how to fall back to default bodies --- src/intrinsic/mod.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index eac8cb437794b..f162ef831b768 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -90,7 +90,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> } impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { - fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) { + fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) -> Result<(), Instance<'tcx>> { let tcx = self.tcx; let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); @@ -137,7 +137,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { args[2].immediate(), llresult, ); - return; + return Ok(()); } sym::breakpoint => { unimplemented!(); @@ -166,12 +166,12 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { sym::volatile_store => { let dst = args[0].deref(self.cx()); args[1].val.volatile_store(self, dst); - return; + return Ok(()); } sym::unaligned_volatile_store => { let dst = args[0].deref(self.cx()); args[1].val.unaligned_volatile_store(self, dst); - return; + return Ok(()); } sym::prefetch_read_data | sym::prefetch_write_data @@ -269,7 +269,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }, None => { tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); - return; + return Ok(()); } } } @@ -339,7 +339,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { extended_asm.set_volatile_flag(true); // We have copied the value to `result` already. - return; + return Ok(()); } sym::ptr_mask => { @@ -357,11 +357,12 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, - Err(()) => return, + Err(()) => return Ok(()), } } - _ => bug!("unknown intrinsic '{}'", name), + // Fall back to default body + _ => return Err(Instance::new(instance.def_id(), instance.args)), }; if !fn_abi.ret.is_ignore() { @@ -376,6 +377,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { .store(self, result); } } + Ok(()) } fn abort(&mut self) { From 5d5137cebce6c3906238fd82d728017cac89a5c4 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 12 Feb 2024 21:20:12 -0400 Subject: [PATCH 105/192] Rework the download function to only contain the platform-specific code --- build_system/src/config.rs | 156 ++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 475f9b300f74c..c9bfcb9e6ba47 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -190,83 +190,6 @@ impl ConfigInfo { command } - fn download_gccjit( - &self, - output_dir: &Path, - libgccjit_so_name: &str, - commit: &str, - ) -> Result<(), String> { - // Download time! - let tempfile_name = format!("{}.download", libgccjit_so_name); - let tempfile = output_dir.join(&tempfile_name); - let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok(); - - let url = format!( - "https://github.com/antoyo/gcc/releases/download/master-{}/libgccjit.so", - commit, - ); - - println!("Downloading `{}`...", url); - // Try curl. If that fails and we are on windows, fallback to PowerShell. - let mut ret = run_command_with_output( - &[ - &"curl", - &"--speed-time", - &"30", - &"--speed-limit", - &"10", // timeout if speed is < 10 bytes/sec for > 30 seconds - &"--connect-timeout", - &"30", // timeout if cannot connect within 30 seconds - &"-o", - &tempfile_name, - &"--retry", - &"3", - &"-SRfL", - if is_in_ci { &"-s" } else { &"--progress-bar" }, - &url.as_str(), - ], - Some(&output_dir), - ); - if ret.is_err() && cfg!(windows) { - eprintln!("Fallback to PowerShell"); - ret = run_command_with_output( - &[ - &"PowerShell.exe", - &"/nologo", - &"-Command", - &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", - &format!( - "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", - url, - tempfile_name, - ).as_str(), - ], - Some(&output_dir), - ); - } - ret?; - - let libgccjit_so = output_dir.join(libgccjit_so_name); - // If we reach this point, it means the file was correctly downloaded, so let's - // rename it! - std::fs::rename(&tempfile, &libgccjit_so).map_err(|err| { - format!( - "Failed to rename `{}` into `{}`: {:?}", - tempfile.display(), - libgccjit_so.display(), - err, - ) - })?; - - println!("Downloaded libgccjit.so version {} successfully!", commit); - // We need to create a link named `libgccjit.so.0` because that's what the linker is - // looking for. - create_symlink( - &libgccjit_so, - output_dir.join(&format!("{}.0", libgccjit_so_name)), - ) - } - fn download_gccjit_if_needed(&mut self) -> Result<(), String> { let output_dir = Path::new( std::env::var("CARGO_TARGET_DIR") @@ -313,7 +236,38 @@ impl ConfigInfo { let libgccjit_so_name = "libgccjit.so"; let libgccjit_so = output_dir.join(libgccjit_so_name); if !libgccjit_so.is_file() && !self.no_download { - self.download_gccjit(&output_dir, libgccjit_so_name, commit)?; + // Download time! + let tempfile_name = format!("{}.download", libgccjit_so_name); + let tempfile = output_dir.join(&tempfile_name); + let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok(); + + let url = format!( + "https://github.com/antoyo/gcc/releases/download/master-{}/libgccjit.so", + commit, + ); + + println!("Downloading `{}`...", url); + download_gccjit(url, &output_dir, tempfile_name, !is_in_ci)?; + + let libgccjit_so = output_dir.join(libgccjit_so_name); + // If we reach this point, it means the file was correctly downloaded, so let's + // rename it! + std::fs::rename(&tempfile, &libgccjit_so).map_err(|err| { + format!( + "Failed to rename `{}` into `{}`: {:?}", + tempfile.display(), + libgccjit_so.display(), + err, + ) + })?; + + println!("Downloaded libgccjit.so version {} successfully!", commit); + // We need to create a link named `libgccjit.so.0` because that's what the linker is + // looking for. + create_symlink( + &libgccjit_so, + output_dir.join(&format!("{}.0", libgccjit_so_name)), + )?; } self.gcc_path = output_dir.display().to_string(); @@ -547,3 +501,49 @@ impl ConfigInfo { ); } } + +fn download_gccjit( + url: String, + output_dir: &Path, + tempfile_name: String, + with_progress_bar: bool, +) -> Result<(), String> { + // Try curl. If that fails and we are on windows, fallback to PowerShell. + let mut ret = run_command_with_output( + &[ + &"curl", + &"--speed-time", + &"30", + &"--speed-limit", + &"10", // timeout if speed is < 10 bytes/sec for > 30 seconds + &"--connect-timeout", + &"30", // timeout if cannot connect within 30 seconds + &"-o", + &tempfile_name, + &"--retry", + &"3", + &"-SRfL", + if with_progress_bar { &"--progress-bar" } else { &"-s" }, + &url.as_str(), + ], + Some(&output_dir), + ); + if ret.is_err() && cfg!(windows) { + eprintln!("Fallback to PowerShell"); + ret = run_command_with_output( + &[ + &"PowerShell.exe", + &"/nologo", + &"-Command", + &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + &format!( + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", + url, + tempfile_name, + ).as_str(), + ], + Some(&output_dir), + ); + } + ret +} From eee04a48d9b0ba2ca7e18c6465c51a63feed8e08 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Feb 2024 18:07:05 +0100 Subject: [PATCH 106/192] Add support for "download" --- build_system/src/config.rs | 201 ++++++++++++++++++++++++++++++++----- libgccjit.version | 1 + 2 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 libgccjit.version diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 49782fc64ef70..0201e3509dcd3 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -1,9 +1,9 @@ -use crate::utils::{get_os_name, rustc_version_info, split_args}; +use crate::utils::{get_os_name, run_command_with_output, rustc_version_info, split_args}; use std::collections::HashMap; use std::env as std_env; use std::ffi::OsStr; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use boml::{types::TomlValue, Toml}; @@ -23,8 +23,12 @@ impl Channel { } } -fn failed_config_parsing(config_file: &str, err: &str) -> Result { - Err(format!("Failed to parse `{}`: {}", config_file, err)) +fn failed_config_parsing(config_file: &Path, err: &str) -> Result { + Err(format!( + "Failed to parse `{}`: {}", + config_file.display(), + err + )) } #[derive(Default)] @@ -34,12 +38,11 @@ pub struct ConfigFile { } impl ConfigFile { - pub fn new(config_file: Option<&str>) -> Result { - let config_file = config_file.unwrap_or("config.toml"); + pub fn new(config_file: &Path) -> Result { let content = fs::read_to_string(config_file).map_err(|_| { format!( "Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project", - config_file, + config_file.display(), ) })?; let toml = Toml::parse(&content).map_err(|err| { @@ -70,19 +73,30 @@ impl ConfigFile { _ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)), } } - if config.gcc_path.is_none() && config.download_gccjit.is_none() { - return failed_config_parsing( - config_file, - "At least one of `gcc-path` or `download-gccjit` value must be set", - ); - } - if let Some(gcc_path) = config.gcc_path.as_mut() { - let path = Path::new(gcc_path); - *gcc_path = path - .canonicalize() - .map_err(|err| format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err))? - .display() - .to_string(); + match (config.gcc_path.as_mut(), config.download_gccjit) { + (None, None | Some(false)) => { + return failed_config_parsing( + config_file, + "At least one of `gcc-path` or `download-gccjit` value must be set", + ) + } + (Some(_), Some(true)) => { + println!( + "WARNING: both `gcc-path` and `download-gccjit` arguments are used, \ + ignoring `gcc-path`" + ); + } + (Some(gcc_path), _) => { + let path = Path::new(gcc_path); + *gcc_path = path + .canonicalize() + .map_err(|err| { + format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err) + })? + .display() + .to_string(); + } + _ => {} } Ok(config) } @@ -104,6 +118,7 @@ pub struct ConfigInfo { pub sysroot_path: String, pub gcc_path: String, config_file: Option, + cg_gcc_path: Option, } impl ConfigInfo { @@ -146,6 +161,14 @@ impl ConfigInfo { "--release-sysroot" => self.sysroot_release_channel = true, "--release" => self.channel = Channel::Release, "--sysroot-panic-abort" => self.sysroot_panic_abort = true, + "--cg_gcc-path" => match args.next() { + Some(arg) if !arg.is_empty() => { + self.cg_gcc_path = Some(arg.into()); + } + _ => { + return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()) + } + }, _ => return Ok(false), } Ok(true) @@ -159,16 +182,144 @@ impl ConfigInfo { command } + fn download_gccjit_if_needed(&mut self) -> Result<(), String> { + let output_dir = Path::new( + std::env::var("CARGO_TARGET_DIR") + .as_deref() + .unwrap_or("target"), + ) + .join("libgccjit"); + + let commit_hash_file = self.compute_path("libgccjit.version"); + let content = fs::read_to_string(&commit_hash_file).map_err(|_| { + format!( + "Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project", + commit_hash_file.display(), + ) + })?; + let commit = content.trim(); + if commit.contains('/') || commit.contains('\\') { + return Err(format!( + "{}: invalid commit hash `{}`", + commit_hash_file.display(), + commit + )); + } + let output_dir = output_dir.join(commit); + if !output_dir.is_dir() { + std::fs::create_dir_all(&output_dir).map_err(|err| { + format!( + "failed to create folder `{}`: {:?}", + output_dir.display(), + err, + ) + })?; + } + let libgccjit_so = output_dir.join("libgccjit.so"); + if !libgccjit_so.is_file() { + // Download time! + let tempfile_name = "libgccjit.so.download"; + let tempfile = output_dir.join(tempfile_name); + let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok(); + + let url = format!( + "https://github.com/antoyo/gcc/releases/download/master-{}/libgccjit.so", + commit, + ); + + println!("Downloading `{}`...", url); + // Try curl. If that fails and we are on windows, fallback to PowerShell. + let mut ret = run_command_with_output( + &[ + &"curl", + &"--speed-time", + &"30", + &"--speed-limit", + &"10", // timeout if speed is < 10 bytes/sec for > 30 seconds + &"--connect-timeout", + &"30", // timeout if cannot connect within 30 seconds + &"-o", + &tempfile_name, + &"--retry", + &"3", + &"-SRfL", + if is_in_ci { &"-s" } else { &"--progress-bar" }, + &url.as_str(), + ], + Some(&output_dir), + ); + if ret.is_err() && cfg!(windows) { + eprintln!("Fallback to PowerShell"); + ret = run_command_with_output( + &[ + &"PowerShell.exe", + &"/nologo", + &"-Command", + &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + &format!( + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", + url, + tempfile_name, + ).as_str(), + ], + Some(&output_dir), + ); + } + ret?; + + // If we reach this point, it means the file was correctly downloaded, so let's + // rename it! + std::fs::rename(&tempfile, &libgccjit_so).map_err(|err| { + format!( + "Failed to rename `{}` into `{}`: {:?}", + tempfile.display(), + libgccjit_so.display(), + err, + ) + })?; + + println!("Downloaded libgccjit.so version {} successfully!", commit); + } + + self.gcc_path = output_dir + .canonicalize() + .map_err(|err| { + format!( + "Failed to get absolute path of `{}`: {:?}", + output_dir.display(), + err + ) + })? + .display() + .to_string(); + println!("Using `{}` as path for libgccjit", self.gcc_path); + Ok(()) + } + + pub fn compute_path>(&self, other: P) -> PathBuf { + match self.cg_gcc_path { + Some(ref path) => path.join(other), + None => PathBuf::new().join(other), + } + } + pub fn setup_gcc_path(&mut self) -> Result<(), String> { - let ConfigFile { gcc_path, .. } = ConfigFile::new(self.config_file.as_deref())?; + let config_file = self.compute_path(self.config_file.as_deref().unwrap_or("config.toml")); + let ConfigFile { + gcc_path, + download_gccjit, + } = ConfigFile::new(&config_file)?; + if let Some(true) = download_gccjit { + self.download_gccjit_if_needed()?; + return Ok(()); + } self.gcc_path = match gcc_path { Some(path) => path, - // FIXME: Once we support "download", rewrite this. None => { return Err(format!( "missing `gcc-path` value from `{}`", - self.config_file.as_deref().unwrap_or("config.toml"), + config_file.display(), )) } }; @@ -362,7 +513,9 @@ impl ConfigInfo { --release : Build in release mode --release-sysroot : Build sysroot in release mode --sysroot-panic-abort : Build the sysroot without unwinding support - --config-file : Location of the config file to be used" + --config-file : Location of the config file to be used + --cg_gcc-path : Location of the rustc_codegen_gcc root folder (used + for accessing any file from the project)" ); } } diff --git a/libgccjit.version b/libgccjit.version new file mode 100644 index 0000000000000..3fc84f4ddd4ec --- /dev/null +++ b/libgccjit.version @@ -0,0 +1 @@ +2fc8940e1 From 0a4b0af141add015d1388c6b457530fcdd3f0316 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Feb 2024 20:09:54 +0100 Subject: [PATCH 107/192] Generate symbolic link to libgccjit.so as well --- build_system/src/config.rs | 17 +++++++++++++++-- build_system/src/utils.rs | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 0201e3509dcd3..a206bab14a9a8 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -1,4 +1,6 @@ -use crate::utils::{get_os_name, run_command_with_output, rustc_version_info, split_args}; +use crate::utils::{ + create_symlink, get_os_name, run_command_with_output, rustc_version_info, split_args, +}; use std::collections::HashMap; use std::env as std_env; use std::ffi::OsStr; @@ -215,7 +217,8 @@ impl ConfigInfo { ) })?; } - let libgccjit_so = output_dir.join("libgccjit.so"); + let libgccjit_so_name = "libgccjit.so"; + let libgccjit_so = output_dir.join(libgccjit_so_name); if !libgccjit_so.is_file() { // Download time! let tempfile_name = "libgccjit.so.download"; @@ -279,6 +282,16 @@ impl ConfigInfo { })?; println!("Downloaded libgccjit.so version {} successfully!", commit); + create_symlink( + &libgccjit_so.canonicalize().map_err(|err| { + format!( + "Failed to get absolute path of `{}`: {:?}", + libgccjit_so.display(), + err, + ) + })?, + output_dir.join(&format!("{}.0", libgccjit_so_name)), + )?; } self.gcc_path = output_dir diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 046008ae1a247..33dcd9ef7005f 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -374,6 +374,22 @@ pub fn remove_file + ?Sized>(file_path: &P) -> Result<(), String> }) } +pub fn create_symlink, Q: AsRef>(original: P, link: Q) -> Result<(), String> { + #[cfg(windows)] + let symlink = std::os::windows::fs::symlink_file; + #[cfg(not(windows))] + let symlink = std::os::unix::fs::symlink; + + symlink(&original, &link).map_err(|err| { + format!( + "failed to create a symlink `{}` to `{}`: {:?}", + original.as_ref().display(), + link.as_ref().display(), + err, + ) + }) +} + #[cfg(test)] mod tests { use super::*; From 5c6cdf5ab6399604695c94031e32087cfe3367ae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Feb 2024 20:55:14 +0100 Subject: [PATCH 108/192] Add `info` command to help get some information --- build_system/src/config.rs | 35 +++++++++++++++-------------------- build_system/src/info.rs | 19 +++++++++++++++++++ build_system/src/main.rs | 5 +++++ 3 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 build_system/src/info.rs diff --git a/build_system/src/config.rs b/build_system/src/config.rs index a206bab14a9a8..48be515a1f0f8 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -121,6 +121,9 @@ pub struct ConfigInfo { pub gcc_path: String, config_file: Option, cg_gcc_path: Option, + // Needed for the `info` command which doesn't want to actually download the lib if needed, + // just to set the `gcc_path` field to display it. + pub no_download: bool, } impl ConfigInfo { @@ -204,7 +207,7 @@ impl ConfigInfo { return Err(format!( "{}: invalid commit hash `{}`", commit_hash_file.display(), - commit + commit, )); } let output_dir = output_dir.join(commit); @@ -217,9 +220,17 @@ impl ConfigInfo { ) })?; } + let output_dir = output_dir.canonicalize().map_err(|err| { + format!( + "Failed to get absolute path of `{}`: {:?}", + output_dir.display(), + err + ) + })?; + let libgccjit_so_name = "libgccjit.so"; let libgccjit_so = output_dir.join(libgccjit_so_name); - if !libgccjit_so.is_file() { + if !libgccjit_so.is_file() && !self.no_download { // Download time! let tempfile_name = "libgccjit.so.download"; let tempfile = output_dir.join(tempfile_name); @@ -283,28 +294,12 @@ impl ConfigInfo { println!("Downloaded libgccjit.so version {} successfully!", commit); create_symlink( - &libgccjit_so.canonicalize().map_err(|err| { - format!( - "Failed to get absolute path of `{}`: {:?}", - libgccjit_so.display(), - err, - ) - })?, + &libgccjit_so, output_dir.join(&format!("{}.0", libgccjit_so_name)), )?; } - self.gcc_path = output_dir - .canonicalize() - .map_err(|err| { - format!( - "Failed to get absolute path of `{}`: {:?}", - output_dir.display(), - err - ) - })? - .display() - .to_string(); + self.gcc_path = output_dir.display().to_string(); println!("Using `{}` as path for libgccjit", self.gcc_path); Ok(()) } diff --git a/build_system/src/info.rs b/build_system/src/info.rs new file mode 100644 index 0000000000000..ea38791d38c9a --- /dev/null +++ b/build_system/src/info.rs @@ -0,0 +1,19 @@ +use crate::config::ConfigInfo; + +pub fn run() -> Result<(), String> { + let mut config = ConfigInfo::default(); + + // We skip binary name and the `info` command. + let mut args = std::env::args().skip(2); + while let Some(arg) = args.next() { + if arg == "--help" { + println!("Display the path where the libgccjit will be located"); + return Ok(()); + } + config.parse_argument(&arg, &mut args)?; + } + config.no_download = true; + config.setup_gcc_path()?; + println!("{}", config.gcc_path); + Ok(()) +} diff --git a/build_system/src/main.rs b/build_system/src/main.rs index 102c5486a75e4..c6958f0c5124e 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -5,6 +5,7 @@ mod build; mod cargo; mod clean; mod config; +mod info; mod prepare; mod rustc_info; mod test; @@ -29,6 +30,7 @@ Available commands for build_system: prepare : Run prepare command build : Run build command test : Run test command + info: : Run info command --help : Show this message" ); } @@ -39,6 +41,7 @@ pub enum Command { Prepare, Build, Test, + Info, } fn main() { @@ -52,6 +55,7 @@ fn main() { Some("prepare") => Command::Prepare, Some("build") => Command::Build, Some("test") => Command::Test, + Some("info") => Command::Info, Some("--help") => { usage(); process::exit(0); @@ -70,6 +74,7 @@ fn main() { Command::Prepare => prepare::run(), Command::Build => build::run(), Command::Test => test::run(), + Command::Info => info::run(), } { eprintln!("Command failed to run: {e}"); process::exit(1); From 65f4b6354d8899e9292f8666d2804a0306b0770e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Feb 2024 18:11:37 +0100 Subject: [PATCH 109/192] Add CI for download config --- .github/workflows/download.yml | 97 ++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 .github/workflows/download.yml diff --git a/.github/workflows/download.yml b/.github/workflows/download.yml new file mode 100644 index 0000000000000..86a8459a33c91 --- /dev/null +++ b/.github/workflows/download.yml @@ -0,0 +1,97 @@ +name: Check download command + +on: + - push + - pull_request + +permissions: + contents: read + +env: + # Enable backtraces for easier debugging + RUST_BACKTRACE: 1 + +jobs: + build: + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + commands: [ + "--mini-tests", + "--std-tests", + # FIXME: re-enable asm tests when GCC can emit in the right syntax. + # "--asm-tests", + "--test-libcore", + "--extended-rand-tests", + "--extended-regex-example-tests", + "--extended-regex-tests", + "--test-successful-rustc --nb-parts 2 --current-part 0", + "--test-successful-rustc --nb-parts 2 --current-part 1", + "--projects", + ] + + steps: + - uses: actions/checkout@v3 + + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + + - name: Install packages + # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. + run: sudo apt-get install ninja-build ripgrep llvm-14-tools + + - name: Setup path to libgccjit + run: | + echo 'download-gccjit = true' > config.toml + + - name: Set env + run: | + echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + + #- name: Cache rust repository + ## We only clone the rust repository for rustc tests + #if: ${{ contains(matrix.commands, 'rustc') }} + #uses: actions/cache@v3 + #id: cache-rust-repository + #with: + #path: rust + #key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }} + + - name: Build + run: | + ./y.sh prepare --only-libcore + # TODO: remove --features master when it is back to the default. + ./y.sh build --features master + # TODO: remove --features master when it is back to the default. + + - name: Set env (part 2) + run: | + # Set the `LD_LIBRARY_PATH` and `LIBRARY_PATH` env variables... + echo "LD_LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV + echo "LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV + + - name: Build (part 2) + run: | + echo "LIBRARY_PATH=" $LIBRARY_PATH + cargo test --features master + ./y.sh clean all + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./y.sh prepare + + - name: Add more failing tests because the sysroot is not compiled with LTO + run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt + + - name: Run tests + run: | + # TODO: remove --features master when it is back to the default. + ./y.sh test --features master --release --clean --build-sysroot ${{ matrix.commands }} From d04ffb0ffc10bbf2623f32fc6840ed3a7614ff33 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Feb 2024 22:52:57 +0100 Subject: [PATCH 110/192] Update lang_tests_common.rs test --- tests/lang_tests_common.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 029a3b98ff23a..33dc6ef62ae52 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -21,11 +21,16 @@ pub fn main_inner(profile: Profile) { let tempdir = TempDir::new().expect("temp dir"); let current_dir = current_dir().expect("current dir"); let current_dir = current_dir.to_str().expect("current dir").to_string(); - let gcc_path = Toml::parse(include_str!("../config.toml")) - .expect("Failed to parse `config.toml`") - .get_string("gcc-path") - .expect("Missing `gcc-path` key in `config.toml`") - .to_string(); + let toml = Toml::parse(include_str!("../config.toml")) + .expect("Failed to parse `config.toml`"); + let gcc_path = if let Ok(gcc_path) = toml.get_string("gcc-path") { + PathBuf::from(gcc_path.to_string()) + } else { + // then we try to retrieve it from the `target` folder. + let commit = include_str!("../libgccjit.version").trim(); + Path::new("target/libgccjit").join(commit) + }; + let gcc_path = Path::new(&gcc_path) .canonicalize() .expect("failed to get absolute path of `gcc-path`") From 59546ea2d53c9f3c9f0e87bb2852d6b972ec8f8b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 14:20:39 +0100 Subject: [PATCH 111/192] Merge `download.yml` into `ci.yml` --- .github/workflows/ci.yml | 20 +++---- .github/workflows/download.yml | 97 ---------------------------------- 2 files changed, 10 insertions(+), 107 deletions(-) delete mode 100644 .github/workflows/download.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba64f40acc4ba..e4678c4e2af4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,19 +49,10 @@ jobs: # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. run: sudo apt-get install ninja-build ripgrep llvm-14-tools - - name: Download artifact - run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/gcc-13.deb - - - name: Setup path to libgccjit - run: | - sudo dpkg --force-overwrite -i gcc-13.deb - echo 'gcc-path = "/usr/lib/"' > config.toml - - name: Set env run: | echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo 'download-gccjit = true' > config.toml #- name: Cache rust repository ## We only clone the rust repository for rustc tests @@ -78,6 +69,15 @@ jobs: # TODO: remove --features master when it is back to the default. ./y.sh build --features master # TODO: remove --features master when it is back to the default. + + - name: Set env (part 2) + run: | + # Set the `LD_LIBRARY_PATH` and `LIBRARY_PATH` env variables... + echo "LD_LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV + echo "LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV + + - name: Build (part 2) + run: | cargo test --features master ./y.sh clean all diff --git a/.github/workflows/download.yml b/.github/workflows/download.yml deleted file mode 100644 index 86a8459a33c91..0000000000000 --- a/.github/workflows/download.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Check download command - -on: - - push - - pull_request - -permissions: - contents: read - -env: - # Enable backtraces for easier debugging - RUST_BACKTRACE: 1 - -jobs: - build: - runs-on: ubuntu-22.04 - - strategy: - fail-fast: false - matrix: - commands: [ - "--mini-tests", - "--std-tests", - # FIXME: re-enable asm tests when GCC can emit in the right syntax. - # "--asm-tests", - "--test-libcore", - "--extended-rand-tests", - "--extended-regex-example-tests", - "--extended-regex-tests", - "--test-successful-rustc --nb-parts 2 --current-part 0", - "--test-successful-rustc --nb-parts 2 --current-part 1", - "--projects", - ] - - steps: - - uses: actions/checkout@v3 - - # `rustup show` installs from rust-toolchain.toml - - name: Setup rust toolchain - run: rustup show - - - name: Setup rust cache - uses: Swatinem/rust-cache@v2 - - - name: Install packages - # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. - run: sudo apt-get install ninja-build ripgrep llvm-14-tools - - - name: Setup path to libgccjit - run: | - echo 'download-gccjit = true' > config.toml - - - name: Set env - run: | - echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - #- name: Cache rust repository - ## We only clone the rust repository for rustc tests - #if: ${{ contains(matrix.commands, 'rustc') }} - #uses: actions/cache@v3 - #id: cache-rust-repository - #with: - #path: rust - #key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }} - - - name: Build - run: | - ./y.sh prepare --only-libcore - # TODO: remove --features master when it is back to the default. - ./y.sh build --features master - # TODO: remove --features master when it is back to the default. - - - name: Set env (part 2) - run: | - # Set the `LD_LIBRARY_PATH` and `LIBRARY_PATH` env variables... - echo "LD_LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV - echo "LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV - - - name: Build (part 2) - run: | - echo "LIBRARY_PATH=" $LIBRARY_PATH - cargo test --features master - ./y.sh clean all - - - name: Prepare dependencies - run: | - git config --global user.email "user@example.com" - git config --global user.name "User" - ./y.sh prepare - - - name: Add more failing tests because the sysroot is not compiled with LTO - run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt - - - name: Run tests - run: | - # TODO: remove --features master when it is back to the default. - ./y.sh test --features master --release --clean --build-sysroot ${{ matrix.commands }} From 2bcc73540cbadaae43b539567252f79dffd43f5a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 14:44:19 +0100 Subject: [PATCH 112/192] Don't join config file path if provided through `--config-file` option --- build_system/src/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 48be515a1f0f8..b48e132ebd2aa 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -312,7 +312,10 @@ impl ConfigInfo { } pub fn setup_gcc_path(&mut self) -> Result<(), String> { - let config_file = self.compute_path(self.config_file.as_deref().unwrap_or("config.toml")); + let config_file = match self.config_file.as_deref() { + Some(config_file) => config_file.into(), + None => self.compute_path("config.toml"), + }; let ConfigFile { gcc_path, download_gccjit, From 1096b1b8db1ac3bdb13f77e3726a00d9516af5a0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 15:01:13 +0100 Subject: [PATCH 113/192] Add more explanation on what `cg_gcc_path` is used for and improve help message for `--cg_gcc-path` --- build_system/src/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index b48e132ebd2aa..fc2ef7b797d56 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -120,6 +120,9 @@ pub struct ConfigInfo { pub sysroot_path: String, pub gcc_path: String, config_file: Option, + // This is used in particular in rust compiler bootstrap because it doesn't run at the root + // of the `cg_gcc` folder, making it complicated for us to get access to local files we need + // like `libgccjit.version` or `config.toml`. cg_gcc_path: Option, // Needed for the `info` command which doesn't want to actually download the lib if needed, // just to set the `gcc_path` field to display it. @@ -526,7 +529,7 @@ impl ConfigInfo { --sysroot-panic-abort : Build the sysroot without unwinding support --config-file : Location of the config file to be used --cg_gcc-path : Location of the rustc_codegen_gcc root folder (used - for accessing any file from the project)" + when ran from another directory)" ); } } From b80a99922be9866d4117931e50127f36010a8dc9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 15:43:07 +0100 Subject: [PATCH 114/192] Improve code readability and add more code comments --- build_system/src/config.rs | 146 ++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 66 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index fc2ef7b797d56..475f9b300f74c 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -190,6 +190,83 @@ impl ConfigInfo { command } + fn download_gccjit( + &self, + output_dir: &Path, + libgccjit_so_name: &str, + commit: &str, + ) -> Result<(), String> { + // Download time! + let tempfile_name = format!("{}.download", libgccjit_so_name); + let tempfile = output_dir.join(&tempfile_name); + let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok(); + + let url = format!( + "https://github.com/antoyo/gcc/releases/download/master-{}/libgccjit.so", + commit, + ); + + println!("Downloading `{}`...", url); + // Try curl. If that fails and we are on windows, fallback to PowerShell. + let mut ret = run_command_with_output( + &[ + &"curl", + &"--speed-time", + &"30", + &"--speed-limit", + &"10", // timeout if speed is < 10 bytes/sec for > 30 seconds + &"--connect-timeout", + &"30", // timeout if cannot connect within 30 seconds + &"-o", + &tempfile_name, + &"--retry", + &"3", + &"-SRfL", + if is_in_ci { &"-s" } else { &"--progress-bar" }, + &url.as_str(), + ], + Some(&output_dir), + ); + if ret.is_err() && cfg!(windows) { + eprintln!("Fallback to PowerShell"); + ret = run_command_with_output( + &[ + &"PowerShell.exe", + &"/nologo", + &"-Command", + &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + &format!( + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", + url, + tempfile_name, + ).as_str(), + ], + Some(&output_dir), + ); + } + ret?; + + let libgccjit_so = output_dir.join(libgccjit_so_name); + // If we reach this point, it means the file was correctly downloaded, so let's + // rename it! + std::fs::rename(&tempfile, &libgccjit_so).map_err(|err| { + format!( + "Failed to rename `{}` into `{}`: {:?}", + tempfile.display(), + libgccjit_so.display(), + err, + ) + })?; + + println!("Downloaded libgccjit.so version {} successfully!", commit); + // We need to create a link named `libgccjit.so.0` because that's what the linker is + // looking for. + create_symlink( + &libgccjit_so, + output_dir.join(&format!("{}.0", libgccjit_so_name)), + ) + } + fn download_gccjit_if_needed(&mut self) -> Result<(), String> { let output_dir = Path::new( std::env::var("CARGO_TARGET_DIR") @@ -206,6 +283,8 @@ impl ConfigInfo { ) })?; let commit = content.trim(); + // This is a very simple check to ensure this is not a path. For the rest, it'll just fail + // when trying to download the file so we should be fine. if commit.contains('/') || commit.contains('\\') { return Err(format!( "{}: invalid commit hash `{}`", @@ -234,72 +313,7 @@ impl ConfigInfo { let libgccjit_so_name = "libgccjit.so"; let libgccjit_so = output_dir.join(libgccjit_so_name); if !libgccjit_so.is_file() && !self.no_download { - // Download time! - let tempfile_name = "libgccjit.so.download"; - let tempfile = output_dir.join(tempfile_name); - let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok(); - - let url = format!( - "https://github.com/antoyo/gcc/releases/download/master-{}/libgccjit.so", - commit, - ); - - println!("Downloading `{}`...", url); - // Try curl. If that fails and we are on windows, fallback to PowerShell. - let mut ret = run_command_with_output( - &[ - &"curl", - &"--speed-time", - &"30", - &"--speed-limit", - &"10", // timeout if speed is < 10 bytes/sec for > 30 seconds - &"--connect-timeout", - &"30", // timeout if cannot connect within 30 seconds - &"-o", - &tempfile_name, - &"--retry", - &"3", - &"-SRfL", - if is_in_ci { &"-s" } else { &"--progress-bar" }, - &url.as_str(), - ], - Some(&output_dir), - ); - if ret.is_err() && cfg!(windows) { - eprintln!("Fallback to PowerShell"); - ret = run_command_with_output( - &[ - &"PowerShell.exe", - &"/nologo", - &"-Command", - &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", - &format!( - "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", - url, - tempfile_name, - ).as_str(), - ], - Some(&output_dir), - ); - } - ret?; - - // If we reach this point, it means the file was correctly downloaded, so let's - // rename it! - std::fs::rename(&tempfile, &libgccjit_so).map_err(|err| { - format!( - "Failed to rename `{}` into `{}`: {:?}", - tempfile.display(), - libgccjit_so.display(), - err, - ) - })?; - - println!("Downloaded libgccjit.so version {} successfully!", commit); - create_symlink( - &libgccjit_so, - output_dir.join(&format!("{}.0", libgccjit_so_name)), - )?; + self.download_gccjit(&output_dir, libgccjit_so_name, commit)?; } self.gcc_path = output_dir.display().to_string(); From 267aaef81dade6f1c1ae09fe820a31ff6de95e38 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 21:26:14 +0100 Subject: [PATCH 115/192] Move some top-level folders into `build` --- build_system/src/clean.rs | 19 ++++------ build_system/src/config.rs | 12 ++++-- build_system/src/main.rs | 2 + build_system/src/prepare.rs | 7 ++-- build_system/src/test.rs | 75 +++++++++++++++++++++---------------- 5 files changed, 62 insertions(+), 53 deletions(-) diff --git a/build_system/src/clean.rs b/build_system/src/clean.rs index 929a878113d69..cd8e691a0ed9f 100644 --- a/build_system/src/clean.rs +++ b/build_system/src/clean.rs @@ -1,6 +1,7 @@ use crate::utils::{remove_file, run_command}; use std::fs::remove_dir_all; +use std::path::Path; #[derive(Default)] enum CleanArg { @@ -46,12 +47,14 @@ fn clean_all() -> Result<(), String> { "build_sysroot/sysroot", "build_sysroot/sysroot_src", "build_sysroot/target", - "regex", - "simple-raytracer", ]; for dir in dirs_to_remove { let _ = remove_dir_all(dir); } + let dirs_to_remove = ["regex", "rand", "simple-raytracer"]; + for dir in dirs_to_remove { + let _ = remove_dir_all(Path::new(crate::BUILD_DIR).join(dir)); + } let files_to_remove = ["build_sysroot/Cargo.lock", "perf.data", "perf.data.old"]; @@ -64,16 +67,8 @@ fn clean_all() -> Result<(), String> { } fn clean_ui_tests() -> Result<(), String> { - run_command( - &[ - &"find", - &"rust/build/x86_64-unknown-linux-gnu/test/ui/", - &"-name", - &"stamp", - &"-delete", - ], - None, - )?; + let path = Path::new(crate::BUILD_DIR).join("rust/build/x86_64-unknown-linux-gnu/test/ui/"); + run_command(&[&"find", &path, &"-name", &"stamp", &"-delete"], None)?; Ok(()) } diff --git a/build_system/src/config.rs b/build_system/src/config.rs index c9bfcb9e6ba47..d1047436cebdb 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -523,7 +523,11 @@ fn download_gccjit( &"--retry", &"3", &"-SRfL", - if with_progress_bar { &"--progress-bar" } else { &"-s" }, + if with_progress_bar { + &"--progress-bar" + } else { + &"-s" + }, &url.as_str(), ], Some(&output_dir), @@ -538,9 +542,9 @@ fn download_gccjit( &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", &format!( "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", - url, - tempfile_name, - ).as_str(), + url, tempfile_name, + ) + .as_str(), ], Some(&output_dir), ); diff --git a/build_system/src/main.rs b/build_system/src/main.rs index c6958f0c5124e..18dc4b21a9623 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -11,6 +11,8 @@ mod rustc_info; mod test; mod utils; +const BUILD_DIR: &str = "build"; + macro_rules! arg_error { ($($err:tt)*) => {{ eprintln!($($err)*); diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index 7f1401e594c4c..979438d041516 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -152,11 +152,11 @@ fn clone_and_setup(repo_url: &str, checkout_commit: &str, extra: Option) - where F: Fn(&Path) -> Result<(), String>, { - let clone_result = git_clone(repo_url, None, false)?; + let clone_result = git_clone(repo_url, Some(&Path::new(crate::BUILD_DIR)), false)?; if !clone_result.ran_clone { println!("`{}` has already been cloned", clone_result.repo_name); } - let repo_path = Path::new(&clone_result.repo_name); + let repo_path = Path::new(crate::BUILD_DIR).join(&clone_result.repo_name); run_command(&[&"git", &"checkout", &"--", &"."], Some(&repo_path))?; run_command(&[&"git", &"checkout", &checkout_commit], Some(&repo_path))?; let filter = format!("-{}-", clone_result.repo_name); @@ -219,8 +219,7 @@ impl PrepareArg { --only-libcore : Only setup libcore and don't clone other repositories --cross : Apply the patches needed to do cross-compilation --libgccjit12-patches : Apply patches needed for libgccjit12 - --help : Show this help -"# + --help : Show this help"# ) } } diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 806e18431c46d..d7f7a0eb47ef1 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -485,19 +485,25 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { Ok(()) } -fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { +fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { let toolchain = format!( "+{channel}-{host}", channel = get_toolchain()?, // May also include date host = args.config_info.host_triple ); - let rust_dir = Some(Path::new("rust")); + let rust_dir_path = Path::new(crate::BUILD_DIR).join("rust"); // If the repository was already cloned, command will fail, so doesn't matter. let _ = run_command_with_output_and_env( - &[&"git", &"clone", &"https://github.com/rust-lang/rust.git"], + &[ + &"git", + &"clone", + &"https://github.com/rust-lang/rust.git", + &rust_dir_path, + ], None, Some(env), ); + let rust_dir: Option<&Path> = Some(&rust_dir_path); run_command(&[&"git", &"checkout", &"--", &"tests/"], rust_dir)?; run_command_with_output_and_env(&[&"git", &"fetch"], rust_dir, Some(env))?; let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash { @@ -561,8 +567,9 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<(), String> { String::new() } }; + let file_path = rust_dir_path.join("config.toml"); std::fs::write( - "rust/config.toml", + &file_path, &format!( r#"change-id = 115898 @@ -587,13 +594,19 @@ download-ci-llvm = false llvm_filecheck = llvm_filecheck.trim(), ), ) - .map_err(|error| format!("Failed to write into `rust/config.toml`: {:?}", error))?; - Ok(()) + .map_err(|error| { + format!( + "Failed to write into `{}`: {:?}", + file_path.display(), + error + ) + })?; + Ok(rust_dir_path) } fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { let mut env = env.clone(); - setup_rustc(&mut env, args)?; + let rust_dir = setup_rustc(&mut env, args)?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rustc asm test suite"); @@ -621,7 +634,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { ) .as_str(), ], - Some(Path::new("rust")), + Some(&rust_dir), Some(&env), )?; Ok(()) @@ -761,11 +774,11 @@ fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { println!("Not using GCC master branch. Skipping `extended_rand_tests`."); return Ok(()); } - let path = Path::new("rand"); - run_cargo_command(&[&"clean"], Some(path), env, args)?; + let path = Path::new(crate::BUILD_DIR).join("rand"); + run_cargo_command(&[&"clean"], Some(&path), env, args)?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rust-random/rand"); - run_cargo_command(&[&"test", &"--workspace"], Some(path), env, args)?; + run_cargo_command(&[&"test", &"--workspace"], Some(&path), env, args)?; Ok(()) } @@ -774,8 +787,8 @@ fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> println!("Not using GCC master branch. Skipping `extended_regex_example_tests`."); return Ok(()); } - let path = Path::new("regex"); - run_cargo_command(&[&"clean"], Some(path), env, args)?; + let path = Path::new(crate::BUILD_DIR).join("regex"); + run_cargo_command(&[&"clean"], Some(&path), env, args)?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rust-lang/regex example shootout-regex-dna"); let mut env = env.clone(); @@ -788,14 +801,14 @@ fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> // Make sure `[codegen mono items] start` doesn't poison the diff run_cargo_command( &[&"build", &"--example", &"shootout-regex-dna"], - Some(path), + Some(&path), &env, args, )?; run_cargo_command_with_callback( &[&"run", &"--example", &"shootout-regex-dna"], - Some(path), + Some(&path), &env, args, |cargo_command, cwd, env| { @@ -838,6 +851,7 @@ fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { env.get("RUSTFLAGS").cloned().unwrap_or_default() ); env.insert("RUSTFLAGS".to_string(), rustflags); + let path = Path::new(crate::BUILD_DIR).join("regex"); run_cargo_command( &[ &"test", @@ -850,7 +864,7 @@ fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"-Zunstable-options", &"-q", ], - Some(Path::new("regex")), + Some(&path), &env, args, )?; @@ -928,17 +942,15 @@ fn should_remove_test(file_path: &Path) -> Result { fn test_rustc_inner(env: &Env, args: &TestArg, prepare_files_callback: F) -> Result<(), String> where - F: Fn() -> Result, + F: Fn(&Path) -> Result, { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rust-lang/rust"); let mut env = env.clone(); - setup_rustc(&mut env, args)?; - - let rust_path = Path::new("rust"); + let rust_path = setup_rustc(&mut env, args)?; walk_dir( - "rust/tests/ui", + rust_path.join("tests/ui"), |dir| { let dir_name = dir.file_name().and_then(|name| name.to_str()).unwrap_or(""); if [ @@ -1001,7 +1013,7 @@ where walk_dir(rust_path.join("tests/ui"), dir_handling, file_handling)?; - if !prepare_files_callback()? { + if !prepare_files_callback(&rust_path)? { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("Keeping all UI tests"); } @@ -1027,7 +1039,7 @@ where &"-path", &"*/auxiliary/*", ], - Some(rust_path), + Some(&rust_path), )? .stdout, ) @@ -1072,18 +1084,18 @@ where &"--rustc-args", &rustc_args, ], - Some(rust_path), + Some(&rust_path), Some(&env), )?; Ok(()) } fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> { - test_rustc_inner(env, args, || Ok(false)) + test_rustc_inner(env, args, |_| Ok(false)) } fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { - test_rustc_inner(env, args, || { + test_rustc_inner(env, args, |rust_path| { // Removing all tests. run_command( &[ @@ -1098,7 +1110,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { &"*/auxiliary/*", &"-delete", ], - Some(Path::new("rust")), + Some(rust_path), )?; // Putting back only the failing ones. let path = "tests/failing-ui-tests.txt"; @@ -1108,10 +1120,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { .map(|line| line.trim()) .filter(|line| !line.is_empty()) { - run_command( - &[&"git", &"checkout", &"--", &file], - Some(Path::new("rust")), - )?; + run_command(&[&"git", &"checkout", &"--", &file], Some(&rust_path))?; } } else { println!( @@ -1124,7 +1133,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { } fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { - test_rustc_inner(env, args, || { + test_rustc_inner(env, args, |rust_path| { // Removing the failing tests. let path = "tests/failing-ui-tests.txt"; if let Ok(files) = std::fs::read_to_string(path) { @@ -1133,7 +1142,7 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> { .map(|line| line.trim()) .filter(|line| !line.is_empty()) { - let path = Path::new("rust").join(file); + let path = rust_path.join(file); remove_file(&path)?; } } else { From 896b1a9049631477e2549144a2a3a773c470213e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 21:50:00 +0100 Subject: [PATCH 116/192] Generate libgccjit.so into the `build` folder --- build_system/src/config.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/build_system/src/config.rs b/build_system/src/config.rs index d1047436cebdb..c89a6d5eb9b20 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -191,12 +191,7 @@ impl ConfigInfo { } fn download_gccjit_if_needed(&mut self) -> Result<(), String> { - let output_dir = Path::new( - std::env::var("CARGO_TARGET_DIR") - .as_deref() - .unwrap_or("target"), - ) - .join("libgccjit"); + let output_dir = Path::new(crate::BUILD_DIR).join("libgccjit"); let commit_hash_file = self.compute_path("libgccjit.version"); let content = fs::read_to_string(&commit_hash_file).map_err(|_| { From 436fea8efbb332362a9c3b7f6854fea6bd35cd11 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 21:50:34 +0100 Subject: [PATCH 117/192] Add `build` folder into the ignored git entries --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 687c3a6797af1..ac695da16f864 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ tools/llvmint-2 llvm build_system/target config.toml +build \ No newline at end of file From 46d6e772c087c3bffb3228f36530010f16a57431 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Feb 2024 21:56:17 +0100 Subject: [PATCH 118/192] Update `tests/lang_tests_common.rs` test --- tests/lang_tests_common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 33dc6ef62ae52..4cc429cfa456f 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -28,7 +28,7 @@ pub fn main_inner(profile: Profile) { } else { // then we try to retrieve it from the `target` folder. let commit = include_str!("../libgccjit.version").trim(); - Path::new("target/libgccjit").join(commit) + Path::new("build/libgccjit").join(commit) }; let gcc_path = Path::new(&gcc_path) From 452ebf5f376971bec12364f56a7bb71125edf1fc Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Wed, 14 Feb 2024 08:12:10 +0800 Subject: [PATCH 119/192] feat(test.rs): Clone only 1 layer in build_system --- build_system/src/test.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index d7f7a0eb47ef1..f4e68ae710c8e 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -499,17 +499,29 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { &"clone", &"https://github.com/rust-lang/rust.git", &rust_dir_path, + &"--depth", + &"1", ], None, Some(env), ); let rust_dir: Option<&Path> = Some(&rust_dir_path); run_command(&[&"git", &"checkout", &"--", &"tests/"], rust_dir)?; - run_command_with_output_and_env(&[&"git", &"fetch"], rust_dir, Some(env))?; let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash { Some(commit_hash) => commit_hash, None => return Err("Couldn't retrieve rustc commit hash".to_string()), }; + run_command_with_output_and_env( + &[ + &"git", + &"fetch", + &"https://github.com/rust-lang/rust.git", + &rustc_commit.as_str(), + &"--depth=1", + ], + rust_dir, + Some(env), + )?; if rustc_commit != "unknown" { run_command_with_output_and_env( &[&"git", &"checkout", &rustc_commit], From 17e329777fedae708cbc5170787bd8481989e7fd Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Wed, 14 Feb 2024 17:59:16 +0800 Subject: [PATCH 120/192] feat(test.rs): Lookup the commit with cat-file to avoid re-fetches --- build_system/src/test.rs | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index f4e68ae710c8e..9fe9708c2917b 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -511,17 +511,30 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { Some(commit_hash) => commit_hash, None => return Err("Couldn't retrieve rustc commit hash".to_string()), }; - run_command_with_output_and_env( - &[ - &"git", - &"fetch", - &"https://github.com/rust-lang/rust.git", - &rustc_commit.as_str(), - &"--depth=1", - ], - rust_dir, - Some(env), - )?; + let has_commit = { + if let Ok(ty) = run_command_with_env( + &[&"git", &"cat-file", &"-t", &rustc_commit.as_str()], + rust_dir, + Some(env), + ) { + String::from_utf8_lossy(&ty.stdout).to_string() == "commit" + } else { + false + } + }; + if !has_commit { + run_command_with_output_and_env( + &[ + &"git", + &"fetch", + &"https://github.com/rust-lang/rust.git", + &rustc_commit.as_str(), + &"--depth=1", + ], + rust_dir, + Some(env), + )? + }; if rustc_commit != "unknown" { run_command_with_output_and_env( &[&"git", &"checkout", &rustc_commit], From a883c6da2055aeb2892781c6f1abe38df6c0ef88 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Feb 2024 13:35:20 +0100 Subject: [PATCH 121/192] Move `crates_patches` and `cross_patches` into the `patches` folder --- build_system/src/prepare.rs | 4 ++-- .../crate_patches}/0002-rand-Disable-failing-test.patch | 0 .../0001-Disable-libstd-and-libtest-dylib.patch | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename {crate_patches => patches/crate_patches}/0002-rand-Disable-failing-test.patch (100%) rename {cross_patches => patches/cross_patches}/0001-Disable-libstd-and-libtest-dylib.patch (100%) diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index 979438d041516..1a3eb7d2e57b4 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -95,7 +95,7 @@ fn prepare_libcore( )?; if cross_compile { walk_dir( - "cross_patches", + "patches/cross_patches", |_| Ok(()), |file_path: &Path| { patches.push(file_path.to_path_buf()); @@ -161,7 +161,7 @@ where run_command(&[&"git", &"checkout", &checkout_commit], Some(&repo_path))?; let filter = format!("-{}-", clone_result.repo_name); walk_dir( - "crate_patches", + "patches/crate_patches", |_| Ok(()), |file_path| { let patch = file_path.as_os_str().to_str().unwrap(); diff --git a/crate_patches/0002-rand-Disable-failing-test.patch b/patches/crate_patches/0002-rand-Disable-failing-test.patch similarity index 100% rename from crate_patches/0002-rand-Disable-failing-test.patch rename to patches/crate_patches/0002-rand-Disable-failing-test.patch diff --git a/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch b/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch similarity index 100% rename from cross_patches/0001-Disable-libstd-and-libtest-dylib.patch rename to patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch From ebac107a554bfdefc1c3932616795e07ff44eea6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Feb 2024 14:18:17 +0100 Subject: [PATCH 122/192] Remove paths that don't exist anymore from file --- .gitignore | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitignore b/.gitignore index ac695da16f864..bf975f92014da 100644 --- a/.gitignore +++ b/.gitignore @@ -10,16 +10,10 @@ perf.data.old /build_sysroot/sysroot_src /build_sysroot/Cargo.lock /build_sysroot/test_target/Cargo.lock -/rust -/simple-raytracer -/regex -/rand gimple* *asm res test-backend -gcc_path -cross_gcc_path projects benchmarks tools/llvm-project From de57533e5644335eccd8c1430b4c60295a0b922c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 12 Feb 2024 20:15:12 -0400 Subject: [PATCH 123/192] Implement dummy emit=llvm-ir --- .ignore | 1 + src/back/write.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.ignore b/.ignore index d8d189e5c7c64..702dd9e2a23f3 100644 --- a/.ignore +++ b/.ignore @@ -8,3 +8,4 @@ !*gimple* !*asm* !.github +!config.toml diff --git a/src/back/write.rs b/src/back/write.rs index 04772d7707abd..792fd47001d57 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -70,7 +70,8 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_hand } if config.emit_ir { - unimplemented!(); + let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); + std::fs::write(out, "").expect("write file"); } if config.emit_asm { From ec5328b3d9aa08986abd3237b40c0bf74b08bc2b Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 14 Feb 2024 14:17:27 +0000 Subject: [PATCH 124/192] errors: only eagerly translate subdiagnostics Subdiagnostics don't need to be lazily translated, they can always be eagerly translated. Eager translation is slightly more complex as we need to have a `DiagCtxt` available to perform the translation, which involves slightly more threading of that context. This slight increase in complexity should enable later simplifications - like passing `DiagCtxt` into `AddToDiagnostic` and moving Fluent messages into the diagnostic structs rather than having them in separate files (working on that was what led to this change). Signed-off-by: David Wood --- src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/errors.rs b/src/errors.rs index cc0fbe46dcc11..79eb4406b8a33 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -122,7 +122,7 @@ impl IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl diag.span(span); }; if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(missing_features); + diag.subdiagnostic(dcx, missing_features); } diag.arg("features", self.features.join(", ")); diag From 98c1efd5b69b64cabab6762d75687fc937d79599 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Feb 2024 12:30:43 +0100 Subject: [PATCH 125/192] Put back `master` feature as default --- .github/workflows/ci.yml | 9 +++------ .github/workflows/failures.yml | 5 +---- .github/workflows/m68k.yml | 9 +++------ .github/workflows/release.yml | 9 +++------ .github/workflows/stdarch.yml | 9 +++------ Cargo.toml | 1 + Readme.md | 4 ++-- 7 files changed, 16 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4678c4e2af4f..37d2bc1c201af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,9 +66,7 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore - # TODO: remove --features master when it is back to the default. - ./y.sh build --features master - # TODO: remove --features master when it is back to the default. + ./y.sh build - name: Set env (part 2) run: | @@ -78,7 +76,7 @@ jobs: - name: Build (part 2) run: | - cargo test --features master + cargo test ./y.sh clean all - name: Prepare dependencies @@ -92,8 +90,7 @@ jobs: - name: Run tests run: | - # TODO: remove --features master when it is back to the default. - ./y.sh test --features master --release --clean --build-sysroot ${{ matrix.commands }} + ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} duplicates: runs-on: ubuntu-latest diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index ae00a257e2486..2bca694e83284 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -21,14 +21,11 @@ jobs: libgccjit_version: - gcc: "libgccjit.so" artifacts_branch: "master" - # TODO: switch back to --no-default-features in the case of libgccjit 12 when the default is to enable - # master again. - extra: "--features master" - gcc: "libgccjit_without_int128.so" artifacts_branch: "master-without-128bit-integers" - extra: "--features master" - gcc: "libgccjit12.so" artifacts_branch: "gcc12" + extra: "--no-default-features" # FIXME(antoyo): we need to set GCC_EXEC_PREFIX so that the linker can find the linker plugin. # Not sure why it's not found otherwise. env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests' GCC_EXEC_PREFIX=/usr/lib/gcc/" diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 2428125483bdd..a8c6b614ce815 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -91,10 +91,8 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore --cross - # TODO: remove --features master when it is back to the default. - ./y.sh build --target-triple m68k-unknown-linux-gnu --features master - # TODO: remove --features master when it is back to the default. - CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test --features master + ./y.sh build --target-triple m68k-unknown-linux-gnu + CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test ./y.sh clean all - name: Prepare dependencies @@ -108,5 +106,4 @@ jobs: - name: Run tests run: | - # TODO: remove --features master when it is back to the default. - ./y.sh test --release --features master --clean --build-sysroot ${{ matrix.commands }} + ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 729a76e80bf90..28336998ffcd7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,10 +53,8 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore - # TODO: remove --features master when it is back to the default. - EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot --features master - # TODO: remove --features master when it is back to the default. - cargo test --features master + EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot + cargo test ./y.sh clean all - name: Prepare dependencies @@ -72,5 +70,4 @@ jobs: - name: Run tests run: | - # TODO: remove --features master when it is back to the default. - EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} --features master + EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 65687756cd4eb..fa40c1a2beab7 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -67,10 +67,8 @@ jobs: - name: Build run: | ./y.sh prepare --only-libcore - # TODO: remove `--features master` when it is back to the default. - ./y.sh build --release --release-sysroot --features master - # TODO: remove --features master when it is back to the default. - cargo test --features master + ./y.sh build --release --release-sysroot + cargo test - name: Clean if: ${{ !matrix.cargo_runner }} @@ -86,8 +84,7 @@ jobs: - name: Run tests if: ${{ !matrix.cargo_runner }} run: | - # TODO: remove `--features master` when it is back to the default. - ./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore --features master + ./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore - name: Run stdarch tests if: ${{ !matrix.cargo_runner }} diff --git a/Cargo.toml b/Cargo.toml index a280ac73de093..5e657c7c53959 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ harness = false [features] master = ["gccjit/master"] +default = ["master"] [dependencies] gccjit = { git = "https://github.com/antoyo/gccjit.rs" } diff --git a/Readme.md b/Readme.md index a380d0d5be6d1..5d960d0c2d606 100644 --- a/Readme.md +++ b/Readme.md @@ -69,13 +69,13 @@ Then you can run commands like this: ```bash $ ./y.sh prepare # download and patch sysroot src and install hyperfine for benchmarking -$ ./y.sh build --release --features master +$ ./y.sh build --release ``` To run the tests: ```bash -$ ./y.sh test --release --features master +$ ./y.sh test --release ``` ## Usage From af289a5eacbdf531ae22c5e90be7c8c627b20a93 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 15 Feb 2024 17:16:04 -0500 Subject: [PATCH 126/192] Use the default rust mangling --- Cargo.lock | 4 ++-- build_system/src/config.rs | 5 ++++- build_system/src/test.rs | 32 ++++++++++++++++++++------------ libgccjit.version | 2 +- src/declare.rs | 7 +++++-- src/lib.rs | 1 + 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a19de10d0d29b..786d753a1505f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#e6109eb8b7ced60b5191e65b34954d04d4abeaec" +source = "git+https://github.com/antoyo/gccjit.rs#4b7aba76891e6436984f7f098fe92824d95194d5" dependencies = [ "gccjit_sys", ] @@ -88,7 +88,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#e6109eb8b7ced60b5191e65b34954d04d4abeaec" +source = "git+https://github.com/antoyo/gccjit.rs#4b7aba76891e6436984f7f098fe92824d95194d5" dependencies = [ "libc", ] diff --git a/build_system/src/config.rs b/build_system/src/config.rs index c89a6d5eb9b20..ddfc0e4a925da 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -415,8 +415,11 @@ impl ConfigInfo { if let Some(linker) = linker { rustflags.push(linker.to_string()); } + + #[cfg(not(feature="master"))] + rustflags.push("-Csymbol-mangling-version=v0".to_string()); + rustflags.extend_from_slice(&[ - "-Csymbol-mangling-version=v0".to_string(), "-Cdebuginfo=2".to_string(), format!("-Zcodegen-backend={}", self.cg_backend_path), ]); diff --git a/build_system/src/test.rs b/build_system/src/test.rs index d7f7a0eb47ef1..ab65fed0f75a4 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -612,6 +612,21 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); + let rustc_args = + &format!( + r#"-Zpanic-abort-tests \ + -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \ + --sysroot "{pwd}/build_sysroot/sysroot" -Cpanic=abort"#, + pwd = std::env::current_dir() + .map_err(|error| format!("`current_dir` failed: {:?}", error))? + .display(), + channel = args.config_info.channel.as_str(), + dylib_ext = args.config_info.dylib_ext, + ); + + #[cfg(not(feature="master"))] + let rustc_args = format!("{} -Csymbol-mangling-version=v0", rustc_args); + run_command_with_env( &[ &"./x.py", @@ -622,17 +637,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"0", &"tests/assembly/asm", &"--rustc-args", - &format!( - r#"-Zpanic-abort-tests -Csymbol-mangling-version=v0 \ - -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \ - --sysroot "{pwd}/build_sysroot/sysroot" -Cpanic=abort"#, - pwd = std::env::current_dir() - .map_err(|error| format!("`current_dir` failed: {:?}", error))? - .display(), - channel = args.config_info.channel.as_str(), - dylib_ext = args.config_info.dylib_ext, - ) - .as_str(), + &rustc_args, ], Some(&rust_dir), Some(&env), @@ -1065,12 +1070,15 @@ where println!("[TEST] rustc test suite"); env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); let rustc_args = format!( - "{} -Csymbol-mangling-version=v0 -Zcodegen-backend={} --sysroot {}", + "{} -Zcodegen-backend={} --sysroot {}", env.get("TEST_FLAGS").unwrap_or(&String::new()), args.config_info.cg_backend_path, args.config_info.sysroot_path, ); + #[cfg(not(feature="master"))] + let rustc_args = format!("{} -Csymbol-mangling-version=v0", rustc_args); + env.get_mut("RUSTFLAGS").unwrap().clear(); run_command_with_output_and_env( &[ diff --git a/libgccjit.version b/libgccjit.version index 3fc84f4ddd4ec..281a3ef5fa65c 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -2fc8940e1 +89a92e561 diff --git a/src/declare.rs b/src/declare.rs index 247454fa58e14..5ed6739883d82 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -125,7 +125,9 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll let params: Vec<_> = param_types.into_iter().enumerate() .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name. .collect(); - let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, mangle_name(name), variadic); + #[cfg(not(feature="master"))] + let name = mangle_name(name); + let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, &name, variadic); cx.functions.borrow_mut().insert(name.to_string(), func); #[cfg(feature="master")] @@ -180,7 +182,8 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll // FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _. // Unsupported characters: `$` and `.`. -pub fn mangle_name(name: &str) -> String { +#[cfg(not(feature="master"))] +fn mangle_name(name: &str) -> String { name.replace(|char: char| { if !char.is_alphanumeric() && char != '_' { debug_assert!("$.*".contains(char), "Unsupported char in function name {}: {}", name, char); diff --git a/src/lib.rs b/src/lib.rs index 5f8d00bb455e8..943a71ed953b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,6 +255,7 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { } #[cfg(feature="master")] { + context.set_allow_special_chars_in_func_names(true); let version = Version::get(); let version = format!("{}.{}.{}", version.major, version.minor, version.patch); context.set_output_ident(&format!("rustc version {} with libgccjit {}", From 7b1ac28f1c235ec5cd25bb0cd42014fdc95a5b46 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 17 Feb 2024 10:51:35 +1100 Subject: [PATCH 127/192] Make `CodegenBackend::join_codegen` infallible. Because they all are, in practice. --- src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 863b6333bcc29..09ce059476ec7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -217,13 +217,11 @@ impl CodegenBackend for GccCodegenBackend { Box::new(res) } - fn join_codegen(&self, ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxIndexMap), ErrorGuaranteed> { - let (codegen_results, work_products) = ongoing_codegen + fn join_codegen(&self, ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames) -> (CodegenResults, FxIndexMap) { + ongoing_codegen .downcast::>() .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") - .join(sess); - - Ok((codegen_results, work_products)) + .join(sess) } fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> { From 6bdcc3c4c71dd63a28a9920be011c20df3099f62 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Feb 2024 16:59:30 +0100 Subject: [PATCH 128/192] Move subtree part of Readme into its own doc file --- Readme.md | 45 ------------------------------------------- doc/subtree.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 45 deletions(-) create mode 100644 doc/subtree.md diff --git a/Readme.md b/Readme.md index 5d960d0c2d606..dc9d0a4fd1279 100644 --- a/Readme.md +++ b/Readme.md @@ -269,51 +269,6 @@ COLLECT_NO_DEMANGLE=1 * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`. -### How to install a forked git-subtree - -Using git-subtree with `rustc` requires a patched git to make it work. -The PR that is needed is [here](https://github.com/gitgitgadget/git/pull/493). -Use the following instructions to install it: - -```bash -git clone git@github.com:tqc/git.git -cd git -git checkout tqc/subtree -make -make install -cd contrib/subtree -make -cp git-subtree ~/bin -``` - -Then, do a sync with this command: - -```bash -PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name -cd ../rustc_codegen_gcc -git checkout master -git pull -git checkout sync_branch_name -git merge master -``` - -To send the changes to the rust repo: - -```bash -cd ../rust -git pull origin master -git checkout -b subtree-update_cg_gcc_YYYY-MM-DD -PATH="$HOME/bin:$PATH" ~/bin/git-subtree pull --prefix=compiler/rustc_codegen_gcc/ https://github.com/rust-lang/rustc_codegen_gcc.git master -git push - -# Immediately merge the merge commit into cg_gcc to prevent merge conflicts when syncing from rust-lang/rust later. -PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name -``` - -TODO: write a script that does the above. - -https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.20madness/near/258877725 - ### How to use [mem-trace](https://github.com/antoyo/mem-trace) `rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. diff --git a/doc/subtree.md b/doc/subtree.md new file mode 100644 index 0000000000000..5d7af2a066bd3 --- /dev/null +++ b/doc/subtree.md @@ -0,0 +1,52 @@ +# git subtree sync + +`rustc_codegen_gcc` is a subtree of the rust compiler. As such, it needs to be +sync from time to time to ensure changes that happened on their side are also +included on our side. + +### How to install a forked git-subtree + +Using git-subtree with `rustc` requires a patched git to make it work. +The PR that is needed is [here](https://github.com/gitgitgadget/git/pull/493). +Use the following instructions to install it: + +```bash +git clone git@github.com:tqc/git.git +cd git +git checkout tqc/subtree +make +make install +cd contrib/subtree +make +cp git-subtree ~/bin +``` + +### Syncing with rust compiler + +Do a sync with this command: + +```bash +PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name +cd ../rustc_codegen_gcc +git checkout master +git pull +git checkout sync_branch_name +git merge master +``` + +To send the changes to the rust repo: + +```bash +cd ../rust +git pull origin master +git checkout -b subtree-update_cg_gcc_YYYY-MM-DD +PATH="$HOME/bin:$PATH" ~/bin/git-subtree pull --prefix=compiler/rustc_codegen_gcc/ https://github.com/rust-lang/rustc_codegen_gcc.git master +git push + +# Immediately merge the merge commit into cg_gcc to prevent merge conflicts when syncing from rust-lang/rust later. +PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name +``` + +TODO: write a script that does the above. + +https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.20madness/near/258877725 From cb14f43de634d3f605559158b705e03e5537ba95 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Feb 2024 17:04:32 +0100 Subject: [PATCH 129/192] Improve instructions to start working on the project --- Readme.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Readme.md b/Readme.md index dc9d0a4fd1279..2c6d21b3f9602 100644 --- a/Readme.md +++ b/Readme.md @@ -17,6 +17,18 @@ A secondary goal is to check if using the gcc backend will provide any run-time **This requires a patched libgccjit in order to work. You need to use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** +```bash +$ cp config.example.toml config.toml +``` + +If don't need to test GCC patches you wrote in our GCC fork, then the default configuration should +be all you need. You can update the `rustc_codegen_gcc` without worrying about GCC. + +### Building with your own GCC version + +If you wrote a patch for GCC and want to test it without this backend, you will need +to do a few more things. + To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue): ```bash @@ -51,18 +63,17 @@ $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-asm.cc" **Put the path to your custom build of libgccjit in the file `config.toml`.** -If you followed the instructions exactly as written (ie, you have created a `gcc-build` folder -where gcc is built), the only thing you need to do is: +You now need to set the `gcc-path` value in `config.toml` with the result of this command: ```bash -$ cp config.example.toml config.toml +$ dirname $(readlink -f `find . -name libgccjit.so`) ``` -But if you did something different, you also need to set the `gcc-path` value in `config.toml` with -the result of this command: +and to comment the `download-gccjit` setting: -```bash -$ dirname $(readlink -f `find . -name libgccjit.so`) +```toml +gcc-path = "[MY PATH]" +# download-gccjit = true ``` Then you can run commands like this: From 79316d4e8313951ace166dd0c96108c3d9b70dab Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Feb 2024 17:13:48 +0100 Subject: [PATCH 130/192] Split Readme even further --- Readme.md | 182 +++---------------------------------- doc/debugging-gcc-lto.md | 3 + doc/debugging-libgccjit.md | 74 +++++++++++++++ doc/errors.md | 27 ++++++ doc/tips.md | 72 +++++++++++++++ 5 files changed, 187 insertions(+), 171 deletions(-) create mode 100644 doc/debugging-gcc-lto.md create mode 100644 doc/debugging-libgccjit.md create mode 100644 doc/errors.md create mode 100644 doc/tips.md diff --git a/Readme.md b/Readme.md index 2c6d21b3f9602..da6e91587fdaf 100644 --- a/Readme.md +++ b/Readme.md @@ -139,179 +139,19 @@ $ LIBRARY_PATH="[gcc-path value]" LD_LIBRARY_PATH="[gcc-path value]" rustc +$(ca
Dump a C-like representation to /tmp/gccjit_dumps and enable debug info in order to debug this C-like representation.
-## Licensing - -While this crate is licensed under a dual Apache/MIT license, it links to `libgccjit` which is under the GPLv3+ and thus, the resulting toolchain (rustc + GCC codegen) will need to be released under the GPL license. - -However, programs compiled with `rustc_codegen_gcc` do not need to be released under a GPL license. - -## Debugging - -Sometimes, libgccjit will crash and output an error like this: - -``` -during RTL pass: expand -libgccjit.so: error: in expmed_mode_index, at expmed.h:249 -0x7f0da2e61a35 expmed_mode_index - ../../../gcc/gcc/expmed.h:249 -0x7f0da2e61aa4 expmed_op_cost_ptr - ../../../gcc/gcc/expmed.h:271 -0x7f0da2e620dc sdiv_cost_ptr - ../../../gcc/gcc/expmed.h:540 -0x7f0da2e62129 sdiv_cost - ../../../gcc/gcc/expmed.h:558 -0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int) - ../../../gcc/gcc/expmed.c:4335 -0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier) - ../../../gcc/gcc/expr.c:9240 -0x7f0da2cd1a1e expand_gimple_stmt_1 - ../../../gcc/gcc/cfgexpand.c:3796 -0x7f0da2cd1c30 expand_gimple_stmt - ../../../gcc/gcc/cfgexpand.c:3857 -0x7f0da2cd90a9 expand_gimple_basic_block - ../../../gcc/gcc/cfgexpand.c:5898 -0x7f0da2cdade8 execute - ../../../gcc/gcc/cfgexpand.c:6582 -``` - -To see the code which causes this error, call the following function: - -```c -gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */) -``` - -This will create a C-like file and add the locations into the IR pointing to this C file. -Then, rerun the program and it will output the location in the second line: - -``` -libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249 -``` - -Or add a breakpoint to `add_error` in gdb and print the line number using: - -``` -p loc->m_line -p loc->m_filename->m_buffer -``` - -To print a debug representation of a tree: - -```c -debug_tree(expr); -``` - -(defined in print-tree.h) - -To print a debug representation of a gimple struct: - -```c -debug_gimple_stmt(gimple_struct) -``` - -To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`. - -To have the correct file paths in `gdb` instead of `/usr/src/debug/gcc/libstdc++-v3/libsupc++/eh_personality.cc`: - -Maybe by calling the following at the beginning of gdb: - -``` -set substitute-path /usr/src/debug/gcc /path/to/gcc-repo/gcc -``` - -TODO(antoyo): but that's not what I remember I was doing. - -### `failed to build archive` error - -When you get this error: - -``` -error: failed to build archive: failed to open object file: No such file or directory (os error 2) -``` - -That can be caused by the fact that you try to compile with `lto = "fat"`, but you didn't compile the sysroot with LTO. -(Not sure if that's the reason since I cannot reproduce anymore. Maybe it happened when forgetting setting `FAT_LTO`.) +## Extra documentation -### ld: cannot find crtbegin.o +More specific documentation is available in the [`doc`](./doc) folder: -When compiling an executable with libgccijt, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors: + * [Common errors](./doc/errors.md) + * [Debugging GCC LTO](./doc/debugging-gcc-lto.md) + * [Debugging libgccjit](./doc/debugging-libgccjit.md) + * [Git subtree sync](./doc/subtree.md) + * [List of useful commands](./doc/tips.md) + * [Send a patch to GCC](./doc/sending-gcc-patch.md) -``` -ld: cannot find crtbegin.o: No such file or directory -ld: cannot find -lgcc: No such file or directory -ld: cannot find -lgcc: No such file or directory -libgccjit.so: error: error invoking gcc driver -``` - -To fix this, set the variables to `gcc-build/build/gcc`. - -### How to debug GCC LTO - -Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. - -### How to send arguments to the GCC linker - -``` -CG_RUSTFLAGS="-Clink-args=-save-temps -v" ../y.sh cargo build -``` - -### How to see the personality functions in the asm dump - -``` -CG_RUSTFLAGS="-Clink-arg=-save-temps -v -Clink-arg=-dA" ../y.sh cargo build -``` - -### How to see the LLVM IR for a sysroot crate - -``` -cargo build -v --target x86_64-unknown-linux-gnu -Zbuild-std -# Take the command from the output and add --emit=llvm-ir -``` - -### To prevent the linker from unmangling symbols - -Run with: - -``` -COLLECT_NO_DEMANGLE=1 -``` - -### How to use a custom-build rustc - - * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). - * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`. - -### How to use [mem-trace](https://github.com/antoyo/mem-trace) - -`rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. - -### How to generate GIMPLE - -If you need to check what gccjit is generating (GIMPLE), then take a look at how to -generate it in [gimple.md](./doc/gimple.md). - -### How to build a cross-compiling libgccjit - -#### Building libgccjit - - * Follow the instructions on [this repo](https://github.com/cross-cg-gcc-tools/cross-gcc). - -#### Configuring rustc_codegen_gcc - - * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case. - * Set the path to the cross-compiling libgccjit in `gcc-path` (in `config.toml`). - * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu`. - * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target m68k-unknown-linux-gnu`. - -If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler). -Then, you can use it the following way: - - * Add the target specification file using `--target` as an **absolute** path to build the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu --target $(pwd)/m68k-unknown-linux-gnu.json` - * Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`. - -If you get the following error: +## Licensing -``` -/usr/bin/ld: unrecognised emulation mode: m68kelf -``` +While this crate is licensed under a dual Apache/MIT license, it links to `libgccjit` which is under the GPLv3+ and thus, the resulting toolchain (rustc + GCC codegen) will need to be released under the GPL license. -Make sure you set `gcc-path` (in `config.toml`) to the install directory. +However, programs compiled with `rustc_codegen_gcc` do not need to be released under a GPL license. diff --git a/doc/debugging-gcc-lto.md b/doc/debugging-gcc-lto.md new file mode 100644 index 0000000000000..93b150d768650 --- /dev/null +++ b/doc/debugging-gcc-lto.md @@ -0,0 +1,3 @@ +# How to debug GCC LTO + +Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. diff --git a/doc/debugging-libgccjit.md b/doc/debugging-libgccjit.md new file mode 100644 index 0000000000000..be0ec83f7cdc6 --- /dev/null +++ b/doc/debugging-libgccjit.md @@ -0,0 +1,74 @@ +# Debugging libgccjit + +Sometimes, libgccjit will crash and output an error like this: + +``` +during RTL pass: expand +libgccjit.so: error: in expmed_mode_index, at expmed.h:249 +0x7f0da2e61a35 expmed_mode_index + ../../../gcc/gcc/expmed.h:249 +0x7f0da2e61aa4 expmed_op_cost_ptr + ../../../gcc/gcc/expmed.h:271 +0x7f0da2e620dc sdiv_cost_ptr + ../../../gcc/gcc/expmed.h:540 +0x7f0da2e62129 sdiv_cost + ../../../gcc/gcc/expmed.h:558 +0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int) + ../../../gcc/gcc/expmed.c:4335 +0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier) + ../../../gcc/gcc/expr.c:9240 +0x7f0da2cd1a1e expand_gimple_stmt_1 + ../../../gcc/gcc/cfgexpand.c:3796 +0x7f0da2cd1c30 expand_gimple_stmt + ../../../gcc/gcc/cfgexpand.c:3857 +0x7f0da2cd90a9 expand_gimple_basic_block + ../../../gcc/gcc/cfgexpand.c:5898 +0x7f0da2cdade8 execute + ../../../gcc/gcc/cfgexpand.c:6582 +``` + +To see the code which causes this error, call the following function: + +```c +gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */) +``` + +This will create a C-like file and add the locations into the IR pointing to this C file. +Then, rerun the program and it will output the location in the second line: + +``` +libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249 +``` + +Or add a breakpoint to `add_error` in gdb and print the line number using: + +``` +p loc->m_line +p loc->m_filename->m_buffer +``` + +To print a debug representation of a tree: + +```c +debug_tree(expr); +``` + +(defined in print-tree.h) + +To print a debug representation of a gimple struct: + +```c +debug_gimple_stmt(gimple_struct) +``` + +To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`. + +To have the correct file paths in `gdb` instead of `/usr/src/debug/gcc/libstdc++-v3/libsupc++/eh_personality.cc`: + +Maybe by calling the following at the beginning of gdb: + +``` +set substitute-path /usr/src/debug/gcc /path/to/gcc-repo/gcc +``` + +TODO(antoyo): but that's not what I remember I was doing. diff --git a/doc/errors.md b/doc/errors.md new file mode 100644 index 0000000000000..5727b0ff7c867 --- /dev/null +++ b/doc/errors.md @@ -0,0 +1,27 @@ +# Common errors + +This file lists errors that were encountered and how to fix them. + +### `failed to build archive` error + +When you get this error: + +``` +error: failed to build archive: failed to open object file: No such file or directory (os error 2) +``` + +That can be caused by the fact that you try to compile with `lto = "fat"`, but you didn't compile the sysroot with LTO. +(Not sure if that's the reason since I cannot reproduce anymore. Maybe it happened when forgetting setting `FAT_LTO`.) + +### ld: cannot find crtbegin.o + +When compiling an executable with libgccijt, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors: + +``` +ld: cannot find crtbegin.o: No such file or directory +ld: cannot find -lgcc: No such file or directory +ld: cannot find -lgcc: No such file or directory +libgccjit.so: error: error invoking gcc driver +``` + +To fix this, set the variables to `gcc-build/build/gcc`. diff --git a/doc/tips.md b/doc/tips.md new file mode 100644 index 0000000000000..1379f5130be02 --- /dev/null +++ b/doc/tips.md @@ -0,0 +1,72 @@ +# Tips + +The following shows how to do different random small things we encountered and thought could +be useful. + +### How to send arguments to the GCC linker + +``` +CG_RUSTFLAGS="-Clink-args=-save-temps -v" ../y.sh cargo build +``` + +### How to see the personality functions in the asm dump + +``` +CG_RUSTFLAGS="-Clink-arg=-save-temps -v -Clink-arg=-dA" ../y.sh cargo build +``` + +### How to see the LLVM IR for a sysroot crate + +``` +cargo build -v --target x86_64-unknown-linux-gnu -Zbuild-std +# Take the command from the output and add --emit=llvm-ir +``` + +### To prevent the linker from unmangling symbols + +Run with: + +``` +COLLECT_NO_DEMANGLE=1 +``` + +### How to use a custom-build rustc + + * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). + * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`. + +### How to use [mem-trace](https://github.com/antoyo/mem-trace) + +`rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. + +### How to generate GIMPLE + +If you need to check what gccjit is generating (GIMPLE), then take a look at how to +generate it in [gimple.md](./doc/gimple.md). + +### How to build a cross-compiling libgccjit + +#### Building libgccjit + + * Follow the instructions on [this repo](https://github.com/cross-cg-gcc-tools/cross-gcc). + +#### Configuring rustc_codegen_gcc + + * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case. + * Set the path to the cross-compiling libgccjit in `gcc-path` (in `config.toml`). + * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu`. + * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target m68k-unknown-linux-gnu`. + +If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler). +Then, you can use it the following way: + + * Add the target specification file using `--target` as an **absolute** path to build the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu --target $(pwd)/m68k-unknown-linux-gnu.json` + * Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`. + +If you get the following error: + +``` +/usr/bin/ld: unrecognised emulation mode: m68kelf +``` + +Make sure you set `gcc-path` (in `config.toml`) to the install directory. From 0a66c555bd4e8599e9710652509bfbdca366f36d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Feb 2024 20:04:17 +0100 Subject: [PATCH 131/192] Revert "Use shallow clone in test.rs to reduce cloning overhead" --- build_system/src/test.rs | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 9fe9708c2917b..d7f7a0eb47ef1 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -499,42 +499,17 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { &"clone", &"https://github.com/rust-lang/rust.git", &rust_dir_path, - &"--depth", - &"1", ], None, Some(env), ); let rust_dir: Option<&Path> = Some(&rust_dir_path); run_command(&[&"git", &"checkout", &"--", &"tests/"], rust_dir)?; + run_command_with_output_and_env(&[&"git", &"fetch"], rust_dir, Some(env))?; let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash { Some(commit_hash) => commit_hash, None => return Err("Couldn't retrieve rustc commit hash".to_string()), }; - let has_commit = { - if let Ok(ty) = run_command_with_env( - &[&"git", &"cat-file", &"-t", &rustc_commit.as_str()], - rust_dir, - Some(env), - ) { - String::from_utf8_lossy(&ty.stdout).to_string() == "commit" - } else { - false - } - }; - if !has_commit { - run_command_with_output_and_env( - &[ - &"git", - &"fetch", - &"https://github.com/rust-lang/rust.git", - &rustc_commit.as_str(), - &"--depth=1", - ], - rust_dir, - Some(env), - )? - }; if rustc_commit != "unknown" { run_command_with_output_and_env( &[&"git", &"checkout", &rustc_commit], From e116cb7811510936c4386322cc27255bc97f656a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 15 Feb 2024 18:12:42 -0400 Subject: [PATCH 132/192] Fix to use the correct libgccjit for the CI where 128-bit integers are disabled --- .github/workflows/ci.yml | 24 ++++++++++++------------ .github/workflows/stdarch.yml | 20 ++++++++++---------- libgccjit.version | 2 +- src/declare.rs | 3 ++- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37d2bc1c201af..ab704aa80a2b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,8 +19,8 @@ jobs: fail-fast: false matrix: libgccjit_version: - - { gcc: "libgccjit.so", artifacts_branch: "master" } - - { gcc: "libgccjit_without_int128.so", artifacts_branch: "master-without-128bit-integers" } + - { gcc: "gcc-13.deb" } + - { gcc: "gcc-13-without-int128.deb" } commands: [ "--mini-tests", "--std-tests", @@ -49,10 +49,19 @@ jobs: # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. run: sudo apt-get install ninja-build ripgrep llvm-14-tools + - name: Download artifact + run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/${{ matrix.libgccjit_version.gcc }} + + - name: Setup path to libgccjit + run: | + sudo dpkg --force-overwrite -i ${{ matrix.libgccjit_version.gcc }} + echo 'gcc-path = "/usr/lib/"' > config.toml + - name: Set env run: | echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - echo 'download-gccjit = true' > config.toml + echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV #- name: Cache rust repository ## We only clone the rust repository for rustc tests @@ -67,15 +76,6 @@ jobs: run: | ./y.sh prepare --only-libcore ./y.sh build - - - name: Set env (part 2) - run: | - # Set the `LD_LIBRARY_PATH` and `LIBRARY_PATH` env variables... - echo "LD_LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV - echo "LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV - - - name: Build (part 2) - run: | cargo test ./y.sh clean all diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index fa40c1a2beab7..41a9318007f15 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -50,24 +50,24 @@ jobs: sudo ln -s /usr/share/intel-sde/sde /usr/bin/sde sudo ln -s /usr/share/intel-sde/sde64 /usr/bin/sde64 - - name: Download artifact - run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/gcc-13.deb - - - name: Setup path to libgccjit - run: | - sudo dpkg --force-overwrite -i gcc-13.deb - echo 'gcc-path = "/usr/lib/"' > config.toml - - name: Set env run: | echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV + echo 'download-gccjit = true' > config.toml - name: Build run: | ./y.sh prepare --only-libcore ./y.sh build --release --release-sysroot + + - name: Set env (part 2) + run: | + # Set the `LD_LIBRARY_PATH` and `LIBRARY_PATH` env variables... + echo "LD_LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV + echo "LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV + + - name: Build (part 2) + run: | cargo test - name: Clean diff --git a/libgccjit.version b/libgccjit.version index 281a3ef5fa65c..12dafeb9edeed 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -89a92e561 +cdd897840 diff --git a/src/declare.rs b/src/declare.rs index 5ed6739883d82..72cba9fbba95a 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -181,7 +181,8 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll } // FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _. -// Unsupported characters: `$` and `.`. +// Unsupported characters: `$`, `.` and `*`. +// FIXME(antoyo): `*` might not be expected: https://github.com/rust-lang/rust/issues/116979#issuecomment-1840926865 #[cfg(not(feature="master"))] fn mangle_name(name: &str) -> String { name.replace(|char: char| { From 5ac9bee7f13c83123cc3d184f50a255248e640f2 Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Sat, 17 Feb 2024 17:19:08 -0600 Subject: [PATCH 133/192] fix tests/ui/simd/issue-89193.rs and mark as passing Work around an issue where usize and isize can sometimes (but not always) get canonicalized to their corresponding integer type. This causes shuffle_vector to panic, since the types of the vectors it got passed aren't the same. Also insert a cast on the mask element, since we might get passed a signed integer of any size, not just i32. For now, we always cast to i32. Signed-off-by: Andy Sadler --- src/intrinsic/simd.rs | 15 +++++++++++---- tests/failing-ui-tests.txt | 1 - 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 5991f061c10cc..33d659f251fe1 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -710,7 +710,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( }; let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type(); - let mut values = vec![]; + let mut values = Vec::with_capacity(in_len as usize); for i in 0..in_len { let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64); let int = bx.context.new_vector_access(None, pointers, index).to_rvalue(); @@ -723,19 +723,26 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let vector = bx.context.new_rvalue_from_vector(None, vector_type, &values); - let mut mask_types = vec![]; - let mut mask_values = vec![]; + let mut mask_types = Vec::with_capacity(in_len as usize); + let mut mask_values = Vec::with_capacity(in_len as usize); for i in 0..in_len { let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64); mask_types.push(bx.context.new_field(None, bx.i32_type, "m")); let mask_value = bx.context.new_vector_access(None, mask, index).to_rvalue(); - let masked = bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value; + let mask_value_cast = bx.context.new_cast(None, mask_value, bx.i32_type); + let masked = bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value_cast; let value = index + masked; mask_values.push(value); } let mask_type = bx.context.new_struct_type(None, "mask_type", &mask_types); let mask = bx.context.new_struct_constructor(None, mask_type.as_type(), None, &mask_values); + // FIXME(antoyo): We sometimes need to bitcast here, since usize/isize sometimes (but not + // always) get canonicalized to their corresponding integer type (i.e. uint64_t/int64_t on + // 64-bit platforms). This causes the shuffle_vector call below to panic, since the types + // of the two vectors aren't the same. This is a workaround for now. + let vector = bx.bitcast_if_needed(vector, default.get_type()); + if invert { bx.shuffle_vector(vector, default, mask) } else { diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 023fe9d7e8311..6e020e9b354da 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -48,7 +48,6 @@ tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs tests/ui/simd/issue-17170.rs tests/ui/simd/issue-39720.rs -tests/ui/simd/issue-89193.rs tests/ui/statics/issue-91050-1.rs tests/ui/statics/issue-91050-2.rs tests/ui/alloc-error/default-alloc-error-hook.rs From 087456f1229998ff28cc25d8d849375f62c66d8e Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Sat, 17 Feb 2024 18:07:11 -0600 Subject: [PATCH 134/192] mark tests/ui/simd/issue-89193.rs as failing for libgccjit12 Signed-off-by: Andy Sadler --- tests/failing-ui-tests12.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/failing-ui-tests12.txt b/tests/failing-ui-tests12.txt index b4615b26852d8..64f89b03eecc8 100644 --- a/tests/failing-ui-tests12.txt +++ b/tests/failing-ui-tests12.txt @@ -33,6 +33,7 @@ tests/ui/coroutine/size-moved-locals.rs tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs tests/ui/simd/intrinsic/generic-gather-pass.rs tests/ui/simd/issue-85915-simd-ptrs.rs +tests/ui/simd/issue-89193.rs tests/ui/issues/issue-68010-large-zst-consts.rs tests/ui/rust-2018/proc-macro-crate-in-paths.rs tests/ui/target-feature/missing-plusminus.rs From b959fc1d0ae090301fa204f37bec8891957243b3 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Sat, 17 Feb 2024 22:01:56 +0300 Subject: [PATCH 135/192] Improve wording of static_mut_ref Rename `static_mut_ref` lint to `static_mut_refs`. --- example/mini_core_hello_world.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 9827e299f2a31..add77880716c8 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -99,8 +99,8 @@ fn start( static mut NUM: u8 = 6 * 7; -// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint -#[allow(static_mut_ref)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint +#[allow(static_mut_refs)] static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { From 1f34c881e87969818cab379cd7ad9dd7d1bc2e3e Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Sun, 18 Feb 2024 14:36:39 +0800 Subject: [PATCH 136/192] feat(Cargo.toml): Set `rustc_private` to `true` to allow lsp parsing --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 5e657c7c53959..85ad69e00fdef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,3 +57,6 @@ debug = false [profile.release.build-override] opt-level = 0 debug = false + +[package.metadata.rust-analyzer] +rustc_private = true \ No newline at end of file From 4ec4209ff5e41a986836d18718da5ab510390cf2 Mon Sep 17 00:00:00 2001 From: Andy Sadler Date: Sun, 18 Feb 2024 12:40:20 -0600 Subject: [PATCH 137/192] use `default` as output type source in simd_gather Signed-off-by: Andy Sadler --- src/intrinsic/simd.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 33d659f251fe1..8599403c914c3 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -697,18 +697,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( default: RValue<'gcc>, pointers: RValue<'gcc>, mask: RValue<'gcc>, - pointer_count: usize, bx: &mut Builder<'a, 'gcc, 'tcx>, in_len: u64, - underlying_ty: Ty<'tcx>, invert: bool, ) -> RValue<'gcc> { - let vector_type = if pointer_count > 1 { - bx.context.new_vector_type(bx.usize_type, in_len) - } else { - vector_ty(bx, underlying_ty, in_len) - }; - let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type(); + let vector_type = default.get_type(); + let elem_type = vector_type.unqualified().dyncast_vector().expect("vector type").get_element_type(); let mut values = Vec::with_capacity(in_len as usize); for i in 0..in_len { @@ -737,12 +731,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let mask_type = bx.context.new_struct_type(None, "mask_type", &mask_types); let mask = bx.context.new_struct_constructor(None, mask_type.as_type(), None, &mask_values); - // FIXME(antoyo): We sometimes need to bitcast here, since usize/isize sometimes (but not - // always) get canonicalized to their corresponding integer type (i.e. uint64_t/int64_t on - // 64-bit platforms). This causes the shuffle_vector call below to panic, since the types - // of the two vectors aren't the same. This is a workaround for now. - let vector = bx.bitcast_if_needed(vector, default.get_type()); - if invert { bx.shuffle_vector(vector, default, mask) } else { @@ -865,10 +853,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( args[0].immediate(), args[1].immediate(), args[2].immediate(), - pointer_count, bx, in_len, - underlying_ty, false, )); } @@ -983,10 +969,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( args[0].immediate(), args[1].immediate(), args[2].immediate(), - pointer_count, bx, in_len, - underlying_ty, true, ); From 6bbbf59951a6ef9f54f5f0e2849bba2ac53928a5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 20 Feb 2024 10:23:05 -0500 Subject: [PATCH 138/192] Update to nightly-2024-02-20 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 1962c217258a4..cd278090924d1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-11-17" +channel = "nightly-2024-02-20" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From c3d5b7fe3ba0c2b04fcd4a7d2ebdb1ab9e357b6e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 20 Feb 2024 10:35:56 -0500 Subject: [PATCH 139/192] Fix patches --- .../0022-core-Disable-not-compiling-tests.patch | 4 +--- .../0001-Disable-libstd-and-libtest-dylib.patch | 16 ---------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/patches/0022-core-Disable-not-compiling-tests.patch b/patches/0022-core-Disable-not-compiling-tests.patch index 4db56fa3bd2c7..a7d523f940826 100644 --- a/patches/0022-core-Disable-not-compiling-tests.patch +++ b/patches/0022-core-Disable-not-compiling-tests.patch @@ -39,6 +39,4 @@ index 42a26ae..5ac1042 100644 +#![cfg(test)] #![feature(alloc_layout_extra)] #![feature(array_chunks)] - #![feature(array_methods)] --- -2.21.0 (Apple Git-122) + #![feature(array_windows)] diff --git a/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch b/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch index 74d9c208a05ac..c220f53040f05 100644 --- a/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch +++ b/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch @@ -21,19 +21,3 @@ index 5b21355..cb0c49b 100644 [dependencies] alloc = { path = "../alloc", public = true } -diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml -index 91a1abd..a58c160 100644 ---- a/library/test/Cargo.toml -+++ b/library/test/Cargo.toml -@@ -4,7 +4,7 @@ version = "0.0.0" - edition = "2021" - - [lib] --crate-type = ["dylib", "rlib"] -+crate-type = ["rlib"] - - [dependencies] - getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } --- -2.42.0 - From e7b7c98e1c9628570bed2915e683ab298c59a0d6 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 20 Feb 2024 11:08:45 -0500 Subject: [PATCH 140/192] Fix tests --- build_system/src/prepare.rs | 17 +------- .../0002-rand-Disable-failing-test.patch | 32 --------------- tests/failing-lto-tests.txt | 16 +++++++- tests/failing-ui-tests.txt | 39 +++++++++++++++++++ tests/failing-ui-tests12.txt | 4 ++ 5 files changed, 59 insertions(+), 49 deletions(-) delete mode 100644 patches/crate_patches/0002-rand-Disable-failing-test.patch diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index 1a3eb7d2e57b4..66f440f53553a 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -159,21 +159,6 @@ where let repo_path = Path::new(crate::BUILD_DIR).join(&clone_result.repo_name); run_command(&[&"git", &"checkout", &"--", &"."], Some(&repo_path))?; run_command(&[&"git", &"checkout", &checkout_commit], Some(&repo_path))?; - let filter = format!("-{}-", clone_result.repo_name); - walk_dir( - "patches/crate_patches", - |_| Ok(()), - |file_path| { - let patch = file_path.as_os_str().to_str().unwrap(); - if patch.contains(&filter) && patch.ends_with(".patch") { - run_command_with_output( - &[&"git", &"am", &file_path.canonicalize().unwrap()], - Some(&repo_path), - )?; - } - Ok(()) - }, - )?; if let Some(extra) = extra { extra(&repo_path)?; } @@ -238,7 +223,7 @@ pub fn run() -> Result<(), String> { let to_clone = &[ ( "https://github.com/rust-random/rand.git", - "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", + "1f4507a8e1cf8050e4ceef95eeda8f64645b6719", None, ), ( diff --git a/patches/crate_patches/0002-rand-Disable-failing-test.patch b/patches/crate_patches/0002-rand-Disable-failing-test.patch deleted file mode 100644 index 449ca5f6e29cd..0000000000000 --- a/patches/crate_patches/0002-rand-Disable-failing-test.patch +++ /dev/null @@ -1,32 +0,0 @@ -From a8fb97120d71252538b6b026695df40d02696bdb Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Sat, 15 Aug 2020 20:04:38 +0200 -Subject: [PATCH] [rand] Disable failing test - ---- - src/distributions/uniform.rs | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs -index 480b859..c80bb6f 100644 ---- a/src/distributions/uniform.rs -+++ b/src/distributions/uniform.rs -@@ -1085,7 +1085,7 @@ mod tests { - _ => panic!("`UniformDurationMode` was not serialized/deserialized correctly") - } - } -- -+ - #[test] - #[cfg(feature = "serde1")] - fn test_uniform_serialization() { -@@ -1314,6 +1314,7 @@ mod tests { - not(target_arch = "wasm32"), - not(target_arch = "asmjs") - ))] -+ #[ignore] // FIXME - fn test_float_assertions() { - use super::SampleUniform; - use std::panic::catch_unwind; --- -2.20.1 diff --git a/tests/failing-lto-tests.txt b/tests/failing-lto-tests.txt index 2e0b6134070b9..8de45ae0f28b1 100644 --- a/tests/failing-lto-tests.txt +++ b/tests/failing-lto-tests.txt @@ -1,6 +1,6 @@ tests/ui/lint/unsafe_code/forge_unsafe_block.rs tests/ui/lint/unused-qualification-in-derive-expansion.rs -tests/ui/macro-quote-test.rs +tests/ui/macros/macro-quote-test.rs tests/ui/macros/proc_macro.rs tests/ui/panic-runtime/lto-unwind.rs tests/ui/resolve/derive-macro-1.rs @@ -21,3 +21,17 @@ tests/ui/fmt/format-args-capture-issue-106408.rs tests/ui/fmt/indoc-issue-106408.rs tests/ui/hygiene/issue-77523-def-site-async-await.rs tests/ui/inherent-impls-overlap-check/no-overlap.rs +tests/ui/annotate-snippet/multispan.rs +tests/ui/enum-discriminant/issue-46519.rs +tests/ui/issues/issue-45731.rs +tests/ui/lint/test-allow-dead-extern-static-no-warning.rs +tests/ui/macros/macro-comma-behavior-rpass.rs +tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs +tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs +tests/ui/macros/stringify.rs +tests/ui/panics/test-panic.rs +tests/ui/panics/test-should-fail-bad-message.rs +tests/ui/panics/test-should-panic-bad-message.rs +tests/ui/panics/test-should-panic-no-message.rs +tests/ui/reexport-test-harness-main.rs +tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 6e020e9b354da..e504021bf2ad2 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -69,3 +69,42 @@ tests/ui/async-await/deep-futures-are-freeze.rs tests/ui/closures/capture-unsized-by-ref.rs tests/ui/coroutine/resume-after-return.rs tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +tests/ui/limits/issue-17913.rs +tests/ui/limits/issue-55878.rs +tests/ui/linkage-attr/common-linkage-non-zero-init.rs +tests/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs +tests/ui/numbers-arithmetic/divide-by-zero.rs +tests/ui/numbers-arithmetic/mod-zero.rs +tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs +tests/ui/numbers-arithmetic/overflowing-neg.rs +tests/ui/optimization-remark.rs +tests/ui/panic-handler/panic-handler-std.rs +tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs +tests/ui/panic-runtime/need-unwind-got-abort.rs +tests/ui/panics/issue-47429-short-backtraces.rs +tests/ui/panics/panic-in-cleanup.rs +tests/ui/panics/panic-in-ffi.rs +tests/ui/panics/runtime-switch.rs +tests/ui/panics/short-ice-remove-middle-frames-2.rs +tests/ui/panics/short-ice-remove-middle-frames.rs +tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs +tests/ui/simd/masked-load-store.rs +tests/ui/simd/repr_packed.rs +tests/ui/type_length_limit.rs +tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs +tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs +tests/ui/c-variadic/issue-86053-1.rs +tests/ui/const-ptr/out_of_bounds_read.rs +tests/ui/consts/const_unsafe_unreachable_ub.rs +tests/ui/consts/miri_unleashed/drop.rs +tests/ui/consts/timeout.rs +tests/ui/consts/try-operator.rs +tests/ui/coroutine/coroutine-resume-after-panic.rs +tests/ui/coroutine/unwind-abort-mix.rs +tests/ui/duplicate/dupe-symbols-7.rs +tests/ui/duplicate/dupe-symbols-8.rs +tests/ui/hygiene/panic-location.rs +tests/ui/invalid/issue-114435-layout-type-err.rs +tests/ui/invalid-compile-flags/invalid-llvm-passes.rs +tests/ui/lto/issue-105637.rs +tests/ui/lto/lto-duplicate-symbols.rs diff --git a/tests/failing-ui-tests12.txt b/tests/failing-ui-tests12.txt index 64f89b03eecc8..1d9bdaa552c6b 100644 --- a/tests/failing-ui-tests12.txt +++ b/tests/failing-ui-tests12.txt @@ -42,3 +42,7 @@ tests/ui/codegen/issue-79865-llvm-miscompile.rs tests/ui/std-backtrace.rs tests/ui/mir/alignment/packed.rs tests/ui/intrinsics/intrinsics-integer.rs +tests/ui/asm/x86_64/evex512-implicit-feature.rs +tests/ui/packed/dyn-trait.rs +tests/ui/packed/issue-118537-field-offset-ice.rs +tests/ui/stable-mir-print/basic_function.rs From 6ff147b2050bc99f2bca7707e29052e7e4737912 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 6 Feb 2024 14:32:00 -0500 Subject: [PATCH 141/192] Add "algebraic" versions of the fast-math intrinsics --- src/builder.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index 42e61b3ccb5ad..5f1e45383765f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -705,6 +705,31 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.frem(lhs, rhs) } + fn fadd_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs + rhs + } + + fn fsub_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs - rhs + } + + fn fmul_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs * rhs + } + + fn fdiv_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs / rhs + } + + fn frem_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + self.frem(lhs, rhs) + } + fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { self.gcc_checked_binop(oop, typ, lhs, rhs) } From b87de7325f60af4072f85ecb22b5b4582e51742b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 Feb 2024 13:30:04 +0100 Subject: [PATCH 142/192] Correctly handle "master" feature --- build_system/src/build.rs | 14 +++++++--- build_system/src/config.rs | 10 +++++-- build_system/src/test.rs | 56 ++++++++++++++++++++------------------ 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 308ad34654941..7ec8b8de62a3d 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -19,9 +19,6 @@ impl BuildArg { while let Some(arg) = args.next() { match arg.as_str() { - "--no-default-features" => { - build_arg.flags.push("--no-default-features".to_string()); - } "--features" => { if let Some(arg) = args.next() { build_arg.flags.push("--features".to_string()); @@ -51,7 +48,6 @@ impl BuildArg { r#" `build` command help: - --no-default-features : Add `--no-default-features` flag --features [arg] : Add a new feature [arg]"# ); ConfigInfo::show_usage(); @@ -111,6 +107,9 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests"); } rustflags.push_str(" -Z force-unstable-if-unmarked"); + if config.no_default_features { + rustflags.push_str(" -Csymbol-mangling-version=v0"); + } let mut env = env.clone(); let channel = if config.sysroot_release_channel { env.insert( @@ -193,6 +192,13 @@ fn build_codegen(args: &mut BuildArg) -> Result<(), String> { args.config_info.gcc_path.clone(), ); + if args.config_info.no_default_features { + env.insert( + "RUSTFLAGS".to_string(), + "-Csymbol-mangling-version=v0".to_string(), + ); + } + let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; if args.config_info.channel == Channel::Release { command.push(&"--release"); diff --git a/build_system/src/config.rs b/build_system/src/config.rs index ddfc0e4a925da..f6f039370180c 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -127,6 +127,7 @@ pub struct ConfigInfo { // Needed for the `info` command which doesn't want to actually download the lib if needed, // just to set the `gcc_path` field to display it. pub no_download: bool, + pub no_default_features: bool, } impl ConfigInfo { @@ -177,6 +178,7 @@ impl ConfigInfo { return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()) } }, + "--no-default-features" => self.no_default_features = true, _ => return Ok(false), } Ok(true) @@ -416,8 +418,9 @@ impl ConfigInfo { rustflags.push(linker.to_string()); } - #[cfg(not(feature="master"))] - rustflags.push("-Csymbol-mangling-version=v0".to_string()); + if self.no_default_features { + rustflags.push("-Csymbol-mangling-version=v0".to_string()); + } rustflags.extend_from_slice(&[ "-Cdebuginfo=2".to_string(), @@ -495,7 +498,8 @@ impl ConfigInfo { --sysroot-panic-abort : Build the sysroot without unwinding support --config-file : Location of the config file to be used --cg_gcc-path : Location of the rustc_codegen_gcc root folder (used - when ran from another directory)" + when ran from another directory) + --no-default-features : Add `--no-default-features` flag to cargo commands" ); } } diff --git a/build_system/src/test.rs b/build_system/src/test.rs index ab65fed0f75a4..17b1868502aa6 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -90,7 +90,6 @@ fn show_usage() { --release : Build codegen in release mode --sysroot-panic-abort : Build the sysroot without unwinding support. - --no-default-features : Add `--no-default-features` flag --features [arg] : Add a new feature [arg] --use-system-gcc : Use system installed libgccjit --build-only : Only build rustc_codegen_gcc then exits @@ -110,7 +109,6 @@ fn show_usage() { #[derive(Default, Debug)] struct TestArg { - no_default_features: bool, build_only: bool, use_system_gcc: bool, runners: BTreeSet, @@ -132,13 +130,6 @@ impl TestArg { while let Some(arg) = args.next() { match arg.as_str() { - "--no-default-features" => { - // To prevent adding it more than once. - if !test_arg.no_default_features { - test_arg.flags.push("--no-default-features".into()); - } - test_arg.no_default_features = true; - } "--features" => match args.next() { Some(feature) if !feature.is_empty() => { test_arg @@ -196,11 +187,14 @@ impl TestArg { ); } } + if test_arg.config_info.no_default_features { + test_arg.flags.push("--no-default-features".into()); + } Ok(Some(test_arg)) } pub fn is_using_gcc_master_branch(&self) -> bool { - !self.no_default_features + !self.config_info.no_default_features } } @@ -612,20 +606,23 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); - let rustc_args = - &format!( - r#"-Zpanic-abort-tests \ - -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \ - --sysroot "{pwd}/build_sysroot/sysroot" -Cpanic=abort"#, - pwd = std::env::current_dir() - .map_err(|error| format!("`current_dir` failed: {:?}", error))? - .display(), - channel = args.config_info.channel.as_str(), - dylib_ext = args.config_info.dylib_ext, - ); + let extra = if args.is_using_gcc_master_branch() { + "" + } else { + " -Csymbol-mangling-version=v0" + }; - #[cfg(not(feature="master"))] - let rustc_args = format!("{} -Csymbol-mangling-version=v0", rustc_args); + let rustc_args = &format!( + r#"-Zpanic-abort-tests \ + -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \ + --sysroot "{pwd}/build_sysroot/sysroot" -Cpanic=abort{extra}"#, + pwd = std::env::current_dir() + .map_err(|error| format!("`current_dir` failed: {:?}", error))? + .display(), + channel = args.config_info.channel.as_str(), + dylib_ext = args.config_info.dylib_ext, + extra = extra, + ); run_command_with_env( &[ @@ -1069,16 +1066,21 @@ where // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rustc test suite"); env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); + + let extra = if args.is_using_gcc_master_branch() { + "" + } else { + " -Csymbol-mangling-version=v0" + }; + let rustc_args = format!( - "{} -Zcodegen-backend={} --sysroot {}", + "{} -Zcodegen-backend={} --sysroot {}{}", env.get("TEST_FLAGS").unwrap_or(&String::new()), args.config_info.cg_backend_path, args.config_info.sysroot_path, + extra, ); - #[cfg(not(feature="master"))] - let rustc_args = format!("{} -Csymbol-mangling-version=v0", rustc_args); - env.get_mut("RUSTFLAGS").unwrap().clear(); run_command_with_output_and_env( &[ From d2210d497670be3fcf342277e3d95882bd9c2700 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 Feb 2024 14:42:24 +0100 Subject: [PATCH 143/192] Correctly pass `--no-default-features` when argument is passed --- build_system/src/build.rs | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 7ec8b8de62a3d..e32971ca0c73a 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -107,38 +107,26 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests"); } rustflags.push_str(" -Z force-unstable-if-unmarked"); + let mut env = env.clone(); + + let mut args: Vec<&dyn AsRef> = vec![&"cargo", &"build", &"--target", &config.target]; + if config.no_default_features { rustflags.push_str(" -Csymbol-mangling-version=v0"); + args.push(&"--no-default-features"); } - let mut env = env.clone(); + let channel = if config.sysroot_release_channel { - env.insert( - "RUSTFLAGS".to_string(), - format!("{} -Zmir-opt-level=3", rustflags), - ); - run_command_with_output_and_env( - &[ - &"cargo", - &"build", - &"--release", - &"--target", - &config.target, - ], - Some(start_dir), - Some(&env), - )?; + rustflags.push_str(" -Zmir-opt-level=3"); + args.push(&"--release"); "release" } else { - env.insert("RUSTFLAGS".to_string(), rustflags); - - run_command_with_output_and_env( - &[&"cargo", &"build", &"--target", &config.target], - Some(start_dir), - Some(&env), - )?; "debug" }; + env.insert("RUSTFLAGS".to_string(), rustflags); + run_command_with_output_and_env(&args, Some(start_dir), Some(&env))?; + // Copy files to sysroot let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple)); fs::create_dir_all(&sysroot_path).map_err(|error| { From 114c25feeb021fc3462056df2a06f715512e89e6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 Feb 2024 14:58:04 +0100 Subject: [PATCH 144/192] Pass `--no-default-features` to codegen as well --- build_system/src/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index e32971ca0c73a..0eabd1d897292 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -195,6 +195,9 @@ fn build_codegen(args: &mut BuildArg) -> Result<(), String> { } else { env.insert("CHANNEL".to_string(), "debug".to_string()); } + if args.config_info.no_default_features { + command.push(&"--no-default-features"); + } let flags = args.flags.iter().map(|s| s.as_str()).collect::>(); for flag in &flags { command.push(flag); From a9b5c0832fc3e7e12916ef827f9de27d968a491a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Feb 2024 23:10:34 +0100 Subject: [PATCH 145/192] make simd_reduce_{mul,add}_unordered use only the 'reassoc' flag, not all fast-math flags --- src/builder.rs | 4 ++-- src/intrinsic/simd.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 5f1e45383765f..7e2139866f49e 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1752,7 +1752,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.vector_reduce(src, |a, b, context| context.new_binary_op(None, op, a.get_type(), a, b)) } - pub fn vector_reduce_fadd_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fadd_reassoc(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } @@ -1772,7 +1772,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - pub fn vector_reduce_fmul_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fmul_reassoc(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 9fa978cd2ef7a..dedd46538589d 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -989,14 +989,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( arith_red!( simd_reduce_add_unordered: BinaryOp::Plus, - vector_reduce_fadd_fast, + vector_reduce_fadd_reassoc, false, add, 0.0 // TODO: Use this argument. ); arith_red!( simd_reduce_mul_unordered: BinaryOp::Mult, - vector_reduce_fmul_fast, + vector_reduce_fmul_reassoc, false, mul, 1.0 From 0abd3b76b7b20076981fcc002ca43de63f836ee8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Feb 2024 09:36:36 +0100 Subject: [PATCH 146/192] remove simd_reduce_{min,max}_nanless --- src/intrinsic/simd.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index dedd46538589d..d8091724d8647 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -1041,9 +1041,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( minmax_red!(simd_reduce_min: vector_reduce_min, vector_reduce_fmin); minmax_red!(simd_reduce_max: vector_reduce_max, vector_reduce_fmax); - // TODO(sadlerap): revisit these intrinsics to generate more optimal reductions - minmax_red!(simd_reduce_min_nanless: vector_reduce_min, vector_reduce_fmin); - minmax_red!(simd_reduce_max_nanless: vector_reduce_max, vector_reduce_fmax); macro_rules! bitwise_red { ($name:ident : $op:expr, $boolean:expr) => { From bb5b75f28dff36bb2ffded0ee3c3384745a1b3e1 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 23 Feb 2024 12:32:14 -0500 Subject: [PATCH 147/192] Update gcc version --- libgccjit.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgccjit.version b/libgccjit.version index 12dafeb9edeed..20aebf091a70a 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -cdd897840 +d24c8dae3 From c638defad75543fe2762a2afd34e4b7f97be5a35 Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Fri, 23 Feb 2024 22:31:05 +0800 Subject: [PATCH 148/192] feat(debuginfo): Init Commit for debuginfo Support TODO: 1. Add int.rs locations 2. Add demangling support 3. Add debug scope support 4. Add vtable support 5. Clean up builder.rs locations --- src/base.rs | 4 +- src/builder.rs | 362 ++++++++++++++++++++++++----------------------- src/context.rs | 4 +- src/debuginfo.rs | 227 ++++++++++++++++++++++++++--- src/int.rs | 10 +- src/lib.rs | 3 +- 6 files changed, 398 insertions(+), 212 deletions(-) diff --git a/src/base.rs b/src/base.rs index 773e234150d1b..bcf467839a45d 100644 --- a/src/base.rs +++ b/src/base.rs @@ -184,8 +184,8 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock // wrapper here maybe_create_entry_wrapper::>(&cx); - // Finalize debuginfo - if cx.sess().opts.debuginfo != DebugInfo::None { + // FINALIZE debuginfo + if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); } } diff --git a/src/builder.rs b/src/builder.rs index 56d9fd30bf675..fc4c4d86a7d63 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,16 +4,7 @@ use std::convert::TryFrom; use std::ops::Deref; use gccjit::{ - BinaryOp, - Block, - ComparisonOp, - Context, - Function, - LValue, - RValue, - ToRValue, - Type, - UnaryOp, + BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type, UnaryOp }; use rustc_apfloat::{ieee, Float, Round, Status}; use rustc_codegen_ssa::MemFlags; @@ -70,6 +61,7 @@ pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, stack_var_count: Cell, + pub loc: Option>, } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { @@ -78,6 +70,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { cx, block, stack_var_count: Cell::new(0), + loc:None } } @@ -93,14 +86,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => order, }; let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size)); - let previous_var = func.new_local(None, previous_value.get_type(), "previous_value"); - let return_value = func.new_local(None, previous_value.get_type(), "return_value"); - self.llbb().add_assignment(None, previous_var, previous_value); - self.llbb().add_assignment(None, return_value, previous_var.to_rvalue()); + let previous_var = func.new_local(self.loc, previous_value.get_type(), "previous_value"); + let return_value = func.new_local(self.loc, previous_value.get_type(), "return_value"); + self.llbb().add_assignment(self.loc, previous_var, previous_value); + self.llbb().add_assignment(self.loc, return_value, previous_var.to_rvalue()); let while_block = func.new_block("while"); let after_block = func.new_block("after_while"); - self.llbb().end_with_jump(None, while_block); + self.llbb().end_with_jump(self.loc, while_block); // NOTE: since jumps were added and compare_exchange doesn't expect this, the current block in the // state need to be updated. @@ -112,12 +105,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ExtremumOperation::Min => ComparisonOp::GreaterThan, }; - let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type())); + let cond1 = self.context.new_comparison(self.loc, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(self.loc, src, previous_value.get_type())); let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false); - let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); - let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); + let cond2 = self.cx.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); + let cond = self.cx.context.new_binary_op(self.loc, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); - while_block.end_with_conditional(None, cond, while_block, after_block); + while_block.end_with_conditional(self.loc, cond, while_block, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -135,17 +128,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let void_ptr_type = self.context.new_type::<*mut ()>(); let volatile_void_ptr_type = void_ptr_type.make_volatile(); - let dst = self.context.new_cast(None, dst, volatile_void_ptr_type); - let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type); + let dst = self.context.new_cast(self.loc, dst, volatile_void_ptr_type); + let expected = self.context.new_cast(self.loc, cmp.get_address(self.loc), void_ptr_type); // NOTE: not sure why, but we have the wrong type here. let int_type = compare_exchange.get_param(2).to_rvalue().get_type(); - let src = self.context.new_cast(None, src, int_type); - self.context.new_call(None, compare_exchange, &[dst, expected, src, weak, order, failure_order]) + let src = self.context.new_cast(self.loc, src, int_type); + self.context.new_call(self.loc, compare_exchange, &[dst, expected, src, weak, order, failure_order]) } pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) { - self.llbb().add_assignment(None, lvalue, value); + self.llbb().add_assignment(self.loc, lvalue, value); } fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { @@ -220,10 +213,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let actual_ty = actual_val.get_type(); if expected_ty != actual_ty { if !actual_ty.is_vector() && !expected_ty.is_vector() && (actual_ty.is_integral() && expected_ty.is_integral()) || (actual_ty.get_pointee().is_some() && expected_ty.get_pointee().is_some()) { - self.context.new_cast(None, actual_val, expected_ty) + self.context.new_cast(self.loc, actual_val, expected_ty) } else if on_stack_param_indices.contains(&index) { - actual_val.dereference(None).to_rvalue() + actual_val.dereference(self.loc).to_rvalue() } else { assert!(!((actual_ty.is_vector() && !expected_ty.is_vector()) || (!actual_ty.is_vector() && expected_ty.is_vector())), "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", actual_ty, actual_ty.is_vector(), expected_ty, expected_ty.is_vector(), func_ptr, index); @@ -268,12 +261,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let current_func = self.block.get_function(); if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; - let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + let result = current_func.new_local(self.loc, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + self.block.add_assignment(self.loc, result, self.cx.context.new_call(self.loc, func, &args)); result.to_rvalue() } else { - self.block.add_eval(None, self.cx.context.new_call(None, func, &args)); + self.block.add_eval(self.loc, self.cx.context.new_call(self.loc, func, &args)); // Return dummy value when not having return value. self.context.new_rvalue_from_long(self.isize_type, 0) } @@ -286,7 +279,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { None => { // NOTE: due to opaque pointers now being used, we need to cast here. let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); - func_ptr = self.context.new_cast(None, func_ptr, typ); + func_ptr = self.context.new_cast(self.loc, func_ptr, typ); new_func_type }, }; @@ -309,26 +302,26 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; - let return_value = self.cx.context.new_call_through_ptr(None, func_ptr, &args); + let return_value = self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args); let return_value = llvm::adjust_intrinsic_return_value(&self, return_value, &func_name, &args, args_adjusted, orig_args); - let result = current_func.new_local(None, return_value.get_type(), &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(None, result, return_value); + let result = current_func.new_local(self.loc, return_value.get_type(), &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); + self.block.add_assignment(self.loc, result, return_value); result.to_rvalue() } else { #[cfg(not(feature="master"))] if gcc_func.get_param_count() == 0 { // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. - self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[])); + self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &[])); } else { - self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args)); } #[cfg(feature="master")] - self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args)); // Return dummy value when not having return value. - let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed"); - self.block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0)); + let result = current_func.new_local(self.loc, self.isize_type, "dummyValueThatShouldNeverBeUsed"); + self.block.add_assignment(self.loc, result, self.context.new_rvalue_from_long(self.isize_type, 0)); result.to_rvalue() } } @@ -340,8 +333,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let current_func = self.block.get_function(); // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects. unsafe { RETURN_VALUE_COUNT += 1 }; - let result = current_func.new_local(None, return_type, &format!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + let result = current_func.new_local(self.loc, return_type, &format!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT })); + self.block.add_assignment(self.loc, result, self.cx.context.new_call(self.loc, func, &args)); result.to_rvalue() } } @@ -429,29 +422,29 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn ret_void(&mut self) { - self.llbb().end_with_void_return(None) + self.llbb().end_with_void_return(self.loc) } fn ret(&mut self, mut value: RValue<'gcc>) { if self.structs_as_pointer.borrow().contains(&value) { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - value = value.dereference(None).to_rvalue(); + value = value.dereference(self.loc).to_rvalue(); } let expected_return_type = self.current_func().get_return_type(); if !expected_return_type.is_compatible_with(value.get_type()) { // NOTE: due to opaque pointers now being used, we need to cast here. - value = self.context.new_cast(None, value, expected_return_type); + value = self.context.new_cast(self.loc, value, expected_return_type); } - self.llbb().end_with_return(None, value); + self.llbb().end_with_return(self.loc, value); } fn br(&mut self, dest: Block<'gcc>) { - self.llbb().end_with_jump(None, dest) + self.llbb().end_with_jump(self.loc, dest) } fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) { - self.llbb().end_with_conditional(None, cond, then_block, else_block) + self.llbb().end_with_conditional(self.loc, cond, then_block, else_block) } fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator)>) { @@ -461,7 +454,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let on_val = self.const_uint_big(typ, on_val); gcc_cases.push(self.context.new_case(on_val, on_val, dest)); } - self.block.end_with_switch(None, value, default_block, &gcc_cases); + self.block.end_with_switch(self.loc, value, default_block, &gcc_cases); } #[cfg(feature="master")] @@ -474,20 +467,20 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.block = current_block; let return_value = self.current_func() - .new_local(None, call.get_type(), "invokeResult"); + .new_local(self.loc, call.get_type(), "invokeResult"); - try_block.add_assignment(None, return_value, call); + try_block.add_assignment(self.loc, return_value, call); - try_block.end_with_jump(None, then); + try_block.end_with_jump(self.loc, then); if self.cleanup_blocks.borrow().contains(&catch) { - self.block.add_try_finally(None, try_block, catch); + self.block.add_try_finally(self.loc, try_block, catch); } else { - self.block.add_try_catch(None, try_block, catch); + self.block.add_try_catch(self.loc, try_block, catch); } - self.block.end_with_jump(None, then); + self.block.end_with_jump(self.loc, then); return_value.to_rvalue() } @@ -496,7 +489,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { let call_site = self.call(typ, fn_attrs, None, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); - self.llbb().end_with_conditional(None, condition, then, catch); + self.llbb().end_with_conditional(self.loc, condition, then, catch); if let Some(_fn_abi) = fn_abi { // TODO(bjorn3): Apply function attributes } @@ -505,16 +498,16 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn unreachable(&mut self) { let func = self.context.get_builtin_function("__builtin_unreachable"); - self.block.add_eval(None, self.context.new_call(None, func, &[])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, func, &[])); let return_type = self.block.get_function().get_return_type(); let void_type = self.context.new_type::<()>(); if return_type == void_type { - self.block.end_with_void_return(None) + self.block.end_with_void_return(self.loc) } else { let return_value = self.current_func() - .new_local(None, return_type, "unreachableReturn"); - self.block.end_with_return(None, return_value) + .new_local(self.loc, return_type, "unreachableReturn"); + self.block.end_with_return(self.loc, return_value) } } @@ -539,7 +532,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - a * b + let i=a * b; + if self.loc.is_some() { + unsafe{ + i.set_location(self.loc.clone().unwrap()); + } + } + i } fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -564,7 +563,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they // should be the same. let typ = a.get_type().to_signed(self); - let b = self.context.new_cast(None, b, typ); + let b = self.context.new_cast(self.loc, b, typ); a / b } @@ -611,7 +610,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if a_type.is_compatible_with(self.cx.float_type) { let fmodf = self.context.get_builtin_function("fmodf"); // FIXME(antoyo): this seems to produce the wrong result. - return self.context.new_call(None, fmodf, &[a, b]); + return self.context.new_call(self.loc, fmodf, &[a, b]); } else if let Some(vector_type) = a_type_unqualified.dyncast_vector() { assert_eq!(a_type_unqualified, b.get_type().unqualified()); @@ -626,12 +625,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }) .collect(); - return self.context.new_rvalue_from_vector(None, a_type, &new_elements) + return self.context.new_rvalue_from_vector(self.loc, a_type, &new_elements) } assert_eq!(a_type_unqualified, self.cx.double_type); let fmod = self.context.get_builtin_function("fmod"); - return self.context.new_call(None, fmod, &[a, b]); + return self.context.new_call(self.loc, fmod, &[a, b]); } fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -665,7 +664,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) + self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a) } fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { @@ -738,7 +737,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. self.stack_var_count.set(self.stack_var_count.get() + 1); - self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None) + self.current_func().new_local(self.loc, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(self.loc) } fn byte_array_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { @@ -760,17 +759,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { else { pointee_ty.get_aligned(align.bytes()) }; - let ptr = self.context.new_cast(None, ptr, aligned_type.make_pointer()); - let deref = ptr.dereference(None).to_rvalue(); + let ptr = self.context.new_cast(self.loc, ptr, aligned_type.make_pointer()); + let deref = ptr.dereference(self.loc).to_rvalue(); unsafe { RETURN_VALUE_COUNT += 1 }; - let loaded_value = function.new_local(None, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); - block.add_assignment(None, loaded_value, deref); + let loaded_value = function.new_local(self.loc, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); + block.add_assignment(self.loc, loaded_value, deref); loaded_value.to_rvalue() } fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { - let ptr = self.context.new_cast(None, ptr, ty.make_volatile().make_pointer()); - ptr.dereference(None).to_rvalue() + let ptr = self.context.new_cast(self.loc, ptr, ty.make_volatile().make_pointer()); + ptr.dereference(self.loc).to_rvalue() } fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> { @@ -783,8 +782,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .make_const() .make_volatile() .make_pointer(); - let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); - self.context.new_call(None, atomic_load, &[ptr, ordering]) + let ptr = self.context.new_cast(self.loc, ptr, volatile_const_void_ptr_type); + self.context.new_call(self.loc, atomic_load, &[ptr, ordering]) } fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> { @@ -859,7 +858,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let next_bb = self.append_sibling_block("repeat_loop_next"); let ptr_type = start.get_type(); - let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var"); + let current = self.llbb().get_function().new_local(self.loc, ptr_type, "loop_var"); let current_val = current.to_rvalue(); self.assign(current, start); @@ -874,7 +873,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); let next = self.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]); - self.llbb().add_assignment(None, current, next); + self.llbb().add_assignment(self.loc, current, next); self.br(header_bb); self.switch_to_block(next_bb); @@ -894,14 +893,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align, _flags: MemFlags) -> RValue<'gcc> { let ptr = self.check_store(val, ptr); - let destination = ptr.dereference(None); + let destination = ptr.dereference(self.loc); // NOTE: libgccjit does not support specifying the alignment on the assignment, so we cast // to type so it gets the proper alignment. let destination_type = destination.to_rvalue().get_type().unqualified(); let aligned_type = destination_type.get_aligned(align.bytes()).make_pointer(); - let aligned_destination = self.cx.context.new_bitcast(None, ptr, aligned_type); - let aligned_destination = aligned_destination.dereference(None); - self.llbb().add_assignment(None, aligned_destination, val); + let aligned_destination = self.cx.context.new_bitcast(self.loc, ptr, aligned_type); + let aligned_destination = aligned_destination.dereference(self.loc); + self.llbb().add_assignment(self.loc, aligned_destination, val); // TODO(antoyo): handle align and flags. // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here? self.cx.context.new_rvalue_zero(self.type_i32()) @@ -914,26 +913,26 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let volatile_const_void_ptr_type = self.context.new_type::<()>() .make_volatile() .make_pointer(); - let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); + let ptr = self.context.new_cast(self.loc, ptr, volatile_const_void_ptr_type); // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because // the following cast is required to avoid this error: // gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int __attribute__((aligned(4)))) let int_type = atomic_store.get_param(1).to_rvalue().get_type(); - let value = self.context.new_cast(None, value, int_type); + let value = self.context.new_cast(self.loc, value, int_type); self.llbb() - .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering])); + .add_eval(self.loc, self.context.new_call(self.loc, atomic_store, &[ptr, value, ordering])); } fn gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { // NOTE: due to opaque pointers now being used, we need to cast here. - let ptr = self.context.new_cast(None, ptr, typ.make_pointer()); + let ptr = self.context.new_cast(self.loc, ptr, typ.make_pointer()); let ptr_type = ptr.get_type(); let mut pointee_type = ptr.get_type(); // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is // always considered in bounds in GCC (TODO(antoyo): to be verified). // So, we have to cast to a number. - let mut result = self.context.new_bitcast(None, ptr, self.sizet_type); + let mut result = self.context.new_bitcast(self.loc, ptr, self.sizet_type); // FIXME(antoyo): if there were more than 1 index, this code is probably wrong and would // require dereferencing the pointer. for index in indices { @@ -941,49 +940,49 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] let pointee_size = { let size = self.cx.context.new_sizeof(pointee_type); - self.context.new_cast(None, size, index.get_type()) + self.context.new_cast(self.loc, size, index.get_type()) }; #[cfg(not(feature="master"))] let pointee_size = self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32); result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type); } - self.context.new_bitcast(None, result, ptr_type) + self.context.new_bitcast(self.loc, result, ptr_type) } fn inbounds_gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { // NOTE: due to opaque pointers now being used, we need to cast here. - let ptr = self.context.new_cast(None, ptr, typ.make_pointer()); + let ptr = self.context.new_cast(self.loc, ptr, typ.make_pointer()); // NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified). let mut indices = indices.into_iter(); let index = indices.next().expect("first index in inbounds_gep"); - let mut result = self.context.new_array_access(None, ptr, *index); + let mut result = self.context.new_array_access(self.loc, ptr, *index); for index in indices { - result = self.context.new_array_access(None, result, *index); + result = self.context.new_array_access(self.loc, result, *index); } - result.get_address(None) + result.get_address(self.loc) } fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> { // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. assert_eq!(idx as usize as u64, idx); - let value = ptr.dereference(None).to_rvalue(); + let value = ptr.dereference(self.loc).to_rvalue(); if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, value, index); - element.get_address(None) + let element = self.context.new_array_access(self.loc, value, index); + element.get_address(self.loc) } else if let Some(vector_type) = value_type.dyncast_vector() { let array_type = vector_type.get_element_type().make_pointer(); let array = self.bitcast(ptr, array_type); let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, array, index); - element.get_address(None) + let element = self.context.new_array_access(self.loc, array, index); + element.get_address(self.loc) } else if let Some(struct_type) = value_type.is_struct() { // NOTE: due to opaque pointers now being used, we need to bitcast here. let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer()); - ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None) + ptr.dereference_field(self.loc, struct_type.get_field(idx as i32)).get_address(self.loc) } else { panic!("Unexpected type {:?}", value_type); @@ -1002,7 +1001,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): nothing to do as it is only for LLVM? return value; } - self.context.new_cast(None, value, dest_ty) + self.context.new_cast(self.loc, value, dest_ty) } fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { @@ -1023,11 +1022,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): make sure it truncates. - self.context.new_cast(None, value, dest_ty) + self.context.new_cast(self.loc, value, dest_ty) } fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.context.new_cast(None, value, dest_ty) + self.context.new_cast(self.loc, value, dest_ty) } fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { @@ -1055,13 +1054,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (false, true) => { // NOTE: Projecting a field of a pointer type will attempt a cast from a signed char to // a pointer, which is not supported by gccjit. - return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty); + return self.cx.context.new_cast(self.loc, self.inttoptr(value, val_type.make_pointer()), dest_ty); }, (false, false) => { // When they are not pointers, we want a transmute (or reinterpret_cast). self.bitcast(value, dest_ty) }, - (true, true) => self.cx.context.new_cast(None, value, dest_ty), + (true, true) => self.cx.context.new_cast(self.loc, value, dest_ty), (true, false) => unimplemented!(), } } @@ -1072,7 +1071,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { - self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) } /* Miscellaneous instructions */ @@ -1084,7 +1083,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let src = self.pointercast(src, self.type_ptr_to(self.type_void())); let memcpy = self.context.get_builtin_function("memcpy"); // TODO(antoyo): handle aligns and is_volatile. - self.block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, memcpy, &[dst, src, size])); } fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) { @@ -1102,7 +1101,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let memmove = self.context.get_builtin_function("memmove"); // TODO(antoyo): handle is_volatile. - self.block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, memmove, &[dst, src, size])); } fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) { @@ -1110,27 +1109,27 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let ptr = self.pointercast(ptr, self.type_i8p()); let memset = self.context.get_builtin_function("memset"); // TODO(antoyo): handle align and is_volatile. - let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type); + let fill_byte = self.context.new_cast(self.loc, fill_byte, self.i32_type); let size = self.intcast(size, self.type_size_t(), false); - self.block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size])); + self.block.add_eval(self.loc, self.context.new_call(self.loc, memset, &[ptr, fill_byte, size])); } fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> { let func = self.current_func(); - let variable = func.new_local(None, then_val.get_type(), "selectVar"); + let variable = func.new_local(self.loc, then_val.get_type(), "selectVar"); let then_block = func.new_block("then"); let else_block = func.new_block("else"); let after_block = func.new_block("after"); - self.llbb().end_with_conditional(None, cond, then_block, else_block); + self.llbb().end_with_conditional(self.loc, cond, then_block, else_block); - then_block.add_assignment(None, variable, then_val); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, variable, then_val); + then_block.end_with_jump(self.loc, after_block); if !then_val.get_type().is_compatible_with(else_val.get_type()) { - else_val = self.context.new_cast(None, else_val, then_val.get_type()); + else_val = self.context.new_cast(self.loc, else_val, then_val.get_type()); } - else_block.add_assignment(None, variable, else_val); - else_block.end_with_jump(None, after_block); + else_block.add_assignment(self.loc, variable, else_val); + else_block.end_with_jump(self.loc, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -1146,7 +1145,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> { - self.context.new_vector_access(None, vec, idx).to_rvalue() + self.context.new_vector_access(self.loc, vec, idx).to_rvalue() } #[cfg(not(feature="master"))] @@ -1154,9 +1153,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let vector_type = vec.get_type().unqualified().dyncast_vector().expect("Called extract_element on a non-vector type"); let element_type = vector_type.get_element_type(); let vec_num_units = vector_type.get_num_units(); - let array_type = self.context.new_array_type(None, element_type, vec_num_units as u64); - let array = self.context.new_bitcast(None, vec, array_type).to_rvalue(); - self.context.new_array_access(None, array, idx).to_rvalue() + let array_type = self.context.new_array_type(self.loc, element_type, vec_num_units as u64); + let array = self.context.new_bitcast(self.loc, vec, array_type).to_rvalue(); + self.context.new_array_access(self.loc, array, idx).to_rvalue() } fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> { @@ -1170,8 +1169,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, aggregate_value, index); - element.get_address(None) + let element = self.context.new_array_access(self.loc, aggregate_value, index); + element.get_address(self.loc) } else if value_type.dyncast_vector().is_some() { panic!(); @@ -1180,14 +1179,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if let Some(struct_type) = pointer_type.is_struct() { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)).to_rvalue() + aggregate_value.dereference_field(self.loc, struct_type.get_field(idx as i32)).to_rvalue() } else { panic!("Unexpected type {:?}", value_type); } } else if let Some(struct_type) = value_type.is_struct() { - aggregate_value.access_field(None, struct_type.get_field(idx as i32)).to_rvalue() + aggregate_value.access_field(self.loc, struct_type.get_field(idx as i32)).to_rvalue() } else { panic!("Unexpected type {:?}", value_type); @@ -1202,7 +1201,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let lvalue = if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - self.context.new_array_access(None, aggregate_value, index) + self.context.new_array_access(self.loc, aggregate_value, index) } else if value_type.dyncast_vector().is_some() { panic!(); @@ -1211,7 +1210,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if let Some(struct_type) = pointer_type.is_struct() { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)) + aggregate_value.dereference_field(self.loc, struct_type.get_field(idx as i32)) } else { panic!("Unexpected type {:?}", value_type); @@ -1225,13 +1224,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let value = // NOTE: sometimes, rustc will create a value with the wrong type. if lvalue_type != value.get_type() { - self.context.new_cast(None, value, lvalue_type) + self.context.new_cast(self.loc, value, lvalue_type) } else { value }; - self.llbb().add_assignment(None, lvalue, value); + self.llbb().add_assignment(self.loc, lvalue, value); aggregate_value } @@ -1254,10 +1253,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let eh_pointer_builtin = self.cx.context.get_target_builtin_function("__builtin_eh_pointer"); let zero = self.cx.context.new_rvalue_zero(self.int_type); - let ptr = self.cx.context.new_call(None, eh_pointer_builtin, &[zero]); + let ptr = self.cx.context.new_call(self.loc, eh_pointer_builtin, &[zero]); let value1_type = self.u8_type.make_pointer(); - let ptr = self.cx.context.new_cast(None, ptr, value1_type); + let ptr = self.cx.context.new_cast(self.loc, ptr, value1_type); let value1 = ptr; let value2 = zero; // TODO(antoyo): set the proper value here (the type of exception?). @@ -1266,9 +1265,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(not(feature="master"))] fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { - let value1 = self.current_func().new_local(None, self.u8_type.make_pointer(), "landing_pad0") + let value1 = self.current_func().new_local(self.loc, self.u8_type.make_pointer(), "landing_pad0") .to_rvalue(); - let value2 = self.current_func().new_local(None, self.i32_type, "landing_pad1").to_rvalue(); + let value2 = self.current_func().new_local(self.loc, self.i32_type, "landing_pad1").to_rvalue(); (value1, value2) } @@ -1280,9 +1279,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { let exn_type = exn0.get_type(); - let exn = self.context.new_cast(None, exn0, exn_type); + let exn = self.context.new_cast(self.loc, exn0, exn_type); let unwind_resume = self.context.get_target_builtin_function("__builtin_unwind_resume"); - self.llbb().add_eval(None, self.context.new_call(None, unwind_resume, &[exn])); + self.llbb().add_eval(self.loc, self.context.new_call(self.loc, unwind_resume, &[exn])); self.unreachable(); } @@ -1329,8 +1328,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // NOTE: since success contains the call to the intrinsic, it must be added to the basic block before // expected so that we store expected after the call. - let success_var = self.current_func().new_local(None, self.bool_type, "success"); - self.llbb().add_assignment(None, success_var, success); + let success_var = self.current_func().new_local(self.loc, self.bool_type, "success"); + self.llbb().add_assignment(self.loc, success_var, success); (expected.to_rvalue(), success_var.to_rvalue()) } @@ -1358,12 +1357,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let void_ptr_type = self.context.new_type::<*mut ()>(); let volatile_void_ptr_type = void_ptr_type.make_volatile(); - let dst = self.context.new_cast(None, dst, volatile_void_ptr_type); + let dst = self.context.new_cast(self.loc, dst, volatile_void_ptr_type); // FIXME(antoyo): not sure why, but we have the wrong type here. let new_src_type = atomic_function.get_param(1).to_rvalue().get_type(); - let src = self.context.new_cast(None, src, new_src_type); - let res = self.context.new_call(None, atomic_function, &[dst, src, order]); - self.context.new_cast(None, res, src.get_type()) + let src = self.context.new_cast(self.loc, src, new_src_type); + let res = self.context.new_call(self.loc, atomic_function, &[dst, src, order]); + self.context.new_cast(self.loc, res, src.get_type()) } fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { @@ -1374,7 +1373,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; let thread_fence = self.context.get_builtin_function(name); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - self.llbb().add_eval(None, self.context.new_call(None, thread_fence, &[order])); + self.llbb().add_eval(self.loc, self.context.new_call(self.loc, thread_fence, &[order])); } fn set_invariant_load(&mut self, load: RValue<'gcc>) { @@ -1650,7 +1649,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }; for i in 0..mask_num_units { let field = struct_type.get_field(i as i32); - vector_elements.push(self.context.new_cast(None, mask.access_field(None, field).to_rvalue(), mask_element_type)); + vector_elements.push(self.context.new_cast(self.loc, mask.access_field(self.loc, field).to_rvalue(), mask_element_type)); } // NOTE: the mask needs to be the same length as the input vectors, so add the missing @@ -1666,14 +1665,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // vectors and create a dummy second vector. let mut elements = vec![]; for i in 0..vec_num_units { - elements.push(self.context.new_vector_access(None, v1, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(self.loc, v1, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } for i in 0..(mask_num_units - vec_num_units) { - elements.push(self.context.new_vector_access(None, v2, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(self.loc, v2, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } - let v1 = self.context.new_rvalue_from_vector(None, result_type, &elements); + let v1 = self.context.new_rvalue_from_vector(self.loc, result_type, &elements); let zero = self.context.new_rvalue_zero(element_type); - let v2 = self.context.new_rvalue_from_vector(None, result_type, &vec![zero; mask_num_units]); + let v2 = self.context.new_rvalue_from_vector(self.loc, result_type, &vec![zero; mask_num_units]); (v1, v2) } else { @@ -1682,17 +1681,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let new_mask_num_units = std::cmp::max(mask_num_units, vec_num_units); let mask_type = self.context.new_vector_type(mask_element_type, new_mask_num_units as u64); - let mask = self.context.new_rvalue_from_vector(None, mask_type, &vector_elements); - let result = self.context.new_rvalue_vector_perm(None, v1, v2, mask); + let mask = self.context.new_rvalue_from_vector(self.loc, mask_type, &vector_elements); + let result = self.context.new_rvalue_vector_perm(self.loc, v1, v2, mask); if vec_num_units != mask_num_units { // NOTE: if padding was added, only select the number of elements of the masks to // remove that padding in the result. let mut elements = vec![]; for i in 0..mask_num_units { - elements.push(self.context.new_vector_access(None, result, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(self.loc, result, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } - self.context.new_rvalue_from_vector(None, result_type, &elements) + self.context.new_rvalue_from_vector(self.loc, result_type, &elements) } else { result @@ -1724,12 +1723,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { vector_elements.iter() .map(|i| self.context.new_rvalue_from_int(mask_element_type, ((i + shift) % element_count) as i32)) .collect(); - let mask = self.context.new_rvalue_from_vector(None, mask_type, &vector_elements); - let shifted = self.context.new_rvalue_vector_perm(None, res, res, mask); + let mask = self.context.new_rvalue_from_vector(self.loc, mask_type, &vector_elements); + let shifted = self.context.new_rvalue_vector_perm(self.loc, res, res, mask); shift *= 2; res = op(res, shifted, &self.context); } - self.context.new_vector_access(None, res, self.context.new_rvalue_zero(self.int_type)) + self.context.new_vector_access(self.loc, res, self.context.new_rvalue_zero(self.int_type)) .to_rvalue() } @@ -1741,7 +1740,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } pub fn vector_reduce_op(&mut self, src: RValue<'gcc>, op: BinaryOp) -> RValue<'gcc> { - self.vector_reduce(src, |a, b, context| context.new_binary_op(None, op, a.get_type(), a, b)) + let loc = self.loc.clone(); + self.vector_reduce(src, |a, b, context| context.new_binary_op(loc, op, a.get_type(), a, b)) } pub fn vector_reduce_fadd_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { @@ -1754,7 +1754,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let element_count = vector_type.get_num_units(); (0..element_count).into_iter() .map(|i| self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue()) .fold(acc, |x, i| x + i) } @@ -1774,7 +1774,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let element_count = vector_type.get_num_units(); (0..element_count).into_iter() .map(|i| self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue()) .fold(acc, |x, i| x * i) } @@ -1786,17 +1786,19 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Inspired by Hacker's Delight min implementation. pub fn vector_reduce_min(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { + let loc = self.loc.clone(); self.vector_reduce(src, |a, b, context| { - let differences_or_zeros = difference_or_zero(a, b, context); - context.new_binary_op(None, BinaryOp::Plus, b.get_type(), b, differences_or_zeros) + let differences_or_zeros = difference_or_zero(loc, a, b, context); + context.new_binary_op(loc, BinaryOp::Plus, b.get_type(), b, differences_or_zeros) }) } // Inspired by Hacker's Delight max implementation. pub fn vector_reduce_max(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { + let loc = self.loc.clone(); self.vector_reduce(src, |a, b, context| { - let differences_or_zeros = difference_or_zero(a, b, context); - context.new_binary_op(None, BinaryOp::Minus, a.get_type(), a, differences_or_zeros) + let differences_or_zeros = difference_or_zero(loc, a, b, context); + context.new_binary_op(loc, BinaryOp::Minus, a.get_type(), a, differences_or_zeros) }) } @@ -1805,23 +1807,23 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // mask out the NaNs in b and replace them with the corresponding lane in a, so when a and // b get compared & spliced together, we get the numeric values instead of NaNs. - let b_nan_mask = self.context.new_comparison(None, ComparisonOp::NotEquals, b, b); + let b_nan_mask = self.context.new_comparison(self.loc, ComparisonOp::NotEquals, b, b); let mask_type = b_nan_mask.get_type(); - let b_nan_mask_inverted = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, mask_type, b_nan_mask); - let a_cast = self.context.new_bitcast(None, a, mask_type); - let b_cast = self.context.new_bitcast(None, b, mask_type); + let b_nan_mask_inverted = self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, mask_type, b_nan_mask); + let a_cast = self.context.new_bitcast(self.loc, a, mask_type); + let b_cast = self.context.new_bitcast(self.loc, b, mask_type); let res = (b_nan_mask & a_cast) | (b_nan_mask_inverted & b_cast); - let b = self.context.new_bitcast(None, res, vector_type); + let b = self.context.new_bitcast(self.loc, res, vector_type); // now do the actual comparison let comparison_op = match direction { ExtremumOperation::Min => ComparisonOp::LessThan, ExtremumOperation::Max => ComparisonOp::GreaterThan, }; - let cmp = self.context.new_comparison(None, comparison_op, a, b); - let cmp_inverted = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, cmp.get_type(), cmp); + let cmp = self.context.new_comparison(self.loc, comparison_op, a, b); + let cmp_inverted = self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, cmp.get_type(), cmp); let res = (cmp & a_cast) | (cmp_inverted & res); - self.context.new_bitcast(None, res, vector_type) + self.context.new_bitcast(self.loc, res, vector_type) } pub fn vector_fmin(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -1832,12 +1834,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn vector_reduce_fmin(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - let mut acc = self.context.new_vector_access(None, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + let mut acc = self.context.new_vector_access(self.loc, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); for i in 1..element_count { let elem = self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue(); - let cmp = self.context.new_comparison(None, ComparisonOp::LessThan, acc, elem); + let cmp = self.context.new_comparison(self.loc, ComparisonOp::LessThan, acc, elem); acc = self.select(cmp, acc, elem); } acc @@ -1856,12 +1858,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn vector_reduce_fmax(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - let mut acc = self.context.new_vector_access(None, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + let mut acc = self.context.new_vector_access(self.loc, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); for i in 1..element_count { let elem = self.context - .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) .to_rvalue(); - let cmp = self.context.new_comparison(None, ComparisonOp::GreaterThan, acc, elem); + let cmp = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, acc, elem); acc = self.select(cmp, acc, elem); } acc @@ -1890,7 +1892,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if then_val_element_size != element_type.get_size() { let new_element_type = self.type_ix(then_val_element_size as u64 * 8); let new_vector_type = self.context.new_vector_type(new_element_type, num_units as u64); - let cond = self.context.convert_vector(None, cond, new_vector_type); + let cond = self.context.convert_vector(self.loc, cond, new_vector_type); (cond, new_element_type) } else { @@ -1901,24 +1903,24 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let cond_type = cond.get_type(); let zeros = vec![self.context.new_rvalue_zero(element_type); num_units]; - let zeros = self.context.new_rvalue_from_vector(None, cond_type, &zeros); + let zeros = self.context.new_rvalue_from_vector(self.loc, cond_type, &zeros); let result_type = then_val.get_type(); - let masks = self.context.new_comparison(None, ComparisonOp::NotEquals, cond, zeros); + let masks = self.context.new_comparison(self.loc, ComparisonOp::NotEquals, cond, zeros); // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make // the & operation work. let then_val = self.bitcast_if_needed(then_val, masks.get_type()); let then_vals = masks & then_val; let minus_ones = vec![self.context.new_rvalue_from_int(element_type, -1); num_units]; - let minus_ones = self.context.new_rvalue_from_vector(None, cond_type, &minus_ones); + let minus_ones = self.context.new_rvalue_from_vector(self.loc, cond_type, &minus_ones); let inverted_masks = masks ^ minus_ones; // NOTE: sometimes, the type of else_val can be different than the type of then_val in // libgccjit (vector of int vs vector of int32_t), but they should be the same for the AND // operation to work. // TODO: remove bitcast now that vector types can be compared? - let else_val = self.context.new_bitcast(None, else_val, then_val.get_type()); + let else_val = self.context.new_bitcast(self.loc, else_val, then_val.get_type()); let else_vals = inverted_masks & else_val; let res = then_vals | else_vals; @@ -1926,15 +1928,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } -fn difference_or_zero<'gcc>(a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Context<'gcc>) -> RValue<'gcc> { +fn difference_or_zero<'gcc>(loc: Option>, a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Context<'gcc>) -> RValue<'gcc> { let difference = a - b; - let masks = context.new_comparison(None, ComparisonOp::GreaterThanEquals, b, a); + let masks = context.new_comparison(loc, ComparisonOp::GreaterThanEquals, b, a); // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make // the & operation work. let a_type = a.get_type(); let masks = if masks.get_type() != a_type { - context.new_bitcast(None, masks, a_type) + context.new_bitcast(loc, masks, a_type) } else { masks @@ -1945,7 +1947,7 @@ fn difference_or_zero<'gcc>(a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Con impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> { // Forward to the `get_static` method of `CodegenCx` - self.cx().get_static(def_id).get_address(None) + self.cx().get_static(def_id).get_address(self.loc) } } diff --git a/src/context.rs b/src/context.rs index 5760d96165ddf..9dbb3751d47b4 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,6 @@ use std::cell::{Cell, RefCell}; -use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, RValue, Type}; +use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type}; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::traits::{ BackendTypes, @@ -345,7 +345,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type Funclet = (); // TODO(antoyo) type DIScope = (); // TODO(antoyo) - type DILocation = (); // TODO(antoyo) + type DILocation = Location<'gcc>; // TODO(antoyo) type DIVariable = (); // TODO(antoyo) } diff --git a/src/debuginfo.rs b/src/debuginfo.rs index d1bfd833cd87f..e01624ce15ea3 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -1,41 +1,172 @@ -use gccjit::RValue; -use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; +use gccjit::{Location, RValue}; +use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; -use rustc_middle::mir; +use rustc_index::bit_set::BitSet; +use rustc_index::IndexVec; +use rustc_middle::mir::{Body, self, SourceScope}; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; -use rustc_span::{SourceFile, Span, Symbol}; +use rustc_session::config::DebugInfo; +use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; +use rustc_data_structures::sync::Lrc; +use crate::rustc_index::Idx; use std::ops::Range; use crate::builder::Builder; use crate::context::CodegenCx; +pub(super) const UNKNOWN_LINE_NUMBER: u32 = 0; +pub(super) const UNKNOWN_COLUMN_NUMBER: u32 = 0; + impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). fn dbg_var_addr( &mut self, _dbg_var: Self::DIVariable, - _scope_metadata: Self::DIScope, - _variable_alloca: Self::Value, + dbg_loc: Self::DILocation, + variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size], _fragment: Option>, ) { - unimplemented!(); + // Not sure if this is correct, probably wrong but still keep it here. + unsafe { + #[cfg(feature = "master")] + variable_alloca.set_location(dbg_loc); + } } fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { // TODO(antoyo): insert reference to gdb debug scripts section global. } - fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) { - unimplemented!(); + /// Currently, this function is not yet implemented. It seems that the + /// debug name and the mangled name should both be included in the LValues. + /// Besides, a function to get the rvalue type(m_is_lvalue) should also be included. + fn set_var_name(&mut self, value: RValue<'gcc>, name: &str) { + //unimplemented!(); + } + + fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { + self.loc = Some(dbg_loc); + } +} + +pub fn compute_mir_scopes<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + instance: Instance<'tcx>, + mir: &Body<'tcx>, + debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>, +) { + // Find all scopes with variables defined in them. + let variables = if cx.sess().opts.debuginfo == DebugInfo::Full { + let mut vars = BitSet::new_empty(mir.source_scopes.len()); + // FIXME(eddyb) take into account that arguments always have debuginfo, + // irrespective of their name (assuming full debuginfo is enabled). + // NOTE(eddyb) actually, on second thought, those are always in the + // function scope, which always exists. + for var_debug_info in &mir.var_debug_info { + vars.insert(var_debug_info.source_info.scope); + } + Some(vars) + } else { + // Nothing to emit, of course. + None + }; + let mut instantiated = BitSet::new_empty(mir.source_scopes.len()); + // Instantiate all scopes. + for idx in 0..mir.source_scopes.len() { + let scope = SourceScope::new(idx); + make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope); + } + assert!(instantiated.count() == mir.source_scopes.len()); +} + +fn make_mir_scope<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + instance: Instance<'tcx>, + mir: &Body<'tcx>, + variables: &Option>, + debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>, + instantiated: &mut BitSet, + scope: SourceScope, +) { + if instantiated.contains(scope) { + return; + } + + let scope_data = &mir.source_scopes[scope]; + let parent_scope = if let Some(parent) = scope_data.parent_scope { + make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent); + debug_context.scopes[parent] + } else { + // The root is the function itself. + let file = cx.sess().source_map().lookup_source_file(mir.span.lo()); + debug_context.scopes[scope] = DebugScope { + file_start_pos: file.start_pos, + file_end_pos: file.end_position(), + ..debug_context.scopes[scope] + }; + instantiated.insert(scope); + return; + }; + + if let Some(vars) = variables + { + if !vars.contains(scope) + && scope_data.inlined.is_none() { + // Do not create a DIScope if there are no variables defined in this + // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. + debug_context.scopes[scope] = parent_scope; + instantiated.insert(scope); + return; + } } - fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) { - unimplemented!(); + let loc = cx.lookup_debug_loc(scope_data.span.lo()); + let dbg_scope = (); + + let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { + // FIXME(eddyb) this doesn't account for the macro-related + // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does. + let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span); + cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span) + }); + let p_inlined_at = parent_scope.inlined_at; + // TODO(tempdragon): dbg_scope: Add support for scope extension here. + inlined_at.or(p_inlined_at); + + debug_context.scopes[scope] = DebugScope { + dbg_scope, + inlined_at, + file_start_pos: loc.0.start_pos, + file_end_pos: loc.0.end_position(), + }; + instantiated.insert(scope); +} + +/// Copied from LLVM backend +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn lookup_debug_loc(&self, pos: BytePos) -> (Lrc, u32, u32) { + match self.sess().source_map().lookup_line(pos) { + Ok(SourceFileAndLine { sf: file, line }) => { + let line_pos = file.lines()[line]; + + // Use 1-based indexing. + let line = (line + 1) as u32; + let col = (file.relative_position(pos) - line_pos).to_u32() + 1; + (file, + line, + if ! self.sess().target.is_like_msvc { + col } else { + UNKNOWN_COLUMN_NUMBER + } + ) + } + Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER), + } } } @@ -51,13 +182,32 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn create_function_debug_context( &self, - _instance: Instance<'tcx>, - _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - _llfn: RValue<'gcc>, - _mir: &mir::Body<'tcx>, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: RValue<'gcc>, + mir: &mir::Body<'tcx>, ) -> Option> { // TODO(antoyo) - None + if self.sess().opts.debuginfo == DebugInfo::None { + return None; + } + + // Initialize fn debug context (including scopes). + let empty_scope = DebugScope { + dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)), + inlined_at: None, + file_start_pos: BytePos(0), + file_end_pos: BytePos(0), + }; + let mut fn_debug_context = FunctionDebugContext { + scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes.as_slice()), + inlined_function_scopes: Default::default(), + }; + + // Fill in all the scopes, with the information from the MIR body. + compute_mir_scopes(self, instance, mir, &mut fn_debug_context); + + Some(fn_debug_context) } fn extend_scope_to_file( @@ -65,11 +215,12 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _scope_metadata: Self::DIScope, _file: &SourceFile, ) -> Self::DIScope { - unimplemented!(); + //unimplemented!(); } fn debuginfo_finalize(&self) { - // TODO(antoyo) + // TODO(antoyo): Get the debug flag/predicate to allow optional generation of debuginfo. + self.context.set_debug_info(true) } fn create_dbg_var( @@ -80,7 +231,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _variable_kind: VariableKind, _span: Span, ) -> Self::DIVariable { - unimplemented!(); + () } fn dbg_scope_fn( @@ -89,15 +240,47 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option>, ) -> Self::DIScope { - unimplemented!(); + //unimplemented!(); } fn dbg_loc( &self, _scope: Self::DIScope, _inlined_at: Option, - _span: Span, + span: Span, ) -> Self::DILocation { - unimplemented!(); + //unimplemented!(); + let pos = span.lo(); + let (file, line, col) = self.lookup_debug_loc(pos); + let loc = match &file.name { + rustc_span::FileName::Real(name) => match name { + rustc_span::RealFileName::LocalPath(name) => { + if let Some(name) = name.to_str() { + self.context + .new_location(name, line as i32, col as i32) + }else{ + Location::null() + } + } + rustc_span::RealFileName::Remapped { + local_path, + virtual_name, + } => if let Some(name) = local_path.as_ref() { + if let Some(name) = name.to_str(){ + self.context.new_location( + name, + line as i32, + col as i32, + ) + } else { + Location::null() + } + }else{ + Location::null() + }, + }, + _ => Location::null(), + }; + loc } } diff --git a/src/int.rs b/src/int.rs index b69e073c4d94d..b0ceacf2ffc20 100644 --- a/src/int.rs +++ b/src/int.rs @@ -195,7 +195,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let a_type = a.get_type(); let b_type = b.get_type(); if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(self.loc, operation, a_type, a, b) } else { debug_assert!(a_type.dyncast_array().is_some()); @@ -208,10 +208,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { "u" }; let func_name = format!("__{}{}ti3", sign, operation_name); - let param_a = self.context.new_parameter(None, a_type, "a"); - let param_b = self.context.new_parameter(None, b_type, "b"); - let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); - self.context.new_call(None, func, &[a, b]) + let param_a = self.context.new_parameter(self.loc, a_type, "a"); + let param_b = self.context.new_parameter(self.loc, b_type, "b"); + let func = self.context.new_function(self.loc, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); + self.context.new_call(self.loc, func, &[a, b]) } } diff --git a/src/lib.rs b/src/lib.rs index 7f0696740b374..cdb7cbebc1cc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,7 @@ extern crate rustc_errors; extern crate rustc_fluent_macro; extern crate rustc_fs_util; extern crate rustc_hir; +extern crate rustc_index; #[cfg(feature="master")] extern crate rustc_interface; extern crate rustc_macros; @@ -174,7 +175,7 @@ impl CodegenBackend for GccCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } - fn init(&self, sess: &Session) { + fn init(&self, sess: &Session) { #[cfg(feature="master")] { let target_cpu = target_cpu(sess); From 2ffe9d1eefb175addf8c14cc48dd7fcf91b2b008 Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Sat, 24 Feb 2024 19:56:29 +0800 Subject: [PATCH 149/192] feat(int.rs&build.rs): Add location info to arithmetic operators TODO: 1. Clean the unnecessary locations in builder.rs & int.rs 2. Add demangling support 3. Add debug scope support 4. Add vtable support 5. Clean up builder.rs locations --- src/builder.rs | 68 +++++++++------ src/int.rs | 204 +++++++++++++++++++++---------------------- src/intrinsic/mod.rs | 108 +++++++++++------------ 3 files changed, 199 insertions(+), 181 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index fc4c4d86a7d63..c5d3ed8c8a1f2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -26,6 +26,7 @@ use rustc_codegen_ssa::traits::{ use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; +use rustc_middle::mir::Rvalue; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_span::Span; @@ -398,6 +399,16 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { type DIVariable = as BackendTypes>::DIVariable; } +pub fn set_rval_location<'a, 'gcc, 'tcx>(bx: &mut Builder<'a,'gcc,'tcx>, r:RValue<'gcc>) -> RValue<'gcc> { + if bx.loc.is_some(){ + unsafe { + r.set_location(bx.loc.unwrap()); + } + } + r + +} + impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> { Builder::with_cx(cx, block) @@ -612,7 +623,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): this seems to produce the wrong result. return self.context.new_call(self.loc, fmodf, &[a, b]); } - else if let Some(vector_type) = a_type_unqualified.dyncast_vector() { + if let Some(vector_type) = a_type_unqualified.dyncast_vector() { assert_eq!(a_type_unqualified, b.get_type().unqualified()); let num_units = vector_type.get_num_units(); @@ -630,7 +641,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(a_type_unqualified, self.cx.double_type); let fmod = self.context.get_builtin_function("fmod"); - return self.context.new_call(self.loc, fmod, &[a, b]); + self.context.new_call(self.loc, fmod, &[a, b]) } fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -652,73 +663,80 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.cx.gcc_or(a, b) + let ret = self.cx.gcc_or(a, b, self.loc); + + if self.loc.is_some() { + unsafe { ret.set_location(self.loc.unwrap()); } + } + ret } fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_xor(a, b) + set_rval_location(self,self.gcc_xor(a, b)) } fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_neg(a) + set_rval_location(self,self.gcc_neg(a)) } fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a) + set_rval_location(self,self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a)) } fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_not(a) + set_rval_location(self,self.gcc_not(a)) } fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_add(a, b) + set_rval_location(self,self.gcc_add(a, b)) } fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_add(a, b) + set_rval_location(self,self.gcc_add(a, b)) } fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_sub(a, b) + set_rval_location(self,self.gcc_sub(a, b)) } fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { // TODO(antoyo): should generate poison value? - self.gcc_sub(a, b) + set_rval_location(self,self.gcc_sub(a, b)) } fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_mul(a, b) + set_rval_location(self,self.gcc_mul(a, b)) } fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_mul(a, b) + set_rval_location(self,self.gcc_mul(a, b)) } fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs + rhs + set_rval_location(self,lhs + rhs) } fn fsub_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs - rhs + set_rval_location(self,lhs - rhs) } fn fmul_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs * rhs + set_rval_location(self,lhs * rhs) } fn fdiv_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - lhs / rhs + set_rval_location(self,lhs / rhs) } fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - self.frem(lhs, rhs) + let i = self.frem(lhs, rhs); + set_rval_location(self,i); + i } fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { @@ -1005,33 +1023,33 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_float_to_uint_cast(value, dest_ty) + set_rval_location(self,self.gcc_float_to_uint_cast(value, dest_ty)) } fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_float_to_int_cast(value, dest_ty) + set_rval_location(self,self.gcc_float_to_int_cast(value, dest_ty)) } fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_uint_to_float_cast(value, dest_ty) + set_rval_location(self,self.gcc_uint_to_float_cast(value, dest_ty)) } fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.gcc_int_to_float_cast(value, dest_ty) + set_rval_location(self,self.gcc_int_to_float_cast(value, dest_ty)) } fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): make sure it truncates. - self.context.new_cast(self.loc, value, dest_ty) + set_rval_location(self,self.context.new_cast(self.loc, value, dest_ty)) } fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - self.context.new_cast(self.loc, value, dest_ty) + set_rval_location(self,self.context.new_cast(self.loc, value, dest_ty)) } fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { let usize_value = self.cx.const_bitcast(value, self.cx.type_isize()); - self.intcast(usize_value, dest_ty, false) + self.intcast(usize_value, dest_ty, false) } fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { diff --git a/src/int.rs b/src/int.rs index b0ceacf2ffc20..fe38d89ff8c3c 100644 --- a/src/int.rs +++ b/src/int.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; -use gccjit::{ComparisonOp, FunctionType, RValue, ToRValue, Type, UnaryOp, BinaryOp}; +use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{ParamEnv, Ty}; @@ -35,13 +35,13 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { else { UnaryOp::BitwiseNegate }; - self.cx.context.new_unary_op(None, operation, typ, a) + self.cx.context.new_unary_op(self.loc, operation, typ, a) } else { let element_type = typ.dyncast_array().expect("element type"); self.from_low_high_rvalues(typ, - self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)), - self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.high(a)), + self.cx.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, element_type, self.low(a)), + self.cx.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, element_type, self.high(a)), ) } } @@ -49,7 +49,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); if self.is_native_int_type(a_type) || a_type.is_vector() { - self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) + self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a) } else { self.gcc_add(self.gcc_not(a), self.gcc_int(a_type, 1)) @@ -57,7 +57,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } pub fn gcc_and(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b) + self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b, self.loc) } pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -69,7 +69,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by a signed number. // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. if a_type.is_signed(self) != b_type.is_signed(self) { - let b = self.context.new_cast(None, b, a_type); + let b = self.context.new_cast(self.loc, b, a_type); a >> b } else { @@ -95,14 +95,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b0_block = func.new_block("b0"); let actual_else_block = func.new_block("actual_else"); - let result = func.new_local(None, a_type, "shiftResult"); + let result = func.new_local(self.loc, a_type, "shiftResult"); let sixty_four = self.gcc_int(native_int_type, 64); let sixty_three = self.gcc_int(native_int_type, 63); let zero = self.gcc_zero(native_int_type); let b = self.gcc_int_cast(b, native_int_type); let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); - self.llbb().end_with_conditional(None, condition, then_block, else_block); + self.llbb().end_with_conditional(self.loc, condition, then_block, else_block); let shift_value = self.gcc_sub(b, sixty_four); let high = self.high(a); @@ -114,27 +114,27 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { zero }; let array_value = self.from_low_high_rvalues(a_type, high >> shift_value, sign); - then_block.add_assignment(None, result, array_value); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, result, array_value); + then_block.end_with_jump(self.loc, after_block); let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); - else_block.end_with_conditional(None, condition, b0_block, actual_else_block); + else_block.end_with_conditional(self.loc, condition, b0_block, actual_else_block); - b0_block.add_assignment(None, result, a); - b0_block.end_with_jump(None, after_block); + b0_block.add_assignment(self.loc, result, a); + b0_block.end_with_jump(self.loc, after_block); let shift_value = self.gcc_sub(sixty_four, b); // NOTE: cast low to its unsigned type in order to perform a logical right shift. let unsigned_type = native_int_type.to_unsigned(&self.cx); - let casted_low = self.context.new_cast(None, self.low(a), unsigned_type); - let shifted_low = casted_low >> self.context.new_cast(None, b, unsigned_type); - let shifted_low = self.context.new_cast(None, shifted_low, native_int_type); + let casted_low = self.context.new_cast(self.loc, self.low(a), unsigned_type); + let shifted_low = casted_low >> self.context.new_cast(self.loc, b, unsigned_type); + let shifted_low = self.context.new_cast(self.loc, shifted_low, native_int_type); let array_value = self.from_low_high_rvalues(a_type, (high << shift_value) | shifted_low, high >> b, ); - actual_else_block.add_assignment(None, result, array_value); - actual_else_block.end_with_jump(None, after_block); + actual_else_block.add_assignment(self.loc, result, array_value); + actual_else_block.end_with_jump(self.loc, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -152,13 +152,13 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_type.is_vector() { // Vector types need to be bitcast. // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - b = self.context.new_bitcast(None, b, a.get_type()); + b = self.context.new_bitcast(self.loc, b, a.get_type()); } else { - b = self.context.new_cast(None, b, a.get_type()); + b = self.context.new_cast(self.loc, b, a.get_type()); } } - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(self.loc, operation, a_type, a, b) } else { debug_assert!(a_type.dyncast_array().is_some()); @@ -172,10 +172,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { (BinaryOp::Minus, false) => "__rust_u128_sub", _ => unreachable!("unexpected additive operation {:?}", operation), }; - let param_a = self.context.new_parameter(None, a_type, "a"); - let param_b = self.context.new_parameter(None, b_type, "b"); - let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); - self.context.new_call(None, func, &[a, b]) + let param_a = self.context.new_parameter(self.loc, a_type, "a"); + let param_b = self.context.new_parameter(self.loc, b_type, "b"); + let func = self.context.new_function(self.loc, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); + self.context.new_call(self.loc, func, &[a, b]) } } @@ -335,10 +335,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let intrinsic = self.context.get_builtin_function(&name); let res = self.current_func() // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? - .new_local(None, rhs.get_type(), "binopResult") - .get_address(None); + .new_local(self.loc, rhs.get_type(), "binopResult") + .get_address(self.loc); let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); - (res.dereference(None).to_rvalue(), overflow) + (res.dereference(self.loc).to_rvalue(), overflow) } pub fn operation_with_overflow(&self, func_name: &str, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { @@ -346,10 +346,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b_type = rhs.get_type(); debug_assert!(a_type.dyncast_array().is_some()); debug_assert!(b_type.dyncast_array().is_some()); - let param_a = self.context.new_parameter(None, a_type, "a"); - let param_b = self.context.new_parameter(None, b_type, "b"); - let result_field = self.context.new_field(None, a_type, "result"); - let overflow_field = self.context.new_field(None, self.bool_type, "overflow"); + let param_a = self.context.new_parameter(self.loc, a_type, "a"); + let param_b = self.context.new_parameter(self.loc, b_type, "b"); + let result_field = self.context.new_field(self.loc, a_type, "result"); + let overflow_field = self.context.new_field(self.loc, self.bool_type, "overflow"); let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]); let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap(); @@ -372,23 +372,23 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); - let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]); + let return_type = self.context.new_struct_type(self.loc, "result_overflow", &[result_field, overflow_field]); let result = if indirect { - let return_value = self.current_func().new_local(None, return_type.as_type(), "return_value"); + let return_value = self.current_func().new_local(self.loc, return_type.as_type(), "return_value"); let return_param_type = return_type.as_type().make_pointer(); - let return_param = self.context.new_parameter(None, return_param_type, "return_value"); - let func = self.context.new_function(None, FunctionType::Extern, self.type_void(), &[return_param, param_a, param_b], func_name, false); - self.llbb().add_eval(None, self.context.new_call(None, func, &[return_value.get_address(None), lhs, rhs])); + let return_param = self.context.new_parameter(self.loc, return_param_type, "return_value"); + let func = self.context.new_function(self.loc, FunctionType::Extern, self.type_void(), &[return_param, param_a, param_b], func_name, false); + self.llbb().add_eval(self.loc, self.context.new_call(self.loc, func, &[return_value.get_address(self.loc), lhs, rhs])); return_value.to_rvalue() } else { - let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false); - self.context.new_call(None, func, &[lhs, rhs]) + let func = self.context.new_function(self.loc, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false); + self.context.new_call(self.loc, func, &[lhs, rhs]) }; - let overflow = result.access_field(None, overflow_field); - let int_result = result.access_field(None, result_field); - return (int_result, overflow); + let overflow = result.access_field(self.loc, overflow_field); + let int_result = result.access_field(self.loc, result_field); + (int_result, overflow) } pub fn gcc_icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { @@ -397,7 +397,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if self.is_non_native_int_type(a_type) || self.is_non_native_int_type(b_type) { // This algorithm is based on compiler-rt's __cmpti2: // https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/cmpti2.c#L21 - let result = self.current_func().new_local(None, self.int_type, "icmp_result"); + let result = self.current_func().new_local(self.loc, self.int_type, "icmp_result"); let block1 = self.current_func().new_block("block1"); let block2 = self.current_func().new_block("block2"); let block3 = self.current_func().new_block("block3"); @@ -413,35 +413,35 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // the sign is only on high). let unsigned_type = native_int_type.to_unsigned(&self.cx); - let lhs_low = self.context.new_cast(None, self.low(lhs), unsigned_type); - let rhs_low = self.context.new_cast(None, self.low(rhs), unsigned_type); + let lhs_low = self.context.new_cast(self.loc, self.low(lhs), unsigned_type); + let rhs_low = self.context.new_cast(self.loc, self.low(rhs), unsigned_type); - let condition = self.context.new_comparison(None, ComparisonOp::LessThan, self.high(lhs), self.high(rhs)); - self.llbb().end_with_conditional(None, condition, block1, block2); + let condition = self.context.new_comparison(self.loc, ComparisonOp::LessThan, self.high(lhs), self.high(rhs)); + self.llbb().end_with_conditional(self.loc, condition, block1, block2); - block1.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type)); - block1.end_with_jump(None, after); + block1.add_assignment(self.loc, result, self.context.new_rvalue_zero(self.int_type)); + block1.end_with_jump(self.loc, after); - let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, self.high(lhs), self.high(rhs)); - block2.end_with_conditional(None, condition, block3, block4); + let condition = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, self.high(lhs), self.high(rhs)); + block2.end_with_conditional(self.loc, condition, block3, block4); - block3.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2)); - block3.end_with_jump(None, after); + block3.add_assignment(self.loc, result, self.context.new_rvalue_from_int(self.int_type, 2)); + block3.end_with_jump(self.loc, after); - let condition = self.context.new_comparison(None, ComparisonOp::LessThan, lhs_low, rhs_low); - block4.end_with_conditional(None, condition, block5, block6); + let condition = self.context.new_comparison(self.loc, ComparisonOp::LessThan, lhs_low, rhs_low); + block4.end_with_conditional(self.loc, condition, block5, block6); - block5.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type)); - block5.end_with_jump(None, after); + block5.add_assignment(self.loc, result, self.context.new_rvalue_zero(self.int_type)); + block5.end_with_jump(self.loc, after); - let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, lhs_low, rhs_low); - block6.end_with_conditional(None, condition, block7, block8); + let condition = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, lhs_low, rhs_low); + block6.end_with_conditional(self.loc, condition, block7, block8); - block7.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2)); - block7.end_with_jump(None, after); + block7.add_assignment(self.loc, result, self.context.new_rvalue_from_int(self.int_type, 2)); + block7.end_with_jump(self.loc, after); - block8.add_assignment(None, result, self.context.new_rvalue_one(self.int_type)); - block8.end_with_jump(None, after); + block8.add_assignment(self.loc, result, self.context.new_rvalue_one(self.int_type)); + block8.end_with_jump(self.loc, after); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -451,10 +451,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let (op, limit) = match op { IntPredicate::IntEQ => { - return self.context.new_comparison(None, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type)); + return self.context.new_comparison(self.loc, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type)); }, IntPredicate::IntNE => { - return self.context.new_comparison(None, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type)); + return self.context.new_comparison(self.loc, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type)); }, // TODO(antoyo): cast to u128 for unsigned comparison. See below. IntPredicate::IntUGT => (ComparisonOp::Equals, 2), @@ -466,39 +466,39 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { IntPredicate::IntSLT => (ComparisonOp::Equals, 0), IntPredicate::IntSLE => (ComparisonOp::LessThanEquals, 1), }; - self.context.new_comparison(None, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit)) + self.context.new_comparison(self.loc, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit)) } else if a_type.get_pointee().is_some() && b_type.get_pointee().is_some() { // NOTE: gcc cannot compare pointers to different objects, but rustc does that, so cast them to usize. - lhs = self.context.new_bitcast(None, lhs, self.usize_type); - rhs = self.context.new_bitcast(None, rhs, self.usize_type); - self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + lhs = self.context.new_bitcast(self.loc, lhs, self.usize_type); + rhs = self.context.new_bitcast(self.loc, rhs, self.usize_type); + self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) } else { if a_type != b_type { // NOTE: because libgccjit cannot compare function pointers. if a_type.dyncast_function_ptr_type().is_some() && b_type.dyncast_function_ptr_type().is_some() { - lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); - rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); + lhs = self.context.new_cast(self.loc, lhs, self.usize_type.make_pointer()); + rhs = self.context.new_cast(self.loc, rhs, self.usize_type.make_pointer()); } // NOTE: hack because we try to cast a vector type to the same vector type. else if format!("{:?}", a_type) != format!("{:?}", b_type) { - rhs = self.context.new_cast(None, rhs, a_type); + rhs = self.context.new_cast(self.loc, rhs, a_type); } } match op { IntPredicate::IntUGT | IntPredicate::IntUGE | IntPredicate::IntULT | IntPredicate::IntULE => { if !a_type.is_vector() { let unsigned_type = a_type.to_unsigned(&self.cx); - lhs = self.context.new_cast(None, lhs, unsigned_type); - rhs = self.context.new_cast(None, rhs, unsigned_type); + lhs = self.context.new_cast(self.loc, lhs, unsigned_type); + rhs = self.context.new_cast(self.loc, rhs, unsigned_type); } }, // TODO(antoyo): we probably need to handle signed comparison for unsigned // integers. _ => (), } - self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) } } @@ -528,12 +528,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_native && b_native { // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. if a_type.is_unsigned(self) && b_type.is_signed(self) { - let a = self.context.new_cast(None, a, b_type); + let a = self.context.new_cast(self.loc, a, b_type); let result = a << b; - self.context.new_cast(None, result, a_type) + self.context.new_cast(self.loc, result, a_type) } else if a_type.is_signed(self) && b_type.is_unsigned(self) { - let b = self.context.new_cast(None, b, a_type); + let b = self.context.new_cast(self.loc, b, a_type); a << b } else { @@ -557,40 +557,40 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b0_block = func.new_block("b0"); let actual_else_block = func.new_block("actual_else"); - let result = func.new_local(None, a_type, "shiftResult"); + let result = func.new_local(self.loc, a_type, "shiftResult"); let b = self.gcc_int_cast(b, native_int_type); let sixty_four = self.gcc_int(native_int_type, 64); let zero = self.gcc_zero(native_int_type); let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); - self.llbb().end_with_conditional(None, condition, then_block, else_block); + self.llbb().end_with_conditional(self.loc, condition, then_block, else_block); let array_value = self.from_low_high_rvalues(a_type, zero, self.low(a) << (b - sixty_four), ); - then_block.add_assignment(None, result, array_value); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, result, array_value); + then_block.end_with_jump(self.loc, after_block); let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); - else_block.end_with_conditional(None, condition, b0_block, actual_else_block); + else_block.end_with_conditional(self.loc, condition, b0_block, actual_else_block); - b0_block.add_assignment(None, result, a); - b0_block.end_with_jump(None, after_block); + b0_block.add_assignment(self.loc, result, a); + b0_block.end_with_jump(self.loc, after_block); // NOTE: cast low to its unsigned type in order to perform a logical right shift. // TODO(antoyo): adjust this ^ comment. let unsigned_type = native_int_type.to_unsigned(&self.cx); - let casted_low = self.context.new_cast(None, self.low(a), unsigned_type); - let shift_value = self.context.new_cast(None, sixty_four - b, unsigned_type); - let high_low = self.context.new_cast(None, casted_low >> shift_value, native_int_type); + let casted_low = self.context.new_cast(self.loc, self.low(a), unsigned_type); + let shift_value = self.context.new_cast(self.loc, sixty_four - b, unsigned_type); + let high_low = self.context.new_cast(self.loc, casted_low >> shift_value, native_int_type); let array_value = self.from_low_high_rvalues(a_type, self.low(a) << b, (self.high(a) << b) | high_low, ); - actual_else_block.add_assignment(None, result, array_value); - actual_else_block.end_with_jump(None, after_block); + actual_else_block.add_assignment(self.loc, result, array_value); + actual_else_block.end_with_jump(self.loc, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -606,10 +606,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let native_int_type = arg_type.dyncast_array().expect("get element type"); let lsb = self.low(arg); let swapped_lsb = self.gcc_bswap(lsb, width / 2); - let swapped_lsb = self.context.new_cast(None, swapped_lsb, native_int_type); + let swapped_lsb = self.context.new_cast(self.loc, swapped_lsb, native_int_type); let msb = self.high(arg); let swapped_msb = self.gcc_bswap(msb, width / 2); - let swapped_msb = self.context.new_cast(None, swapped_msb, native_int_type); + let swapped_msb = self.context.new_cast(self.loc, swapped_msb, native_int_type); // NOTE: we also need to swap the two elements here, in addition to swapping inside // the elements themselves like done above. @@ -625,7 +625,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if param_type != arg_type { arg = self.bitcast(arg, param_type); } - self.cx.context.new_call(None, bswap, &[arg]) + self.cx.context.new_call(self.loc, bswap, &[arg]) } } @@ -700,33 +700,33 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } - fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>, loc: Option>) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); let a_native = self.is_native_int_type_or_bool(a_type); let b_native = self.is_native_int_type_or_bool(b_type); if a_type.is_vector() && b_type.is_vector() { let b = self.bitcast_if_needed(b, a_type); - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(loc, operation, a_type, a, b) } else if a_native && b_native { if a_type != b_type { - b = self.context.new_cast(None, b, a_type); + b = self.context.new_cast(loc, b, a_type); } - self.context.new_binary_op(None, operation, a_type, a, b) + self.context.new_binary_op(loc, operation, a_type, a, b) } else { assert!(!a_native && !b_native, "both types should either be native or non-native for or operation"); let native_int_type = a_type.dyncast_array().expect("get element type"); self.from_low_high_rvalues(a_type, - self.context.new_binary_op(None, operation, native_int_type, self.low(a), self.low(b)), - self.context.new_binary_op(None, operation, native_int_type, self.high(a), self.high(b)), + self.context.new_binary_op(loc, operation, native_int_type, self.low(a), self.low(b)), + self.context.new_binary_op(loc, operation, native_int_type, self.high(a), self.high(b)), ) } } - pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.bitwise_operation(BinaryOp::BitwiseOr, a, b) + pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>, loc: Option>) -> RValue<'gcc> { + self.bitwise_operation(BinaryOp::BitwiseOr, a, b, loc) } // TODO(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead? diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index f162ef831b768..0849c6266f19b 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -640,7 +640,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let new_low = self.gcc_int_cast(reversed_high, typ); let new_high = self.shl(self.gcc_int_cast(reversed_low, typ), sixty_four); - self.gcc_or(new_low, new_high) + self.gcc_or(new_low, new_high, self.loc) }, _ => { panic!("cannot bit reverse with width = {}", width); @@ -685,44 +685,44 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let first_elem = self.context.new_array_access(None, result, zero); let first_value = self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), arg_type); self.llbb() - .add_assignment(None, first_elem, first_value); + .add_assignment(self.loc, first_elem, first_value); - let second_elem = self.context.new_array_access(None, result, one); - let cast = self.gcc_int_cast(self.context.new_call(None, clzll, &[low]), arg_type); + let second_elem = self.context.new_array_access(self.loc, result, one); + let cast = self.gcc_int_cast(self.context.new_call(self.loc, clzll, &[low]), arg_type); let second_value = self.add(cast, sixty_four); self.llbb() - .add_assignment(None, second_elem, second_value); + .add_assignment(self.loc, second_elem, second_value); - let third_elem = self.context.new_array_access(None, result, two); + let third_elem = self.context.new_array_access(self.loc, result, two); let third_value = self.const_uint(arg_type, 128); self.llbb() - .add_assignment(None, third_elem, third_value); + .add_assignment(self.loc, third_elem, third_value); - let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); - let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, low); let not_low_and_not_high = not_low & not_high; let index = not_high + not_low_and_not_high; // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in // gcc. // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the // compilation stage. - let index = self.context.new_cast(None, index, self.i32_type); + let index = self.context.new_cast(self.loc, index, self.i32_type); - let res = self.context.new_array_access(None, result, index); + let res = self.context.new_array_access(self.loc, result, index); return self.gcc_int_cast(res.to_rvalue(), arg_type); } else { let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); - let arg = self.context.new_cast(None, arg, self.ulonglong_type); + let arg = self.context.new_cast(self.loc, arg, self.ulonglong_type); let diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64; let diff = self.context.new_rvalue_from_long(self.int_type, diff * 8); - let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff; - return self.context.new_cast(None, res, arg_type); + let res = self.context.new_call(self.loc, count_leading_zeroes, &[arg]) - diff; + return self.context.new_cast(self.loc, res, arg_type); }; let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes); - let res = self.context.new_call(None, count_leading_zeroes, &[arg]); - self.context.new_cast(None, res, arg_type) + let res = self.context.new_call(self.loc, count_leading_zeroes, &[arg]); + self.context.new_cast(self.loc, res, arg_type) } fn count_trailing_zeroes(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { @@ -766,58 +766,58 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let ctzll = self.context.get_builtin_function("__builtin_ctzll"); - let first_elem = self.context.new_array_access(None, result, zero); - let first_value = self.gcc_int_cast(self.context.new_call(None, ctzll, &[low]), arg_type); + let first_elem = self.context.new_array_access(self.loc, result, zero); + let first_value = self.gcc_int_cast(self.context.new_call(self.loc, ctzll, &[low]), arg_type); self.llbb() - .add_assignment(None, first_elem, first_value); + .add_assignment(self.loc, first_elem, first_value); - let second_elem = self.context.new_array_access(None, result, one); - let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(None, ctzll, &[high]), arg_type), sixty_four); + let second_elem = self.context.new_array_access(self.loc, result, one); + let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(self.loc, ctzll, &[high]), arg_type), sixty_four); self.llbb() - .add_assignment(None, second_elem, second_value); + .add_assignment(self.loc, second_elem, second_value); - let third_elem = self.context.new_array_access(None, result, two); + let third_elem = self.context.new_array_access(self.loc, result, two); let third_value = self.gcc_int(arg_type, 128); self.llbb() - .add_assignment(None, third_elem, third_value); + .add_assignment(self.loc, third_elem, third_value); - let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); - let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, high); let not_low_and_not_high = not_low & not_high; let index = not_low + not_low_and_not_high; // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in // gcc. // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the // compilation stage. - let index = self.context.new_cast(None, index, self.i32_type); + let index = self.context.new_cast(self.loc, index, self.i32_type); - let res = self.context.new_array_access(None, result, index); + let res = self.context.new_array_access(self.loc, result, index); return self.gcc_int_cast(res.to_rvalue(), result_type); } else { let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll"); let arg_size = arg_type.get_size(); - let casted_arg = self.context.new_cast(None, arg, self.ulonglong_type); + let casted_arg = self.context.new_cast(self.loc, arg, self.ulonglong_type); let byte_diff = self.ulonglong_type.get_size() as i64 - arg_size as i64; let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8); let mask = self.context.new_rvalue_from_long(arg_type, -1); // To get the value with all bits set. - let masked = mask & self.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, arg); - let cond = self.context.new_comparison(None, ComparisonOp::Equals, masked, mask); - let diff = diff * self.context.new_cast(None, cond, self.int_type); - let res = self.context.new_call(None, count_trailing_zeroes, &[casted_arg]) - diff; - return self.context.new_cast(None, res, result_type); + let masked = mask & self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, arg_type, arg); + let cond = self.context.new_comparison(self.loc, ComparisonOp::Equals, masked, mask); + let diff = diff * self.context.new_cast(self.loc, cond, self.int_type); + let res = self.context.new_call(self.loc, count_trailing_zeroes, &[casted_arg]) - diff; + return self.context.new_cast(self.loc, res, result_type); }; let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes); let arg = if arg_type != expected_type { - self.context.new_cast(None, arg, expected_type) + self.context.new_cast(self.loc, arg, expected_type) } else { arg }; - let res = self.context.new_call(None, count_trailing_zeroes, &[arg]); - self.context.new_cast(None, res, result_type) + let res = self.context.new_call(self.loc, count_trailing_zeroes, &[arg]); + self.context.new_cast(self.loc, res, result_type) } fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> { @@ -859,8 +859,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let counter = self.current_func().new_local(None, counter_type, "popcount_counter"); let val = self.current_func().new_local(None, value_type, "popcount_value"); let zero = self.gcc_zero(counter_type); - self.llbb().add_assignment(None, counter, zero); - self.llbb().add_assignment(None, val, value); + self.llbb().add_assignment(self.loc, counter, zero); + self.llbb().add_assignment(self.loc, val, value); self.br(loop_head); // check if value isn't zero @@ -874,12 +874,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let one = self.gcc_int(value_type, 1); let sub = self.gcc_sub(val.to_rvalue(), one); let op = self.gcc_and(val.to_rvalue(), sub); - loop_body.add_assignment(None, val, op); + loop_body.add_assignment(self.loc, val, op); // counter += 1 let one = self.gcc_int(counter_type, 1); let op = self.gcc_add(counter.to_rvalue(), one); - loop_body.add_assignment(None, counter, op); + loop_body.add_assignment(self.loc, counter, op); self.br(loop_head); // end of loop @@ -922,7 +922,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 let func = self.current_func.borrow().expect("func"); - let res = func.new_local(None, result_type, "saturating_sum"); + let res = func.new_local(self.loc, result_type, "saturating_sum"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -936,7 +936,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let overflow_func = self.context.get_builtin_function(func_name); - self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None) + self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.loc)], None) } else { let func_name = @@ -945,7 +945,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); - self.llbb().add_assignment(None, res, int_result); + self.llbb().add_assignment(self.loc, res, int_result); overflow }; @@ -958,10 +958,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1)); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); - then_block.add_assignment(None, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); + then_block.end_with_jump(self.loc, after_block); - self.llbb().end_with_conditional(None, overflow, then_block, after_block); + self.llbb().end_with_conditional(self.loc, overflow, then_block, after_block); // NOTE: since jumps were added in a place rustc does not // expect, the current block in the state need to be updated. @@ -974,7 +974,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let res = self.gcc_add(lhs, rhs); let cond = self.gcc_icmp(IntPredicate::IntULT, res, lhs); let value = self.gcc_neg(self.gcc_int_cast(cond, result_type)); - self.gcc_or(res, value) + self.gcc_or(res, value, self.loc) } } @@ -984,7 +984,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 let func = self.current_func.borrow().expect("func"); - let res = func.new_local(None, result_type, "saturating_diff"); + let res = func.new_local(self.loc, result_type, "saturating_diff"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -998,7 +998,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let overflow_func = self.context.get_builtin_function(func_name); - self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None) + self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.loc)], None) } else { let func_name = @@ -1007,7 +1007,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _ => unreachable!(), }; let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); - self.llbb().add_assignment(None, res, int_result); + self.llbb().add_assignment(self.loc, res, int_result); overflow }; @@ -1020,10 +1020,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1)); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); - then_block.add_assignment(None, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); - then_block.end_with_jump(None, after_block); + then_block.add_assignment(self.loc, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); + then_block.end_with_jump(self.loc, after_block); - self.llbb().end_with_conditional(None, overflow, then_block, after_block); + self.llbb().end_with_conditional(self.loc, overflow, then_block, after_block); // NOTE: since jumps were added in a place rustc does not // expect, the current block in the state need to be updated. From a06a87b37dfc4aa9e0043d72b16df8051f92e98c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Feb 2024 18:51:22 +0100 Subject: [PATCH 150/192] rename 'try' intrinsic to 'catch_unwind' --- src/intrinsic/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index f162ef831b768..d43f5d74757ae 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature="master")] use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use rustc_span::{Span, Symbol, symbol::kw, sym}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::HasDataLayout; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::PanicStrategy; @@ -129,7 +129,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let res = self.context.new_call(None, builtin, &[a]); self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) } - kw::Try => { + sym::catch_unwind => { try_intrinsic( self, args[0].immediate(), From 7f34119c1a6ec425f549e12f1490555acda74c65 Mon Sep 17 00:00:00 2001 From: 823984418 <823984418@qq.com> Date: Mon, 26 Feb 2024 22:37:04 +0800 Subject: [PATCH 151/192] remove useless lifetime of ArchiveBuilder --- src/archive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/archive.rs b/src/archive.rs index 11fa074f5ac79..73ff0c37b6656 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -10,7 +10,7 @@ use rustc_session::cstore::DllImport; pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { - fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { + fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) } From aed59f0a510b4e47496d871051026c885bccc3a1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Feb 2024 18:12:12 +0100 Subject: [PATCH 152/192] Add `clone-gcc` command --- build_system/src/clone_gcc.rs | 79 +++++++++++++++++++++++++++++++++++ build_system/src/config.rs | 13 ++++-- build_system/src/main.rs | 19 +++++---- build_system/src/prepare.rs | 4 +- build_system/src/test.rs | 17 +++----- build_system/src/utils.rs | 57 +++++++++++++++++++------ 6 files changed, 153 insertions(+), 36 deletions(-) create mode 100644 build_system/src/clone_gcc.rs diff --git a/build_system/src/clone_gcc.rs b/build_system/src/clone_gcc.rs new file mode 100644 index 0000000000000..aee46afaeb040 --- /dev/null +++ b/build_system/src/clone_gcc.rs @@ -0,0 +1,79 @@ +use crate::config::ConfigInfo; +use crate::utils::{git_clone, run_command_with_output}; + +use std::path::{Path, PathBuf}; + +fn show_usage() { + println!( + r#" +`clone-gcc` command help: + + --out-path : Location where the GCC repository will be cloned (default: `./gcc`)"# + ); + ConfigInfo::show_usage(); + println!(" --help : Show this help"); +} + +#[derive(Default)] +struct Args { + out_path: PathBuf, + config_info: ConfigInfo, +} + +impl Args { + fn new() -> Result, String> { + let mut command_args = Self::default(); + + let mut out_path = None; + + // We skip binary name and the `clone-gcc` command. + let mut args = std::env::args().skip(2); + + while let Some(arg) = args.next() { + match arg.as_str() { + "--out-path" => match args.next() { + Some(path) if !path.is_empty() => out_path = Some(path), + _ => { + return Err("Expected an argument after `--out-path`, found nothing".into()) + } + }, + "--help" => { + show_usage(); + return Ok(None); + } + arg => { + if !command_args.config_info.parse_argument(arg, &mut args)? { + return Err(format!("Unknown option {}", arg)); + } + } + } + } + command_args.out_path = match out_path { + Some(p) => p.into(), + None => PathBuf::from("./gcc"), + }; + return Ok(Some(command_args)); + } +} + +pub fn run() -> Result<(), String> { + let Some(args) = Args::new()? else { + return Ok(()); + }; + + let result = git_clone("https://github.com/antoyo/gcc", Some(&args.out_path), false)?; + if result.ran_clone { + let gcc_commit = args.config_info.get_gcc_commit()?; + println!("Checking out GCC commit `{}`...", gcc_commit); + run_command_with_output( + &[&"git", &"checkout", &gcc_commit], + Some(Path::new(&result.repo_dir)), + )?; + } else { + println!( + "There is already a GCC folder in `{}`, leaving things as is...", + args.out_path.display() + ); + } + Ok(()) +} diff --git a/build_system/src/config.rs b/build_system/src/config.rs index f6f039370180c..c633ee57d4a34 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -192,9 +192,7 @@ impl ConfigInfo { command } - fn download_gccjit_if_needed(&mut self) -> Result<(), String> { - let output_dir = Path::new(crate::BUILD_DIR).join("libgccjit"); - + pub fn get_gcc_commit(&self) -> Result { let commit_hash_file = self.compute_path("libgccjit.version"); let content = fs::read_to_string(&commit_hash_file).map_err(|_| { format!( @@ -212,7 +210,14 @@ impl ConfigInfo { commit, )); } - let output_dir = output_dir.join(commit); + Ok(commit.to_string()) + } + + fn download_gccjit_if_needed(&mut self) -> Result<(), String> { + let output_dir = Path::new(crate::BUILD_DIR).join("libgccjit"); + let commit = self.get_gcc_commit()?; + + let output_dir = output_dir.join(&commit); if !output_dir.is_dir() { std::fs::create_dir_all(&output_dir).map_err(|err| { format!( diff --git a/build_system/src/main.rs b/build_system/src/main.rs index 18dc4b21a9623..48ffbc7a9075a 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -4,6 +4,7 @@ use std::process; mod build; mod cargo; mod clean; +mod clone_gcc; mod config; mod info; mod prepare; @@ -27,19 +28,21 @@ fn usage() { "\ Available commands for build_system: - cargo : Run cargo command - clean : Run clean command - prepare : Run prepare command - build : Run build command - test : Run test command - info: : Run info command - --help : Show this message" + cargo : Run cargo command + clean : Run clean command + prepare : Run prepare command + build : Run build command + test : Run test command + info : Run info command + clone-gcc : Run clone-gcc command + --help : Show this message" ); } pub enum Command { Cargo, Clean, + CloneGcc, Prepare, Build, Test, @@ -58,6 +61,7 @@ fn main() { Some("build") => Command::Build, Some("test") => Command::Test, Some("info") => Command::Info, + Some("clone-gcc") => Command::CloneGcc, Some("--help") => { usage(); process::exit(0); @@ -77,6 +81,7 @@ fn main() { Command::Build => build::run(), Command::Test => test::run(), Command::Info => info::run(), + Command::CloneGcc => clone_gcc::run(), } { eprintln!("Command failed to run: {e}"); process::exit(1); diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index 66f440f53553a..4ea334ad8b907 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -1,6 +1,6 @@ use crate::rustc_info::get_rustc_path; use crate::utils::{ - cargo_install, git_clone, remove_file, run_command, run_command_with_output, walk_dir, + cargo_install, git_clone_root_dir, remove_file, run_command, run_command_with_output, walk_dir, }; use std::fs; @@ -152,7 +152,7 @@ fn clone_and_setup(repo_url: &str, checkout_commit: &str, extra: Option) - where F: Fn(&Path) -> Result<(), String>, { - let clone_result = git_clone(repo_url, Some(&Path::new(crate::BUILD_DIR)), false)?; + let clone_result = git_clone_root_dir(repo_url, &Path::new(crate::BUILD_DIR), false)?; if !clone_result.ran_clone { println!("`{}` has already been cloned", clone_result.repo_name); } diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 17b1868502aa6..470bb2431d563 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -1,7 +1,7 @@ use crate::build; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ - get_toolchain, git_clone, remove_file, run_command, run_command_with_env, + get_toolchain, git_clone, git_clone_root_dir, remove_file, run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, split_args, walk_dir, }; @@ -487,15 +487,10 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { ); let rust_dir_path = Path::new(crate::BUILD_DIR).join("rust"); // If the repository was already cloned, command will fail, so doesn't matter. - let _ = run_command_with_output_and_env( - &[ - &"git", - &"clone", - &"https://github.com/rust-lang/rust.git", - &rust_dir_path, - ], - None, - Some(env), + let _ = git_clone( + "https://github.com/rust-lang/rust.git", + Some(&rust_dir_path), + false, ); let rust_dir: Option<&Path> = Some(&rust_dir_path); run_command(&[&"git", &"checkout", &"--", &"tests/"], rust_dir)?; @@ -720,7 +715,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { let run_tests = |projects_path, iter: &mut dyn Iterator| -> Result<(), String> { for project in iter { - let clone_result = git_clone(project, Some(projects_path), true)?; + let clone_result = git_clone_root_dir(project, projects_path, true)?; let repo_path = Path::new(&clone_result.repo_dir); run_cargo_command(&[&"build", &"--release"], Some(repo_path), env, args)?; run_cargo_command(&[&"test"], Some(repo_path), env, args)?; diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 33dcd9ef7005f..56f1abaf19844 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::ffi::OsStr; use std::fmt::Debug; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Output}; fn get_command_inner( @@ -254,20 +254,12 @@ pub struct CloneResult { pub repo_dir: String, } -pub fn git_clone( +fn git_clone_inner( to_clone: &str, - dest: Option<&Path>, + dest: &Path, shallow_clone: bool, + repo_name: String, ) -> Result { - let repo_name = to_clone.split('/').last().unwrap(); - let repo_name = match repo_name.strip_suffix(".git") { - Some(n) => n.to_string(), - None => repo_name.to_string(), - }; - - let dest = dest - .map(|dest| dest.join(&repo_name)) - .unwrap_or_else(|| Path::new(&repo_name).into()); if dest.is_dir() { return Ok(CloneResult { ran_clone: false, @@ -289,6 +281,47 @@ pub fn git_clone( }) } +fn get_repo_name(url: &str) -> String { + let repo_name = url.split('/').last().unwrap(); + match repo_name.strip_suffix(".git") { + Some(n) => n.to_string(), + None => repo_name.to_string(), + } +} + +pub fn git_clone( + to_clone: &str, + dest: Option<&Path>, + shallow_clone: bool, +) -> Result { + let repo_name = get_repo_name(to_clone); + let tmp: PathBuf; + + let dest = match dest { + Some(dest) => dest, + None => { + tmp = repo_name.clone().into(); + &tmp + } + }; + git_clone_inner(to_clone, dest, shallow_clone, repo_name) +} + +pub fn git_clone_root_dir( + to_clone: &str, + dest_parent_dir: &Path, + shallow_clone: bool, +) -> Result { + let repo_name = get_repo_name(to_clone); + + git_clone_inner( + to_clone, + &dest_parent_dir.join(&repo_name), + shallow_clone, + repo_name, + ) +} + pub fn walk_dir(dir: P, mut dir_cb: D, mut file_cb: F) -> Result<(), String> where P: AsRef, From 7d086c72f72ca64e57c52110eef6ae50eab484fd Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Fri, 23 Feb 2024 23:23:35 -0500 Subject: [PATCH 153/192] always use gep inbounds i8 (ptradd) for field offsets --- src/type_of.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/type_of.rs b/src/type_of.rs index 25149b8020162..e327051ca1d58 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -151,7 +151,6 @@ pub trait LayoutGccExt<'tcx> { fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc>; - fn gcc_field_index(&self, index: usize) -> u64; fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option; } @@ -304,24 +303,6 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { self.scalar_gcc_type_at(cx, scalar, offset) } - fn gcc_field_index(&self, index: usize) -> u64 { - match self.abi { - Abi::Scalar(_) | Abi::ScalarPair(..) => { - bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self) - } - _ => {} - } - match self.fields { - FieldsShape::Primitive | FieldsShape::Union(_) => { - bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self) - } - - FieldsShape::Array { .. } => index as u64, - - FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2, - } - } - fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option { if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { return pointee; @@ -351,10 +332,6 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { layout.is_gcc_scalar_pair() } - fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 { - layout.gcc_field_index(index) - } - fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, _immediate: bool) -> Type<'gcc> { layout.scalar_pair_element_gcc_type(self, index) } From 19a648218feee406b7ed50c8ef722adba71f4029 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 24 Feb 2024 01:46:30 -0500 Subject: [PATCH 154/192] remove struct_gep, use manual layout calculations for va_arg --- src/builder.rs | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 7e2139866f49e..bae0cc3655df6 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -834,10 +834,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { let b_offset = a.size(self).align_to(b.align(self).abi); - let pair_type = place.layout.gcc_type(self); let mut load = |i, scalar: &abi::Scalar, align| { - let llptr = self.struct_gep(pair_type, place.llval, i as u64); + let llptr = if i == 0 { + place.llval + } else { + self.inbounds_gep( + self.type_i8(), + place.llval, + &[self.const_usize(b_offset.bytes())], + ) + }; let llty = place.layout.scalar_pair_element_gcc_type(self, i); let load = self.load(llty, llptr, align); scalar_load_metadata(self, load, scalar); @@ -971,33 +978,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { result.get_address(None) } - fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> { - // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. - assert_eq!(idx as usize as u64, idx); - let value = ptr.dereference(None).to_rvalue(); - - if value_type.dyncast_array().is_some() { - let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, value, index); - element.get_address(None) - } - else if let Some(vector_type) = value_type.dyncast_vector() { - let array_type = vector_type.get_element_type().make_pointer(); - let array = self.bitcast(ptr, array_type); - let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(None, array, index); - element.get_address(None) - } - else if let Some(struct_type) = value_type.is_struct() { - // NOTE: due to opaque pointers now being used, we need to bitcast here. - let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer()); - ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None) - } - else { - panic!("Unexpected type {:?}", value_type); - } - } - /* Casts */ fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): check that it indeed truncate the value. From 70346fe2a455c754d93994922cbfaa9393c0002b Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 24 Feb 2024 02:01:41 -0500 Subject: [PATCH 155/192] introduce and use ptradd/inbounds_ptradd instead of gep --- src/builder.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index bae0cc3655df6..71a0a4c2e96f2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -839,11 +839,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let llptr = if i == 0 { place.llval } else { - self.inbounds_gep( - self.type_i8(), - place.llval, - &[self.const_usize(b_offset.bytes())], - ) + self.inbounds_ptradd(place.llval, self.const_usize(b_offset.bytes())) }; let llty = place.layout.scalar_pair_element_gcc_type(self, i); let load = self.load(llty, llptr, align); From 6560fecbdfba0d4b2bd874e26008fe5716891589 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 27 Feb 2024 18:48:29 +0100 Subject: [PATCH 156/192] Add documentation on git_clone_root_dir --- build_system/src/utils.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 56f1abaf19844..d9c13fd143d15 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -307,6 +307,10 @@ pub fn git_clone( git_clone_inner(to_clone, dest, shallow_clone, repo_name) } +/// This function differs from `git_clone` in how it handles *where* the repository will be cloned. +/// In `git_clone`, it is cloned in the provided path. In this function, the path you provide is +/// the parent folder. So if you pass "a" as folder and try to clone "b.git", it will be cloned into +/// `a/b`. pub fn git_clone_root_dir( to_clone: &str, dest_parent_dir: &Path, From 7005ef96993d04d1440c310d116fc5373478e361 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 Feb 2024 10:20:45 +1100 Subject: [PATCH 157/192] Rename `DiagnosticBuilder` as `Diag`. Much better! Note that this involves renaming (and updating the value of) `DIAGNOSTIC_BUILDER` in clippy. --- src/errors.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 79eb4406b8a33..fd03c5bf37ab2 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,5 @@ use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, - IntoDiagnosticArg, Level, + DiagCtxt, DiagnosticArgValue, Diag, EmissionGuarantee, IntoDiagnostic, IntoDiagnosticArg, Level, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -112,12 +111,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { - let mut diag = DiagnosticBuilder::new( - dcx, - level, - fluent::codegen_gcc_target_feature_disable_or_enable - ); + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + let mut diag = Diag::new(dcx, level, fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.span(span); }; From 427d6176c5856b0edeb33c46633c8d8acf97affb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 Feb 2024 14:37:48 +1100 Subject: [PATCH 158/192] Rename `DiagnosticArg{,Map,Name,Value}` as `DiagArg{,Map,Name,Value}`. --- src/errors.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index fd03c5bf37ab2..988a7e1033e28 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, Diag, EmissionGuarantee, IntoDiagnostic, IntoDiagnosticArg, Level, + DiagCtxt, DiagArgValue, Diag, EmissionGuarantee, IntoDiagnostic, IntoDiagnosticArg, Level, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -34,11 +34,11 @@ pub(crate) enum PossibleFeature<'a> { struct ExitCode(Option); impl IntoDiagnosticArg for ExitCode { - fn into_diagnostic_arg(self) -> DiagnosticArgValue { + fn into_diagnostic_arg(self) -> DiagArgValue { let ExitCode(exit_code) = self; match exit_code { Some(t) => t.into_diagnostic_arg(), - None => DiagnosticArgValue::Str(Cow::Borrowed("")), + None => DiagArgValue::Str(Cow::Borrowed("")), } } } From 8879155e563cf9050754f12abcd170806fa63acd Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Wed, 28 Feb 2024 09:09:56 +0800 Subject: [PATCH 159/192] fix(libgccjit.version): Update GCC commit version --- libgccjit.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgccjit.version b/libgccjit.version index 20aebf091a70a..ad2c3b12b874a 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -d24c8dae3 +cf9554126 From 5b053a3c3c62ea77f0b8865a4ac97a90bb606c78 Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Wed, 28 Feb 2024 09:18:22 +0800 Subject: [PATCH 160/192] fix(Cargo.lock): Update Cargo.lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d73101f97d6ac..c004c7b992f7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#4b7aba76891e6436984f7f098fe92824d95194d5" +source = "git+https://github.com/antoyo/gccjit.rs#af31863f5f2a32f1c805444bfb6e8c174d6da8f4" dependencies = [ "gccjit_sys", ] @@ -88,7 +88,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#4b7aba76891e6436984f7f098fe92824d95194d5" +source = "git+https://github.com/antoyo/gccjit.rs#af31863f5f2a32f1c805444bfb6e8c174d6da8f4" dependencies = [ "libc", ] From 6170f48e3f5800a75e2ded5e55669048acfcbb2f Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Wed, 28 Feb 2024 10:04:25 +0800 Subject: [PATCH 161/192] fix(builder.rs): Add `cfg(feature = "master")` to set_location --- src/builder.rs | 14 ++++++-------- src/debuginfo.rs | 10 ++++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index c5d3ed8c8a1f2..663e42aaf85dc 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -26,7 +26,6 @@ use rustc_codegen_ssa::traits::{ use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::mir::Rvalue; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_span::Span; @@ -401,9 +400,8 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { pub fn set_rval_location<'a, 'gcc, 'tcx>(bx: &mut Builder<'a,'gcc,'tcx>, r:RValue<'gcc>) -> RValue<'gcc> { if bx.loc.is_some(){ - unsafe { - r.set_location(bx.loc.unwrap()); - } + #[cfg(feature = "master")] + r.set_location(bx.loc.unwrap()); } r @@ -545,9 +543,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { let i=a * b; if self.loc.is_some() { - unsafe{ - i.set_location(self.loc.clone().unwrap()); - } + #[cfg(feature = "master")] + i.set_location(self.loc.clone().unwrap()); } i } @@ -666,7 +663,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let ret = self.cx.gcc_or(a, b, self.loc); if self.loc.is_some() { - unsafe { ret.set_location(self.loc.unwrap()); } + #[cfg(feature = "master")] + ret.set_location(self.loc.unwrap()); } ret } diff --git a/src/debuginfo.rs b/src/debuginfo.rs index e01624ce15ea3..0ac5841df6337 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -32,10 +32,8 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { _fragment: Option>, ) { // Not sure if this is correct, probably wrong but still keep it here. - unsafe { - #[cfg(feature = "master")] - variable_alloca.set_location(dbg_loc); - } + #[cfg(feature = "master")] + variable_alloca.set_location(dbg_loc); } fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { @@ -45,7 +43,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { /// Currently, this function is not yet implemented. It seems that the /// debug name and the mangled name should both be included in the LValues. /// Besides, a function to get the rvalue type(m_is_lvalue) should also be included. - fn set_var_name(&mut self, value: RValue<'gcc>, name: &str) { + fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) { //unimplemented!(); } @@ -264,7 +262,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } rustc_span::RealFileName::Remapped { local_path, - virtual_name, + virtual_name:_, } => if let Some(name) = local_path.as_ref() { if let Some(name) = name.to_str(){ self.context.new_location( From 09fd9087b6ee5245e5b87fdb2dd48e7770c41fd6 Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Wed, 28 Feb 2024 11:37:49 +0800 Subject: [PATCH 162/192] fix(code fmt): builder.rs & base.rs --- src/base.rs | 4 ++-- src/builder.rs | 17 +++-------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/base.rs b/src/base.rs index bcf467839a45d..773e234150d1b 100644 --- a/src/base.rs +++ b/src/base.rs @@ -184,8 +184,8 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock // wrapper here maybe_create_entry_wrapper::>(&cx); - // FINALIZE debuginfo - if cx.sess().opts.debuginfo != DebugInfo::None { + // Finalize debuginfo + if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); } } diff --git a/src/builder.rs b/src/builder.rs index 663e42aaf85dc..87b5b04af1396 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -70,7 +70,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { cx, block, stack_var_count: Cell::new(0), - loc:None + loc: None } } @@ -541,12 +541,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - let i=a * b; - if self.loc.is_some() { - #[cfg(feature = "master")] - i.set_location(self.loc.clone().unwrap()); - } - i + self.cx.context.new_binary_op(self.loc, BinaryOp::Mult, a.get_type(), a, b) } fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -660,13 +655,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - let ret = self.cx.gcc_or(a, b, self.loc); - - if self.loc.is_some() { - #[cfg(feature = "master")] - ret.set_location(self.loc.unwrap()); - } - ret + self.cx.gcc_or(a, b, self.loc) } fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { From 51cd5f1c78462860890da4487616569400369378 Mon Sep 17 00:00:00 2001 From: tempdragon <88025134+tempdragon@users.noreply.github.com> Date: Thu, 29 Feb 2024 01:10:51 +0800 Subject: [PATCH 163/192] fix(code fmt): Apply style suggestions from code review Co-authored-by: antoyo --- src/context.rs | 2 +- src/debuginfo.rs | 14 ++++++-------- src/lib.rs | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/context.rs b/src/context.rs index 9dbb3751d47b4..cca37168880b5 100644 --- a/src/context.rs +++ b/src/context.rs @@ -345,7 +345,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type Funclet = (); // TODO(antoyo) type DIScope = (); // TODO(antoyo) - type DILocation = Location<'gcc>; // TODO(antoyo) + type DILocation = Location<'gcc>; type DIVariable = (); // TODO(antoyo) } diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 0ac5841df6337..51c5de2920b56 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -31,7 +31,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { _indirect_offsets: &[Size], _fragment: Option>, ) { - // Not sure if this is correct, probably wrong but still keep it here. + // FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here. #[cfg(feature = "master")] variable_alloca.set_location(dbg_loc); } @@ -40,11 +40,10 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): insert reference to gdb debug scripts section global. } - /// Currently, this function is not yet implemented. It seems that the + /// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the /// debug name and the mangled name should both be included in the LValues. /// Besides, a function to get the rvalue type(m_is_lvalue) should also be included. fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) { - //unimplemented!(); } fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { @@ -213,7 +212,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _scope_metadata: Self::DIScope, _file: &SourceFile, ) -> Self::DIScope { - //unimplemented!(); + // TODO(antoyo): implement. } fn debuginfo_finalize(&self) { @@ -238,7 +237,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option>, ) -> Self::DIScope { - //unimplemented!(); + // TODO(antoyo): implement. } fn dbg_loc( @@ -247,7 +246,6 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _inlined_at: Option, span: Span, ) -> Self::DILocation { - //unimplemented!(); let pos = span.lo(); let (file, line, col) = self.lookup_debug_loc(pos); let loc = match &file.name { @@ -256,7 +254,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if let Some(name) = name.to_str() { self.context .new_location(name, line as i32, col as i32) - }else{ + } else{ Location::null() } } @@ -273,7 +271,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } else { Location::null() } - }else{ + } else{ Location::null() }, }, diff --git a/src/lib.rs b/src/lib.rs index cdb7cbebc1cc5..1c1f82c3221cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,7 +175,7 @@ impl CodegenBackend for GccCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } - fn init(&self, sess: &Session) { + fn init(&self, sess: &Session) { #[cfg(feature="master")] { let target_cpu = target_cpu(sess); From eaeb54448e66edff57118bf9fe2ab3f13b98c04e Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Thu, 29 Feb 2024 01:28:08 +0800 Subject: [PATCH 164/192] fix(base): Remove the `set_debug_info()` in `compile_codegen_unit` --- src/base.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/base.rs b/src/base.rs index 773e234150d1b..10aaf904bca03 100644 --- a/src/base.rs +++ b/src/base.rs @@ -152,7 +152,6 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") { context.set_dump_initial_gimple(true); } - context.set_debug_info(true); if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") { context.set_dump_everything(true); } From 8dd96baddff3903a695a20d0e12ed92b3d2e435c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 Feb 2024 03:44:23 -0500 Subject: [PATCH 165/192] Add `f16` and `f128` to `rustc_type_ir::FloatTy` and `rustc_abi::Primitive` Make changes necessary to support these types in the compiler. --- src/type_.rs | 10 ++++++++++ src/type_of.rs | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/type_.rs b/src/type_.rs index 7a89fe81d3844..7e5aa1c1766df 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -83,8 +83,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn type_float_from_ty(&self, t: ty::FloatTy) -> Type<'gcc> { match t { + ty::FloatTy::F16 => self.type_f16(), ty::FloatTy::F32 => self.type_f32(), ty::FloatTy::F64 => self.type_f64(), + ty::FloatTy::F128 => self.type_f128(), } } } @@ -118,6 +120,10 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.isize_type } + fn type_f16(&self) -> Type<'gcc> { + unimplemented!("f16_f128") + } + fn type_f32(&self) -> Type<'gcc> { self.float_type } @@ -125,6 +131,10 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_f64(&self) -> Type<'gcc> { self.double_type } + + fn type_f128(&self) -> Type<'gcc> { + unimplemented!("f16_f128") + } fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> { self.context.new_function_pointer_type(None, return_type, params, false) diff --git a/src/type_of.rs b/src/type_of.rs index 25149b8020162..62136d24a2cb7 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; +use rustc_target::abi::{self, Abi, Align, F16, F128, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType}; @@ -257,8 +257,10 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { match scalar.primitive() { Int(i, true) => cx.type_from_integer(i), Int(i, false) => cx.type_from_unsigned_integer(i), + F16 => cx.type_f16(), F32 => cx.type_f32(), F64 => cx.type_f64(), + F128 => cx.type_f128(), Pointer(address_space) => { // If we know the alignment, pick something better than i8. let pointee = From ef158f295ecd37413a11b9f01d203f7b2440cbe6 Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Thu, 29 Feb 2024 02:37:37 +0800 Subject: [PATCH 166/192] feat(debuginfo.rs): Add Comments on functions of LLVM Origin --- src/base.rs | 1 - src/debuginfo.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/base.rs b/src/base.rs index 10aaf904bca03..b1d0f541702b1 100644 --- a/src/base.rs +++ b/src/base.rs @@ -158,7 +158,6 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") { context.set_keep_intermediates(true); } - if env::var("CG_GCCJIT_VERBOSE").as_deref() == Ok("1") { context.add_driver_option("-v"); } diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 51c5de2920b56..6c3f2367063d7 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -51,7 +51,10 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { } } -pub fn compute_mir_scopes<'gcc, 'tcx>( +/// Generate the `debug_context` in an MIR Body. +/// # Souce of Origin +/// Copied from `create_scope_map.rs` of rustc_codegen_llvm +fn compute_mir_scopes<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>, mir: &Body<'tcx>, @@ -81,6 +84,12 @@ pub fn compute_mir_scopes<'gcc, 'tcx>( assert!(instantiated.count() == mir.source_scopes.len()); } +/// Update the `debug_context`, adding new scope to it, +/// if it's not added as is denoted in `instantiated`. +/// +/// # Souce of Origin +/// Copied from `create_scope_map.rs` of rustc_codegen_llvm +/// FIXME(tempdragon/?): Add Scope Support Here. fn make_mir_scope<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>, @@ -123,6 +132,39 @@ fn make_mir_scope<'gcc, 'tcx>( } let loc = cx.lookup_debug_loc(scope_data.span.lo()); + + /* + // FIXME(?): Uncommented when the scope is supported. + let file_metadata = file_metadata(cx, &loc.file); + + let parent_dbg_scope = match scope_data.inlined { + Some((callee, _)) => { + // FIXME(eddyb) this would be `self.monomorphize(&callee)` + // if this is moved to `rustc_codegen_ssa::mir::debuginfo`. + let callee = cx.tcx.instantiate_and_normalize_erasing_regions( + instance.args, + ty::ParamEnv::reveal_all(), + ty::EarlyBinder::bind(callee), + ); + debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { + let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); + cx.dbg_scope_fn(callee, callee_fn_abi, None) + }) + } + None => parent_scope.dbg_scope, + }; + + let dbg_scope = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlock( + DIB(cx), + parent_dbg_scope, + file_metadata, + loc.line, + loc.col, + ) + }; + */ + let dbg_scope = (); let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { @@ -144,8 +186,13 @@ fn make_mir_scope<'gcc, 'tcx>( instantiated.insert(scope); } -/// Copied from LLVM backend impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + /// Look up the file, the 1-based indexing line number and column number. + /// # Argument + /// - `pos`: `BytePos`, the starting position of a piece of code + /// # Source of Origin + /// Copied from LLVM backend(with a return type from struct to tuple). + /// No need to change since you may end up something like this. pub fn lookup_debug_loc(&self, pos: BytePos) -> (Lrc, u32, u32) { match self.sess().source_map().lookup_line(pos) { Ok(SourceFileAndLine { sf: file, line }) => { @@ -216,7 +263,6 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn debuginfo_finalize(&self) { - // TODO(antoyo): Get the debug flag/predicate to allow optional generation of debuginfo. self.context.set_debug_info(true) } From e18d3c3dfdfbf9c8f50479ac64de5da6754035fb Mon Sep 17 00:00:00 2001 From: tempdragon <88025134+tempdragon@users.noreply.github.com> Date: Thu, 29 Feb 2024 03:00:46 +0800 Subject: [PATCH 167/192] fix(builder.rs): Apply suggestions from code review Co-authored-by: antoyo --- src/builder.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 87b5b04af1396..9afca472b5fa4 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -659,7 +659,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_xor(a, b)) + set_rval_location(self, self.gcc_xor(a, b)) } fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { @@ -721,9 +721,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - let i = self.frem(lhs, rhs); - set_rval_location(self,i); - i + let result = self.frem(lhs, rhs); + set_rval_location(self, i); + result } fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { @@ -1010,7 +1010,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_float_to_uint_cast(value, dest_ty)) + set_rval_location(self, self.gcc_float_to_uint_cast(value, dest_ty)) } fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { @@ -1036,7 +1036,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { let usize_value = self.cx.const_bitcast(value, self.cx.type_isize()); - self.intcast(usize_value, dest_ty, false) + self.intcast(usize_value, dest_ty, false) } fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { From fba0dae5feade451cf0adb4409396711623ae00e Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Thu, 29 Feb 2024 03:03:33 +0800 Subject: [PATCH 168/192] fix(builder.rs): Apply a variable name change to func param. --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 9afca472b5fa4..aac4028268915 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -722,7 +722,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. let result = self.frem(lhs, rhs); - set_rval_location(self, i); + set_rval_location(self, result); result } From 8c975d98619eec49c65c51e0303abdfeb126f133 Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Thu, 29 Feb 2024 03:18:51 +0800 Subject: [PATCH 169/192] fix(builder.rs): Rename `r` to `rvalue` in `set_rval_location` --- src/builder.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index aac4028268915..6df4313949d71 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -398,12 +398,12 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { type DIVariable = as BackendTypes>::DIVariable; } -pub fn set_rval_location<'a, 'gcc, 'tcx>(bx: &mut Builder<'a,'gcc,'tcx>, r:RValue<'gcc>) -> RValue<'gcc> { +pub fn set_rval_location<'a, 'gcc, 'tcx>(bx: &mut Builder<'a,'gcc,'tcx>, rvalue:RValue<'gcc>) -> RValue<'gcc> { if bx.loc.is_some(){ #[cfg(feature = "master")] - r.set_location(bx.loc.unwrap()); + rvalue.set_location(bx.loc.unwrap()); } - r + rvalue } From 9cc0a4204d1d1dba72b79d009e5f526505ea2d3c Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Thu, 29 Feb 2024 03:56:17 +0800 Subject: [PATCH 170/192] fix(debuginfo.rs): Cleanup of redundant code. 1. Revert to the original `lookup_debug_loc` of DebugLoc return type 2. Removed the commented code of scope lookup --- src/debuginfo.rs | 85 ++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 6c3f2367063d7..cd01785edbf0d 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -133,38 +133,7 @@ fn make_mir_scope<'gcc, 'tcx>( let loc = cx.lookup_debug_loc(scope_data.span.lo()); - /* - // FIXME(?): Uncommented when the scope is supported. - let file_metadata = file_metadata(cx, &loc.file); - - let parent_dbg_scope = match scope_data.inlined { - Some((callee, _)) => { - // FIXME(eddyb) this would be `self.monomorphize(&callee)` - // if this is moved to `rustc_codegen_ssa::mir::debuginfo`. - let callee = cx.tcx.instantiate_and_normalize_erasing_regions( - instance.args, - ty::ParamEnv::reveal_all(), - ty::EarlyBinder::bind(callee), - ); - debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { - let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); - cx.dbg_scope_fn(callee, callee_fn_abi, None) - }) - } - None => parent_scope.dbg_scope, - }; - - let dbg_scope = unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_dbg_scope, - file_metadata, - loc.line, - loc.col, - ) - }; - */ - + // FIXME(tempdragon): Add the scope related code here if the scope is supported. let dbg_scope = (); let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { @@ -180,36 +149,52 @@ fn make_mir_scope<'gcc, 'tcx>( debug_context.scopes[scope] = DebugScope { dbg_scope, inlined_at, - file_start_pos: loc.0.start_pos, - file_end_pos: loc.0.end_position(), + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_position(), }; instantiated.insert(scope); } +/// A source code location used to generate debug information. +// FIXME(eddyb) rename this to better indicate it's a duplicate of +// `rustc_span::Loc` rather than `DILocation`, perhaps by making +// `lookup_char_pos` return the right information instead. +pub struct DebugLoc { + /// Information about the original source file. + pub file: Lrc, + /// The (1-based) line number. + pub line: u32, + /// The (1-based) column number. + pub col: u32, +} + impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - /// Look up the file, the 1-based indexing line number and column number. - /// # Argument - /// - `pos`: `BytePos`, the starting position of a piece of code - /// # Source of Origin - /// Copied from LLVM backend(with a return type from struct to tuple). - /// No need to change since you may end up something like this. - pub fn lookup_debug_loc(&self, pos: BytePos) -> (Lrc, u32, u32) { - match self.sess().source_map().lookup_line(pos) { + /// Looks up debug source information about a `BytePos`. + // FIXME(eddyb) rename this to better indicate it's a duplicate of + // `lookup_char_pos` rather than `dbg_loc`, perhaps by making + // `lookup_char_pos` return the right information instead. + // Source of Origin: cg_llvm + pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc { + let (file, line, col) = match self.sess().source_map().lookup_line(pos) { Ok(SourceFileAndLine { sf: file, line }) => { let line_pos = file.lines()[line]; // Use 1-based indexing. let line = (line + 1) as u32; let col = (file.relative_position(pos) - line_pos).to_u32() + 1; - (file, - line, - if ! self.sess().target.is_like_msvc { - col } else { - UNKNOWN_COLUMN_NUMBER - } - ) + + (file, line, col) } Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER), + }; + + // For MSVC, omit the column number. + // Otherwise, emit it. This mimics clang behaviour. + // See discussion in https://github.com/rust-lang/rust/issues/42921 + if self.sess().target.is_like_msvc { + DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER } + } else { + DebugLoc { file, line, col } } } } @@ -293,7 +278,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { span: Span, ) -> Self::DILocation { let pos = span.lo(); - let (file, line, col) = self.lookup_debug_loc(pos); + let DebugLoc{file, line, col} = self.lookup_debug_loc(pos); let loc = match &file.name { rustc_span::FileName::Real(name) => match name { rustc_span::RealFileName::LocalPath(name) => { From 7c3565e569bb5017baad3a2a708dcdf7c1822d82 Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Thu, 29 Feb 2024 04:01:38 +0800 Subject: [PATCH 171/192] fix(builder.rs): Add space after self when necessary --- src/builder.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 6df4313949d71..dcac066f39534 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -663,60 +663,60 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_neg(a)) + set_rval_location(self, self.gcc_neg(a)) } fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a)) + set_rval_location(self, self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a)) } fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_not(a)) + set_rval_location(self, self.gcc_not(a)) } fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_add(a, b)) + set_rval_location(self, self.gcc_add(a, b)) } fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_add(a, b)) + set_rval_location(self, self.gcc_add(a, b)) } fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_sub(a, b)) + set_rval_location(self, self.gcc_sub(a, b)) } fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { // TODO(antoyo): should generate poison value? - set_rval_location(self,self.gcc_sub(a, b)) + set_rval_location(self, self.gcc_sub(a, b)) } fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_mul(a, b)) + set_rval_location(self, self.gcc_mul(a, b)) } fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_mul(a, b)) + set_rval_location(self, self.gcc_mul(a, b)) } fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self,lhs + rhs) + set_rval_location(self, lhs + rhs) } fn fsub_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self,lhs - rhs) + set_rval_location(self, lhs - rhs) } fn fmul_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self,lhs * rhs) + set_rval_location(self, lhs * rhs) } fn fdiv_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self,lhs / rhs) + set_rval_location(self, lhs / rhs) } fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { @@ -1014,24 +1014,24 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_float_to_int_cast(value, dest_ty)) + set_rval_location(self, self.gcc_float_to_int_cast(value, dest_ty)) } fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_uint_to_float_cast(value, dest_ty)) + set_rval_location(self, self.gcc_uint_to_float_cast(value, dest_ty)) } fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.gcc_int_to_float_cast(value, dest_ty)) + set_rval_location(self, self.gcc_int_to_float_cast(value, dest_ty)) } fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): make sure it truncates. - set_rval_location(self,self.context.new_cast(self.loc, value, dest_ty)) + set_rval_location(self, self.context.new_cast(self.loc, value, dest_ty)) } fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self,self.context.new_cast(self.loc, value, dest_ty)) + set_rval_location(self, self.context.new_cast(self.loc, value, dest_ty)) } fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { @@ -1059,7 +1059,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (false, true) => { // NOTE: Projecting a field of a pointer type will attempt a cast from a signed char to // a pointer, which is not supported by gccjit. - return self.cx.context.new_cast(self.loc, self.inttoptr(value, val_type.make_pointer()), dest_ty); + self.cx.context.new_cast(self.loc, self.inttoptr(value, val_type.make_pointer()), dest_ty) }, (false, false) => { // When they are not pointers, we want a transmute (or reinterpret_cast). From c2c68e3f4dcfd43aa2cbaddd8fdfe61ee086966d Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 28 Feb 2024 17:06:24 -0500 Subject: [PATCH 172/192] Format the code --- .github/workflows/ci.yml | 6 + .rustfmt.toml | 2 +- src/abi.rs | 107 +-- src/allocator.rs | 56 +- src/asm.rs | 217 +++--- src/attributes.rs | 77 +- src/back/lto.rs | 85 ++- src/back/write.rs | 51 +- src/base.rs | 55 +- src/builder.rs | 1419 +++++++++++++++++++++++------------- src/callee.rs | 259 ++++--- src/common.rs | 168 ++--- src/consts.rs | 135 ++-- src/context.rs | 250 ++++--- src/debuginfo.rs | 68 +- src/declare.rs | 223 ++++-- src/errors.rs | 2 +- src/gcc_util.rs | 67 +- src/int.rs | 928 +++++++++++++---------- src/intrinsic/llvm.rs | 522 ++++++++----- src/intrinsic/mod.rs | 1094 ++++++++++++++------------- src/intrinsic/simd.rs | 50 +- src/lib.rs | 232 ++++-- src/mono_item.rs | 35 +- src/type_.rs | 59 +- src/type_of.rs | 163 +++-- tests/lang_tests_common.rs | 51 +- 27 files changed, 3748 insertions(+), 2633 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab704aa80a2b7..839f3ba4de362 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,9 @@ jobs: # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. run: sudo apt-get install ninja-build ripgrep llvm-14-tools + - name: Install rustfmt + run: rustup component add rustfmt + - name: Download artifact run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/${{ matrix.libgccjit_version.gcc }} @@ -92,6 +95,9 @@ jobs: run: | ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} + - name: Check formatting + run: cargo fmt -- --check + duplicates: runs-on: ubuntu-latest steps: diff --git a/.rustfmt.toml b/.rustfmt.toml index 87f034950e3b2..2a35f0230c690 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1 +1 @@ -ignore = ["/src", "/tests"] +use_small_heuristics = "Max" diff --git a/src/abi.rs b/src/abi.rs index f601cd95f2a68..b098594dbcc35 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -18,17 +18,16 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn get_param(&mut self, index: usize) -> Self::Value { let func = self.current_func(); let param = func.get_param(index as i32); - let on_stack = - if let Some(on_stack_param_indices) = self.on_stack_function_params.borrow().get(&func) { - on_stack_param_indices.contains(&index) - } - else { - false - }; + let on_stack = if let Some(on_stack_param_indices) = + self.on_stack_function_params.borrow().get(&func) + { + on_stack_param_indices.contains(&index) + } else { + false + }; if on_stack { param.to_lvalue().get_address(None) - } - else { + } else { param.to_rvalue() } } @@ -37,13 +36,14 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { impl GccType for CastTarget { fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { let rest_gcc_unit = self.rest.unit.gcc_type(cx); - let (rest_count, rem_bytes) = - if self.rest.unit.size.bytes() == 0 { - (0, 0) - } - else { - (self.rest.total.bytes() / self.rest.unit.size.bytes(), self.rest.total.bytes() % self.rest.unit.size.bytes()) - }; + let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 { + (0, 0) + } else { + ( + self.rest.total.bytes() / self.rest.unit.size.bytes(), + self.rest.total.bytes() % self.rest.unit.size.bytes(), + ) + }; if self.prefix.iter().all(|x| x.is_none()) { // Simplify to a single unit when there is no prefix and size <= unit size @@ -61,9 +61,7 @@ impl GccType for CastTarget { let mut args: Vec<_> = self .prefix .iter() - .flat_map(|option_reg| { - option_reg.map(|reg| reg.gcc_type(cx)) - }) + .flat_map(|option_reg| option_reg.map(|reg| reg.gcc_type(cx))) .chain((0..rest_count).map(|_| rest_gcc_unit)) .collect(); @@ -86,12 +84,10 @@ impl GccType for Reg { fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { match self.kind { RegKind::Integer => cx.type_ix(self.size.bits()), - RegKind::Float => { - match self.size.bits() { - 32 => cx.type_f32(), - 64 => cx.type_f64(), - _ => bug!("unsupported float: {:?}", self), - } + RegKind::Float => match self.size.bits() { + 32 => cx.type_f32(), + 64 => cx.type_f64(), + _ => bug!("unsupported float: {:?}", self), }, RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()), } @@ -119,19 +115,18 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // This capacity calculation is approximate. let mut argument_tys = Vec::with_capacity( - self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } + self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 }, ); - let return_type = - match self.ret.mode { - PassMode::Ignore => cx.type_void(), - PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), - PassMode::Cast { ref cast, .. } => cast.gcc_type(cx), - PassMode::Indirect { .. } => { - argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); - cx.type_void() - } - }; + let return_type = match self.ret.mode { + PassMode::Ignore => cx.type_void(), + PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), + PassMode::Cast { ref cast, .. } => cast.gcc_type(cx), + PassMode::Indirect { .. } => { + argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); + cx.type_void() + } + }; #[cfg(feature = "master")] let mut non_null_args = Vec::new(); @@ -149,17 +144,23 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ty }; #[cfg(not(feature = "master"))] - let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| { - ty - }; + let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| ty; for arg in self.args.iter() { let arg_ty = match arg.mode { PassMode::Ignore => continue, PassMode::Pair(a, b) => { let arg_pos = argument_tys.len(); - argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a, arg_pos)); - argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b, arg_pos + 1)); + argument_tys.push(apply_attrs( + arg.layout.scalar_pair_element_gcc_type(cx, 0), + &a, + arg_pos, + )); + argument_tys.push(apply_attrs( + arg.layout.scalar_pair_element_gcc_type(cx, 1), + &b, + arg_pos + 1, + )); continue; } PassMode::Cast { ref cast, pad_i32 } => { @@ -174,14 +175,17 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // This is a "byval" argument, so we don't apply the `restrict` attribute on it. on_stack_param_indices.insert(argument_tys.len()); arg.memory_ty(cx) - }, - PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs, argument_tys.len()), + } + PassMode::Direct(attrs) => { + apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs, argument_tys.len()) + } PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len()) } PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { assert!(!on_stack); - let ty = apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len()); + let ty = + apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len()); apply_attrs(ty, &meta_attrs, argument_tys.len()) } }; @@ -207,15 +211,14 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { // FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`? - let FnAbiGcc { - return_type, - arguments_type, - is_c_variadic, + let FnAbiGcc { return_type, arguments_type, is_c_variadic, on_stack_param_indices, .. } = + self.gcc_type(cx); + let pointer_type = + cx.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic); + cx.on_stack_params.borrow_mut().insert( + pointer_type.dyncast_function_ptr_type().expect("function ptr type"), on_stack_param_indices, - .. - } = self.gcc_type(cx); - let pointer_type = cx.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic); - cx.on_stack_params.borrow_mut().insert(pointer_type.dyncast_function_ptr_type().expect("function ptr type"), on_stack_param_indices); + ); pointer_type } } diff --git a/src/allocator.rs b/src/allocator.rs index 7c7044830f3d4..5cfd654a2049d 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,4 +1,4 @@ -#[cfg(feature="master")] +#[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type}; use rustc_ast::expand::allocator::{ @@ -11,15 +11,20 @@ use rustc_session::config::OomStrategy; use crate::GccContext; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) { +pub(crate) unsafe fn codegen( + tcx: TyCtxt<'_>, + mods: &mut GccContext, + _module_name: &str, + kind: AllocatorKind, + alloc_error_handler_kind: AllocatorKind, +) { let context = &mods.context; - let usize = - match tcx.sess.target.pointer_width { - 16 => context.new_type::(), - 32 => context.new_type::(), - 64 => context.new_type::(), - tws => bug!("Unsupported target word size for int: {}", tws), - }; + let usize = match tcx.sess.target.pointer_width { + 16 => context.new_type::(), + 32 => context.new_type::(), + 64 => context.new_type::(), + tws => bug!("Unsupported target word size for int: {}", tws), + }; let i8 = context.new_type::(); let i8p = i8.make_pointer(); @@ -85,24 +90,42 @@ fn create_wrapper_function( ) { let void = context.new_type::<()>(); - let args: Vec<_> = types.iter().enumerate() + let args: Vec<_> = types + .iter() + .enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); - let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, from_name, false); + let func = context.new_function( + None, + FunctionType::Exported, + output.unwrap_or(void), + &args, + from_name, + false, + ); if tcx.sess.default_hidden_visibility() { - #[cfg(feature="master")] + #[cfg(feature = "master")] func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); } if tcx.sess.must_emit_unwind_tables() { // TODO(antoyo): emit unwind tables. } - let args: Vec<_> = types.iter().enumerate() + let args: Vec<_> = types + .iter() + .enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); - let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, to_name, false); - #[cfg(feature="master")] + let callee = context.new_function( + None, + FunctionType::Extern, + output.unwrap_or(void), + &args, + to_name, + false, + ); + #[cfg(feature = "master")] callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); let block = func.new_block("entry"); @@ -116,8 +139,7 @@ fn create_wrapper_function( //llvm::LLVMSetTailCall(ret, True); if output.is_some() { block.end_with_return(None, ret); - } - else { + } else { block.end_with_void_return(None); } diff --git a/src/asm.rs b/src/asm.rs index 78e8e32b97299..bded806cafdeb 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -2,7 +2,10 @@ use gccjit::{LValue, RValue, ToRValue, Type}; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; use rustc_codegen_ssa::mir::place::PlaceRef; -use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; +use rustc_codegen_ssa::traits::{ + AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, + InlineAsmOperandRef, +}; use rustc_middle::{bug, ty::Instance}; use rustc_span::Span; @@ -11,11 +14,10 @@ use rustc_target::asm::*; use std::borrow::Cow; use crate::builder::Builder; +use crate::callee::get_fn; use crate::context::CodegenCx; use crate::errors::UnwindingInlineAsm; use crate::type_of::LayoutGccExt; -use crate::callee::get_fn; - // Rust asm! and GCC Extended Asm semantics differ substantially. // @@ -68,7 +70,6 @@ use crate::callee::get_fn; const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t"; const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix"; - struct AsmOutOperand<'a, 'tcx, 'gcc> { rust_idx: usize, constraint: &'a str, @@ -76,13 +77,13 @@ struct AsmOutOperand<'a, 'tcx, 'gcc> { readwrite: bool, tmp_var: LValue<'gcc>, - out_place: Option>> + out_place: Option>>, } struct AsmInOperand<'a, 'tcx> { rust_idx: usize, constraint: Cow<'a, str>, - val: RValue<'tcx> + val: RValue<'tcx>, } impl AsmOutOperand<'_, '_, '_> { @@ -102,16 +103,21 @@ impl AsmOutOperand<'_, '_, '_> { enum ConstraintOrRegister { Constraint(&'static str), - Register(&'static str) + Register(&'static str), } - impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { - fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) { + fn codegen_inline_asm( + &mut self, + template: &[InlineAsmTemplatePiece], + rust_operands: &[InlineAsmOperandRef<'tcx, Self>], + options: InlineAsmOptions, + span: &[Span], + instance: Instance<'_>, + _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>, + ) { if options.contains(InlineAsmOptions::MAY_UNWIND) { - self.sess().dcx() - .create_err(UnwindingInlineAsm { span: span[0] }) - .emit(); + self.sess().dcx().create_err(UnwindingInlineAsm { span: span[0] }).emit(); return; } @@ -157,32 +163,40 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { use ConstraintOrRegister::*; let (constraint, ty) = match (reg_to_gcc(reg), place) { - (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx)), + (Constraint(constraint), Some(place)) => { + (constraint, place.layout.gcc_type(self.cx)) + } // When `reg` is a class and not an explicit register but the out place is not specified, // we need to create an unused output variable to assign the output to. This var // needs to be of a type that's "compatible" with the register class, but specific type // doesn't matter. - (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())), + (Constraint(constraint), None) => { + (constraint, dummy_output_type(self.cx, reg.reg_class())) + } (Register(_), Some(_)) => { // left for the next pass - continue - }, + continue; + } (Register(reg_name), None) => { // `clobber_abi` can add lots of clobbers that are not supported by the target, // such as AVX-512 registers, so we just ignore unsupported registers - let is_target_supported = reg.reg_class().supported_types(asm_arch).iter() - .any(|&(_, feature)| { - if let Some(feature) = feature { - self.tcx.asm_target_features(instance.def_id()).contains(&feature) - } else { - true // Register class is unconditionally supported - } - }); + let is_target_supported = + reg.reg_class().supported_types(asm_arch).iter().any( + |&(_, feature)| { + if let Some(feature) = feature { + self.tcx + .asm_target_features(instance.def_id()) + .contains(&feature) + } else { + true // Register class is unconditionally supported + } + }, + ); if is_target_supported && !clobbers.contains(®_name) { clobbers.push(reg_name); } - continue + continue; } }; @@ -193,7 +207,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { late, readwrite: false, tmp_var, - out_place: place + out_place: place, }); } @@ -202,23 +216,22 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { inputs.push(AsmInOperand { constraint: Cow::Borrowed(constraint), rust_idx, - val: value.immediate() + val: value.immediate(), }); - } - else { + } else { // left for the next pass - continue + continue; } } InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { - let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { - constraint - } - else { - // left for the next pass - continue - }; + let constraint = + if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { + constraint + } else { + // left for the next pass + continue; + }; // Rustc frontend guarantees that input and output types are "compatible", // so we can just use input var's type for the output variable. @@ -249,7 +262,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { inputs.push(AsmInOperand { constraint, rust_idx, - val: in_value.immediate() + val: in_value.immediate(), }); } } @@ -267,7 +280,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::SymStatic { def_id } => { // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O). - constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len(); + constants_len += + self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len(); } } } @@ -280,10 +294,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { let out_place = if let Some(place) = place { place - } - else { + } else { // processed in the previous pass - continue + continue; }; let ty = out_place.layout.gcc_type(self.cx); @@ -296,7 +309,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { late, readwrite: false, tmp_var, - out_place: Some(out_place) + out_place: Some(out_place), }); } @@ -314,7 +327,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { inputs.push(AsmInOperand { constraint: "r".into(), rust_idx, - val: reg_var.to_rvalue() + val: reg_var.to_rvalue(), }); } @@ -342,7 +355,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { inputs.push(AsmInOperand { constraint, rust_idx, - val: in_value.immediate() + val: in_value.immediate(), }); } @@ -373,7 +386,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // 3. Build the template string - let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect)); + let mut template_str = + String::with_capacity(estimate_template_length(template, constants_len, att_dialect)); if att_dialect { template_str.push_str(ATT_SYNTAX_INS); } @@ -383,16 +397,15 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmTemplatePiece::String(ref string) => { for char in string.chars() { // TODO(antoyo): might also need to escape | if rustc doesn't do it. - let escaped_char = - match char { - '%' => "%%", - '{' => "%{", - '}' => "%}", - _ => { - template_str.push(char); - continue; - }, - }; + let escaped_char = match char { + '%' => "%%", + '{' => "%{", + '}' => "%}", + _ => { + template_str.push(char); + continue; + } + }; template_str.push_str(escaped_char); } } @@ -408,9 +421,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }; match rust_operands[operand_idx] { - InlineAsmOperandRef::Out { reg, .. } => { + InlineAsmOperandRef::Out { reg, .. } => { let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); - let gcc_index = outputs.iter() + let gcc_index = outputs + .iter() .position(|op| operand_idx == op.rust_idx) .expect("wrong rust index"); push_to_template(modifier, gcc_index); @@ -418,7 +432,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::In { reg, .. } => { let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); - let in_gcc_index = inputs.iter() + let in_gcc_index = inputs + .iter() .position(|op| operand_idx == op.rust_idx) .expect("wrong rust index"); let gcc_index = in_gcc_index + outputs.len(); @@ -429,7 +444,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); // The input register is tied to the output, so we can just use the index of the output register - let gcc_index = outputs.iter() + let gcc_index = outputs + .iter() .position(|op| operand_idx == op.rust_idx) .expect("wrong rust index"); push_to_template(modifier, gcc_index); @@ -496,7 +512,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } if options.contains(InlineAsmOptions::NORETURN) { let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); - let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) }; + let builtin_unreachable: RValue<'gcc> = + unsafe { std::mem::transmute(builtin_unreachable) }; self.call(self.type_void(), None, None, builtin_unreachable, &[], None); } @@ -517,19 +534,23 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } } -fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len: usize, att_dialect: bool) -> usize { - let len: usize = template.iter().map(|piece| { - match *piece { - InlineAsmTemplatePiece::String(ref string) => { - string.len() - } - InlineAsmTemplatePiece::Placeholder { .. } => { - // '%' + 1 char modifier + 1 char index - 3 +fn estimate_template_length( + template: &[InlineAsmTemplatePiece], + constants_len: usize, + att_dialect: bool, +) -> usize { + let len: usize = template + .iter() + .map(|piece| { + match *piece { + InlineAsmTemplatePiece::String(ref string) => string.len(), + InlineAsmTemplatePiece::Placeholder { .. } => { + // '%' + 1 char modifier + 1 char index + 3 + } } - } - }) - .sum(); + }) + .sum(); // increase it by 5% to account for possible '%' signs that'll be duplicated // I pulled the number out of blue, but should be fair enough @@ -562,7 +583,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { _ => unimplemented!(), } - }, + } // They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html InlineAsmRegOrRegClass::RegClass(reg) => match reg { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", @@ -610,7 +631,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { unreachable!("clobber-only") - }, + } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { @@ -637,7 +658,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Err => unreachable!(), - } + }, }; ConstraintOrRegister::Constraint(constraint) @@ -653,7 +674,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { unimplemented!() } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)=> cx.type_i32(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) @@ -686,7 +707,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { unreachable!("clobber-only") - }, + } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => cx.type_f32(), @@ -704,9 +725,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") - }, + } InlineAsmRegClass::S390x( - S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr + S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr, ) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::Err => unreachable!(), @@ -714,7 +735,13 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl } impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span]) { + fn codegen_global_asm( + &self, + template: &[InlineAsmTemplatePiece], + operands: &[GlobalAsmOperandRef<'tcx>], + options: InlineAsmOptions, + _line_spans: &[Span], + ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); // Default to Intel syntax on x86 @@ -732,15 +759,17 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let mut index = 0; while index < string.len() { // NOTE: gcc does not allow inline comment, so remove them. - let comment_index = string[index..].find("//") + let comment_index = string[index..] + .find("//") .map(|comment_index| comment_index + index) .unwrap_or(string.len()); template_str.push_str(&string[index..comment_index]); - index = string[comment_index..].find('\n') + index = string[comment_index..] + .find('\n') .map(|index| index + comment_index) .unwrap_or(string.len()); } - }, + } InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { match operands[operand_idx] { GlobalAsmOperandRef::Const { ref string } => { @@ -782,14 +811,22 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } -fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option) -> Option { +fn modifier_to_gcc( + arch: InlineAsmArch, + reg: InlineAsmRegClass, + modifier: Option, +) -> Option { // The modifiers can be retrieved from // https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html#Modifiers match reg { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier, InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { - if modifier == Some('v') { None } else { modifier } + if modifier == Some('v') { + None + } else { + modifier + } } InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") @@ -821,7 +858,13 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option } InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier { - None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') }, + None => { + if arch == InlineAsmArch::X86_64 { + Some('q') + } else { + Some('k') + } + } Some('l') => Some('b'), Some('h') => Some('h'), Some('x') => Some('w'), diff --git a/src/attributes.rs b/src/attributes.rs index 142f86b003ddb..8602566ab8fa2 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -1,21 +1,24 @@ -#[cfg(feature="master")] +#[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::Function; -use rustc_attr::InstructionSetAttr; -#[cfg(feature="master")] +#[cfg(feature = "master")] use rustc_attr::InlineAttr; -use rustc_middle::ty; -#[cfg(feature="master")] +use rustc_attr::InstructionSetAttr; +#[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::ty; use rustc_span::symbol::sym; -use crate::{context::CodegenCx, errors::TiedTargetFeatures}; use crate::gcc_util::{check_tied_features, to_gcc_features}; +use crate::{context::CodegenCx, errors::TiedTargetFeatures}; /// Get GCC attribute for the provided inline heuristic. -#[cfg(feature="master")] +#[cfg(feature = "master")] #[inline] -fn inline_attr<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr) -> Option> { +fn inline_attr<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + inline: InlineAttr, +) -> Option> { match inline { InlineAttr::Hint => Some(FnAttribute::Inline), InlineAttr::Always => Some(FnAttribute::AlwaysInline), @@ -34,24 +37,22 @@ fn inline_attr<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr) -> Op /// attributes. pub fn from_fn_attrs<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, - #[cfg_attr(not(feature="master"), allow(unused_variables))] - func: Function<'gcc>, + #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>, instance: ty::Instance<'tcx>, ) { let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); - #[cfg(feature="master")] + #[cfg(feature = "master")] { - let inline = - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - InlineAttr::Never - } - else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) { - InlineAttr::Hint - } - else { - codegen_fn_attrs.inline - }; + let inline = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + InlineAttr::Never + } else if codegen_fn_attrs.inline == InlineAttr::None + && instance.def.requires_inline(cx.tcx) + { + InlineAttr::Hint + } else { + codegen_fn_attrs.inline + }; if let Some(attr) = inline_attr(cx, inline) { if let FnAttribute::AlwaysInline = attr { func.add_attribute(FnAttribute::Inline); @@ -70,18 +71,21 @@ pub fn from_fn_attrs<'gcc, 'tcx>( } } - let function_features = - codegen_fn_attrs.target_features.iter().map(|features| features.as_str()).collect::>(); + let function_features = codegen_fn_attrs + .target_features + .iter() + .map(|features| features.as_str()) + .collect::>(); - if let Some(features) = check_tied_features(cx.tcx.sess, &function_features.iter().map(|features| (*features, true)).collect()) { - let span = cx.tcx + if let Some(features) = check_tied_features( + cx.tcx.sess, + &function_features.iter().map(|features| (*features, true)).collect(), + ) { + let span = cx + .tcx .get_attr(instance.def_id(), sym::target_feature) .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); - cx.tcx.dcx().create_err(TiedTargetFeatures { - features: features.join(", "), - span, - }) - .emit(); + cx.tcx.dcx().create_err(TiedTargetFeatures { features: features.join(", "), span }).emit(); return; } @@ -105,24 +109,25 @@ pub fn from_fn_attrs<'gcc, 'tcx>( // compiling Rust for Linux: // SSE register return with SSE disabled // TODO(antoyo): support soft-float and retpoline-external-thunk. - if feature.contains("soft-float") || feature.contains("retpoline-external-thunk") || *feature == "-sse" { + if feature.contains("soft-float") + || feature.contains("retpoline-external-thunk") + || *feature == "-sse" + { return None; } if feature.starts_with('-') { Some(format!("no{}", feature)) - } - else if feature.starts_with('+') { + } else if feature.starts_with('+') { Some(feature[1..].to_string()) - } - else { + } else { Some(feature.to_string()) } }) .collect::>() .join(","); if !target_features.is_empty() { - #[cfg(feature="master")] + #[cfg(feature = "master")] func.add_attribute(FnAttribute::Target(&target_features)); } } diff --git a/src/back/lto.rs b/src/back/lto.rs index c21b768682399..42837a57bade8 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -1,7 +1,6 @@ /// GCC requires to use the same toolchain for the whole compilation when doing LTO. /// So, we need the same version/commit of the linker (gcc) and lto front-end binaries (lto1, /// lto-wrapper, liblto_plugin.so). - // FIXME(antoyo): the executables compiled with LTO are bigger than those compiled without LTO. // Since it is the opposite for cg_llvm, check if this is normal. // @@ -17,7 +16,6 @@ // /usr/bin/ld: warning: type of symbol `_RNvNvNvNtCs5JWOrf9uCus_5rayon11thread_pool19WORKER_THREAD_STATE7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o // /usr/bin/ld: warning: type of symbol `_RNvNvNvNvNtNtNtCsAj5i4SGTR7_3std4sync4mpmc5waker17current_thread_id5DUMMY7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o // /usr/bin/ld: warning: incremental linking of LTO and non-LTO objects; using -flinker-output=nolto-rel which will bypass whole program optimization - use std::ffi::CString; use std::fs::{self, File}; use std::path::{Path, PathBuf}; @@ -30,18 +28,16 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{FatalError, DiagCtxt}; +use rustc_errors::{DiagCtxt, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_session::config::{CrateType, Lto}; -use tempfile::{TempDir, tempdir}; +use tempfile::{tempdir, TempDir}; use crate::back::write::save_temp_bitcode; -use crate::errors::{ - DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, -}; -use crate::{GccCodegenBackend, GccContext, to_gcc_opt_level}; +use crate::errors::{DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib}; +use crate::{to_gcc_opt_level, GccCodegenBackend, GccContext}; /// We keep track of the computed LTO cache keys from the previous /// session to determine which CGUs we can reuse. @@ -61,7 +57,10 @@ struct LtoData { tmp_path: TempDir, } -fn prepare_lto(cgcx: &CodegenContext, dcx: &DiagCtxt) -> Result { +fn prepare_lto( + cgcx: &CodegenContext, + dcx: &DiagCtxt, +) -> Result { let export_threshold = match cgcx.lto { // We're just doing LTO for our one crate Lto::ThinLocal => SymbolExportLevel::Rust, @@ -72,14 +71,13 @@ fn prepare_lto(cgcx: &CodegenContext, dcx: &DiagCtxt) -> Resu Lto::No => panic!("didn't request LTO but we're doing LTO"), }; - let tmp_path = - match tempdir() { - Ok(tmp_path) => tmp_path, - Err(error) => { - eprintln!("Cannot create temporary directory: {}", error); - return Err(FatalError); - }, - }; + let tmp_path = match tempdir() { + Ok(tmp_path) => tmp_path, + Err(error) => { + eprintln!("Cannot create temporary directory: {}", error); + return Err(FatalError); + } + }; let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| { if info.level.is_below_threshold(export_threshold) || info.used { @@ -125,8 +123,7 @@ fn prepare_lto(cgcx: &CodegenContext, dcx: &DiagCtxt) -> Resu let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO"); { - let _timer = - cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold"); + let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold"); symbols_below_threshold .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter)); } @@ -170,10 +167,9 @@ fn prepare_lto(cgcx: &CodegenContext, dcx: &DiagCtxt) -> Resu } fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> { - fs::write(path, obj) - .map_err(|error| LtoBitcodeFromRlib { - gcc_err: format!("write object file to temp dir: {}", error) - }) + fs::write(path, obj).map_err(|error| LtoBitcodeFromRlib { + gcc_err: format!("write object file to temp dir: {}", error), + }) } /// Performs fat LTO by merging all modules into a single one and returning it @@ -186,13 +182,25 @@ pub(crate) fn run_fat( let dcx = cgcx.create_dcx(); let lto_data = prepare_lto(cgcx, &dcx)?; /*let symbols_below_threshold = - lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>();*/ - fat_lto(cgcx, &dcx, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path, + lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>();*/ + fat_lto( + cgcx, + &dcx, + modules, + cached_modules, + lto_data.upstream_modules, + lto_data.tmp_path, //&symbols_below_threshold, ) } -fn fat_lto(cgcx: &CodegenContext, _dcx: &DiagCtxt, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, +fn fat_lto( + cgcx: &CodegenContext, + _dcx: &DiagCtxt, + modules: Vec>, + cached_modules: Vec<(SerializedModule, WorkProduct)>, + mut serialized_modules: Vec<(SerializedModule, CString)>, + tmp_path: TempDir, //symbols_below_threshold: &[*const libc::c_char], ) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); @@ -298,10 +306,15 @@ fn fat_lto(cgcx: &CodegenContext, _dcx: &DiagCtxt, modules: V match bc_decoded { SerializedModule::Local(ref module_buffer) => { module.module_llvm.should_combine_object_files = true; - module.module_llvm.context.add_driver_option(module_buffer.0.to_str().expect("path")); - }, + module + .module_llvm + .context + .add_driver_option(module_buffer.0.to_str().expect("path")); + } SerializedModule::FromRlib(_) => unimplemented!("from rlib"), - SerializedModule::FromUncompressedFile(_) => unimplemented!("from uncompressed file"), + SerializedModule::FromUncompressedFile(_) => { + unimplemented!("from uncompressed file") + } } serialized_bitcode.push(bc_decoded); } @@ -309,13 +322,13 @@ fn fat_lto(cgcx: &CodegenContext, _dcx: &DiagCtxt, modules: V // Internalize everything below threshold to help strip out more modules and such. /*unsafe { - let ptr = symbols_below_threshold.as_ptr(); - llvm::LLVMRustRunRestrictionPass( - llmod, - ptr as *const *const libc::c_char, - symbols_below_threshold.len() as libc::size_t, - );*/ - save_temp_bitcode(cgcx, &module, "lto.after-restriction"); + let ptr = symbols_below_threshold.as_ptr(); + llvm::LLVMRustRunRestrictionPass( + llmod, + ptr as *const *const libc::c_char, + symbols_below_threshold.len() as libc::size_t, + );*/ + save_temp_bitcode(cgcx, &module, "lto.after-restriction"); //} } diff --git a/src/back/write.rs b/src/back/write.rs index eea62adca07e5..76a619a1af782 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -1,19 +1,24 @@ use std::{env, fs}; use gccjit::OutputKind; -use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_errors::DiagCtxt; use rustc_fs_util::link_or_copy; use rustc_session::config::OutputType; use rustc_span::fatal_error::FatalError; use rustc_target::spec::SplitDebuginfo; -use crate::{GccCodegenBackend, GccContext}; use crate::errors::CopyBitcode; +use crate::{GccCodegenBackend, GccContext}; -pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { +pub(crate) unsafe fn codegen( + cgcx: &CodegenContext, + dcx: &DiagCtxt, + module: ModuleCodegen, + config: &ModuleConfig, +) -> Result { let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; @@ -51,7 +56,8 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &Dia .generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name); context.add_command_line_option("-flto=auto"); context.add_command_line_option("-flto-partition=one"); - context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str")); + context + .compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str")); } if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) { @@ -65,7 +71,8 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &Dia context.add_command_line_option("-flto-partition=one"); context.add_command_line_option("-ffat-lto-objects"); // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument). - context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str")); + context + .compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str")); } } @@ -75,9 +82,8 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &Dia } if config.emit_asm { - let _timer = cgcx - .prof - .generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name); + let _timer = + cgcx.prof.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name); let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str")); } @@ -90,7 +96,9 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &Dia if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") { println!("Module {}", module.name); } - if env::var("CG_GCCJIT_DUMP_ALL_MODULES").as_deref() == Ok("1") || env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) { + if env::var("CG_GCCJIT_DUMP_ALL_MODULES").as_deref() == Ok("1") + || env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) + { println!("Dumping reproducer {}", module.name); let _ = fs::create_dir("/tmp/reproducers"); // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by @@ -118,10 +126,15 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &Dia context.add_driver_option("-fuse-linker-plugin"); // NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o. - context.compile_to_file(OutputKind::Executable, obj_out.to_str().expect("path to str")); - } - else { - context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); + context.compile_to_file( + OutputKind::Executable, + obj_out.to_str().expect("path to str"), + ); + } else { + context.compile_to_file( + OutputKind::ObjectFile, + obj_out.to_str().expect("path to str"), + ); } } @@ -149,11 +162,19 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, dcx: &Dia )) } -pub(crate) fn link(_cgcx: &CodegenContext, _dcx: &DiagCtxt, mut _modules: Vec>) -> Result, FatalError> { +pub(crate) fn link( + _cgcx: &CodegenContext, + _dcx: &DiagCtxt, + mut _modules: Vec>, +) -> Result, FatalError> { unimplemented!(); } -pub(crate) fn save_temp_bitcode(cgcx: &CodegenContext, _module: &ModuleCodegen, _name: &str) { +pub(crate) fn save_temp_bitcode( + cgcx: &CodegenContext, + _module: &ModuleCodegen, + _name: &str, +) { if !cgcx.save_temps { return; } diff --git a/src/base.rs b/src/base.rs index b1d0f541702b1..2a2d5741d1318 100644 --- a/src/base.rs +++ b/src/base.rs @@ -2,29 +2,26 @@ use std::collections::HashSet; use std::env; use std::time::Instant; -use gccjit::{ - FunctionType, - GlobalKind, -}; -use rustc_middle::dep_graph; -use rustc_middle::ty::TyCtxt; -#[cfg(feature="master")] -use rustc_middle::mir::mono::Visibility; -use rustc_middle::mir::mono::Linkage; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; +use gccjit::{FunctionType, GlobalKind}; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::DebugInfoMethods; +use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; +use rustc_middle::dep_graph; +use rustc_middle::mir::mono::Linkage; +#[cfg(feature = "master")] +use rustc_middle::mir::mono::Visibility; +use rustc_middle::ty::TyCtxt; use rustc_session::config::DebugInfo; use rustc_span::Symbol; use rustc_target::spec::PanicStrategy; -use crate::{LockedTargetInfo, gcc_util, new_context}; -use crate::GccContext; use crate::builder::Builder; use crate::context::CodegenCx; +use crate::GccContext; +use crate::{gcc_util, new_context, LockedTargetInfo}; -#[cfg(feature="master")] +#[cfg(feature = "master")] pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility { match linkage { Visibility::Default => gccjit::Visibility::Default, @@ -66,7 +63,11 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { } } -pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: LockedTargetInfo) -> (ModuleCodegen, u64) { +pub fn compile_codegen_unit( + tcx: TyCtxt<'_>, + cgu_name: Symbol, + target_info: LockedTargetInfo, +) -> (ModuleCodegen, u64) { let prof_timer = tcx.prof.generic_activity("codegen_module"); let start_time = Instant::now(); @@ -85,7 +86,10 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock // the time we needed for codegenning it. let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; - fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen { + fn module_codegen( + tcx: TyCtxt<'_>, + (cgu_name, target_info): (Symbol, LockedTargetInfo), + ) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); // Instantiate monomorphizations without filling out definitions yet... let context = new_context(tcx); @@ -95,7 +99,12 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock context.add_driver_option("-fexceptions"); } - let disabled_features: HashSet<_> = tcx.sess.opts.cg.target_feature.split(',') + let disabled_features: HashSet<_> = tcx + .sess + .opts + .cg + .target_feature + .split(',') .filter(|feature| feature.starts_with('-')) .map(|string| &string[1..]) .collect(); @@ -129,7 +138,13 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock context.add_command_line_option(&format!("-march={}", target_cpu)); } - if tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) { + if tcx + .sess + .opts + .unstable_opts + .function_sections + .unwrap_or(tcx.sess.target.function_sections) + { context.add_command_line_option("-ffunction-sections"); context.add_command_line_option("-fdata-sections"); } @@ -190,11 +205,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock ModuleCodegen { name: cgu_name.to_string(), - module_llvm: GccContext { - context, - should_combine_object_files: false, - temp_dir: None, - }, + module_llvm: GccContext { context, should_combine_object_files: false, temp_dir: None }, kind: ModuleKind::Regular, } } diff --git a/src/builder.rs b/src/builder.rs index dcac066f39534..26967fb495350 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,44 +4,36 @@ use std::convert::TryFrom; use std::ops::Deref; use gccjit::{ - BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type, UnaryOp + BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type, + UnaryOp, }; use rustc_apfloat::{ieee, Float, Round, Status}; -use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{ AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, }; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ - BackendTypes, - BaseTypeMethods, - BuilderMethods, - ConstMethods, - LayoutTypeMethods, - HasCodegen, - OverflowOp, - StaticBuilderMethods, + BackendTypes, BaseTypeMethods, BuilderMethods, ConstMethods, HasCodegen, LayoutTypeMethods, + OverflowOp, StaticBuilderMethods, }; +use rustc_codegen_ssa::MemFlags; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, + TyAndLayout, +}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; -use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; -use rustc_span::Span; use rustc_span::def_id::DefId; +use rustc_span::Span; use rustc_target::abi::{ - self, - call::FnAbi, - Align, - HasDataLayout, - Size, - TargetDataLayout, - WrappingRange, + self, call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange, }; use rustc_target::spec::{HasTargetSpec, Target}; -use crate::common::{SignType, TypeReflection, type_is_pointer}; +use crate::common::{type_is_pointer, SignType, TypeReflection}; use crate::context::CodegenCx; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -61,56 +53,74 @@ pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, stack_var_count: Cell, - pub loc: Option>, + pub location: Option>, } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { - Builder { - cx, - block, - stack_var_count: Cell::new(0), - loc: None - } + Builder { cx, block, stack_var_count: Cell::new(0), location: None } } - fn atomic_extremum(&mut self, operation: ExtremumOperation, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> { + fn atomic_extremum( + &mut self, + operation: ExtremumOperation, + dst: RValue<'gcc>, + src: RValue<'gcc>, + order: AtomicOrdering, + ) -> RValue<'gcc> { let size = src.get_type().get_size(); let func = self.current_func(); - let load_ordering = - match order { - // TODO(antoyo): does this make sense? - AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire, - _ => order, - }; - let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size)); - let previous_var = func.new_local(self.loc, previous_value.get_type(), "previous_value"); - let return_value = func.new_local(self.loc, previous_value.get_type(), "return_value"); - self.llbb().add_assignment(self.loc, previous_var, previous_value); - self.llbb().add_assignment(self.loc, return_value, previous_var.to_rvalue()); + let load_ordering = match order { + // TODO(antoyo): does this make sense? + AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire, + _ => order, + }; + let previous_value = + self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size)); + let previous_var = + func.new_local(self.location, previous_value.get_type(), "previous_value"); + let return_value = func.new_local(self.location, previous_value.get_type(), "return_value"); + self.llbb().add_assignment(self.location, previous_var, previous_value); + self.llbb().add_assignment(self.location, return_value, previous_var.to_rvalue()); let while_block = func.new_block("while"); let after_block = func.new_block("after_while"); - self.llbb().end_with_jump(self.loc, while_block); + self.llbb().end_with_jump(self.location, while_block); // NOTE: since jumps were added and compare_exchange doesn't expect this, the current block in the // state need to be updated. self.switch_to_block(while_block); - let comparison_operator = - match operation { - ExtremumOperation::Max => ComparisonOp::LessThan, - ExtremumOperation::Min => ComparisonOp::GreaterThan, - }; - - let cond1 = self.context.new_comparison(self.loc, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(self.loc, src, previous_value.get_type())); - let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false); - let cond2 = self.cx.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); - let cond = self.cx.context.new_binary_op(self.loc, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); + let comparison_operator = match operation { + ExtremumOperation::Max => ComparisonOp::LessThan, + ExtremumOperation::Min => ComparisonOp::GreaterThan, + }; - while_block.end_with_conditional(self.loc, cond, while_block, after_block); + let cond1 = self.context.new_comparison( + self.location, + comparison_operator, + previous_var.to_rvalue(), + self.context.new_cast(self.location, src, previous_value.get_type()), + ); + let compare_exchange = + self.compare_exchange(dst, previous_var, src, order, load_ordering, false); + let cond2 = self.cx.context.new_unary_op( + self.location, + UnaryOp::LogicalNegate, + compare_exchange.get_type(), + compare_exchange, + ); + let cond = self.cx.context.new_binary_op( + self.location, + BinaryOp::LogicalAnd, + self.cx.bool_type, + cond1, + cond2, + ); + + while_block.end_with_conditional(self.location, cond, while_block, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -119,29 +129,48 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { return_value.to_rvalue() } - fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { + fn compare_exchange( + &self, + dst: RValue<'gcc>, + cmp: LValue<'gcc>, + src: RValue<'gcc>, + order: AtomicOrdering, + failure_order: AtomicOrdering, + weak: bool, + ) -> RValue<'gcc> { let size = src.get_type().get_size(); - let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size)); + let compare_exchange = + self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size)); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc()); let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32); let void_ptr_type = self.context.new_type::<*mut ()>(); let volatile_void_ptr_type = void_ptr_type.make_volatile(); - let dst = self.context.new_cast(self.loc, dst, volatile_void_ptr_type); - let expected = self.context.new_cast(self.loc, cmp.get_address(self.loc), void_ptr_type); + let dst = self.context.new_cast(self.location, dst, volatile_void_ptr_type); + let expected = + self.context.new_cast(self.location, cmp.get_address(self.location), void_ptr_type); // NOTE: not sure why, but we have the wrong type here. let int_type = compare_exchange.get_param(2).to_rvalue().get_type(); - let src = self.context.new_cast(self.loc, src, int_type); - self.context.new_call(self.loc, compare_exchange, &[dst, expected, src, weak, order, failure_order]) + let src = self.context.new_cast(self.location, src, int_type); + self.context.new_call( + self.location, + compare_exchange, + &[dst, expected, src, weak, order, failure_order], + ) } pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) { - self.llbb().add_assignment(self.loc, lvalue, value); + self.llbb().add_assignment(self.location, lvalue, value); } - fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { + fn check_call<'b>( + &mut self, + _typ: &str, + func: Function<'gcc>, + args: &'b [RValue<'gcc>], + ) -> Cow<'b, [RValue<'gcc>]> { let mut all_args_match = true; let mut param_types = vec![]; let param_count = func.get_param_count(); @@ -166,8 +195,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let actual_ty = actual_val.get_type(); if expected_ty != actual_ty { self.bitcast(actual_val, expected_ty) - } - else { + } else { actual_val } }) @@ -178,7 +206,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { Cow::Owned(casted_args) } - fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { + fn check_ptr_call<'b>( + &mut self, + _typ: &str, + func_ptr: RValue<'gcc>, + args: &'b [RValue<'gcc>], + ) -> Cow<'b, [RValue<'gcc>]> { let mut all_args_match = true; let mut param_types = vec![]; let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); @@ -212,20 +245,32 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let actual_ty = actual_val.get_type(); if expected_ty != actual_ty { - if !actual_ty.is_vector() && !expected_ty.is_vector() && (actual_ty.is_integral() && expected_ty.is_integral()) || (actual_ty.get_pointee().is_some() && expected_ty.get_pointee().is_some()) { - self.context.new_cast(self.loc, actual_val, expected_ty) - } - else if on_stack_param_indices.contains(&index) { - actual_val.dereference(self.loc).to_rvalue() - } - else { - assert!(!((actual_ty.is_vector() && !expected_ty.is_vector()) || (!actual_ty.is_vector() && expected_ty.is_vector())), "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", actual_ty, actual_ty.is_vector(), expected_ty, expected_ty.is_vector(), func_ptr, index); + if !actual_ty.is_vector() + && !expected_ty.is_vector() + && (actual_ty.is_integral() && expected_ty.is_integral()) + || (actual_ty.get_pointee().is_some() + && expected_ty.get_pointee().is_some()) + { + self.context.new_cast(self.location, actual_val, expected_ty) + } else if on_stack_param_indices.contains(&index) { + actual_val.dereference(self.location).to_rvalue() + } else { + assert!( + !((actual_ty.is_vector() && !expected_ty.is_vector()) + || (!actual_ty.is_vector() && expected_ty.is_vector())), + "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", + actual_ty, + actual_ty.is_vector(), + expected_ty, + expected_ty.is_vector(), + func_ptr, + index + ); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. // TODO: remove bitcast now that vector types can be compared? self.bitcast(actual_val, expected_ty) } - } - else { + } else { actual_val } }) @@ -249,7 +294,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.block.get_function() } - fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + fn function_call( + &mut self, + func: RValue<'gcc>, + args: &[RValue<'gcc>], + _funclet: Option<&Funclet>, + ) -> RValue<'gcc> { // TODO(antoyo): remove when the API supports a different type for functions. let func: Function<'gcc> = self.cx.rvalue_as_function(func); let args = self.check_call("call", func, args); @@ -261,35 +311,54 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let current_func = self.block.get_function(); if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; - let result = current_func.new_local(self.loc, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(self.loc, result, self.cx.context.new_call(self.loc, func, &args)); + let result = current_func.new_local( + self.location, + return_type, + &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }), + ); + self.block.add_assignment( + self.location, + result, + self.cx.context.new_call(self.location, func, &args), + ); result.to_rvalue() - } - else { - self.block.add_eval(self.loc, self.cx.context.new_call(self.loc, func, &args)); + } else { + self.block + .add_eval(self.location, self.cx.context.new_call(self.location, func, &args)); // Return dummy value when not having return value. self.context.new_rvalue_from_long(self.isize_type, 0) } } - fn function_ptr_call(&mut self, typ: Type<'gcc>, mut func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { - let gcc_func = - match func_ptr.get_type().dyncast_function_ptr_type() { - Some(func) => func, - None => { - // NOTE: due to opaque pointers now being used, we need to cast here. - let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); - func_ptr = self.context.new_cast(self.loc, func_ptr, typ); - new_func_type - }, - }; + fn function_ptr_call( + &mut self, + typ: Type<'gcc>, + mut func_ptr: RValue<'gcc>, + args: &[RValue<'gcc>], + _funclet: Option<&Funclet>, + ) -> RValue<'gcc> { + let gcc_func = match func_ptr.get_type().dyncast_function_ptr_type() { + Some(func) => func, + None => { + // NOTE: due to opaque pointers now being used, we need to cast here. + let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); + func_ptr = self.context.new_cast(self.location, func_ptr, typ); + new_func_type + } + }; let func_name = format!("{:?}", func_ptr); let previous_arg_count = args.len(); let orig_args = args; let args = { let function_address_names = self.function_address_names.borrow(); let original_function_name = function_address_names.get(&func_ptr); - llvm::adjust_intrinsic_arguments(&self, gcc_func, args.into(), &func_name, original_function_name) + llvm::adjust_intrinsic_arguments( + &self, + gcc_func, + args.into(), + &func_name, + original_function_name, + ) }; let args_adjusted = args.len() != previous_arg_count; let args = self.check_ptr_call("call", func_ptr, &*args); @@ -302,39 +371,78 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; - let return_value = self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args); - let return_value = llvm::adjust_intrinsic_return_value(&self, return_value, &func_name, &args, args_adjusted, orig_args); - let result = current_func.new_local(self.loc, return_value.get_type(), &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(self.loc, result, return_value); + let return_value = self.cx.context.new_call_through_ptr(self.location, func_ptr, &args); + let return_value = llvm::adjust_intrinsic_return_value( + &self, + return_value, + &func_name, + &args, + args_adjusted, + orig_args, + ); + let result = current_func.new_local( + self.location, + return_value.get_type(), + &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT }), + ); + self.block.add_assignment(self.location, result, return_value); result.to_rvalue() - } - else { - #[cfg(not(feature="master"))] + } else { + #[cfg(not(feature = "master"))] if gcc_func.get_param_count() == 0 { // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. - self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &[])); - } - else { - self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args)); + self.block.add_eval( + self.location, + self.cx.context.new_call_through_ptr(self.location, func_ptr, &[]), + ); + } else { + self.block.add_eval( + self.location, + self.cx.context.new_call_through_ptr(self.location, func_ptr, &args), + ); } - #[cfg(feature="master")] - self.block.add_eval(self.loc, self.cx.context.new_call_through_ptr(self.loc, func_ptr, &args)); + #[cfg(feature = "master")] + self.block.add_eval( + self.location, + self.cx.context.new_call_through_ptr(self.location, func_ptr, &args), + ); // Return dummy value when not having return value. - let result = current_func.new_local(self.loc, self.isize_type, "dummyValueThatShouldNeverBeUsed"); - self.block.add_assignment(self.loc, result, self.context.new_rvalue_from_long(self.isize_type, 0)); + let result = current_func.new_local( + self.location, + self.isize_type, + "dummyValueThatShouldNeverBeUsed", + ); + self.block.add_assignment( + self.location, + result, + self.context.new_rvalue_from_long(self.isize_type, 0), + ); result.to_rvalue() } } - pub fn overflow_call(&self, func: Function<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + pub fn overflow_call( + &self, + func: Function<'gcc>, + args: &[RValue<'gcc>], + _funclet: Option<&Funclet>, + ) -> RValue<'gcc> { // gccjit requires to use the result of functions, even when it's not used. // That's why we assign the result to a local. let return_type = self.context.new_type::(); let current_func = self.block.get_function(); // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects. unsafe { RETURN_VALUE_COUNT += 1 }; - let result = current_func.new_local(self.loc, return_type, &format!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - self.block.add_assignment(self.loc, result, self.cx.context.new_call(self.loc, func, &args)); + let result = current_func.new_local( + self.location, + return_type, + &format!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT }), + ); + self.block.add_assignment( + self.location, + result, + self.cx.context.new_call(self.location, func, &args), + ); result.to_rvalue() } } @@ -398,13 +506,15 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { type DIVariable = as BackendTypes>::DIVariable; } -pub fn set_rval_location<'a, 'gcc, 'tcx>(bx: &mut Builder<'a,'gcc,'tcx>, rvalue:RValue<'gcc>) -> RValue<'gcc> { - if bx.loc.is_some(){ +fn set_rvalue_location<'a, 'gcc, 'tcx>( + bx: &mut Builder<'a, 'gcc, 'tcx>, + rvalue: RValue<'gcc>, +) -> RValue<'gcc> { + if bx.location.is_some() { #[cfg(feature = "master")] - rvalue.set_location(bx.loc.unwrap()); + rvalue.set_location(bx.location.unwrap()); } rvalue - } impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { @@ -431,43 +541,58 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn ret_void(&mut self) { - self.llbb().end_with_void_return(self.loc) + self.llbb().end_with_void_return(self.location) } fn ret(&mut self, mut value: RValue<'gcc>) { if self.structs_as_pointer.borrow().contains(&value) { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - value = value.dereference(self.loc).to_rvalue(); + value = value.dereference(self.location).to_rvalue(); } let expected_return_type = self.current_func().get_return_type(); if !expected_return_type.is_compatible_with(value.get_type()) { // NOTE: due to opaque pointers now being used, we need to cast here. - value = self.context.new_cast(self.loc, value, expected_return_type); + value = self.context.new_cast(self.location, value, expected_return_type); } - self.llbb().end_with_return(self.loc, value); + self.llbb().end_with_return(self.location, value); } fn br(&mut self, dest: Block<'gcc>) { - self.llbb().end_with_jump(self.loc, dest) + self.llbb().end_with_jump(self.location, dest) } fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) { - self.llbb().end_with_conditional(self.loc, cond, then_block, else_block) + self.llbb().end_with_conditional(self.location, cond, then_block, else_block) } - fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator)>) { + fn switch( + &mut self, + value: RValue<'gcc>, + default_block: Block<'gcc>, + cases: impl ExactSizeIterator)>, + ) { let mut gcc_cases = vec![]; let typ = self.val_ty(value); for (on_val, dest) in cases { let on_val = self.const_uint_big(typ, on_val); gcc_cases.push(self.context.new_case(on_val, on_val, dest)); } - self.block.end_with_switch(self.loc, value, default_block, &gcc_cases); + self.block.end_with_switch(self.location, value, default_block, &gcc_cases); } - #[cfg(feature="master")] - fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + #[cfg(feature = "master")] + fn invoke( + &mut self, + typ: Type<'gcc>, + fn_attrs: Option<&CodegenFnAttrs>, + _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + func: RValue<'gcc>, + args: &[RValue<'gcc>], + then: Block<'gcc>, + catch: Block<'gcc>, + _funclet: Option<&Funclet>, + ) -> RValue<'gcc> { let try_block = self.current_func().new_block("try"); let current_block = self.block.clone(); @@ -475,30 +600,39 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let call = self.call(typ, fn_attrs, None, func, args, None); // TODO(antoyo): use funclet here? self.block = current_block; - let return_value = self.current_func() - .new_local(self.loc, call.get_type(), "invokeResult"); + let return_value = + self.current_func().new_local(self.location, call.get_type(), "invokeResult"); - try_block.add_assignment(self.loc, return_value, call); + try_block.add_assignment(self.location, return_value, call); - try_block.end_with_jump(self.loc, then); + try_block.end_with_jump(self.location, then); if self.cleanup_blocks.borrow().contains(&catch) { - self.block.add_try_finally(self.loc, try_block, catch); - } - else { - self.block.add_try_catch(self.loc, try_block, catch); + self.block.add_try_finally(self.location, try_block, catch); + } else { + self.block.add_try_catch(self.location, try_block, catch); } - self.block.end_with_jump(self.loc, then); + self.block.end_with_jump(self.location, then); return_value.to_rvalue() } - #[cfg(not(feature="master"))] - fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + #[cfg(not(feature = "master"))] + fn invoke( + &mut self, + typ: Type<'gcc>, + fn_attrs: Option<&CodegenFnAttrs>, + fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + func: RValue<'gcc>, + args: &[RValue<'gcc>], + then: Block<'gcc>, + catch: Block<'gcc>, + _funclet: Option<&Funclet>, + ) -> RValue<'gcc> { let call_site = self.call(typ, fn_attrs, None, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); - self.llbb().end_with_conditional(self.loc, condition, then, catch); + self.llbb().end_with_conditional(self.location, condition, then, catch); if let Some(_fn_abi) = fn_abi { // TODO(bjorn3): Apply function attributes } @@ -507,16 +641,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn unreachable(&mut self) { let func = self.context.get_builtin_function("__builtin_unreachable"); - self.block.add_eval(self.loc, self.context.new_call(self.loc, func, &[])); + self.block.add_eval(self.location, self.context.new_call(self.location, func, &[])); let return_type = self.block.get_function().get_return_type(); let void_type = self.context.new_type::<()>(); if return_type == void_type { - self.block.end_with_void_return(self.loc) - } - else { - let return_value = self.current_func() - .new_local(self.loc, return_type, "unreachableReturn"); - self.block.end_with_return(self.loc, return_value) + self.block.end_with_void_return(self.location) + } else { + let return_value = + self.current_func().new_local(self.location, return_type, "unreachableReturn"); + self.block.end_with_return(self.location, return_value) } } @@ -541,7 +674,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.cx.context.new_binary_op(self.loc, BinaryOp::Mult, a.get_type(), a, b) + self.cx.context.new_binary_op(self.location, BinaryOp::Mult, a.get_type(), a, b) } fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -566,7 +699,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they // should be the same. let typ = a.get_type().to_signed(self); - let b = self.context.new_cast(self.loc, b, typ); + let b = self.context.new_cast(self.location, b, typ); a / b } @@ -613,7 +746,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { if a_type.is_compatible_with(self.cx.float_type) { let fmodf = self.context.get_builtin_function("fmodf"); // FIXME(antoyo): this seems to produce the wrong result. - return self.context.new_call(self.loc, fmodf, &[a, b]); + return self.context.new_call(self.location, fmodf, &[a, b]); } if let Some(vector_type) = a_type_unqualified.dyncast_vector() { assert_eq!(a_type_unqualified, b.get_type().unqualified()); @@ -628,12 +761,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }) .collect(); - return self.context.new_rvalue_from_vector(self.loc, a_type, &new_elements) + return self.context.new_rvalue_from_vector(self.location, a_type, &new_elements); } assert_eq!(a_type_unqualified, self.cx.double_type); let fmod = self.context.get_builtin_function("fmod"); - self.context.new_call(self.loc, fmod, &[a, b]) + self.context.new_call(self.location, fmod, &[a, b]) } fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -655,94 +788,107 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.cx.gcc_or(a, b, self.loc) + self.cx.gcc_or(a, b, self.location) } fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_xor(a, b)) + set_rvalue_location(self, self.gcc_xor(a, b)) } fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_neg(a)) + set_rvalue_location(self, self.gcc_neg(a)) } fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a)) + set_rvalue_location( + self, + self.cx.context.new_unary_op(self.location, UnaryOp::Minus, a.get_type(), a), + ) } fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_not(a)) + set_rvalue_location(self, self.gcc_not(a)) } fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_add(a, b)) + set_rvalue_location(self, self.gcc_add(a, b)) } fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_add(a, b)) + set_rvalue_location(self, self.gcc_add(a, b)) } fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_sub(a, b)) + set_rvalue_location(self, self.gcc_sub(a, b)) } fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { // TODO(antoyo): should generate poison value? - set_rval_location(self, self.gcc_sub(a, b)) + set_rvalue_location(self, self.gcc_sub(a, b)) } fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_mul(a, b)) + set_rvalue_location(self, self.gcc_mul(a, b)) } fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_mul(a, b)) + set_rvalue_location(self, self.gcc_mul(a, b)) } fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self, lhs + rhs) + set_rvalue_location(self, lhs + rhs) } fn fsub_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self, lhs - rhs) + set_rvalue_location(self, lhs - rhs) } fn fmul_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self, lhs * rhs) + set_rvalue_location(self, lhs * rhs) } fn fdiv_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. - set_rval_location(self, lhs / rhs) + set_rvalue_location(self, lhs / rhs) } fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. let result = self.frem(lhs, rhs); - set_rval_location(self, result); + set_rvalue_location(self, result); result } - fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { + fn checked_binop( + &mut self, + oop: OverflowOp, + typ: Ty<'_>, + lhs: Self::Value, + rhs: Self::Value, + ) -> (Self::Value, Self::Value) { self.gcc_checked_binop(oop, typ, lhs, rhs) } fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> { // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. // Ideally, we shouldn't need to do this check. - let aligned_type = - if ty == self.cx.u128_type || ty == self.cx.i128_type { - ty - } - else { - ty.get_aligned(align.bytes()) - }; + let aligned_type = if ty == self.cx.u128_type || ty == self.cx.i128_type { + ty + } else { + ty.get_aligned(align.bytes()) + }; // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. self.stack_var_count.set(self.stack_var_count.get() + 1); - self.current_func().new_local(self.loc, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(self.loc) + self.current_func() + .new_local( + self.location, + aligned_type, + &format!("stack_var_{}", self.stack_var_count.get()), + ) + .get_address(self.location) } fn byte_array_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { @@ -757,48 +903,62 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // dereference after a drop, for instance. // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. // Ideally, we shouldn't need to do this check. - let aligned_type = - if pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type { - pointee_ty - } - else { - pointee_ty.get_aligned(align.bytes()) - }; - let ptr = self.context.new_cast(self.loc, ptr, aligned_type.make_pointer()); - let deref = ptr.dereference(self.loc).to_rvalue(); + let aligned_type = if pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type { + pointee_ty + } else { + pointee_ty.get_aligned(align.bytes()) + }; + let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer()); + let deref = ptr.dereference(self.location).to_rvalue(); unsafe { RETURN_VALUE_COUNT += 1 }; - let loaded_value = function.new_local(self.loc, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); - block.add_assignment(self.loc, loaded_value, deref); + let loaded_value = function.new_local( + self.location, + aligned_type, + &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }), + ); + block.add_assignment(self.location, loaded_value, deref); loaded_value.to_rvalue() } fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { - let ptr = self.context.new_cast(self.loc, ptr, ty.make_volatile().make_pointer()); - ptr.dereference(self.loc).to_rvalue() + let ptr = self.context.new_cast(self.location, ptr, ty.make_volatile().make_pointer()); + ptr.dereference(self.location).to_rvalue() } - fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> { + fn atomic_load( + &mut self, + _ty: Type<'gcc>, + ptr: RValue<'gcc>, + order: AtomicOrdering, + size: Size, + ) -> RValue<'gcc> { // TODO(antoyo): use ty. // TODO(antoyo): handle alignment. - let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); + let atomic_load = + self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - let volatile_const_void_ptr_type = self.context.new_type::<()>() - .make_const() - .make_volatile() - .make_pointer(); - let ptr = self.context.new_cast(self.loc, ptr, volatile_const_void_ptr_type); - self.context.new_call(self.loc, atomic_load, &[ptr, ordering]) + let volatile_const_void_ptr_type = + self.context.new_type::<()>().make_const().make_volatile().make_pointer(); + let ptr = self.context.new_cast(self.location, ptr, volatile_const_void_ptr_type); + self.context.new_call(self.location, atomic_load, &[ptr, ordering]) } - fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> { + fn load_operand( + &mut self, + place: PlaceRef<'tcx, RValue<'gcc>>, + ) -> OperandRef<'tcx, RValue<'gcc>> { assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { return OperandRef::zero_sized(place.layout); } - fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) { + fn scalar_load_metadata<'a, 'gcc, 'tcx>( + bx: &mut Builder<'a, 'gcc, 'tcx>, + load: RValue<'gcc>, + scalar: &abi::Scalar, + ) { let vr = scalar.valid_range(bx); match scalar.primitive() { abi::Int(..) => { @@ -813,46 +973,47 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } } - let val = - if let Some(llextra) = place.llextra { - OperandValue::Ref(place.llval, Some(llextra), place.align) + let val = if let Some(llextra) = place.llextra { + OperandValue::Ref(place.llval, Some(llextra), place.align) + } else if place.layout.is_gcc_immediate() { + let load = self.load(place.layout.gcc_type(self), place.llval, place.align); + if let abi::Abi::Scalar(ref scalar) = place.layout.abi { + scalar_load_metadata(self, load, scalar); } - else if place.layout.is_gcc_immediate() { - let load = self.load( - place.layout.gcc_type(self), - place.llval, - place.align, - ); - if let abi::Abi::Scalar(ref scalar) = place.layout.abi { - scalar_load_metadata(self, load, scalar); + OperandValue::Immediate(self.to_immediate(load, place.layout)) + } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { + let b_offset = a.size(self).align_to(b.align(self).abi); + let pair_type = place.layout.gcc_type(self); + + let mut load = |i, scalar: &abi::Scalar, align| { + let llptr = self.struct_gep(pair_type, place.llval, i as u64); + let llty = place.layout.scalar_pair_element_gcc_type(self, i); + let load = self.load(llty, llptr, align); + scalar_load_metadata(self, load, scalar); + if scalar.is_bool() { + self.trunc(load, self.type_i1()) + } else { + load } - OperandValue::Immediate(self.to_immediate(load, place.layout)) - } - else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { - let b_offset = a.size(self).align_to(b.align(self).abi); - let pair_type = place.layout.gcc_type(self); - - let mut load = |i, scalar: &abi::Scalar, align| { - let llptr = self.struct_gep(pair_type, place.llval, i as u64); - let llty = place.layout.scalar_pair_element_gcc_type(self, i); - let load = self.load(llty, llptr, align); - scalar_load_metadata(self, load, scalar); - if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } - }; - - OperandValue::Pair( - load(0, a, place.align), - load(1, b, place.align.restrict_for_offset(b_offset)), - ) - } - else { - OperandValue::Ref(place.llval, None, place.align) }; + OperandValue::Pair( + load(0, a, place.align), + load(1, b, place.align.restrict_for_offset(b_offset)), + ) + } else { + OperandValue::Ref(place.llval, None, place.align) + }; + OperandRef { val, layout: place.layout } } - fn write_operand_repeatedly(&mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) { + fn write_operand_repeatedly( + &mut self, + cg_elem: OperandRef<'tcx, RValue<'gcc>>, + count: u64, + dest: PlaceRef<'tcx, RValue<'gcc>>, + ) { let zero = self.const_usize(0); let count = self.const_usize(count); let start = dest.project_index(self, zero).llval; @@ -863,7 +1024,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let next_bb = self.append_sibling_block("repeat_loop_next"); let ptr_type = start.get_type(); - let current = self.llbb().get_function().new_local(self.loc, ptr_type, "loop_var"); + let current = self.llbb().get_function().new_local(self.location, ptr_type, "loop_var"); let current_val = current.to_rvalue(); self.assign(current, start); @@ -877,8 +1038,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); - let next = self.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]); - self.llbb().add_assignment(self.loc, current, next); + let next = self.inbounds_gep( + self.backend_type(cg_elem.layout), + current.to_rvalue(), + &[self.const_usize(1)], + ); + self.llbb().add_assignment(self.location, current, next); self.br(header_bb); self.switch_to_block(next_bb); @@ -896,100 +1061,127 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.store_with_flags(val, ptr, align, MemFlags::empty()) } - fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align, _flags: MemFlags) -> RValue<'gcc> { + fn store_with_flags( + &mut self, + val: RValue<'gcc>, + ptr: RValue<'gcc>, + align: Align, + _flags: MemFlags, + ) -> RValue<'gcc> { let ptr = self.check_store(val, ptr); - let destination = ptr.dereference(self.loc); + let destination = ptr.dereference(self.location); // NOTE: libgccjit does not support specifying the alignment on the assignment, so we cast // to type so it gets the proper alignment. let destination_type = destination.to_rvalue().get_type().unqualified(); let aligned_type = destination_type.get_aligned(align.bytes()).make_pointer(); - let aligned_destination = self.cx.context.new_bitcast(self.loc, ptr, aligned_type); - let aligned_destination = aligned_destination.dereference(self.loc); - self.llbb().add_assignment(self.loc, aligned_destination, val); + let aligned_destination = self.cx.context.new_bitcast(self.location, ptr, aligned_type); + let aligned_destination = aligned_destination.dereference(self.location); + self.llbb().add_assignment(self.location, aligned_destination, val); // TODO(antoyo): handle align and flags. // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here? self.cx.context.new_rvalue_zero(self.type_i32()) } - fn atomic_store(&mut self, value: RValue<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) { + fn atomic_store( + &mut self, + value: RValue<'gcc>, + ptr: RValue<'gcc>, + order: AtomicOrdering, + size: Size, + ) { // TODO(antoyo): handle alignment. - let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); + let atomic_store = + self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - let volatile_const_void_ptr_type = self.context.new_type::<()>() - .make_volatile() - .make_pointer(); - let ptr = self.context.new_cast(self.loc, ptr, volatile_const_void_ptr_type); + let volatile_const_void_ptr_type = + self.context.new_type::<()>().make_volatile().make_pointer(); + let ptr = self.context.new_cast(self.location, ptr, volatile_const_void_ptr_type); // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because // the following cast is required to avoid this error: // gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int __attribute__((aligned(4)))) let int_type = atomic_store.get_param(1).to_rvalue().get_type(); - let value = self.context.new_cast(self.loc, value, int_type); - self.llbb() - .add_eval(self.loc, self.context.new_call(self.loc, atomic_store, &[ptr, value, ordering])); + let value = self.context.new_cast(self.location, value, int_type); + self.llbb().add_eval( + self.location, + self.context.new_call(self.location, atomic_store, &[ptr, value, ordering]), + ); } - fn gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + fn gep( + &mut self, + typ: Type<'gcc>, + ptr: RValue<'gcc>, + indices: &[RValue<'gcc>], + ) -> RValue<'gcc> { // NOTE: due to opaque pointers now being used, we need to cast here. - let ptr = self.context.new_cast(self.loc, ptr, typ.make_pointer()); + let ptr = self.context.new_cast(self.location, ptr, typ.make_pointer()); let ptr_type = ptr.get_type(); let mut pointee_type = ptr.get_type(); // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is // always considered in bounds in GCC (TODO(antoyo): to be verified). // So, we have to cast to a number. - let mut result = self.context.new_bitcast(self.loc, ptr, self.sizet_type); + let mut result = self.context.new_bitcast(self.location, ptr, self.sizet_type); // FIXME(antoyo): if there were more than 1 index, this code is probably wrong and would // require dereferencing the pointer. for index in indices { pointee_type = pointee_type.get_pointee().expect("pointee type"); - #[cfg(feature="master")] + #[cfg(feature = "master")] let pointee_size = { let size = self.cx.context.new_sizeof(pointee_type); - self.context.new_cast(self.loc, size, index.get_type()) + self.context.new_cast(self.location, size, index.get_type()) }; - #[cfg(not(feature="master"))] - let pointee_size = self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32); + #[cfg(not(feature = "master"))] + let pointee_size = + self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32); result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type); } - self.context.new_bitcast(self.loc, result, ptr_type) + self.context.new_bitcast(self.location, result, ptr_type) } - fn inbounds_gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + fn inbounds_gep( + &mut self, + typ: Type<'gcc>, + ptr: RValue<'gcc>, + indices: &[RValue<'gcc>], + ) -> RValue<'gcc> { // NOTE: due to opaque pointers now being used, we need to cast here. - let ptr = self.context.new_cast(self.loc, ptr, typ.make_pointer()); + let ptr = self.context.new_cast(self.location, ptr, typ.make_pointer()); // NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified). let mut indices = indices.into_iter(); let index = indices.next().expect("first index in inbounds_gep"); - let mut result = self.context.new_array_access(self.loc, ptr, *index); + let mut result = self.context.new_array_access(self.location, ptr, *index); for index in indices { - result = self.context.new_array_access(self.loc, result, *index); + result = self.context.new_array_access(self.location, result, *index); } - result.get_address(self.loc) + result.get_address(self.location) } fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> { // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. assert_eq!(idx as usize as u64, idx); - let value = ptr.dereference(self.loc).to_rvalue(); + let value = ptr.dereference(self.location).to_rvalue(); if value_type.dyncast_array().is_some() { - let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(self.loc, value, index); - element.get_address(self.loc) - } - else if let Some(vector_type) = value_type.dyncast_vector() { + let index = self + .context + .new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(self.location, value, index); + element.get_address(self.location) + } else if let Some(vector_type) = value_type.dyncast_vector() { let array_type = vector_type.get_element_type().make_pointer(); let array = self.bitcast(ptr, array_type); - let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(self.loc, array, index); - element.get_address(self.loc) - } - else if let Some(struct_type) = value_type.is_struct() { + let index = self + .context + .new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(self.location, array, index); + element.get_address(self.location) + } else if let Some(struct_type) = value_type.is_struct() { // NOTE: due to opaque pointers now being used, we need to bitcast here. let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer()); - ptr.dereference_field(self.loc, struct_type.get_field(idx as i32)).get_address(self.loc) - } - else { + ptr.dereference_field(self.location, struct_type.get_field(idx as i32)) + .get_address(self.location) + } else { panic!("Unexpected type {:?}", value_type); } } @@ -1006,32 +1198,32 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): nothing to do as it is only for LLVM? return value; } - self.context.new_cast(self.loc, value, dest_ty) + self.context.new_cast(self.location, value, dest_ty) } fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_float_to_uint_cast(value, dest_ty)) + set_rvalue_location(self, self.gcc_float_to_uint_cast(value, dest_ty)) } fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_float_to_int_cast(value, dest_ty)) + set_rvalue_location(self, self.gcc_float_to_int_cast(value, dest_ty)) } fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_uint_to_float_cast(value, dest_ty)) + set_rvalue_location(self, self.gcc_uint_to_float_cast(value, dest_ty)) } fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.gcc_int_to_float_cast(value, dest_ty)) + set_rvalue_location(self, self.gcc_int_to_float_cast(value, dest_ty)) } fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): make sure it truncates. - set_rval_location(self, self.context.new_cast(self.loc, value, dest_ty)) + set_rvalue_location(self, self.context.new_cast(self.location, value, dest_ty)) } fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - set_rval_location(self, self.context.new_cast(self.loc, value, dest_ty)) + set_rvalue_location(self, self.context.new_cast(self.location, value, dest_ty)) } fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { @@ -1048,7 +1240,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.cx.const_bitcast(value, dest_ty) } - fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> { + fn intcast( + &mut self, + value: RValue<'gcc>, + dest_typ: Type<'gcc>, + _is_signed: bool, + ) -> RValue<'gcc> { // NOTE: is_signed is for value, not dest_typ. self.gcc_int_cast(value, dest_typ) } @@ -1059,13 +1256,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (false, true) => { // NOTE: Projecting a field of a pointer type will attempt a cast from a signed char to // a pointer, which is not supported by gccjit. - self.cx.context.new_cast(self.loc, self.inttoptr(value, val_type.make_pointer()), dest_ty) - }, + self.cx.context.new_cast( + self.location, + self.inttoptr(value, val_type.make_pointer()), + dest_ty, + ) + } (false, false) => { // When they are not pointers, we want a transmute (or reinterpret_cast). self.bitcast(value, dest_ty) - }, - (true, true) => self.cx.context.new_cast(self.loc, value, dest_ty), + } + (true, true) => self.cx.context.new_cast(self.location, value, dest_ty), (true, false) => unimplemented!(), } } @@ -1076,11 +1277,19 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { - self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) + self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs) } /* Miscellaneous instructions */ - fn memcpy(&mut self, dst: RValue<'gcc>, _dst_align: Align, src: RValue<'gcc>, _src_align: Align, size: RValue<'gcc>, flags: MemFlags) { + fn memcpy( + &mut self, + dst: RValue<'gcc>, + _dst_align: Align, + src: RValue<'gcc>, + _src_align: Align, + size: RValue<'gcc>, + flags: MemFlags, + ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported"); let size = self.intcast(size, self.type_size_t(), false); let _is_volatile = flags.contains(MemFlags::VOLATILE); @@ -1088,10 +1297,21 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let src = self.pointercast(src, self.type_ptr_to(self.type_void())); let memcpy = self.context.get_builtin_function("memcpy"); // TODO(antoyo): handle aligns and is_volatile. - self.block.add_eval(self.loc, self.context.new_call(self.loc, memcpy, &[dst, src, size])); + self.block.add_eval( + self.location, + self.context.new_call(self.location, memcpy, &[dst, src, size]), + ); } - fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) { + fn memmove( + &mut self, + dst: RValue<'gcc>, + dst_align: Align, + src: RValue<'gcc>, + src_align: Align, + size: RValue<'gcc>, + flags: MemFlags, + ) { if flags.contains(MemFlags::NONTEMPORAL) { // HACK(nox): This is inefficient but there is no nontemporal memmove. let val = self.load(src.get_type().get_pointee().expect("get_pointee"), src, src_align); @@ -1106,35 +1326,53 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let memmove = self.context.get_builtin_function("memmove"); // TODO(antoyo): handle is_volatile. - self.block.add_eval(self.loc, self.context.new_call(self.loc, memmove, &[dst, src, size])); + self.block.add_eval( + self.location, + self.context.new_call(self.location, memmove, &[dst, src, size]), + ); } - fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) { + fn memset( + &mut self, + ptr: RValue<'gcc>, + fill_byte: RValue<'gcc>, + size: RValue<'gcc>, + _align: Align, + flags: MemFlags, + ) { let _is_volatile = flags.contains(MemFlags::VOLATILE); let ptr = self.pointercast(ptr, self.type_i8p()); let memset = self.context.get_builtin_function("memset"); // TODO(antoyo): handle align and is_volatile. - let fill_byte = self.context.new_cast(self.loc, fill_byte, self.i32_type); + let fill_byte = self.context.new_cast(self.location, fill_byte, self.i32_type); let size = self.intcast(size, self.type_size_t(), false); - self.block.add_eval(self.loc, self.context.new_call(self.loc, memset, &[ptr, fill_byte, size])); + self.block.add_eval( + self.location, + self.context.new_call(self.location, memset, &[ptr, fill_byte, size]), + ); } - fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> { + fn select( + &mut self, + cond: RValue<'gcc>, + then_val: RValue<'gcc>, + mut else_val: RValue<'gcc>, + ) -> RValue<'gcc> { let func = self.current_func(); - let variable = func.new_local(self.loc, then_val.get_type(), "selectVar"); + let variable = func.new_local(self.location, then_val.get_type(), "selectVar"); let then_block = func.new_block("then"); let else_block = func.new_block("else"); let after_block = func.new_block("after"); - self.llbb().end_with_conditional(self.loc, cond, then_block, else_block); + self.llbb().end_with_conditional(self.location, cond, then_block, else_block); - then_block.add_assignment(self.loc, variable, then_val); - then_block.end_with_jump(self.loc, after_block); + then_block.add_assignment(self.location, variable, then_val); + then_block.end_with_jump(self.location, after_block); if !then_val.get_type().is_compatible_with(else_val.get_type()) { - else_val = self.context.new_cast(self.loc, else_val, then_val.get_type()); + else_val = self.context.new_cast(self.location, else_val, then_val.get_type()); } - else_block.add_assignment(self.loc, variable, else_val); - else_block.end_with_jump(self.loc, after_block); + else_block.add_assignment(self.location, variable, else_val); + else_block.end_with_jump(self.location, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -1148,19 +1386,24 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - #[cfg(feature="master")] + #[cfg(feature = "master")] fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> { - self.context.new_vector_access(self.loc, vec, idx).to_rvalue() + self.context.new_vector_access(self.location, vec, idx).to_rvalue() } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> { - let vector_type = vec.get_type().unqualified().dyncast_vector().expect("Called extract_element on a non-vector type"); + let vector_type = vec + .get_type() + .unqualified() + .dyncast_vector() + .expect("Called extract_element on a non-vector type"); let element_type = vector_type.get_element_type(); let vec_num_units = vector_type.get_num_units(); - let array_type = self.context.new_array_type(self.loc, element_type, vec_num_units as u64); - let array = self.context.new_bitcast(self.loc, vec, array_type).to_rvalue(); - self.context.new_array_access(self.loc, array, idx).to_rvalue() + let array_type = + self.context.new_array_type(self.location, element_type, vec_num_units as u64); + let array = self.context.new_bitcast(self.location, vec, array_type).to_rvalue(); + self.context.new_array_access(self.location, array, idx).to_rvalue() } fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> { @@ -1173,82 +1416,85 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let value_type = aggregate_value.get_type(); if value_type.dyncast_array().is_some() { - let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - let element = self.context.new_array_access(self.loc, aggregate_value, index); - element.get_address(self.loc) - } - else if value_type.dyncast_vector().is_some() { + let index = self + .context + .new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(self.location, aggregate_value, index); + element.get_address(self.location) + } else if value_type.dyncast_vector().is_some() { panic!(); - } - else if let Some(pointer_type) = value_type.get_pointee() { + } else if let Some(pointer_type) = value_type.get_pointee() { if let Some(struct_type) = pointer_type.is_struct() { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(self.loc, struct_type.get_field(idx as i32)).to_rvalue() - } - else { + aggregate_value + .dereference_field(self.location, struct_type.get_field(idx as i32)) + .to_rvalue() + } else { panic!("Unexpected type {:?}", value_type); } - } - else if let Some(struct_type) = value_type.is_struct() { - aggregate_value.access_field(self.loc, struct_type.get_field(idx as i32)).to_rvalue() - } - else { + } else if let Some(struct_type) = value_type.is_struct() { + aggregate_value + .access_field(self.location, struct_type.get_field(idx as i32)) + .to_rvalue() + } else { panic!("Unexpected type {:?}", value_type); } } - fn insert_value(&mut self, aggregate_value: RValue<'gcc>, value: RValue<'gcc>, idx: u64) -> RValue<'gcc> { + fn insert_value( + &mut self, + aggregate_value: RValue<'gcc>, + value: RValue<'gcc>, + idx: u64, + ) -> RValue<'gcc> { // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. assert_eq!(idx as usize as u64, idx); let value_type = aggregate_value.get_type(); - let lvalue = - if value_type.dyncast_array().is_some() { - let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - self.context.new_array_access(self.loc, aggregate_value, index) - } - else if value_type.dyncast_vector().is_some() { - panic!(); - } - else if let Some(pointer_type) = value_type.get_pointee() { - if let Some(struct_type) = pointer_type.is_struct() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(self.loc, struct_type.get_field(idx as i32)) - } - else { - panic!("Unexpected type {:?}", value_type); - } - } - else { + let lvalue = if value_type.dyncast_array().is_some() { + let index = self + .context + .new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + self.context.new_array_access(self.location, aggregate_value, index) + } else if value_type.dyncast_vector().is_some() { + panic!(); + } else if let Some(pointer_type) = value_type.get_pointee() { + if let Some(struct_type) = pointer_type.is_struct() { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + aggregate_value.dereference_field(self.location, struct_type.get_field(idx as i32)) + } else { panic!("Unexpected type {:?}", value_type); - }; + } + } else { + panic!("Unexpected type {:?}", value_type); + }; let lvalue_type = lvalue.to_rvalue().get_type(); let value = // NOTE: sometimes, rustc will create a value with the wrong type. if lvalue_type != value.get_type() { - self.context.new_cast(self.loc, value, lvalue_type) + self.context.new_cast(self.location, value, lvalue_type) } else { value }; - self.llbb().add_assignment(self.loc, lvalue, value); + self.llbb().add_assignment(self.location, lvalue, value); aggregate_value } fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { - #[cfg(feature="master")] + #[cfg(feature = "master")] { let personality = self.rvalue_as_function(_personality); self.current_func().set_personality_function(personality); } } - #[cfg(feature="master")] + #[cfg(feature = "master")] fn cleanup_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { self.set_personality_fn(pers_fn); @@ -1256,23 +1502,27 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // generate a try/finally instead of a try/catch for this block. self.cleanup_blocks.borrow_mut().insert(self.block); - let eh_pointer_builtin = self.cx.context.get_target_builtin_function("__builtin_eh_pointer"); + let eh_pointer_builtin = + self.cx.context.get_target_builtin_function("__builtin_eh_pointer"); let zero = self.cx.context.new_rvalue_zero(self.int_type); - let ptr = self.cx.context.new_call(self.loc, eh_pointer_builtin, &[zero]); + let ptr = self.cx.context.new_call(self.location, eh_pointer_builtin, &[zero]); let value1_type = self.u8_type.make_pointer(); - let ptr = self.cx.context.new_cast(self.loc, ptr, value1_type); + let ptr = self.cx.context.new_cast(self.location, ptr, value1_type); let value1 = ptr; let value2 = zero; // TODO(antoyo): set the proper value here (the type of exception?). (value1, value2) } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { - let value1 = self.current_func().new_local(self.loc, self.u8_type.make_pointer(), "landing_pad0") - .to_rvalue(); - let value2 = self.current_func().new_local(self.loc, self.i32_type, "landing_pad1").to_rvalue(); + let value1 = self + .current_func() + .new_local(self.location, self.u8_type.make_pointer(), "landing_pad0") + .to_rvalue(); + let value2 = + self.current_func().new_local(self.location, self.i32_type, "landing_pad1").to_rvalue(); (value1, value2) } @@ -1281,16 +1531,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.cleanup_landing_pad(pers_fn) } - #[cfg(feature="master")] + #[cfg(feature = "master")] fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { let exn_type = exn0.get_type(); - let exn = self.context.new_cast(self.loc, exn0, exn_type); + let exn = self.context.new_cast(self.location, exn0, exn_type); let unwind_resume = self.context.get_target_builtin_function("__builtin_unwind_resume"); - self.llbb().add_eval(self.loc, self.context.new_call(self.loc, unwind_resume, &[exn])); + self.llbb() + .add_eval(self.location, self.context.new_call(self.location, unwind_resume, &[exn])); self.unreachable(); } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] fn resume(&mut self, _exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { self.unreachable(); } @@ -1317,68 +1568,82 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } // Atomic Operations - fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> (RValue<'gcc>, RValue<'gcc>) { + fn atomic_cmpxchg( + &mut self, + dst: RValue<'gcc>, + cmp: RValue<'gcc>, + src: RValue<'gcc>, + order: AtomicOrdering, + failure_order: AtomicOrdering, + weak: bool, + ) -> (RValue<'gcc>, RValue<'gcc>) { let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); self.llbb().add_assignment(None, expected, cmp); // NOTE: gcc doesn't support a failure memory model that is stronger than the success // memory model. - let order = - if failure_order as i32 > order as i32 { - failure_order - } - else { - order - }; + let order = if failure_order as i32 > order as i32 { failure_order } else { order }; let success = self.compare_exchange(dst, expected, src, order, failure_order, weak); // NOTE: since success contains the call to the intrinsic, it must be added to the basic block before // expected so that we store expected after the call. - let success_var = self.current_func().new_local(self.loc, self.bool_type, "success"); - self.llbb().add_assignment(self.loc, success_var, success); + let success_var = self.current_func().new_local(self.location, self.bool_type, "success"); + self.llbb().add_assignment(self.location, success_var, success); (expected.to_rvalue(), success_var.to_rvalue()) } - fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> { + fn atomic_rmw( + &mut self, + op: AtomicRmwBinOp, + dst: RValue<'gcc>, + src: RValue<'gcc>, + order: AtomicOrdering, + ) -> RValue<'gcc> { let size = src.get_type().get_size(); - let name = - match op { - AtomicRmwBinOp::AtomicXchg => format!("__atomic_exchange_{}", size), - AtomicRmwBinOp::AtomicAdd => format!("__atomic_fetch_add_{}", size), - AtomicRmwBinOp::AtomicSub => format!("__atomic_fetch_sub_{}", size), - AtomicRmwBinOp::AtomicAnd => format!("__atomic_fetch_and_{}", size), - AtomicRmwBinOp::AtomicNand => format!("__atomic_fetch_nand_{}", size), - AtomicRmwBinOp::AtomicOr => format!("__atomic_fetch_or_{}", size), - AtomicRmwBinOp::AtomicXor => format!("__atomic_fetch_xor_{}", size), - AtomicRmwBinOp::AtomicMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order), - AtomicRmwBinOp::AtomicMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order), - AtomicRmwBinOp::AtomicUMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order), - AtomicRmwBinOp::AtomicUMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order), - }; - + let name = match op { + AtomicRmwBinOp::AtomicXchg => format!("__atomic_exchange_{}", size), + AtomicRmwBinOp::AtomicAdd => format!("__atomic_fetch_add_{}", size), + AtomicRmwBinOp::AtomicSub => format!("__atomic_fetch_sub_{}", size), + AtomicRmwBinOp::AtomicAnd => format!("__atomic_fetch_and_{}", size), + AtomicRmwBinOp::AtomicNand => format!("__atomic_fetch_nand_{}", size), + AtomicRmwBinOp::AtomicOr => format!("__atomic_fetch_or_{}", size), + AtomicRmwBinOp::AtomicXor => format!("__atomic_fetch_xor_{}", size), + AtomicRmwBinOp::AtomicMax => { + return self.atomic_extremum(ExtremumOperation::Max, dst, src, order); + } + AtomicRmwBinOp::AtomicMin => { + return self.atomic_extremum(ExtremumOperation::Min, dst, src, order); + } + AtomicRmwBinOp::AtomicUMax => { + return self.atomic_extremum(ExtremumOperation::Max, dst, src, order); + } + AtomicRmwBinOp::AtomicUMin => { + return self.atomic_extremum(ExtremumOperation::Min, dst, src, order); + } + }; let atomic_function = self.context.get_builtin_function(name); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let void_ptr_type = self.context.new_type::<*mut ()>(); let volatile_void_ptr_type = void_ptr_type.make_volatile(); - let dst = self.context.new_cast(self.loc, dst, volatile_void_ptr_type); + let dst = self.context.new_cast(self.location, dst, volatile_void_ptr_type); // FIXME(antoyo): not sure why, but we have the wrong type here. let new_src_type = atomic_function.get_param(1).to_rvalue().get_type(); - let src = self.context.new_cast(self.loc, src, new_src_type); - let res = self.context.new_call(self.loc, atomic_function, &[dst, src, order]); - self.context.new_cast(self.loc, res, src.get_type()) + let src = self.context.new_cast(self.location, src, new_src_type); + let res = self.context.new_call(self.location, atomic_function, &[dst, src, order]); + self.context.new_cast(self.location, res, src.get_type()) } fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { - let name = - match scope { - SynchronizationScope::SingleThread => "__atomic_signal_fence", - SynchronizationScope::CrossThread => "__atomic_thread_fence", - }; + let name = match scope { + SynchronizationScope::SingleThread => "__atomic_signal_fence", + SynchronizationScope::CrossThread => "__atomic_thread_fence", + }; let thread_fence = self.context.get_builtin_function(name); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - self.llbb().add_eval(self.loc, self.context.new_call(self.loc, thread_fence, &[order])); + self.llbb() + .add_eval(self.location, self.context.new_call(self.location, thread_fence, &[order])); } fn set_invariant_load(&mut self, load: RValue<'gcc>) { @@ -1408,8 +1673,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let gcc_func = unsafe { std::mem::transmute(func) }; let call = if self.functions.borrow().values().any(|value| *value == gcc_func) { self.function_call(func, args, funclet) - } - else { + } else { // If it's a not function that was defined, it's a function pointer. self.function_ptr_call(typ, func, args, funclet) }; @@ -1442,8 +1706,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn from_immediate(&mut self, val: Self::Value) -> Self::Value { if self.cx().val_ty(val) == self.cx().type_i1() { self.zext(val, self.cx().type_i8()) - } - else { + } else { val } } @@ -1463,13 +1726,24 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.fptoint_sat(true, val, dest_ty) } - fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) { + fn instrprof_increment( + &mut self, + _fn_name: RValue<'gcc>, + _hash: RValue<'gcc>, + _num_counters: RValue<'gcc>, + _index: RValue<'gcc>, + ) { unimplemented!(); } } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { - fn fptoint_sat(&mut self, signed: bool, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + fn fptoint_sat( + &mut self, + signed: bool, + val: RValue<'gcc>, + dest_ty: Type<'gcc>, + ) -> RValue<'gcc> { let src_ty = self.cx.val_ty(val); let (float_ty, int_ty) = if self.cx.type_kind(src_ty) == TypeKind::Vector { assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty)); @@ -1506,10 +1780,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. let int_max = |signed: bool, int_width: u64| -> u128 { let shift_amount = 128 - int_width; - if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount } + if signed { + i128::MAX as u128 >> shift_amount + } else { + u128::MAX >> shift_amount + } }; let int_min = |signed: bool, int_width: u64| -> i128 { - if signed { i128::MIN >> (128 - int_width) } else { 0 } + if signed { + i128::MIN >> (128 - int_width) + } else { + 0 + } }; let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) { @@ -1593,7 +1875,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let zero = maybe_splat(self, zero); // Step 1 ... - let fptosui_result = if signed { self.fptosi(val, dest_ty) } else { self.fptoui(val, dest_ty) }; + let fptosui_result = + if signed { self.fptosi(val, dest_ty) } else { self.fptoui(val, dest_ty) }; let less_or_nan = self.fcmp(RealPredicate::RealULT, val, f_min); let greater = self.fcmp(RealPredicate::RealOGT, val, f_max); @@ -1629,8 +1912,13 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } - #[cfg(feature="master")] - pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> { + #[cfg(feature = "master")] + pub fn shuffle_vector( + &mut self, + v1: RValue<'gcc>, + v2: RValue<'gcc>, + mask: RValue<'gcc>, + ) -> RValue<'gcc> { let struct_type = mask.get_type().is_struct().expect("mask should be of struct type"); // TODO(antoyo): use a recursive unqualified() here. @@ -1640,21 +1928,23 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let mask_num_units = struct_type.get_field_count(); let mut vector_elements = vec![]; - let mask_element_type = - if element_type.is_integral() { - element_type + let mask_element_type = if element_type.is_integral() { + element_type + } else { + #[cfg(feature = "master")] + { + self.cx.type_ix(element_type.get_size() as u64 * 8) } - else { - #[cfg(feature="master")] - { - self.cx.type_ix(element_type.get_size() as u64 * 8) - } - #[cfg(not(feature="master"))] - self.int_type - }; + #[cfg(not(feature = "master"))] + self.int_type + }; for i in 0..mask_num_units { let field = struct_type.get_field(i as i32); - vector_elements.push(self.context.new_cast(self.loc, mask.access_field(self.loc, field).to_rvalue(), mask_element_type)); + vector_elements.push(self.context.new_cast( + self.location, + mask.access_field(self.location, field).to_rvalue(), + mask_element_type, + )); } // NOTE: the mask needs to be the same length as the input vectors, so add the missing @@ -1664,53 +1954,84 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } let result_type = self.context.new_vector_type(element_type, mask_num_units as u64); - let (v1, v2) = - if vec_num_units < mask_num_units { - // NOTE: the mask needs to be the same length as the input vectors, so join the 2 - // vectors and create a dummy second vector. - let mut elements = vec![]; - for i in 0..vec_num_units { - elements.push(self.context.new_vector_access(self.loc, v1, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); - } - for i in 0..(mask_num_units - vec_num_units) { - elements.push(self.context.new_vector_access(self.loc, v2, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); - } - let v1 = self.context.new_rvalue_from_vector(self.loc, result_type, &elements); - let zero = self.context.new_rvalue_zero(element_type); - let v2 = self.context.new_rvalue_from_vector(self.loc, result_type, &vec![zero; mask_num_units]); - (v1, v2) + let (v1, v2) = if vec_num_units < mask_num_units { + // NOTE: the mask needs to be the same length as the input vectors, so join the 2 + // vectors and create a dummy second vector. + let mut elements = vec![]; + for i in 0..vec_num_units { + elements.push( + self.context + .new_vector_access( + self.location, + v1, + self.context.new_rvalue_from_int(self.int_type, i as i32), + ) + .to_rvalue(), + ); } - else { - (v1, v2) - }; + for i in 0..(mask_num_units - vec_num_units) { + elements.push( + self.context + .new_vector_access( + self.location, + v2, + self.context.new_rvalue_from_int(self.int_type, i as i32), + ) + .to_rvalue(), + ); + } + let v1 = self.context.new_rvalue_from_vector(self.location, result_type, &elements); + let zero = self.context.new_rvalue_zero(element_type); + let v2 = self.context.new_rvalue_from_vector( + self.location, + result_type, + &vec![zero; mask_num_units], + ); + (v1, v2) + } else { + (v1, v2) + }; let new_mask_num_units = std::cmp::max(mask_num_units, vec_num_units); let mask_type = self.context.new_vector_type(mask_element_type, new_mask_num_units as u64); - let mask = self.context.new_rvalue_from_vector(self.loc, mask_type, &vector_elements); - let result = self.context.new_rvalue_vector_perm(self.loc, v1, v2, mask); + let mask = self.context.new_rvalue_from_vector(self.location, mask_type, &vector_elements); + let result = self.context.new_rvalue_vector_perm(self.location, v1, v2, mask); if vec_num_units != mask_num_units { // NOTE: if padding was added, only select the number of elements of the masks to // remove that padding in the result. let mut elements = vec![]; for i in 0..mask_num_units { - elements.push(self.context.new_vector_access(self.loc, result, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push( + self.context + .new_vector_access( + self.location, + result, + self.context.new_rvalue_from_int(self.int_type, i as i32), + ) + .to_rvalue(), + ); } - self.context.new_rvalue_from_vector(self.loc, result_type, &elements) - } - else { + self.context.new_rvalue_from_vector(self.location, result_type, &elements) + } else { result } } - #[cfg(not(feature="master"))] - pub fn shuffle_vector(&mut self, _v1: RValue<'gcc>, _v2: RValue<'gcc>, _mask: RValue<'gcc>) -> RValue<'gcc> { + #[cfg(not(feature = "master"))] + pub fn shuffle_vector( + &mut self, + _v1: RValue<'gcc>, + _v2: RValue<'gcc>, + _mask: RValue<'gcc>, + ) -> RValue<'gcc> { unimplemented!(); } - #[cfg(feature="master")] + #[cfg(feature = "master")] pub fn vector_reduce(&mut self, src: RValue<'gcc>, op: F) -> RValue<'gcc> - where F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc> + where + F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc>, { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_type = vector_type.get_element_type(); @@ -1724,74 +2045,104 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let mut shift = 1; let mut res = src; while shift < element_count { - let vector_elements: Vec<_> = - vector_elements.iter() - .map(|i| self.context.new_rvalue_from_int(mask_element_type, ((i + shift) % element_count) as i32)) - .collect(); - let mask = self.context.new_rvalue_from_vector(self.loc, mask_type, &vector_elements); - let shifted = self.context.new_rvalue_vector_perm(self.loc, res, res, mask); + let vector_elements: Vec<_> = vector_elements + .iter() + .map(|i| { + self.context.new_rvalue_from_int( + mask_element_type, + ((i + shift) % element_count) as i32, + ) + }) + .collect(); + let mask = + self.context.new_rvalue_from_vector(self.location, mask_type, &vector_elements); + let shifted = self.context.new_rvalue_vector_perm(self.location, res, res, mask); shift *= 2; res = op(res, shifted, &self.context); } - self.context.new_vector_access(self.loc, res, self.context.new_rvalue_zero(self.int_type)) + self.context + .new_vector_access(self.location, res, self.context.new_rvalue_zero(self.int_type)) .to_rvalue() } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] pub fn vector_reduce(&mut self, _src: RValue<'gcc>, _op: F) -> RValue<'gcc> - where F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc> + where + F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc>, { unimplemented!(); } pub fn vector_reduce_op(&mut self, src: RValue<'gcc>, op: BinaryOp) -> RValue<'gcc> { - let loc = self.loc.clone(); + let loc = self.location.clone(); self.vector_reduce(src, |a, b, context| context.new_binary_op(loc, op, a.get_type(), a, b)) } - pub fn vector_reduce_fadd_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fadd_fast( + &mut self, + _acc: RValue<'gcc>, + _src: RValue<'gcc>, + ) -> RValue<'gcc> { unimplemented!(); } - #[cfg(feature="master")] + #[cfg(feature = "master")] pub fn vector_reduce_fadd(&mut self, acc: RValue<'gcc>, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - (0..element_count).into_iter() - .map(|i| self.context - .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) - .to_rvalue()) + (0..element_count) + .into_iter() + .map(|i| { + self.context + .new_vector_access( + self.location, + src, + self.context.new_rvalue_from_int(self.int_type, i as _), + ) + .to_rvalue() + }) .fold(acc, |x, i| x + i) } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] pub fn vector_reduce_fadd(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } - pub fn vector_reduce_fmul_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fmul_fast( + &mut self, + _acc: RValue<'gcc>, + _src: RValue<'gcc>, + ) -> RValue<'gcc> { unimplemented!(); } - #[cfg(feature="master")] + #[cfg(feature = "master")] pub fn vector_reduce_fmul(&mut self, acc: RValue<'gcc>, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - (0..element_count).into_iter() - .map(|i| self.context - .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) - .to_rvalue()) + (0..element_count) + .into_iter() + .map(|i| { + self.context + .new_vector_access( + self.location, + src, + self.context.new_rvalue_from_int(self.int_type, i as _), + ) + .to_rvalue() + }) .fold(acc, |x, i| x * i) } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] pub fn vector_reduce_fmul(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!() } // Inspired by Hacker's Delight min implementation. pub fn vector_reduce_min(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { - let loc = self.loc.clone(); + let loc = self.location.clone(); self.vector_reduce(src, |a, b, context| { let differences_or_zeros = difference_or_zero(loc, a, b, context); context.new_binary_op(loc, BinaryOp::Plus, b.get_type(), b, differences_or_zeros) @@ -1800,57 +2151,72 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Inspired by Hacker's Delight max implementation. pub fn vector_reduce_max(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { - let loc = self.loc.clone(); + let loc = self.location.clone(); self.vector_reduce(src, |a, b, context| { let differences_or_zeros = difference_or_zero(loc, a, b, context); context.new_binary_op(loc, BinaryOp::Minus, a.get_type(), a, differences_or_zeros) }) } - fn vector_extremum(&mut self, a: RValue<'gcc>, b: RValue<'gcc>, direction: ExtremumOperation) -> RValue<'gcc> { + fn vector_extremum( + &mut self, + a: RValue<'gcc>, + b: RValue<'gcc>, + direction: ExtremumOperation, + ) -> RValue<'gcc> { let vector_type = a.get_type(); // mask out the NaNs in b and replace them with the corresponding lane in a, so when a and // b get compared & spliced together, we get the numeric values instead of NaNs. - let b_nan_mask = self.context.new_comparison(self.loc, ComparisonOp::NotEquals, b, b); + let b_nan_mask = self.context.new_comparison(self.location, ComparisonOp::NotEquals, b, b); let mask_type = b_nan_mask.get_type(); - let b_nan_mask_inverted = self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, mask_type, b_nan_mask); - let a_cast = self.context.new_bitcast(self.loc, a, mask_type); - let b_cast = self.context.new_bitcast(self.loc, b, mask_type); + let b_nan_mask_inverted = + self.context.new_unary_op(self.location, UnaryOp::BitwiseNegate, mask_type, b_nan_mask); + let a_cast = self.context.new_bitcast(self.location, a, mask_type); + let b_cast = self.context.new_bitcast(self.location, b, mask_type); let res = (b_nan_mask & a_cast) | (b_nan_mask_inverted & b_cast); - let b = self.context.new_bitcast(self.loc, res, vector_type); + let b = self.context.new_bitcast(self.location, res, vector_type); // now do the actual comparison let comparison_op = match direction { ExtremumOperation::Min => ComparisonOp::LessThan, ExtremumOperation::Max => ComparisonOp::GreaterThan, }; - let cmp = self.context.new_comparison(self.loc, comparison_op, a, b); - let cmp_inverted = self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, cmp.get_type(), cmp); + let cmp = self.context.new_comparison(self.location, comparison_op, a, b); + let cmp_inverted = + self.context.new_unary_op(self.location, UnaryOp::BitwiseNegate, cmp.get_type(), cmp); let res = (cmp & a_cast) | (cmp_inverted & res); - self.context.new_bitcast(self.loc, res, vector_type) + self.context.new_bitcast(self.location, res, vector_type) } pub fn vector_fmin(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { self.vector_extremum(a, b, ExtremumOperation::Min) } - #[cfg(feature="master")] + #[cfg(feature = "master")] pub fn vector_reduce_fmin(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - let mut acc = self.context.new_vector_access(self.loc, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + let mut acc = self + .context + .new_vector_access(self.location, src, self.context.new_rvalue_zero(self.int_type)) + .to_rvalue(); for i in 1..element_count { - let elem = self.context - .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + let elem = self + .context + .new_vector_access( + self.location, + src, + self.context.new_rvalue_from_int(self.int_type, i as _), + ) .to_rvalue(); - let cmp = self.context.new_comparison(self.loc, ComparisonOp::LessThan, acc, elem); + let cmp = self.context.new_comparison(self.location, ComparisonOp::LessThan, acc, elem); acc = self.select(cmp, acc, elem); } acc } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] pub fn vector_reduce_fmin(&mut self, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } @@ -1859,36 +2225,51 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.vector_extremum(a, b, ExtremumOperation::Max) } - #[cfg(feature="master")] + #[cfg(feature = "master")] pub fn vector_reduce_fmax(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); let element_count = vector_type.get_num_units(); - let mut acc = self.context.new_vector_access(self.loc, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + let mut acc = self + .context + .new_vector_access(self.location, src, self.context.new_rvalue_zero(self.int_type)) + .to_rvalue(); for i in 1..element_count { - let elem = self.context - .new_vector_access(self.loc, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + let elem = self + .context + .new_vector_access( + self.location, + src, + self.context.new_rvalue_from_int(self.int_type, i as _), + ) .to_rvalue(); - let cmp = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, acc, elem); + let cmp = + self.context.new_comparison(self.location, ComparisonOp::GreaterThan, acc, elem); acc = self.select(cmp, acc, elem); } acc } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] pub fn vector_reduce_fmax(&mut self, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } - pub fn vector_select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, else_val: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_select( + &mut self, + cond: RValue<'gcc>, + then_val: RValue<'gcc>, + else_val: RValue<'gcc>, + ) -> RValue<'gcc> { // cond is a vector of integers, not of bools. let vector_type = cond.get_type().unqualified().dyncast_vector().expect("vector type"); let num_units = vector_type.get_num_units(); let element_type = vector_type.get_element_type(); - #[cfg(feature="master")] + #[cfg(feature = "master")] let (cond, element_type) = { // TODO(antoyo): dyncast_vector should not require a call to unqualified. - let then_val_vector_type = then_val.get_type().unqualified().dyncast_vector().expect("vector type"); + let then_val_vector_type = + then_val.get_type().unqualified().dyncast_vector().expect("vector type"); let then_val_element_type = then_val_vector_type.get_element_type(); let then_val_element_size = then_val_element_type.get_size(); @@ -1896,11 +2277,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // operation to work. if then_val_element_size != element_type.get_size() { let new_element_type = self.type_ix(then_val_element_size as u64 * 8); - let new_vector_type = self.context.new_vector_type(new_element_type, num_units as u64); - let cond = self.context.convert_vector(self.loc, cond, new_vector_type); + let new_vector_type = + self.context.new_vector_type(new_element_type, num_units as u64); + let cond = self.context.convert_vector(self.location, cond, new_vector_type); (cond, new_element_type) - } - else { + } else { (cond, element_type) } }; @@ -1908,24 +2289,25 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let cond_type = cond.get_type(); let zeros = vec![self.context.new_rvalue_zero(element_type); num_units]; - let zeros = self.context.new_rvalue_from_vector(self.loc, cond_type, &zeros); + let zeros = self.context.new_rvalue_from_vector(self.location, cond_type, &zeros); let result_type = then_val.get_type(); - let masks = self.context.new_comparison(self.loc, ComparisonOp::NotEquals, cond, zeros); + let masks = + self.context.new_comparison(self.location, ComparisonOp::NotEquals, cond, zeros); // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make // the & operation work. let then_val = self.bitcast_if_needed(then_val, masks.get_type()); let then_vals = masks & then_val; let minus_ones = vec![self.context.new_rvalue_from_int(element_type, -1); num_units]; - let minus_ones = self.context.new_rvalue_from_vector(self.loc, cond_type, &minus_ones); + let minus_ones = self.context.new_rvalue_from_vector(self.location, cond_type, &minus_ones); let inverted_masks = masks ^ minus_ones; // NOTE: sometimes, the type of else_val can be different than the type of then_val in // libgccjit (vector of int vs vector of int32_t), but they should be the same for the AND // operation to work. // TODO: remove bitcast now that vector types can be compared? - let else_val = self.context.new_bitcast(self.loc, else_val, then_val.get_type()); + let else_val = self.context.new_bitcast(self.location, else_val, then_val.get_type()); let else_vals = inverted_masks & else_val; let res = then_vals | else_vals; @@ -1933,26 +2315,26 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } -fn difference_or_zero<'gcc>(loc: Option>, a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Context<'gcc>) -> RValue<'gcc> { +fn difference_or_zero<'gcc>( + loc: Option>, + a: RValue<'gcc>, + b: RValue<'gcc>, + context: &'gcc Context<'gcc>, +) -> RValue<'gcc> { let difference = a - b; let masks = context.new_comparison(loc, ComparisonOp::GreaterThanEquals, b, a); // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make // the & operation work. let a_type = a.get_type(); let masks = - if masks.get_type() != a_type { - context.new_bitcast(loc, masks, a_type) - } - else { - masks - }; + if masks.get_type() != a_type { context.new_bitcast(loc, masks, a_type) } else { masks }; difference & masks } impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> { // Forward to the `get_static` method of `CodegenCx` - self.cx().get_static(def_id).get_address(self.loc) + self.cx().get_static(def_id).get_address(self.location) } } @@ -2032,15 +2414,14 @@ impl ToGccOrdering for AtomicOrdering { fn to_gcc(self) -> i32 { use MemOrdering::*; - let ordering = - match self { - AtomicOrdering::Unordered => __ATOMIC_RELAXED, - AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. - AtomicOrdering::Acquire => __ATOMIC_ACQUIRE, - AtomicOrdering::Release => __ATOMIC_RELEASE, - AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL, - AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST, - }; + let ordering = match self { + AtomicOrdering::Unordered => __ATOMIC_RELAXED, + AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Acquire => __ATOMIC_ACQUIRE, + AtomicOrdering::Release => __ATOMIC_RELEASE, + AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL, + AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST, + }; ordering as i32 } } diff --git a/src/callee.rs b/src/callee.rs index 9fc77627b1bc5..84f49b6856d4d 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -1,8 +1,8 @@ -#[cfg(feature="master")] +#[cfg(feature = "master")] use gccjit::{FnAttribute, Visibility}; -use gccjit::{FunctionType, Function}; -use rustc_middle::ty::{self, Instance, TypeVisitableExt}; +use gccjit::{Function, FunctionType}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; +use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use crate::attributes; use crate::context::CodegenCx; @@ -28,145 +28,144 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); - let func = - if let Some(_func) = cx.get_declared_value(&sym) { - // FIXME(antoyo): we never reach this because get_declared_value only returns global variables - // and here we try to get a function. - unreachable!(); - /* - // Create a fn pointer with the new signature. - let ptrty = fn_abi.ptr_to_gcc_type(cx); - - // This is subtle and surprising, but sometimes we have to bitcast - // the resulting fn pointer. The reason has to do with external - // functions. If you have two crates that both bind the same C - // library, they may not use precisely the same types: for - // example, they will probably each declare their own structs, - // which are distinct types from LLVM's point of view (nominal - // types). - // - // Now, if those two crates are linked into an application, and - // they contain inlined code, you can wind up with a situation - // where both of those functions wind up being loaded into this - // application simultaneously. In that case, the same function - // (from LLVM's point of view) requires two types. But of course - // LLVM won't allow one function to have two types. - // - // What we currently do, therefore, is declare the function with - // one of the two types (whichever happens to come first) and then - // bitcast as needed when the function is referenced to make sure - // it has the type we expect. - // - // This can occur on either a crate-local or crate-external - // reference. It also occurs when testing libcore and in some - // other weird situations. Annoying. - if cx.val_ty(func) != ptrty { - // TODO(antoyo): cast the pointer. - func - } - else { - func - }*/ + let func = if let Some(_func) = cx.get_declared_value(&sym) { + // FIXME(antoyo): we never reach this because get_declared_value only returns global variables + // and here we try to get a function. + unreachable!(); + /* + // Create a fn pointer with the new signature. + let ptrty = fn_abi.ptr_to_gcc_type(cx); + + // This is subtle and surprising, but sometimes we have to bitcast + // the resulting fn pointer. The reason has to do with external + // functions. If you have two crates that both bind the same C + // library, they may not use precisely the same types: for + // example, they will probably each declare their own structs, + // which are distinct types from LLVM's point of view (nominal + // types). + // + // Now, if those two crates are linked into an application, and + // they contain inlined code, you can wind up with a situation + // where both of those functions wind up being loaded into this + // application simultaneously. In that case, the same function + // (from LLVM's point of view) requires two types. But of course + // LLVM won't allow one function to have two types. + // + // What we currently do, therefore, is declare the function with + // one of the two types (whichever happens to come first) and then + // bitcast as needed when the function is referenced to make sure + // it has the type we expect. + // + // This can occur on either a crate-local or crate-external + // reference. It also occurs when testing libcore and in some + // other weird situations. Annoying. + if cx.val_ty(func) != ptrty { + // TODO(antoyo): cast the pointer. + func } else { - cx.linkage.set(FunctionType::Extern); - let func = cx.declare_fn(&sym, &fn_abi); - - attributes::from_fn_attrs(cx, func, instance); - - let instance_def_id = instance.def_id(); - - // TODO(antoyo): set linkage and attributes. - - // Apply an appropriate linkage/visibility value to our item that we - // just declared. - // - // This is sort of subtle. Inside our codegen unit we started off - // compilation by predefining all our own `MonoItem` instances. That - // is, everything we're codegenning ourselves is already defined. That - // means that anything we're actually codegenning in this codegen unit - // will have hit the above branch in `get_declared_value`. As a result, - // we're guaranteed here that we're declaring a symbol that won't get - // defined, or in other words we're referencing a value from another - // codegen unit or even another crate. - // - // So because this is a foreign value we blanket apply an external - // linkage directive because it's coming from a different object file. - // The visibility here is where it gets tricky. This symbol could be - // referencing some foreign crate or foreign library (an `extern` - // block) in which case we want to leave the default visibility. We may - // also, though, have multiple codegen units. It could be a - // monomorphization, in which case its expected visibility depends on - // whether we are sharing generics or not. The important thing here is - // that the visibility we apply to the declaration is the same one that - // has been applied to the definition (wherever that definition may be). - let is_generic = instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some(); - - if is_generic { - // This is a monomorphization. Its expected visibility depends - // on whether we are in share-generics mode. - - if cx.tcx.sess.opts.share_generics() { - // We are in share_generics mode. - - if let Some(instance_def_id) = instance_def_id.as_local() { - // This is a definition from the current crate. If the - // definition is unreachable for downstream crates or - // the current crate does not re-export generics, the - // definition of the instance will have been declared - // as `hidden`. - if cx.tcx.is_unreachable_local_definition(instance_def_id) - || !cx.tcx.local_crate_exports_generics() - { - #[cfg(feature="master")] - func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); - } + func + }*/ + } else { + cx.linkage.set(FunctionType::Extern); + let func = cx.declare_fn(&sym, &fn_abi); + + attributes::from_fn_attrs(cx, func, instance); + + let instance_def_id = instance.def_id(); + + // TODO(antoyo): set linkage and attributes. + + // Apply an appropriate linkage/visibility value to our item that we + // just declared. + // + // This is sort of subtle. Inside our codegen unit we started off + // compilation by predefining all our own `MonoItem` instances. That + // is, everything we're codegenning ourselves is already defined. That + // means that anything we're actually codegenning in this codegen unit + // will have hit the above branch in `get_declared_value`. As a result, + // we're guaranteed here that we're declaring a symbol that won't get + // defined, or in other words we're referencing a value from another + // codegen unit or even another crate. + // + // So because this is a foreign value we blanket apply an external + // linkage directive because it's coming from a different object file. + // The visibility here is where it gets tricky. This symbol could be + // referencing some foreign crate or foreign library (an `extern` + // block) in which case we want to leave the default visibility. We may + // also, though, have multiple codegen units. It could be a + // monomorphization, in which case its expected visibility depends on + // whether we are sharing generics or not. The important thing here is + // that the visibility we apply to the declaration is the same one that + // has been applied to the definition (wherever that definition may be). + let is_generic = + instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some(); + + if is_generic { + // This is a monomorphization. Its expected visibility depends + // on whether we are in share-generics mode. + + if cx.tcx.sess.opts.share_generics() { + // We are in share_generics mode. + + if let Some(instance_def_id) = instance_def_id.as_local() { + // This is a definition from the current crate. If the + // definition is unreachable for downstream crates or + // the current crate does not re-export generics, the + // definition of the instance will have been declared + // as `hidden`. + if cx.tcx.is_unreachable_local_definition(instance_def_id) + || !cx.tcx.local_crate_exports_generics() + { + #[cfg(feature = "master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); + } + } else { + // This is a monomorphization of a generic function + // defined in an upstream crate. + if instance.upstream_monomorphization(tcx).is_some() { + // This is instantiated in another crate. It cannot + // be `hidden`. } else { - // This is a monomorphization of a generic function - // defined in an upstream crate. - if instance.upstream_monomorphization(tcx).is_some() { - // This is instantiated in another crate. It cannot - // be `hidden`. - } else { - // This is a local instantiation of an upstream definition. - // If the current crate does not re-export it - // (because it is a C library or an executable), it - // will have been declared `hidden`. - if !cx.tcx.local_crate_exports_generics() { - #[cfg(feature="master")] - func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); - } + // This is a local instantiation of an upstream definition. + // If the current crate does not re-export it + // (because it is a C library or an executable), it + // will have been declared `hidden`. + if !cx.tcx.local_crate_exports_generics() { + #[cfg(feature = "master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); } } - } else { - // When not sharing generics, all instances are in the same - // crate and have hidden visibility - #[cfg(feature="master")] - func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); } } else { - // This is a non-generic function - if cx.tcx.is_codegened_item(instance_def_id) { - // This is a function that is instantiated in the local crate - - if instance_def_id.is_local() { - // This is function that is defined in the local crate. - // If it is not reachable, it is hidden. - if !cx.tcx.is_reachable_non_generic(instance_def_id) { - #[cfg(feature="master")] - func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); - } - } else { - // This is a function from an upstream crate that has - // been instantiated here. These are always hidden. - #[cfg(feature="master")] + // When not sharing generics, all instances are in the same + // crate and have hidden visibility + #[cfg(feature = "master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); + } + } else { + // This is a non-generic function + if cx.tcx.is_codegened_item(instance_def_id) { + // This is a function that is instantiated in the local crate + + if instance_def_id.is_local() { + // This is function that is defined in the local crate. + // If it is not reachable, it is hidden. + if !cx.tcx.is_reachable_non_generic(instance_def_id) { + #[cfg(feature = "master")] func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); } + } else { + // This is a function from an upstream crate that has + // been instantiated here. These are always hidden. + #[cfg(feature = "master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); } } + } - func - }; + func + }; cx.function_instances.borrow_mut().insert(instance, func); diff --git a/src/common.rs b/src/common.rs index c6edd52d1e416..d243d7088ada9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,14 +1,9 @@ use gccjit::LValue; -use gccjit::{RValue, Type, ToRValue}; -use rustc_codegen_ssa::traits::{ - BaseTypeMethods, - ConstMethods, - MiscMethods, - StaticMethods, -}; -use rustc_middle::mir::Mutability; -use rustc_middle::ty::layout::{LayoutOf}; +use gccjit::{RValue, ToRValue, Type}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; +use rustc_middle::mir::Mutability; +use rustc_middle::ty::layout::LayoutOf; use rustc_target::abi::{self, HasDataLayout, Pointer}; use crate::consts::const_alloc_to_gcc; @@ -40,9 +35,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> let byte_type = context.new_type::(); let typ = context.new_array_type(None, byte_type, bytes.len() as u64); let elements: Vec<_> = - bytes.iter() - .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) - .collect(); + bytes.iter().map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)).collect(); context.new_array_constructor(None, typ, &elements) } @@ -54,23 +47,20 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { if type_is_pointer(typ) { self.context.new_null(typ) - } - else { + } else { self.const_int(typ, 0) } } fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { - let local = self.current_func.borrow().expect("func") - .new_local(None, typ, "undefined"); + let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined"); if typ.is_struct().is_some() { // NOTE: hack to workaround a limitation of the rustc API: see comment on // CodegenCx.structs_as_pointer let pointer = local.get_address(None); self.structs_as_pointer.borrow_mut().insert(pointer); pointer - } - else { + } else { local.to_rvalue() } } @@ -143,16 +133,15 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { .or_insert_with(|| (s.to_owned(), self.global_string(s))) .1; let len = s.len(); - let cs = self.const_ptrcast(str_global.get_address(None), + let cs = self.const_ptrcast( + str_global.get_address(None), self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self)), ); (cs, self.const_usize(len as u64)) } fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> { - let fields: Vec<_> = values.iter() - .map(|value| value.get_type()) - .collect(); + let fields: Vec<_> = values.iter().map(|value| value.get_type()).collect(); // TODO(antoyo): cache the type? It's anonymous, so probably not. let typ = self.type_struct(&fields, packed); let struct_type = typ.is_struct().expect("struct type"); @@ -178,9 +167,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code // the paths for floating-point values. if ty == self.float_type { - return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); - } - else if ty == self.double_type { + return self + .context + .new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); + } else if ty == self.double_type { return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64)); } @@ -192,8 +182,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): fix bitcast to work in constant contexts. // TODO(antoyo): perhaps only use bitcast for pointers? self.context.new_cast(None, value, ty) - } - else { + } else { // TODO(bjorn3): assert size is correct self.const_bitcast(value, ty) } @@ -201,42 +190,41 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { Scalar::Ptr(ptr, _size) => { let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative let alloc_id = prov.alloc_id(); - let base_addr = - match self.tcx.global_alloc(alloc_id) { - GlobalAlloc::Memory(alloc) => { - let init = const_alloc_to_gcc(self, alloc); - let alloc = alloc.inner(); - let value = - match alloc.mutability { - Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), - _ => self.static_addr_of(init, alloc.align, None), - }; - if !self.sess().fewer_names() { - // TODO(antoyo): set value name. - } - value - }, - GlobalAlloc::Function(fn_instance) => { - self.get_fn_addr(fn_instance) - }, - GlobalAlloc::VTable(ty, trait_ref) => { - let alloc = self.tcx.global_alloc(self.tcx.vtable_allocation((ty, trait_ref))).unwrap_memory(); - let init = const_alloc_to_gcc(self, alloc); - self.static_addr_of(init, alloc.inner().align, None) + let base_addr = match self.tcx.global_alloc(alloc_id) { + GlobalAlloc::Memory(alloc) => { + let init = const_alloc_to_gcc(self, alloc); + let alloc = alloc.inner(); + let value = match alloc.mutability { + Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), + _ => self.static_addr_of(init, alloc.align, None), + }; + if !self.sess().fewer_names() { + // TODO(antoyo): set value name. } - GlobalAlloc::Static(def_id) => { - assert!(self.tcx.is_static(def_id)); - self.get_static(def_id).get_address(None) - }, - }; + value + } + GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance), + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc = self + .tcx + .global_alloc(self.tcx.vtable_allocation((ty, trait_ref))) + .unwrap_memory(); + let init = const_alloc_to_gcc(self, alloc); + self.static_addr_of(init, alloc.inner().align, None) + } + GlobalAlloc::Static(def_id) => { + assert!(self.tcx.is_static(def_id)); + self.get_static(def_id).get_address(None) + } + }; let ptr_type = base_addr.get_type(); let base_addr = self.const_bitcast(base_addr, self.usize_type); - let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64); + let offset = + self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64); let ptr = self.const_bitcast(base_addr + offset, ptr_type); if !matches!(layout.primitive(), Pointer(_)) { self.const_bitcast(ptr.dereference(None).to_rvalue(), ty) - } - else { + } else { self.const_bitcast(ptr, ty) } } @@ -261,7 +249,9 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { - self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None) + self.context + .new_array_access(None, base_addr, self.const_usize(offset.bytes())) + .get_address(None) } } @@ -284,35 +274,25 @@ impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> { fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { if self.is_u8(cx) { cx.i8_type - } - else if self.is_u16(cx) { + } else if self.is_u16(cx) { cx.i16_type - } - else if self.is_u32(cx) { + } else if self.is_u32(cx) { cx.i32_type - } - else if self.is_u64(cx) { + } else if self.is_u64(cx) { cx.i64_type - } - else if self.is_u128(cx) { + } else if self.is_u128(cx) { cx.i128_type - } - else if self.is_uchar(cx) { + } else if self.is_uchar(cx) { cx.char_type - } - else if self.is_ushort(cx) { + } else if self.is_ushort(cx) { cx.short_type - } - else if self.is_uint(cx) { + } else if self.is_uint(cx) { cx.int_type - } - else if self.is_ulong(cx) { + } else if self.is_ulong(cx) { cx.long_type - } - else if self.is_ulonglong(cx) { + } else if self.is_ulonglong(cx) { cx.longlong_type - } - else { + } else { self.clone() } } @@ -320,41 +300,31 @@ impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> { fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { if self.is_i8(cx) { cx.u8_type - } - else if self.is_i16(cx) { + } else if self.is_i16(cx) { cx.u16_type - } - else if self.is_i32(cx) { + } else if self.is_i32(cx) { cx.u32_type - } - else if self.is_i64(cx) { + } else if self.is_i64(cx) { cx.u64_type - } - else if self.is_i128(cx) { + } else if self.is_i128(cx) { cx.u128_type - } - else if self.is_char(cx) { + } else if self.is_char(cx) { cx.uchar_type - } - else if self.is_short(cx) { + } else if self.is_short(cx) { cx.ushort_type - } - else if self.is_int(cx) { + } else if self.is_int(cx) { cx.uint_type - } - else if self.is_long(cx) { + } else if self.is_long(cx) { cx.ulong_type - } - else if self.is_longlong(cx) { + } else if self.is_longlong(cx) { cx.ulonglong_type - } - else { + } else { self.clone() } } } -pub trait TypeReflection<'gcc, 'tcx> { +pub trait TypeReflection<'gcc, 'tcx> { fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; diff --git a/src/consts.rs b/src/consts.rs index 054741e164230..1c66ad8cc5a12 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -2,12 +2,14 @@ use gccjit::{FnAttribute, VarAttribute, Visibility}; use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; -use rustc_middle::span_bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::mir::interpret::{ + self, read_target_uint, ConstAllocation, ErrorHandled, Scalar as InterpScalar, +}; use rustc_middle::mir::mono::MonoItem; -use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::span_bug; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint}; +use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::def_id::DefId; use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; @@ -16,7 +18,11 @@ use crate::context::CodegenCx; use crate::errors::InvalidMinimumAlignment; use crate::type_of::LayoutGccExt; -fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>, mut align: Align) { +fn set_global_alignment<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + gv: LValue<'gcc>, + mut align: Align, +) { // The target may require greater alignment for globals than the type does. // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, // which can force it to be smaller. Rust doesn't support this yet. @@ -48,7 +54,9 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { } let global_value = self.static_addr_of_mut(cv, align, kind); #[cfg(feature = "master")] - self.global_lvalues.borrow().get(&global_value) + self.global_lvalues + .borrow() + .get(&global_value) .expect("`static_addr_of_mut` did not add the global to `self.global_lvalues`") .global_set_readonly(); self.const_globals.borrow_mut().insert(cv, global_value); @@ -58,25 +66,22 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { fn codegen_static(&self, def_id: DefId, is_mutable: bool) { let attrs = self.tcx.codegen_fn_attrs(def_id); - let value = - match codegen_static_initializer(&self, def_id) { - Ok((value, _)) => value, - // Error has already been reported - Err(_) => return, - }; + let value = match codegen_static_initializer(&self, def_id) { + Ok((value, _)) => value, + // Error has already been reported + Err(_) => return, + }; let global = self.get_static(def_id); // boolean SSA values are i1, but they have to be stored in i8 slots, // otherwise some LLVM optimization passes don't work as expected let val_llty = self.val_ty(value); - let value = - if val_llty == self.type_i1() { - unimplemented!(); - } - else { - value - }; + let value = if val_llty == self.type_i1() { + unimplemented!(); + } else { + value + }; let instance = Instance::mono(self.tcx, def_id); let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); @@ -149,7 +154,9 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { // TODO(antoyo): set link section. } - if attrs.flags.contains(CodegenFnAttrFlags::USED) || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + if attrs.flags.contains(CodegenFnAttrFlags::USED) + || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + { self.add_used_global(global.to_rvalue()); } } @@ -166,29 +173,33 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - #[cfg_attr(not(feature="master"), allow(unused_variables))] + #[cfg_attr(not(feature = "master"), allow(unused_variables))] pub fn add_used_function(&self, function: Function<'gcc>) { #[cfg(feature = "master")] function.add_attribute(FnAttribute::Used); } - pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { - let global = - match kind { - Some(kind) if !self.tcx.sess.fewer_names() => { - let name = self.generate_local_symbol_name(kind); - // TODO(antoyo): check if it's okay that no link_section is set. - - let typ = self.val_ty(cv).get_aligned(align.bytes()); - let global = self.declare_private_global(&name[..], typ); - global - } - _ => { - let typ = self.val_ty(cv).get_aligned(align.bytes()); - let global = self.declare_unnamed_global(typ); - global - }, - }; + pub fn static_addr_of_mut( + &self, + cv: RValue<'gcc>, + align: Align, + kind: Option<&str>, + ) -> RValue<'gcc> { + let global = match kind { + Some(kind) if !self.tcx.sess.fewer_names() => { + let name = self.generate_local_symbol_name(kind); + // TODO(antoyo): check if it's okay that no link_section is set. + + let typ = self.val_ty(cv).get_aligned(align.bytes()); + let global = self.declare_private_global(&name[..], typ); + global + } + _ => { + let typ = self.val_ty(cv).get_aligned(align.bytes()); + let global = self.declare_unnamed_global(typ); + global + } + }; global.global_set_initializer_rvalue(cv); // TODO(antoyo): set unnamed address. let rvalue = global.get_address(None); @@ -215,8 +226,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); let sym = self.tcx.symbol_name(instance).name; - let global = - if def_id.is_local() && !self.tcx.is_foreign_item(def_id) { + let global = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) { let llty = self.layout_of(ty).gcc_type(self); if let Some(global) = self.get_declared_value(sym) { if self.val_ty(global) != self.type_ptr_to(llty) { @@ -278,7 +288,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> { +pub fn const_alloc_to_gcc<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + alloc: ConstAllocation<'tcx>, +) -> RValue<'gcc> { let alloc = alloc.inner(); let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); let dl = cx.data_layout(); @@ -300,14 +313,14 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset); llvals.push(cx.const_bytes(bytes)); } - let ptr_offset = - read_target_uint( dl.endian, - // This `inspect` is okay since it is within the bounds of the allocation, it doesn't - // affect interpreter execution (we inspect the result after interpreter execution), - // and we properly interpret the provenance as a relocation pointer offset. - alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), - ) - .expect("const_alloc_to_llvm: could not read relocation pointer") + let ptr_offset = read_target_uint( + dl.endian, + // This `inspect` is okay since it is within the bounds of the allocation, it doesn't + // affect interpreter execution (we inspect the result after interpreter execution), + // and we properly interpret the provenance as a relocation pointer offset. + alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), + ) + .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx); @@ -317,7 +330,10 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl interpret::Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx, ), - abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) }, + abi::Scalar::Initialized { + value: Primitive::Pointer(address_space), + valid_range: WrappingRange::full(dl.pointer_size), + }, cx.type_i8p_ext(address_space), )); next_offset = offset + pointer_size; @@ -337,17 +353,29 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl cx.const_struct(&llvals, true) } -pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> { +pub fn codegen_static_initializer<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + def_id: DefId, +) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> { let alloc = cx.tcx.eval_static_initializer(def_id)?; Ok((const_alloc_to_gcc(cx, alloc), alloc)) } -fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str) -> LValue<'gcc> { +fn check_and_apply_linkage<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + attrs: &CodegenFnAttrs, + ty: Ty<'tcx>, + sym: &str, +) -> LValue<'gcc> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let gcc_type = cx.layout_of(ty).gcc_type(cx); if let Some(linkage) = attrs.import_linkage { // Declare a symbol `foo` with the desired linkage. - let global1 = cx.declare_global_with_linkage(&sym, cx.type_i8(), base::global_linkage_to_gcc(linkage)); + let global1 = cx.declare_global_with_linkage( + &sym, + cx.type_i8(), + base::global_linkage_to_gcc(linkage), + ); // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is @@ -363,8 +391,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg global2.global_set_initializer_rvalue(value); // TODO(antoyo): use global_set_initializer() when it will work. global2 - } - else { + } else { // Generate an external declaration. // FIXME(nagisa): investigate whether it can be changed into define_global diff --git a/src/context.rs b/src/context.rs index cca37168880b5..bc3d62f2679d9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,22 +1,25 @@ use std::cell::{Cell, RefCell}; -use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type}; -use rustc_codegen_ssa::base::wants_msvc_seh; -use rustc_codegen_ssa::traits::{ - BackendTypes, - BaseTypeMethods, - MiscMethods, +use gccjit::{ + Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type, }; +use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::errors as ssa_errors; +use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods}; use rustc_data_structures::base_n; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_middle::span_bug; use rustc_middle::mir::mono::CodegenUnit; +use rustc_middle::span_bug; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, + LayoutOfHelpers, TyAndLayout, +}; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; -use rustc_middle::ty::layout::{FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; use rustc_session::Session; -use rustc_span::{Span, source_map::respan}; -use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; +use rustc_span::{source_map::respan, Span}; +use rustc_target::abi::{ + call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, +}; use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; use crate::callee::get_fn; @@ -81,7 +84,8 @@ pub struct CodegenCx<'gcc, 'tcx> { /// Cache function instances of monomorphic and polymorphic items pub function_instances: RefCell, Function<'gcc>>>, /// Cache generated vtables - pub vtables: RefCell, Option>), RValue<'gcc>>>, + pub vtables: + RefCell, Option>), RValue<'gcc>>>, // TODO(antoyo): improve the SSA API to not require those. /// Mapping from function pointer type to indexes of on stack parameters. @@ -121,24 +125,28 @@ pub struct CodegenCx<'gcc, 'tcx> { } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>, supports_128bit_integers: bool) -> Self { + pub fn new( + context: &'gcc Context<'gcc>, + codegen_unit: &'tcx CodegenUnit<'tcx>, + tcx: TyCtxt<'tcx>, + supports_128bit_integers: bool, + ) -> Self { let check_overflow = tcx.sess.overflow_checks(); let create_type = |ctype, rust_type| { let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap(); let align = layout.align.abi.bytes(); - #[cfg(feature="master")] + #[cfg(feature = "master")] { context.new_c_type(ctype).get_aligned(align) } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] { // Since libgccjit 12 doesn't contain the fix to compare aligned integer types, // only align u128 and i128. if layout.ty.int_size_and_signed(tcx).0.bytes() == 16 { context.new_c_type(ctype).get_aligned(align) - } - else { + } else { context.new_c_type(ctype) } } @@ -153,24 +161,22 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let u32_type = create_type(CType::UInt32t, tcx.types.u32); let u64_type = create_type(CType::UInt64t, tcx.types.u64); - let (i128_type, u128_type) = - if supports_128bit_integers { - let i128_type = create_type(CType::Int128t, tcx.types.i128); - let u128_type = create_type(CType::UInt128t, tcx.types.u128); - (i128_type, u128_type) - } - else { - /*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap(); - let i128_align = layout.align.abi.bytes(); - let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap(); - let u128_align = layout.align.abi.bytes();*/ - - // TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in - // gcc_jit_context_new_array_constructor (it should not use reinterpret_cast). - let i128_type = context.new_array_type(None, i64_type, 2)/*.get_aligned(i128_align)*/; - let u128_type = context.new_array_type(None, u64_type, 2)/*.get_aligned(u128_align)*/; - (i128_type, u128_type) - }; + let (i128_type, u128_type) = if supports_128bit_integers { + let i128_type = create_type(CType::Int128t, tcx.types.i128); + let u128_type = create_type(CType::UInt128t, tcx.types.u128); + (i128_type, u128_type) + } else { + /*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap(); + let i128_align = layout.align.abi.bytes(); + let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap(); + let u128_align = layout.align.abi.bytes();*/ + + // TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in + // gcc_jit_context_new_array_constructor (it should not use reinterpret_cast). + let i128_type = context.new_array_type(None, i64_type, 2)/*.get_aligned(i128_align)*/; + let u128_type = context.new_array_type(None, u64_type, 2)/*.get_aligned(u128_align)*/; + (i128_type, u128_type) + }; let tls_model = to_gcc_tls_mode(tcx.sess.tls_model()); @@ -196,16 +202,65 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let mut functions = FxHashMap::default(); let builtins = [ - "__builtin_unreachable", "abort", "__builtin_expect", /*"__builtin_expect_with_probability",*/ - "__builtin_constant_p", "__builtin_add_overflow", "__builtin_mul_overflow", "__builtin_saddll_overflow", - /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ - "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow", - "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow", - "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos", - "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf", - "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf", - "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round", - + "__builtin_unreachable", + "abort", + "__builtin_expect", /*"__builtin_expect_with_probability",*/ + "__builtin_constant_p", + "__builtin_add_overflow", + "__builtin_mul_overflow", + "__builtin_saddll_overflow", + /*"__builtin_sadd_overflow",*/ + "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ + "__builtin_ssubll_overflow", + /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", + "__builtin_uaddll_overflow", + "__builtin_uadd_overflow", + "__builtin_umulll_overflow", + "__builtin_umul_overflow", + "__builtin_usubll_overflow", + "__builtin_usub_overflow", + "sqrtf", + "sqrt", + "__builtin_powif", + "__builtin_powi", + "sinf", + "sin", + "cosf", + "cos", + "powf", + "pow", + "expf", + "exp", + "exp2f", + "exp2", + "logf", + "log", + "log10f", + "log10", + "log2f", + "log2", + "fmaf", + "fma", + "fabsf", + "fabs", + "fminf", + "fmin", + "fmaxf", + "fmax", + "copysignf", + "copysign", + "floorf", + "floor", + "ceilf", + "ceil", + "truncf", + "trunc", + "rintf", + "rint", + "nearbyintf", + "nearbyint", + "roundf", + "round", ]; for builtin in builtins.iter() { @@ -282,8 +337,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> { let function: Function<'gcc> = unsafe { std::mem::transmute(value) }; - debug_assert!(self.functions.borrow().values().any(|value| *value == function), - "{:?} ({:?}) is not a function", value, value.get_type()); + debug_assert!( + self.functions.borrow().values().any(|value| *value == function), + "{:?} ({:?}) is not a function", + value, + value.get_type() + ); function } @@ -305,13 +364,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } - self.supports_128bit_integers && - (self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ)) + self.supports_128bit_integers + && (self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ)) } pub fn is_non_native_int_type(&self, typ: Type<'gcc>) -> bool { - !self.supports_128bit_integers && - (self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ)) + !self.supports_128bit_integers + && (self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ)) } pub fn is_native_int_type_or_bool(&self, typ: Type<'gcc>) -> bool { @@ -319,18 +378,23 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } pub fn is_int_type_or_bool(&self, typ: Type<'gcc>) -> bool { - self.is_native_int_type(typ) || self.is_non_native_int_type(typ) || typ.is_compatible_with(self.bool_type) + self.is_native_int_type(typ) + || self.is_non_native_int_type(typ) + || typ.is_compatible_with(self.bool_type) } pub fn sess(&self) -> &'tcx Session { &self.tcx.sess } - pub fn bitcast_if_needed(&self, value: RValue<'gcc>, expected_type: Type<'gcc>) -> RValue<'gcc> { + pub fn bitcast_if_needed( + &self, + value: RValue<'gcc>, + expected_type: Type<'gcc>, + ) -> RValue<'gcc> { if value.get_type() != expected_type { self.context.new_bitcast(None, value, expected_type) - } - else { + } else { value } } @@ -350,7 +414,9 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { } impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn vtables(&self) -> &RefCell, Option>), RValue<'gcc>>> { + fn vtables( + &self, + ) -> &RefCell, Option>), RValue<'gcc>>> { &self.vtables } @@ -364,13 +430,11 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { let func_name = self.tcx.symbol_name(instance).name; - let func = - if self.intrinsics.borrow().contains_key(func_name) { - self.intrinsics.borrow()[func_name].clone() - } - else { - get_fn(self, instance) - }; + let func = if self.intrinsics.borrow().contains_key(func_name) { + self.intrinsics.borrow()[func_name].clone() + } else { + get_fn(self, instance) + }; let ptr = func.get_address(None); // TODO(antoyo): don't do this twice: i.e. in declare_fn and here. @@ -407,37 +471,34 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { return llpersonality; } let tcx = self.tcx; - let func = - match tcx.lang_items().eh_personality() { - Some(def_id) if !wants_msvc_seh(self.sess()) => { - let instance = - ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - ty::List::empty(), - ) - .unwrap().unwrap(); - - let symbol_name = tcx.symbol_name(instance).name; - let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); - self.linkage.set(FunctionType::Extern); - let func = self.declare_fn(symbol_name, &fn_abi); - let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - func - }, - _ => { - let name = - if wants_msvc_seh(self.sess()) { - "__CxxFrameHandler3" - } - else { - "rust_eh_personality" - }; - let func = self.declare_func(name, self.type_i32(), &[], true); - unsafe { std::mem::transmute(func) } - } - }; + let func = match tcx.lang_items().eh_personality() { + Some(def_id) if !wants_msvc_seh(self.sess()) => { + let instance = ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + ty::List::empty(), + ) + .unwrap() + .unwrap(); + + let symbol_name = tcx.symbol_name(instance).name; + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); + self.linkage.set(FunctionType::Extern); + let func = self.declare_fn(symbol_name, &fn_abi); + let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; + func + } + _ => { + let name = if wants_msvc_seh(self.sess()) { + "__CxxFrameHandler3" + } else { + "rust_eh_personality" + }; + let func = self.declare_func(name, self.type_i32(), &[], true); + unsafe { std::mem::transmute(func) } + } + }; // TODO(antoyo): apply target cpu attributes. self.eh_personality.set(Some(func)); func @@ -467,8 +528,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let entry_name = self.sess().target.entry_name.as_ref(); if self.get_declared_value(entry_name).is_none() { Some(self.declare_entry_fn(entry_name, fn_type, ())) - } - else { + } else { // If the symbol already exists, it is an error: for example, the user wrote // #[no_mangle] extern "C" fn main(..) {..} // instead of #[start] diff --git a/src/debuginfo.rs b/src/debuginfo.rs index cd01785edbf0d..a072a5092a798 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -1,16 +1,16 @@ +use crate::rustc_index::Idx; use gccjit::{Location, RValue}; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; +use rustc_data_structures::sync::Lrc; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; -use rustc_middle::mir::{Body, self, SourceScope}; +use rustc_middle::mir::{self, Body, SourceScope}; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_session::config::DebugInfo; use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; -use rustc_data_structures::sync::Lrc; -use crate::rustc_index::Idx; use std::ops::Range; use crate::builder::Builder; @@ -25,15 +25,15 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn dbg_var_addr( &mut self, _dbg_var: Self::DIVariable, - dbg_loc: Self::DILocation, - variable_alloca: Self::Value, + _dbg_loc: Self::DILocation, + _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size], _fragment: Option>, ) { // FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here. #[cfg(feature = "master")] - variable_alloca.set_location(dbg_loc); + _variable_alloca.set_location(_dbg_loc); } fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { @@ -43,11 +43,10 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { /// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the /// debug name and the mangled name should both be included in the LValues. /// Besides, a function to get the rvalue type(m_is_lvalue) should also be included. - fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) { - } + fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {} fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { - self.loc = Some(dbg_loc); + self.location = Some(dbg_loc); } } @@ -86,7 +85,7 @@ fn compute_mir_scopes<'gcc, 'tcx>( /// Update the `debug_context`, adding new scope to it, /// if it's not added as is denoted in `instantiated`. -/// +/// /// # Souce of Origin /// Copied from `create_scope_map.rs` of rustc_codegen_llvm /// FIXME(tempdragon/?): Add Scope Support Here. @@ -119,16 +118,14 @@ fn make_mir_scope<'gcc, 'tcx>( return; }; - if let Some(vars) = variables - { - if !vars.contains(scope) - && scope_data.inlined.is_none() { - // Do not create a DIScope if there are no variables defined in this - // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. - debug_context.scopes[scope] = parent_scope; - instantiated.insert(scope); - return; - } + if let Some(vars) = variables { + if !vars.contains(scope) && scope_data.inlined.is_none() { + // Do not create a DIScope if there are no variables defined in this + // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. + debug_context.scopes[scope] = parent_scope; + instantiated.insert(scope); + return; + } } let loc = cx.lookup_debug_loc(scope_data.span.lo()); @@ -145,7 +142,7 @@ fn make_mir_scope<'gcc, 'tcx>( let p_inlined_at = parent_scope.inlined_at; // TODO(tempdragon): dbg_scope: Add support for scope extension here. inlined_at.or(p_inlined_at); - + debug_context.scopes[scope] = DebugScope { dbg_scope, inlined_at, @@ -216,7 +213,6 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { llfn: RValue<'gcc>, mir: &mir::Body<'tcx>, ) -> Option> { - // TODO(antoyo) if self.sess().opts.debuginfo == DebugInfo::None { return None; } @@ -278,33 +274,27 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { span: Span, ) -> Self::DILocation { let pos = span.lo(); - let DebugLoc{file, line, col} = self.lookup_debug_loc(pos); + let DebugLoc { file, line, col } = self.lookup_debug_loc(pos); let loc = match &file.name { rustc_span::FileName::Real(name) => match name { rustc_span::RealFileName::LocalPath(name) => { if let Some(name) = name.to_str() { - self.context - .new_location(name, line as i32, col as i32) - } else{ + self.context.new_location(name, line as i32, col as i32) + } else { Location::null() } } - rustc_span::RealFileName::Remapped { - local_path, - virtual_name:_, - } => if let Some(name) = local_path.as_ref() { - if let Some(name) = name.to_str(){ - self.context.new_location( - name, - line as i32, - col as i32, - ) + rustc_span::RealFileName::Remapped { local_path, virtual_name: _ } => { + if let Some(name) = local_path.as_ref() { + if let Some(name) = name.to_str() { + self.context.new_location(name, line as i32, col as i32) + } else { + Location::null() + } } else { Location::null() } - } else{ - Location::null() - }, + } }, _ => Location::null(), }; diff --git a/src/declare.rs b/src/declare.rs index 72cba9fbba95a..db6edbab12d4d 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -1,6 +1,6 @@ -use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type}; -#[cfg(feature="master")] +#[cfg(feature = "master")] use gccjit::{FnAttribute, ToRValue}; +use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type}; use rustc_codegen_ssa::traits::BaseTypeMethods; use rustc_middle::ty::Ty; use rustc_span::Symbol; @@ -11,7 +11,13 @@ use crate::context::CodegenCx; use crate::intrinsic::llvm; impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + pub fn get_or_insert_global( + &self, + name: &str, + ty: Type<'gcc>, + is_tls: bool, + link_section: Option, + ) -> LValue<'gcc> { if self.globals.borrow().contains_key(name) { let typ = self.globals.borrow()[name].get_type(); let global = self.context.new_global(None, GlobalKind::Imported, typ, name); @@ -22,8 +28,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global.set_link_section(link_section.as_str()); } global - } - else { + } else { self.declare_global(name, ty, GlobalKind::Exported, is_tls, link_section) } } @@ -33,19 +38,37 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { self.context.new_global(None, GlobalKind::Internal, ty, &name) } - pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> { + pub fn declare_global_with_linkage( + &self, + name: &str, + ty: Type<'gcc>, + linkage: GlobalKind, + ) -> LValue<'gcc> { let global = self.context.new_global(None, linkage, ty, name); let global_address = global.get_address(None); self.globals.borrow_mut().insert(name.to_string(), global_address); global } - pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> Function<'gcc> { + pub fn declare_func( + &self, + name: &str, + return_type: Type<'gcc>, + params: &[Type<'gcc>], + variadic: bool, + ) -> Function<'gcc> { self.linkage.set(FunctionType::Extern); declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic) } - pub fn declare_global(&self, name: &str, ty: Type<'gcc>, global_kind: GlobalKind, is_tls: bool, link_section: Option) -> LValue<'gcc> { + pub fn declare_global( + &self, + name: &str, + ty: Type<'gcc>, + global_kind: GlobalKind, + is_tls: bool, + link_section: Option, + ) -> LValue<'gcc> { let global = self.context.new_global(None, global_kind, ty, name); if is_tls { global.set_tls_model(self.tls_model); @@ -65,13 +88,25 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global } - pub fn declare_entry_fn(&self, name: &str, _fn_type: Type<'gcc>, callconv: () /*llvm::CCallConv*/) -> RValue<'gcc> { + pub fn declare_entry_fn( + &self, + name: &str, + _fn_type: Type<'gcc>, + callconv: (), /*llvm::CCallConv*/ + ) -> RValue<'gcc> { // TODO(antoyo): use the fn_type parameter. let const_string = self.context.new_type::().make_pointer().make_pointer(); let return_type = self.type_i32(); let variadic = false; self.linkage.set(FunctionType::Exported); - let func = declare_raw_fn(self, name, callconv, return_type, &[self.type_i32(), const_string], variadic); + let func = declare_raw_fn( + self, + name, + callconv, + return_type, + &[self.type_i32(), const_string], + variadic, + ); // NOTE: it is needed to set the current_func here as well, because get_fn() is not called // for the main function. *self.current_func.borrow_mut() = Some(func); @@ -85,19 +120,32 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { arguments_type, is_c_variadic, on_stack_param_indices, - #[cfg(feature="master")] + #[cfg(feature = "master")] fn_attributes, } = fn_abi.gcc_type(self); - let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &arguments_type, is_c_variadic); + let func = declare_raw_fn( + self, + name, + (), /*fn_abi.llvm_cconv()*/ + return_type, + &arguments_type, + is_c_variadic, + ); self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices); - #[cfg(feature="master")] + #[cfg(feature = "master")] for fn_attr in fn_attributes { func.add_attribute(fn_attr); } func } - pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + pub fn define_global( + &self, + name: &str, + ty: Type<'gcc>, + is_tls: bool, + link_section: Option, + ) -> LValue<'gcc> { self.get_or_insert_global(name, ty, is_tls, link_section) } @@ -111,64 +159,84 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { /// /// If there’s a value with the same name already declared, the function will /// update the declaration and return existing Value instead. -fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> { +fn declare_raw_fn<'gcc>( + cx: &CodegenCx<'gcc, '_>, + name: &str, + _callconv: (), /*llvm::CallConv*/ + return_type: Type<'gcc>, + param_types: &[Type<'gcc>], + variadic: bool, +) -> Function<'gcc> { if name.starts_with("llvm.") { let intrinsic = llvm::intrinsic(name, cx); cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic); return intrinsic; } - let func = - if cx.functions.borrow().contains_key(name) { - cx.functions.borrow()[name] - } - else { - let params: Vec<_> = param_types.into_iter().enumerate() - .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name. + let func = if cx.functions.borrow().contains_key(name) { + cx.functions.borrow()[name] + } else { + let params: Vec<_> = param_types + .into_iter() + .enumerate() + .map(|(index, param)| { + cx.context.new_parameter(None, *param, &format!("param{}", index)) + }) // TODO(antoyo): set name. + .collect(); + #[cfg(not(feature = "master"))] + let name = mangle_name(name); + let func = + cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, &name, variadic); + cx.functions.borrow_mut().insert(name.to_string(), func); + + #[cfg(feature = "master")] + if name == "rust_eh_personality" { + // NOTE: GCC will sometimes change the personality function set on a function from + // rust_eh_personality to __gcc_personality_v0 as an optimization. + // As such, we need to create a weak alias from __gcc_personality_v0 to + // rust_eh_personality in order to avoid a linker error. + // This needs to be weak in order to still allow using the standard + // __gcc_personality_v0 when the linking to it. + // Since aliases don't work (maybe because of a bug in LTO partitioning?), we + // create a wrapper function that calls rust_eh_personality. + + let params: Vec<_> = param_types + .into_iter() + .enumerate() + .map(|(index, param)| { + cx.context.new_parameter(None, *param, &format!("param{}", index)) + }) // TODO(antoyo): set name. .collect(); - #[cfg(not(feature="master"))] - let name = mangle_name(name); - let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, &name, variadic); - cx.functions.borrow_mut().insert(name.to_string(), func); - - #[cfg(feature="master")] - if name == "rust_eh_personality" { - // NOTE: GCC will sometimes change the personality function set on a function from - // rust_eh_personality to __gcc_personality_v0 as an optimization. - // As such, we need to create a weak alias from __gcc_personality_v0 to - // rust_eh_personality in order to avoid a linker error. - // This needs to be weak in order to still allow using the standard - // __gcc_personality_v0 when the linking to it. - // Since aliases don't work (maybe because of a bug in LTO partitioning?), we - // create a wrapper function that calls rust_eh_personality. - - let params: Vec<_> = param_types.into_iter().enumerate() - .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name. - .collect(); - let gcc_func = cx.context.new_function(None, FunctionType::Exported, return_type, ¶ms, "__gcc_personality_v0", variadic); - - // We need a normal extern function for the crates that access rust_eh_personality - // without defining it, otherwise we'll get a compiler error. - // - // For the crate defining it, that needs to be a weak alias instead. - gcc_func.add_attribute(FnAttribute::Weak); - - let block = gcc_func.new_block("start"); - let mut args = vec![]; - for param in ¶ms { - args.push(param.to_rvalue()); - } - let call = cx.context.new_call(None, func, &args); - if return_type == cx.type_void() { - block.add_eval(None, call); - block.end_with_void_return(None); - } - else { - block.end_with_return(None, call); - } + let gcc_func = cx.context.new_function( + None, + FunctionType::Exported, + return_type, + ¶ms, + "__gcc_personality_v0", + variadic, + ); + + // We need a normal extern function for the crates that access rust_eh_personality + // without defining it, otherwise we'll get a compiler error. + // + // For the crate defining it, that needs to be a weak alias instead. + gcc_func.add_attribute(FnAttribute::Weak); + + let block = gcc_func.new_block("start"); + let mut args = vec![]; + for param in ¶ms { + args.push(param.to_rvalue()); } + let call = cx.context.new_call(None, func, &args); + if return_type == cx.type_void() { + block.add_eval(None, call); + block.end_with_void_return(None); + } else { + block.end_with_return(None, call); + } + } - func - }; + func + }; // TODO(antoyo): set function calling convention. // TODO(antoyo): set unnamed address. @@ -183,15 +251,22 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll // FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _. // Unsupported characters: `$`, `.` and `*`. // FIXME(antoyo): `*` might not be expected: https://github.com/rust-lang/rust/issues/116979#issuecomment-1840926865 -#[cfg(not(feature="master"))] +#[cfg(not(feature = "master"))] fn mangle_name(name: &str) -> String { - name.replace(|char: char| { - if !char.is_alphanumeric() && char != '_' { - debug_assert!("$.*".contains(char), "Unsupported char in function name {}: {}", name, char); - true - } - else { - false - } - }, "_") + name.replace( + |char: char| { + if !char.is_alphanumeric() && char != '_' { + debug_assert!( + "$.*".contains(char), + "Unsupported char in function name {}: {}", + name, + char + ); + true + } else { + false + } + }, + "_", + ) } diff --git a/src/errors.rs b/src/errors.rs index 79eb4406b8a33..62be9e9b379a1 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -116,7 +116,7 @@ impl IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl let mut diag = DiagnosticBuilder::new( dcx, level, - fluent::codegen_gcc_target_feature_disable_or_enable + fluent::codegen_gcc_target_feature_disable_or_enable, ); if let Some(span) = self.span { diag.span(span); diff --git a/src/gcc_util.rs b/src/gcc_util.rs index 4babe5bfb813f..53877e8ff7fad 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -1,4 +1,4 @@ -#[cfg(feature="master")] +#[cfg(feature = "master")] use gccjit::Context; use smallvec::{smallvec, SmallVec}; @@ -7,7 +7,10 @@ use rustc_middle::bug; use rustc_session::Session; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; -use crate::errors::{PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; +use crate::errors::{ + PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, + UnknownCTargetFeaturePrefix, +}; /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). @@ -44,7 +47,10 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Vec Vec>(), + Some( + to_gcc_features(sess, feature) + .iter() + .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) + .map(|feature| { + if enable_disable == '-' { + format!("-{}", feature) + } else { + feature.to_string() + } + }) + .collect::>(), ) }) .flatten(); @@ -184,7 +188,10 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> // Given a map from target_features to whether they are enabled or disabled, // ensure only valid combinations are allowed. -pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> { +pub fn check_tied_features( + sess: &Session, + features: &FxHashMap<&str, bool>, +) -> Option<&'static [&'static str]> { for tied in sess.target.tied_target_features() { // Tied features must be set to the same value, or not set at all let mut tied_iter = tied.iter(); @@ -199,7 +206,7 @@ pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> fn arch_to_gcc(name: &str) -> &str { match name { "M68020" => "68020", - _ => name, + _ => name, } } @@ -208,15 +215,13 @@ fn handle_native(name: &str) -> &str { return arch_to_gcc(name); } - #[cfg(feature="master")] + #[cfg(feature = "master")] { // Get the native arch. let context = Context::default(); - context.get_target_info().arch().unwrap() - .to_str() - .unwrap() + context.get_target_info().arch().unwrap().to_str().unwrap() } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] unimplemented!(); } diff --git a/src/int.rs b/src/int.rs index fe38d89ff8c3c..841bcf592e489 100644 --- a/src/int.rs +++ b/src/int.rs @@ -8,11 +8,18 @@ use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, T use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{ParamEnv, Ty}; -use rustc_target::abi::{Endian, call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}}; +use rustc_target::abi::{ + call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}, + Endian, +}; use rustc_target::spec; use crate::builder::ToGccComp; -use crate::{builder::Builder, common::{SignType, TypeReflection}, context::CodegenCx}; +use crate::{ + builder::Builder, + common::{SignType, TypeReflection}, + context::CodegenCx, +}; impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn gcc_urem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -29,19 +36,24 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let typ = a.get_type(); if self.is_native_int_type_or_bool(typ) { let operation = - if typ.is_bool() { - UnaryOp::LogicalNegate - } - else { - UnaryOp::BitwiseNegate - }; - self.cx.context.new_unary_op(self.loc, operation, typ, a) - } - else { + if typ.is_bool() { UnaryOp::LogicalNegate } else { UnaryOp::BitwiseNegate }; + self.cx.context.new_unary_op(self.location, operation, typ, a) + } else { let element_type = typ.dyncast_array().expect("element type"); - self.from_low_high_rvalues(typ, - self.cx.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, element_type, self.low(a)), - self.cx.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, element_type, self.high(a)), + self.from_low_high_rvalues( + typ, + self.cx.context.new_unary_op( + self.location, + UnaryOp::BitwiseNegate, + element_type, + self.low(a), + ), + self.cx.context.new_unary_op( + self.location, + UnaryOp::BitwiseNegate, + element_type, + self.high(a), + ), ) } } @@ -49,15 +61,14 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); if self.is_native_int_type(a_type) || a_type.is_vector() { - self.cx.context.new_unary_op(self.loc, UnaryOp::Minus, a.get_type(), a) - } - else { + self.cx.context.new_unary_op(self.location, UnaryOp::Minus, a.get_type(), a) + } else { self.gcc_add(self.gcc_not(a), self.gcc_int(a_type, 1)) } } pub fn gcc_and(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b, self.loc) + self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b, self.location) } pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -69,20 +80,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by a signed number. // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. if a_type.is_signed(self) != b_type.is_signed(self) { - let b = self.context.new_cast(self.loc, b, a_type); + let b = self.context.new_cast(self.location, b, a_type); a >> b - } - else { + } else { a >> b } - } - else if a_type.is_vector() && a_type.is_vector() { + } else if a_type.is_vector() && a_type.is_vector() { a >> b - } - else if a_native && !b_native { + } else if a_native && !b_native { self.gcc_lshr(a, self.gcc_int_cast(b, a_type)) - } - else { + } else { // NOTE: we cannot use the lshr builtin because it's calling hi() (to get the most // significant half of the number) which uses lshr. @@ -95,46 +102,38 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b0_block = func.new_block("b0"); let actual_else_block = func.new_block("actual_else"); - let result = func.new_local(self.loc, a_type, "shiftResult"); + let result = func.new_local(self.location, a_type, "shiftResult"); let sixty_four = self.gcc_int(native_int_type, 64); let sixty_three = self.gcc_int(native_int_type, 63); let zero = self.gcc_zero(native_int_type); let b = self.gcc_int_cast(b, native_int_type); let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); - self.llbb().end_with_conditional(self.loc, condition, then_block, else_block); + self.llbb().end_with_conditional(self.location, condition, then_block, else_block); let shift_value = self.gcc_sub(b, sixty_four); let high = self.high(a); - let sign = - if a_type.is_signed(self) { - high >> sixty_three - } - else { - zero - }; + let sign = if a_type.is_signed(self) { high >> sixty_three } else { zero }; let array_value = self.from_low_high_rvalues(a_type, high >> shift_value, sign); - then_block.add_assignment(self.loc, result, array_value); - then_block.end_with_jump(self.loc, after_block); + then_block.add_assignment(self.location, result, array_value); + then_block.end_with_jump(self.location, after_block); let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); - else_block.end_with_conditional(self.loc, condition, b0_block, actual_else_block); + else_block.end_with_conditional(self.location, condition, b0_block, actual_else_block); - b0_block.add_assignment(self.loc, result, a); - b0_block.end_with_jump(self.loc, after_block); + b0_block.add_assignment(self.location, result, a); + b0_block.end_with_jump(self.location, after_block); let shift_value = self.gcc_sub(sixty_four, b); // NOTE: cast low to its unsigned type in order to perform a logical right shift. let unsigned_type = native_int_type.to_unsigned(&self.cx); - let casted_low = self.context.new_cast(self.loc, self.low(a), unsigned_type); - let shifted_low = casted_low >> self.context.new_cast(self.loc, b, unsigned_type); - let shifted_low = self.context.new_cast(self.loc, shifted_low, native_int_type); - let array_value = self.from_low_high_rvalues(a_type, - (high << shift_value) | shifted_low, - high >> b, - ); - actual_else_block.add_assignment(self.loc, result, array_value); - actual_else_block.end_with_jump(self.loc, after_block); + let casted_low = self.context.new_cast(self.location, self.low(a), unsigned_type); + let shifted_low = casted_low >> self.context.new_cast(self.location, b, unsigned_type); + let shifted_low = self.context.new_cast(self.location, shifted_low, native_int_type); + let array_value = + self.from_low_high_rvalues(a_type, (high << shift_value) | shifted_low, high >> b); + actual_else_block.add_assignment(self.location, result, array_value); + actual_else_block.end_with_jump(self.location, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -144,38 +143,49 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } - fn additive_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + fn additive_operation( + &self, + operation: BinaryOp, + a: RValue<'gcc>, + mut b: RValue<'gcc>, + ) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); - if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { + if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) + || (a_type.is_vector() && b_type.is_vector()) + { if a_type != b_type { if a_type.is_vector() { // Vector types need to be bitcast. // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - b = self.context.new_bitcast(self.loc, b, a.get_type()); - } - else { - b = self.context.new_cast(self.loc, b, a.get_type()); + b = self.context.new_bitcast(self.location, b, a.get_type()); + } else { + b = self.context.new_cast(self.location, b, a.get_type()); } } - self.context.new_binary_op(self.loc, operation, a_type, a, b) - } - else { + self.context.new_binary_op(self.location, operation, a_type, a, b) + } else { debug_assert!(a_type.dyncast_array().is_some()); debug_assert!(b_type.dyncast_array().is_some()); let signed = a_type.is_compatible_with(self.i128_type); - let func_name = - match (operation, signed) { - (BinaryOp::Plus, true) => "__rust_i128_add", - (BinaryOp::Plus, false) => "__rust_u128_add", - (BinaryOp::Minus, true) => "__rust_i128_sub", - (BinaryOp::Minus, false) => "__rust_u128_sub", - _ => unreachable!("unexpected additive operation {:?}", operation), - }; - let param_a = self.context.new_parameter(self.loc, a_type, "a"); - let param_b = self.context.new_parameter(self.loc, b_type, "b"); - let func = self.context.new_function(self.loc, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); - self.context.new_call(self.loc, func, &[a, b]) + let func_name = match (operation, signed) { + (BinaryOp::Plus, true) => "__rust_i128_add", + (BinaryOp::Plus, false) => "__rust_u128_add", + (BinaryOp::Minus, true) => "__rust_i128_sub", + (BinaryOp::Minus, false) => "__rust_u128_sub", + _ => unreachable!("unexpected additive operation {:?}", operation), + }; + let param_a = self.context.new_parameter(self.location, a_type, "a"); + let param_b = self.context.new_parameter(self.location, b_type, "b"); + let func = self.context.new_function( + self.location, + FunctionType::Extern, + a_type, + &[param_a, param_b], + func_name, + false, + ); + self.context.new_call(self.location, func, &[a, b]) } } @@ -191,27 +201,36 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.additive_operation(BinaryOp::Minus, a, b) } - fn multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + fn multiplicative_operation( + &self, + operation: BinaryOp, + operation_name: &str, + signed: bool, + a: RValue<'gcc>, + b: RValue<'gcc>, + ) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); - if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { - self.context.new_binary_op(self.loc, operation, a_type, a, b) - } - else { + if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) + || (a_type.is_vector() && b_type.is_vector()) + { + self.context.new_binary_op(self.location, operation, a_type, a, b) + } else { debug_assert!(a_type.dyncast_array().is_some()); debug_assert!(b_type.dyncast_array().is_some()); - let sign = - if signed { - "" - } - else { - "u" - }; + let sign = if signed { "" } else { "u" }; let func_name = format!("__{}{}ti3", sign, operation_name); - let param_a = self.context.new_parameter(self.loc, a_type, "a"); - let param_b = self.context.new_parameter(self.loc, b_type, "b"); - let func = self.context.new_function(self.loc, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); - self.context.new_call(self.loc, func, &[a, b]) + let param_a = self.context.new_parameter(self.location, a_type, "a"); + let param_b = self.context.new_parameter(self.location, b_type, "b"); + let func = self.context.new_function( + self.location, + FunctionType::Extern, + a_type, + &[param_a, param_b], + func_name, + false, + ); + self.context.new_call(self.location, func, &[a, b]) } } @@ -227,137 +246,133 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.multiplicative_operation(BinaryOp::Divide, "div", false, a, b) } - pub fn gcc_checked_binop(&self, oop: OverflowOp, typ: Ty<'_>, lhs: ::Value, rhs: ::Value) -> (::Value, ::Value) { + pub fn gcc_checked_binop( + &self, + oop: OverflowOp, + typ: Ty<'_>, + lhs: ::Value, + rhs: ::Value, + ) -> (::Value, ::Value) { use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*}; - let new_kind = - match typ.kind() { - Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), - Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), - t @ (Uint(_) | Int(_)) => t.clone(), - _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), - }; + let new_kind = match typ.kind() { + Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), + Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), + t @ (Uint(_) | Int(_)) => t.clone(), + _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), + }; // TODO(antoyo): remove duplication with intrinsic? - let name = - if self.is_native_int_type(lhs.get_type()) { - match oop { - OverflowOp::Add => - match new_kind { - Int(I8) => "__builtin_add_overflow", - Int(I16) => "__builtin_add_overflow", - Int(I32) => "__builtin_sadd_overflow", - Int(I64) => "__builtin_saddll_overflow", - Int(I128) => "__builtin_add_overflow", - - Uint(U8) => "__builtin_add_overflow", - Uint(U16) => "__builtin_add_overflow", - Uint(U32) => "__builtin_uadd_overflow", - Uint(U64) => "__builtin_uaddll_overflow", - Uint(U128) => "__builtin_add_overflow", - + let name = if self.is_native_int_type(lhs.get_type()) { + match oop { + OverflowOp::Add => match new_kind { + Int(I8) => "__builtin_add_overflow", + Int(I16) => "__builtin_add_overflow", + Int(I32) => "__builtin_sadd_overflow", + Int(I64) => "__builtin_saddll_overflow", + Int(I128) => "__builtin_add_overflow", + + Uint(U8) => "__builtin_add_overflow", + Uint(U16) => "__builtin_add_overflow", + Uint(U32) => "__builtin_uadd_overflow", + Uint(U64) => "__builtin_uaddll_overflow", + Uint(U128) => "__builtin_add_overflow", + + _ => unreachable!(), + }, + OverflowOp::Sub => match new_kind { + Int(I8) => "__builtin_sub_overflow", + Int(I16) => "__builtin_sub_overflow", + Int(I32) => "__builtin_ssub_overflow", + Int(I64) => "__builtin_ssubll_overflow", + Int(I128) => "__builtin_sub_overflow", + + Uint(U8) => "__builtin_sub_overflow", + Uint(U16) => "__builtin_sub_overflow", + Uint(U32) => "__builtin_usub_overflow", + Uint(U64) => "__builtin_usubll_overflow", + Uint(U128) => "__builtin_sub_overflow", + + _ => unreachable!(), + }, + OverflowOp::Mul => match new_kind { + Int(I8) => "__builtin_mul_overflow", + Int(I16) => "__builtin_mul_overflow", + Int(I32) => "__builtin_smul_overflow", + Int(I64) => "__builtin_smulll_overflow", + Int(I128) => "__builtin_mul_overflow", + + Uint(U8) => "__builtin_mul_overflow", + Uint(U16) => "__builtin_mul_overflow", + Uint(U32) => "__builtin_umul_overflow", + Uint(U64) => "__builtin_umulll_overflow", + Uint(U128) => "__builtin_mul_overflow", + + _ => unreachable!(), + }, + } + } else { + match new_kind { + Int(I128) | Uint(U128) => { + let func_name = match oop { + OverflowOp::Add => match new_kind { + Int(I128) => "__rust_i128_addo", + Uint(U128) => "__rust_u128_addo", _ => unreachable!(), }, - OverflowOp::Sub => - match new_kind { - Int(I8) => "__builtin_sub_overflow", - Int(I16) => "__builtin_sub_overflow", - Int(I32) => "__builtin_ssub_overflow", - Int(I64) => "__builtin_ssubll_overflow", - Int(I128) => "__builtin_sub_overflow", - - Uint(U8) => "__builtin_sub_overflow", - Uint(U16) => "__builtin_sub_overflow", - Uint(U32) => "__builtin_usub_overflow", - Uint(U64) => "__builtin_usubll_overflow", - Uint(U128) => "__builtin_sub_overflow", - + OverflowOp::Sub => match new_kind { + Int(I128) => "__rust_i128_subo", + Uint(U128) => "__rust_u128_subo", _ => unreachable!(), }, - OverflowOp::Mul => - match new_kind { - Int(I8) => "__builtin_mul_overflow", - Int(I16) => "__builtin_mul_overflow", - Int(I32) => "__builtin_smul_overflow", - Int(I64) => "__builtin_smulll_overflow", - Int(I128) => "__builtin_mul_overflow", - - Uint(U8) => "__builtin_mul_overflow", - Uint(U16) => "__builtin_mul_overflow", - Uint(U32) => "__builtin_umul_overflow", - Uint(U64) => "__builtin_umulll_overflow", - Uint(U128) => "__builtin_mul_overflow", - + OverflowOp::Mul => match new_kind { + Int(I128) => "__rust_i128_mulo", // TODO(antoyo): use __muloti4d instead? + Uint(U128) => "__rust_u128_mulo", _ => unreachable!(), }, + }; + return self.operation_with_overflow(func_name, lhs, rhs); } - } - else { - match new_kind { - Int(I128) | Uint(U128) => { - let func_name = - match oop { - OverflowOp::Add => - match new_kind { - Int(I128) => "__rust_i128_addo", - Uint(U128) => "__rust_u128_addo", - _ => unreachable!(), - }, - OverflowOp::Sub => - match new_kind { - Int(I128) => "__rust_i128_subo", - Uint(U128) => "__rust_u128_subo", - _ => unreachable!(), - }, - OverflowOp::Mul => - match new_kind { - Int(I128) => "__rust_i128_mulo", // TODO(antoyo): use __muloti4d instead? - Uint(U128) => "__rust_u128_mulo", - _ => unreachable!(), - }, - }; - return self.operation_with_overflow(func_name, lhs, rhs); + _ => match oop { + OverflowOp::Mul => match new_kind { + Int(I32) => "__mulosi4", + Int(I64) => "__mulodi4", + _ => unreachable!(), }, - _ => { - match oop { - OverflowOp::Mul => - match new_kind { - Int(I32) => "__mulosi4", - Int(I64) => "__mulodi4", - _ => unreachable!(), - }, - _ => unimplemented!("overflow operation for {:?}", new_kind), - } - } - } - }; + _ => unimplemented!("overflow operation for {:?}", new_kind), + }, + } + }; let intrinsic = self.context.get_builtin_function(&name); - let res = self.current_func() + let res = self + .current_func() // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? - .new_local(self.loc, rhs.get_type(), "binopResult") - .get_address(self.loc); + .new_local(self.location, rhs.get_type(), "binopResult") + .get_address(self.location); let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); - (res.dereference(self.loc).to_rvalue(), overflow) + (res.dereference(self.location).to_rvalue(), overflow) } - pub fn operation_with_overflow(&self, func_name: &str, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + pub fn operation_with_overflow( + &self, + func_name: &str, + lhs: RValue<'gcc>, + rhs: RValue<'gcc>, + ) -> (RValue<'gcc>, RValue<'gcc>) { let a_type = lhs.get_type(); let b_type = rhs.get_type(); debug_assert!(a_type.dyncast_array().is_some()); debug_assert!(b_type.dyncast_array().is_some()); - let param_a = self.context.new_parameter(self.loc, a_type, "a"); - let param_b = self.context.new_parameter(self.loc, b_type, "b"); - let result_field = self.context.new_field(self.loc, a_type, "result"); - let overflow_field = self.context.new_field(self.loc, self.bool_type, "overflow"); + let param_a = self.context.new_parameter(self.location, a_type, "a"); + let param_b = self.context.new_parameter(self.location, b_type, "b"); + let result_field = self.context.new_field(self.location, a_type, "result"); + let overflow_field = self.context.new_field(self.location, self.bool_type, "overflow"); let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]); let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap(); - let arg_abi = ArgAbi { - layout, - mode: PassMode::Direct(ArgAttributes::new()), - }; + let arg_abi = ArgAbi { layout, mode: PassMode::Direct(ArgAttributes::new()) }; let mut fn_abi = FnAbi { args: vec![arg_abi.clone(), arg_abi.clone()].into_boxed_slice(), ret: arg_abi, @@ -366,38 +381,66 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { conv: Conv::C, can_unwind: false, }; - fn_abi.adjust_for_foreign_abi(self.cx, spec::abi::Abi::C { - unwind: false, - }).unwrap(); + fn_abi.adjust_for_foreign_abi(self.cx, spec::abi::Abi::C { unwind: false }).unwrap(); let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); - let return_type = self.context.new_struct_type(self.loc, "result_overflow", &[result_field, overflow_field]); - let result = - if indirect { - let return_value = self.current_func().new_local(self.loc, return_type.as_type(), "return_value"); - let return_param_type = return_type.as_type().make_pointer(); - let return_param = self.context.new_parameter(self.loc, return_param_type, "return_value"); - let func = self.context.new_function(self.loc, FunctionType::Extern, self.type_void(), &[return_param, param_a, param_b], func_name, false); - self.llbb().add_eval(self.loc, self.context.new_call(self.loc, func, &[return_value.get_address(self.loc), lhs, rhs])); - return_value.to_rvalue() - } - else { - let func = self.context.new_function(self.loc, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false); - self.context.new_call(self.loc, func, &[lhs, rhs]) - }; - let overflow = result.access_field(self.loc, overflow_field); - let int_result = result.access_field(self.loc, result_field); + let return_type = self.context.new_struct_type( + self.location, + "result_overflow", + &[result_field, overflow_field], + ); + let result = if indirect { + let return_value = + self.current_func().new_local(self.location, return_type.as_type(), "return_value"); + let return_param_type = return_type.as_type().make_pointer(); + let return_param = + self.context.new_parameter(self.location, return_param_type, "return_value"); + let func = self.context.new_function( + self.location, + FunctionType::Extern, + self.type_void(), + &[return_param, param_a, param_b], + func_name, + false, + ); + self.llbb().add_eval( + self.location, + self.context.new_call( + self.location, + func, + &[return_value.get_address(self.location), lhs, rhs], + ), + ); + return_value.to_rvalue() + } else { + let func = self.context.new_function( + self.location, + FunctionType::Extern, + return_type.as_type(), + &[param_a, param_b], + func_name, + false, + ); + self.context.new_call(self.location, func, &[lhs, rhs]) + }; + let overflow = result.access_field(self.location, overflow_field); + let int_result = result.access_field(self.location, result_field); (int_result, overflow) } - pub fn gcc_icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { + pub fn gcc_icmp( + &mut self, + op: IntPredicate, + mut lhs: RValue<'gcc>, + mut rhs: RValue<'gcc>, + ) -> RValue<'gcc> { let a_type = lhs.get_type(); let b_type = rhs.get_type(); if self.is_non_native_int_type(a_type) || self.is_non_native_int_type(b_type) { // This algorithm is based on compiler-rt's __cmpti2: // https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/cmpti2.c#L21 - let result = self.current_func().new_local(self.loc, self.int_type, "icmp_result"); + let result = self.current_func().new_local(self.location, self.int_type, "icmp_result"); let block1 = self.current_func().new_block("block1"); let block2 = self.current_func().new_block("block2"); let block3 = self.current_func().new_block("block3"); @@ -413,92 +456,149 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // the sign is only on high). let unsigned_type = native_int_type.to_unsigned(&self.cx); - let lhs_low = self.context.new_cast(self.loc, self.low(lhs), unsigned_type); - let rhs_low = self.context.new_cast(self.loc, self.low(rhs), unsigned_type); + let lhs_low = self.context.new_cast(self.location, self.low(lhs), unsigned_type); + let rhs_low = self.context.new_cast(self.location, self.low(rhs), unsigned_type); - let condition = self.context.new_comparison(self.loc, ComparisonOp::LessThan, self.high(lhs), self.high(rhs)); - self.llbb().end_with_conditional(self.loc, condition, block1, block2); + let condition = self.context.new_comparison( + self.location, + ComparisonOp::LessThan, + self.high(lhs), + self.high(rhs), + ); + self.llbb().end_with_conditional(self.location, condition, block1, block2); - block1.add_assignment(self.loc, result, self.context.new_rvalue_zero(self.int_type)); - block1.end_with_jump(self.loc, after); + block1.add_assignment( + self.location, + result, + self.context.new_rvalue_zero(self.int_type), + ); + block1.end_with_jump(self.location, after); - let condition = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, self.high(lhs), self.high(rhs)); - block2.end_with_conditional(self.loc, condition, block3, block4); + let condition = self.context.new_comparison( + self.location, + ComparisonOp::GreaterThan, + self.high(lhs), + self.high(rhs), + ); + block2.end_with_conditional(self.location, condition, block3, block4); - block3.add_assignment(self.loc, result, self.context.new_rvalue_from_int(self.int_type, 2)); - block3.end_with_jump(self.loc, after); + block3.add_assignment( + self.location, + result, + self.context.new_rvalue_from_int(self.int_type, 2), + ); + block3.end_with_jump(self.location, after); - let condition = self.context.new_comparison(self.loc, ComparisonOp::LessThan, lhs_low, rhs_low); - block4.end_with_conditional(self.loc, condition, block5, block6); + let condition = self.context.new_comparison( + self.location, + ComparisonOp::LessThan, + lhs_low, + rhs_low, + ); + block4.end_with_conditional(self.location, condition, block5, block6); - block5.add_assignment(self.loc, result, self.context.new_rvalue_zero(self.int_type)); - block5.end_with_jump(self.loc, after); + block5.add_assignment( + self.location, + result, + self.context.new_rvalue_zero(self.int_type), + ); + block5.end_with_jump(self.location, after); - let condition = self.context.new_comparison(self.loc, ComparisonOp::GreaterThan, lhs_low, rhs_low); - block6.end_with_conditional(self.loc, condition, block7, block8); + let condition = self.context.new_comparison( + self.location, + ComparisonOp::GreaterThan, + lhs_low, + rhs_low, + ); + block6.end_with_conditional(self.location, condition, block7, block8); - block7.add_assignment(self.loc, result, self.context.new_rvalue_from_int(self.int_type, 2)); - block7.end_with_jump(self.loc, after); + block7.add_assignment( + self.location, + result, + self.context.new_rvalue_from_int(self.int_type, 2), + ); + block7.end_with_jump(self.location, after); - block8.add_assignment(self.loc, result, self.context.new_rvalue_one(self.int_type)); - block8.end_with_jump(self.loc, after); + block8.add_assignment( + self.location, + result, + self.context.new_rvalue_one(self.int_type), + ); + block8.end_with_jump(self.location, after); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. self.switch_to_block(after); let cmp = result.to_rvalue(); - let (op, limit) = - match op { - IntPredicate::IntEQ => { - return self.context.new_comparison(self.loc, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type)); - }, - IntPredicate::IntNE => { - return self.context.new_comparison(self.loc, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type)); - }, - // TODO(antoyo): cast to u128 for unsigned comparison. See below. - IntPredicate::IntUGT => (ComparisonOp::Equals, 2), - IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1), - IntPredicate::IntULT => (ComparisonOp::Equals, 0), - IntPredicate::IntULE => (ComparisonOp::LessThanEquals, 1), - IntPredicate::IntSGT => (ComparisonOp::Equals, 2), - IntPredicate::IntSGE => (ComparisonOp::GreaterThanEquals, 1), - IntPredicate::IntSLT => (ComparisonOp::Equals, 0), - IntPredicate::IntSLE => (ComparisonOp::LessThanEquals, 1), - }; - self.context.new_comparison(self.loc, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit)) - } - else if a_type.get_pointee().is_some() && b_type.get_pointee().is_some() { + let (op, limit) = match op { + IntPredicate::IntEQ => { + return self.context.new_comparison( + self.location, + ComparisonOp::Equals, + cmp, + self.context.new_rvalue_one(self.int_type), + ); + } + IntPredicate::IntNE => { + return self.context.new_comparison( + self.location, + ComparisonOp::NotEquals, + cmp, + self.context.new_rvalue_one(self.int_type), + ); + } + // TODO(antoyo): cast to u128 for unsigned comparison. See below. + IntPredicate::IntUGT => (ComparisonOp::Equals, 2), + IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1), + IntPredicate::IntULT => (ComparisonOp::Equals, 0), + IntPredicate::IntULE => (ComparisonOp::LessThanEquals, 1), + IntPredicate::IntSGT => (ComparisonOp::Equals, 2), + IntPredicate::IntSGE => (ComparisonOp::GreaterThanEquals, 1), + IntPredicate::IntSLT => (ComparisonOp::Equals, 0), + IntPredicate::IntSLE => (ComparisonOp::LessThanEquals, 1), + }; + self.context.new_comparison( + self.location, + op, + cmp, + self.context.new_rvalue_from_int(self.int_type, limit), + ) + } else if a_type.get_pointee().is_some() && b_type.get_pointee().is_some() { // NOTE: gcc cannot compare pointers to different objects, but rustc does that, so cast them to usize. - lhs = self.context.new_bitcast(self.loc, lhs, self.usize_type); - rhs = self.context.new_bitcast(self.loc, rhs, self.usize_type); - self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) - } - else { + lhs = self.context.new_bitcast(self.location, lhs, self.usize_type); + rhs = self.context.new_bitcast(self.location, rhs, self.usize_type); + self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs) + } else { if a_type != b_type { // NOTE: because libgccjit cannot compare function pointers. - if a_type.dyncast_function_ptr_type().is_some() && b_type.dyncast_function_ptr_type().is_some() { - lhs = self.context.new_cast(self.loc, lhs, self.usize_type.make_pointer()); - rhs = self.context.new_cast(self.loc, rhs, self.usize_type.make_pointer()); + if a_type.dyncast_function_ptr_type().is_some() + && b_type.dyncast_function_ptr_type().is_some() + { + lhs = self.context.new_cast(self.location, lhs, self.usize_type.make_pointer()); + rhs = self.context.new_cast(self.location, rhs, self.usize_type.make_pointer()); } // NOTE: hack because we try to cast a vector type to the same vector type. else if format!("{:?}", a_type) != format!("{:?}", b_type) { - rhs = self.context.new_cast(self.loc, rhs, a_type); + rhs = self.context.new_cast(self.location, rhs, a_type); } } match op { - IntPredicate::IntUGT | IntPredicate::IntUGE | IntPredicate::IntULT | IntPredicate::IntULE => { + IntPredicate::IntUGT + | IntPredicate::IntUGE + | IntPredicate::IntULT + | IntPredicate::IntULE => { if !a_type.is_vector() { let unsigned_type = a_type.to_unsigned(&self.cx); - lhs = self.context.new_cast(self.loc, lhs, unsigned_type); - rhs = self.context.new_cast(self.loc, rhs, unsigned_type); + lhs = self.context.new_cast(self.location, lhs, unsigned_type); + rhs = self.context.new_cast(self.location, rhs, unsigned_type); } - }, + } // TODO(antoyo): we probably need to handle signed comparison for unsigned // integers. _ => (), } - self.context.new_comparison(self.loc, op.to_gcc_comparison(), lhs, rhs) + self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs) } } @@ -508,12 +608,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_type.is_vector() && b_type.is_vector() { let b = self.bitcast_if_needed(b, a_type); a ^ b - } - else if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { + } else if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) + { a ^ b - } - else { - self.from_low_high_rvalues(a_type, + } else { + self.from_low_high_rvalues( + a_type, self.low(a) ^ self.low(b), self.high(a) ^ self.high(b), ) @@ -528,25 +628,20 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_native && b_native { // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. if a_type.is_unsigned(self) && b_type.is_signed(self) { - let a = self.context.new_cast(self.loc, a, b_type); + let a = self.context.new_cast(self.location, a, b_type); let result = a << b; - self.context.new_cast(self.loc, result, a_type) - } - else if a_type.is_signed(self) && b_type.is_unsigned(self) { - let b = self.context.new_cast(self.loc, b, a_type); + self.context.new_cast(self.location, result, a_type) + } else if a_type.is_signed(self) && b_type.is_unsigned(self) { + let b = self.context.new_cast(self.location, b, a_type); a << b - } - else { + } else { a << b } - } - else if a_type.is_vector() && a_type.is_vector() { + } else if a_type.is_vector() && a_type.is_vector() { a << b - } - else if a_native && !b_native { + } else if a_native && !b_native { self.gcc_shl(a, self.gcc_int_cast(b, a_type)) - } - else { + } else { // NOTE: we cannot use the ashl builtin because it's calling widen_hi() which uses ashl. let native_int_type = a_type.dyncast_array().expect("get element type"); @@ -557,40 +652,40 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let b0_block = func.new_block("b0"); let actual_else_block = func.new_block("actual_else"); - let result = func.new_local(self.loc, a_type, "shiftResult"); + let result = func.new_local(self.location, a_type, "shiftResult"); let b = self.gcc_int_cast(b, native_int_type); let sixty_four = self.gcc_int(native_int_type, 64); let zero = self.gcc_zero(native_int_type); let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); - self.llbb().end_with_conditional(self.loc, condition, then_block, else_block); + self.llbb().end_with_conditional(self.location, condition, then_block, else_block); - let array_value = self.from_low_high_rvalues(a_type, - zero, - self.low(a) << (b - sixty_four), - ); - then_block.add_assignment(self.loc, result, array_value); - then_block.end_with_jump(self.loc, after_block); + let array_value = + self.from_low_high_rvalues(a_type, zero, self.low(a) << (b - sixty_four)); + then_block.add_assignment(self.location, result, array_value); + then_block.end_with_jump(self.location, after_block); let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); - else_block.end_with_conditional(self.loc, condition, b0_block, actual_else_block); + else_block.end_with_conditional(self.location, condition, b0_block, actual_else_block); - b0_block.add_assignment(self.loc, result, a); - b0_block.end_with_jump(self.loc, after_block); + b0_block.add_assignment(self.location, result, a); + b0_block.end_with_jump(self.location, after_block); // NOTE: cast low to its unsigned type in order to perform a logical right shift. // TODO(antoyo): adjust this ^ comment. let unsigned_type = native_int_type.to_unsigned(&self.cx); - let casted_low = self.context.new_cast(self.loc, self.low(a), unsigned_type); - let shift_value = self.context.new_cast(self.loc, sixty_four - b, unsigned_type); - let high_low = self.context.new_cast(self.loc, casted_low >> shift_value, native_int_type); + let casted_low = self.context.new_cast(self.location, self.low(a), unsigned_type); + let shift_value = self.context.new_cast(self.location, sixty_four - b, unsigned_type); + let high_low = + self.context.new_cast(self.location, casted_low >> shift_value, native_int_type); - let array_value = self.from_low_high_rvalues(a_type, + let array_value = self.from_low_high_rvalues( + a_type, self.low(a) << b, (self.high(a) << b) | high_low, ); - actual_else_block.add_assignment(self.loc, result, array_value); - actual_else_block.end_with_jump(self.loc, after_block); + actual_else_block.add_assignment(self.location, result, array_value); + actual_else_block.end_with_jump(self.location, after_block); // NOTE: since jumps were added in a place rustc does not expect, the current block in the // state need to be updated. @@ -606,10 +701,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let native_int_type = arg_type.dyncast_array().expect("get element type"); let lsb = self.low(arg); let swapped_lsb = self.gcc_bswap(lsb, width / 2); - let swapped_lsb = self.context.new_cast(self.loc, swapped_lsb, native_int_type); + let swapped_lsb = self.context.new_cast(self.location, swapped_lsb, native_int_type); let msb = self.high(arg); let swapped_msb = self.gcc_bswap(msb, width / 2); - let swapped_msb = self.context.new_cast(self.loc, swapped_msb, native_int_type); + let swapped_msb = self.context.new_cast(self.location, swapped_msb, native_int_type); // NOTE: we also need to swap the two elements here, in addition to swapping inside // the elements themselves like done above. @@ -625,7 +720,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if param_type != arg_type { arg = self.bitcast(arg, param_type); } - self.cx.context.new_call(self.loc, bswap, &[arg]) + self.cx.context.new_call(self.location, bswap, &[arg]) } } @@ -633,8 +728,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn gcc_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { if self.is_native_int_type_or_bool(typ) { self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from")) - } - else { + } else { // NOTE: set the sign in high. self.from_low_high(typ, int, -(int.is_negative() as i64)) } @@ -645,11 +739,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): libgccjit cannot create 128-bit values yet. let num = self.context.new_rvalue_from_long(self.u64_type, int as i64); self.gcc_int_cast(num, typ) - } - else if self.is_native_int_type_or_bool(typ) { - self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64) - } - else { + } else if self.is_native_int_type_or_bool(typ) { + self.context + .new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64) + } else { self.from_low_high(typ, int as i64, 0) } } @@ -666,17 +759,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let sixty_four = self.context.new_rvalue_from_long(typ, 64); let shift = high << sixty_four; shift | self.context.new_cast(None, low, typ) - } - else { + } else { self.from_low_high(typ, low as i64, high as i64) } - } - else if typ.is_i128(self) { + } else if typ.is_i128(self) { // FIXME(antoyo): libgccjit cannot create 128-bit values yet. let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); self.gcc_int_cast(num, typ) - } - else { + } else { self.gcc_uint(typ, num as u64) } } @@ -684,8 +774,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn gcc_zero(&self, typ: Type<'gcc>) -> RValue<'gcc> { if self.is_native_int_type_or_bool(typ) { self.context.new_rvalue_zero(typ) - } - else { + } else { self.from_low_high(typ, 0, 0) } } @@ -693,14 +782,19 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn gcc_int_width(&self, typ: Type<'gcc>) -> u64 { if self.is_native_int_type_or_bool(typ) { typ.get_size() as u64 * 8 - } - else { + } else { // NOTE: the only unsupported types are u128 and i128. 128 } } - fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>, loc: Option>) -> RValue<'gcc> { + fn bitwise_operation( + &self, + operation: BinaryOp, + a: RValue<'gcc>, + mut b: RValue<'gcc>, + loc: Option>, + ) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); let a_native = self.is_native_int_type_or_bool(a_type); @@ -708,49 +802,68 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { if a_type.is_vector() && b_type.is_vector() { let b = self.bitcast_if_needed(b, a_type); self.context.new_binary_op(loc, operation, a_type, a, b) - } - else if a_native && b_native { + } else if a_native && b_native { if a_type != b_type { b = self.context.new_cast(loc, b, a_type); } self.context.new_binary_op(loc, operation, a_type, a, b) - } - else { - assert!(!a_native && !b_native, "both types should either be native or non-native for or operation"); + } else { + assert!( + !a_native && !b_native, + "both types should either be native or non-native for or operation" + ); let native_int_type = a_type.dyncast_array().expect("get element type"); - self.from_low_high_rvalues(a_type, - self.context.new_binary_op(loc, operation, native_int_type, self.low(a), self.low(b)), - self.context.new_binary_op(loc, operation, native_int_type, self.high(a), self.high(b)), + self.from_low_high_rvalues( + a_type, + self.context.new_binary_op( + loc, + operation, + native_int_type, + self.low(a), + self.low(b), + ), + self.context.new_binary_op( + loc, + operation, + native_int_type, + self.high(a), + self.high(b), + ), ) } } - pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>, loc: Option>) -> RValue<'gcc> { + pub fn gcc_or( + &self, + a: RValue<'gcc>, + b: RValue<'gcc>, + loc: Option>, + ) -> RValue<'gcc> { self.bitwise_operation(BinaryOp::BitwiseOr, a, b, loc) } // TODO(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead? pub fn gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { let value_type = value.get_type(); - if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type) { + if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type) + { self.context.new_cast(None, value, dest_typ) - } - else if self.is_native_int_type_or_bool(dest_typ) { + } else if self.is_native_int_type_or_bool(dest_typ) { self.context.new_cast(None, self.low(value), dest_typ) - } - else if self.is_native_int_type_or_bool(value_type) { + } else if self.is_native_int_type_or_bool(value_type) { let dest_element_type = dest_typ.dyncast_array().expect("get element type"); // NOTE: set the sign of the value. let zero = self.context.new_rvalue_zero(value_type); - let is_negative = self.context.new_comparison(None, ComparisonOp::LessThan, value, zero); + let is_negative = + self.context.new_comparison(None, ComparisonOp::LessThan, value, zero); let is_negative = self.gcc_int_cast(is_negative, dest_element_type); - self.from_low_high_rvalues(dest_typ, + self.from_low_high_rvalues( + dest_typ, self.context.new_cast(None, value, dest_element_type), self.context.new_unary_op(None, UnaryOp::Minus, dest_element_type, is_negative), ) - } - else { + } else { // Since u128 and i128 are the only types that can be unsupported, we know the type of // value and the destination type have the same size, so a bitcast is fine. @@ -759,29 +872,34 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } - fn int_to_float_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { + fn int_to_float_cast( + &self, + signed: bool, + value: RValue<'gcc>, + dest_typ: Type<'gcc>, + ) -> RValue<'gcc> { let value_type = value.get_type(); if self.is_native_int_type_or_bool(value_type) { return self.context.new_cast(None, value, dest_typ); } debug_assert!(value_type.dyncast_array().is_some()); - let name_suffix = - match self.type_kind(dest_typ) { - TypeKind::Float => "tisf", - TypeKind::Double => "tidf", - kind => panic!("cannot cast a non-native integer to type {:?}", kind), - }; - let sign = - if signed { - "" - } - else { - "un" - }; + let name_suffix = match self.type_kind(dest_typ) { + TypeKind::Float => "tisf", + TypeKind::Double => "tidf", + kind => panic!("cannot cast a non-native integer to type {:?}", kind), + }; + let sign = if signed { "" } else { "un" }; let func_name = format!("__float{}{}", sign, name_suffix); let param = self.context.new_parameter(None, value_type, "n"); - let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false); + let func = self.context.new_function( + None, + FunctionType::Extern, + dest_typ, + &[param], + func_name, + false, + ); self.context.new_call(None, func, &[value]) } @@ -789,33 +907,42 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { self.int_to_float_cast(true, value, dest_typ) } - pub fn gcc_uint_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { + pub fn gcc_uint_to_float_cast( + &self, + value: RValue<'gcc>, + dest_typ: Type<'gcc>, + ) -> RValue<'gcc> { self.int_to_float_cast(false, value, dest_typ) } - fn float_to_int_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { + fn float_to_int_cast( + &self, + signed: bool, + value: RValue<'gcc>, + dest_typ: Type<'gcc>, + ) -> RValue<'gcc> { let value_type = value.get_type(); if self.is_native_int_type_or_bool(dest_typ) { return self.context.new_cast(None, value, dest_typ); } debug_assert!(value_type.dyncast_array().is_some()); - let name_suffix = - match self.type_kind(value_type) { - TypeKind::Float => "sfti", - TypeKind::Double => "dfti", - kind => panic!("cannot cast a {:?} to non-native integer", kind), - }; - let sign = - if signed { - "" - } - else { - "uns" - }; + let name_suffix = match self.type_kind(value_type) { + TypeKind::Float => "sfti", + TypeKind::Double => "dfti", + kind => panic!("cannot cast a {:?} to non-native integer", kind), + }; + let sign = if signed { "" } else { "uns" }; let func_name = format!("__fix{}{}", sign, name_suffix); let param = self.context.new_parameter(None, value_type, "n"); - let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false); + let func = self.context.new_function( + None, + FunctionType::Extern, + dest_typ, + &[param], + func_name, + false, + ); self.context.new_call(None, func, &[value]) } @@ -823,47 +950,54 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { self.float_to_int_cast(true, value, dest_typ) } - pub fn gcc_float_to_uint_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { + pub fn gcc_float_to_uint_cast( + &self, + value: RValue<'gcc>, + dest_typ: Type<'gcc>, + ) -> RValue<'gcc> { self.float_to_int_cast(false, value, dest_typ) } fn high(&self, value: RValue<'gcc>) -> RValue<'gcc> { - let index = - match self.sess().target.options.endian { - Endian::Little => 1, - Endian::Big => 0, - }; - self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index)) + let index = match self.sess().target.options.endian { + Endian::Little => 1, + Endian::Big => 0, + }; + self.context + .new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index)) .to_rvalue() } fn low(&self, value: RValue<'gcc>) -> RValue<'gcc> { - let index = - match self.sess().target.options.endian { - Endian::Little => 0, - Endian::Big => 1, - }; - self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index)) + let index = match self.sess().target.options.endian { + Endian::Little => 0, + Endian::Big => 1, + }; + self.context + .new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index)) .to_rvalue() } - fn from_low_high_rvalues(&self, typ: Type<'gcc>, low: RValue<'gcc>, high: RValue<'gcc>) -> RValue<'gcc> { - let (first, last) = - match self.sess().target.options.endian { - Endian::Little => (low, high), - Endian::Big => (high, low), - }; + fn from_low_high_rvalues( + &self, + typ: Type<'gcc>, + low: RValue<'gcc>, + high: RValue<'gcc>, + ) -> RValue<'gcc> { + let (first, last) = match self.sess().target.options.endian { + Endian::Little => (low, high), + Endian::Big => (high, low), + }; let values = [first, last]; self.context.new_array_constructor(None, typ, &values) } fn from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc> { - let (first, last) = - match self.sess().target.options.endian { - Endian::Little => (low, high), - Endian::Big => (high, low), - }; + let (first, last) = match self.sess().target.options.endian { + Endian::Little => (low, high), + Endian::Big => (high, low), + }; let native_int_type = typ.dyncast_array().expect("get element type"); let values = [ diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 0d2ce20c654cf..ce8dee69a9886 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -3,94 +3,185 @@ use std::borrow::Cow; use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; use rustc_codegen_ssa::traits::BuilderMethods; -use crate::{context::CodegenCx, builder::Builder}; +use crate::{builder::Builder, context::CodegenCx}; -pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, gcc_func: FunctionPtrType<'gcc>, mut args: Cow<'b, [RValue<'gcc>]>, func_name: &str, original_function_name: Option<&String>) -> Cow<'b, [RValue<'gcc>]> { +pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( + builder: &Builder<'a, 'gcc, 'tcx>, + gcc_func: FunctionPtrType<'gcc>, + mut args: Cow<'b, [RValue<'gcc>]>, + func_name: &str, + original_function_name: Option<&String>, +) -> Cow<'b, [RValue<'gcc>]> { // Some LLVM intrinsics do not map 1-to-1 to GCC intrinsics, so we add the missing // arguments here. if gcc_func.get_param_count() != args.len() { match &*func_name { // NOTE: the following intrinsics have a different number of parameters in LLVM and GCC. - "__builtin_ia32_prold512_mask" | "__builtin_ia32_pmuldq512_mask" | "__builtin_ia32_pmuludq512_mask" - | "__builtin_ia32_pmaxsd512_mask" | "__builtin_ia32_pmaxsq512_mask" | "__builtin_ia32_pmaxsq256_mask" - | "__builtin_ia32_pmaxsq128_mask" | "__builtin_ia32_pmaxud512_mask" | "__builtin_ia32_pmaxuq512_mask" - | "__builtin_ia32_pminsd512_mask" | "__builtin_ia32_pminsq512_mask" | "__builtin_ia32_pminsq256_mask" - | "__builtin_ia32_pminsq128_mask" | "__builtin_ia32_pminud512_mask" | "__builtin_ia32_pminuq512_mask" - | "__builtin_ia32_prolq512_mask" | "__builtin_ia32_prorq512_mask" | "__builtin_ia32_pslldi512_mask" - | "__builtin_ia32_psrldi512_mask" | "__builtin_ia32_psllqi512_mask" | "__builtin_ia32_psrlqi512_mask" - | "__builtin_ia32_pslld512_mask" | "__builtin_ia32_psrld512_mask" | "__builtin_ia32_psllq512_mask" - | "__builtin_ia32_psrlq512_mask" | "__builtin_ia32_psrad512_mask" | "__builtin_ia32_psraq512_mask" - | "__builtin_ia32_psradi512_mask" | "__builtin_ia32_psraqi512_mask" | "__builtin_ia32_psrav16si_mask" - | "__builtin_ia32_psrav8di_mask" | "__builtin_ia32_prolvd512_mask" | "__builtin_ia32_prorvd512_mask" - | "__builtin_ia32_prolvq512_mask" | "__builtin_ia32_prorvq512_mask" | "__builtin_ia32_psllv16si_mask" - | "__builtin_ia32_psrlv16si_mask" | "__builtin_ia32_psllv8di_mask" | "__builtin_ia32_psrlv8di_mask" - | "__builtin_ia32_permvarsi512_mask" | "__builtin_ia32_vpermilvarps512_mask" - | "__builtin_ia32_vpermilvarpd512_mask" | "__builtin_ia32_permvardi512_mask" - | "__builtin_ia32_permvarsf512_mask" | "__builtin_ia32_permvarqi512_mask" - | "__builtin_ia32_permvarqi256_mask" | "__builtin_ia32_permvarqi128_mask" - | "__builtin_ia32_vpmultishiftqb512_mask" | "__builtin_ia32_vpmultishiftqb256_mask" - | "__builtin_ia32_vpmultishiftqb128_mask" - => { + "__builtin_ia32_prold512_mask" + | "__builtin_ia32_pmuldq512_mask" + | "__builtin_ia32_pmuludq512_mask" + | "__builtin_ia32_pmaxsd512_mask" + | "__builtin_ia32_pmaxsq512_mask" + | "__builtin_ia32_pmaxsq256_mask" + | "__builtin_ia32_pmaxsq128_mask" + | "__builtin_ia32_pmaxud512_mask" + | "__builtin_ia32_pmaxuq512_mask" + | "__builtin_ia32_pminsd512_mask" + | "__builtin_ia32_pminsq512_mask" + | "__builtin_ia32_pminsq256_mask" + | "__builtin_ia32_pminsq128_mask" + | "__builtin_ia32_pminud512_mask" + | "__builtin_ia32_pminuq512_mask" + | "__builtin_ia32_prolq512_mask" + | "__builtin_ia32_prorq512_mask" + | "__builtin_ia32_pslldi512_mask" + | "__builtin_ia32_psrldi512_mask" + | "__builtin_ia32_psllqi512_mask" + | "__builtin_ia32_psrlqi512_mask" + | "__builtin_ia32_pslld512_mask" + | "__builtin_ia32_psrld512_mask" + | "__builtin_ia32_psllq512_mask" + | "__builtin_ia32_psrlq512_mask" + | "__builtin_ia32_psrad512_mask" + | "__builtin_ia32_psraq512_mask" + | "__builtin_ia32_psradi512_mask" + | "__builtin_ia32_psraqi512_mask" + | "__builtin_ia32_psrav16si_mask" + | "__builtin_ia32_psrav8di_mask" + | "__builtin_ia32_prolvd512_mask" + | "__builtin_ia32_prorvd512_mask" + | "__builtin_ia32_prolvq512_mask" + | "__builtin_ia32_prorvq512_mask" + | "__builtin_ia32_psllv16si_mask" + | "__builtin_ia32_psrlv16si_mask" + | "__builtin_ia32_psllv8di_mask" + | "__builtin_ia32_psrlv8di_mask" + | "__builtin_ia32_permvarsi512_mask" + | "__builtin_ia32_vpermilvarps512_mask" + | "__builtin_ia32_vpermilvarpd512_mask" + | "__builtin_ia32_permvardi512_mask" + | "__builtin_ia32_permvarsf512_mask" + | "__builtin_ia32_permvarqi512_mask" + | "__builtin_ia32_permvarqi256_mask" + | "__builtin_ia32_permvarqi128_mask" + | "__builtin_ia32_vpmultishiftqb512_mask" + | "__builtin_ia32_vpmultishiftqb256_mask" + | "__builtin_ia32_vpmultishiftqb128_mask" => { let mut new_args = args.to_vec(); let arg3_type = gcc_func.get_param_type(2); - let first_arg = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue(); + let first_arg = builder + .current_func() + .new_local(None, arg3_type, "undefined_for_intrinsic") + .to_rvalue(); new_args.push(first_arg); let arg4_type = gcc_func.get_param_type(3); let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); new_args.push(minus_one); args = new_args.into(); - }, - "__builtin_ia32_pmaxuq256_mask" | "__builtin_ia32_pmaxuq128_mask" | "__builtin_ia32_pminuq256_mask" - | "__builtin_ia32_pminuq128_mask" | "__builtin_ia32_prold256_mask" | "__builtin_ia32_prold128_mask" - | "__builtin_ia32_prord512_mask" | "__builtin_ia32_prord256_mask" | "__builtin_ia32_prord128_mask" - | "__builtin_ia32_prolq256_mask" | "__builtin_ia32_prolq128_mask" | "__builtin_ia32_prorq256_mask" - | "__builtin_ia32_prorq128_mask" | "__builtin_ia32_psraq256_mask" | "__builtin_ia32_psraq128_mask" - | "__builtin_ia32_psraqi256_mask" | "__builtin_ia32_psraqi128_mask" | "__builtin_ia32_psravq256_mask" - | "__builtin_ia32_psravq128_mask" | "__builtin_ia32_prolvd256_mask" | "__builtin_ia32_prolvd128_mask" - | "__builtin_ia32_prorvd256_mask" | "__builtin_ia32_prorvd128_mask" | "__builtin_ia32_prolvq256_mask" - | "__builtin_ia32_prolvq128_mask" | "__builtin_ia32_prorvq256_mask" | "__builtin_ia32_prorvq128_mask" - | "__builtin_ia32_permvardi256_mask" | "__builtin_ia32_permvardf512_mask" | "__builtin_ia32_permvardf256_mask" - | "__builtin_ia32_pmulhuw512_mask" | "__builtin_ia32_pmulhw512_mask" | "__builtin_ia32_pmulhrsw512_mask" - | "__builtin_ia32_pmaxuw512_mask" | "__builtin_ia32_pmaxub512_mask" | "__builtin_ia32_pmaxsw512_mask" - | "__builtin_ia32_pmaxsb512_mask" | "__builtin_ia32_pminuw512_mask" | "__builtin_ia32_pminub512_mask" - | "__builtin_ia32_pminsw512_mask" | "__builtin_ia32_pminsb512_mask" - | "__builtin_ia32_pmaddwd512_mask" | "__builtin_ia32_pmaddubsw512_mask" | "__builtin_ia32_packssdw512_mask" - | "__builtin_ia32_packsswb512_mask" | "__builtin_ia32_packusdw512_mask" | "__builtin_ia32_packuswb512_mask" - | "__builtin_ia32_pavgw512_mask" | "__builtin_ia32_pavgb512_mask" | "__builtin_ia32_psllw512_mask" - | "__builtin_ia32_psllwi512_mask" | "__builtin_ia32_psllv32hi_mask" | "__builtin_ia32_psrlw512_mask" - | "__builtin_ia32_psrlwi512_mask" | "__builtin_ia32_psllv16hi_mask" | "__builtin_ia32_psllv8hi_mask" - | "__builtin_ia32_psrlv32hi_mask" | "__builtin_ia32_psraw512_mask" | "__builtin_ia32_psrawi512_mask" - | "__builtin_ia32_psrlv16hi_mask" | "__builtin_ia32_psrlv8hi_mask" | "__builtin_ia32_psrav32hi_mask" - | "__builtin_ia32_permvarhi512_mask" | "__builtin_ia32_pshufb512_mask" | "__builtin_ia32_psrav16hi_mask" - | "__builtin_ia32_psrav8hi_mask" | "__builtin_ia32_permvarhi256_mask" | "__builtin_ia32_permvarhi128_mask" - => { + } + "__builtin_ia32_pmaxuq256_mask" + | "__builtin_ia32_pmaxuq128_mask" + | "__builtin_ia32_pminuq256_mask" + | "__builtin_ia32_pminuq128_mask" + | "__builtin_ia32_prold256_mask" + | "__builtin_ia32_prold128_mask" + | "__builtin_ia32_prord512_mask" + | "__builtin_ia32_prord256_mask" + | "__builtin_ia32_prord128_mask" + | "__builtin_ia32_prolq256_mask" + | "__builtin_ia32_prolq128_mask" + | "__builtin_ia32_prorq256_mask" + | "__builtin_ia32_prorq128_mask" + | "__builtin_ia32_psraq256_mask" + | "__builtin_ia32_psraq128_mask" + | "__builtin_ia32_psraqi256_mask" + | "__builtin_ia32_psraqi128_mask" + | "__builtin_ia32_psravq256_mask" + | "__builtin_ia32_psravq128_mask" + | "__builtin_ia32_prolvd256_mask" + | "__builtin_ia32_prolvd128_mask" + | "__builtin_ia32_prorvd256_mask" + | "__builtin_ia32_prorvd128_mask" + | "__builtin_ia32_prolvq256_mask" + | "__builtin_ia32_prolvq128_mask" + | "__builtin_ia32_prorvq256_mask" + | "__builtin_ia32_prorvq128_mask" + | "__builtin_ia32_permvardi256_mask" + | "__builtin_ia32_permvardf512_mask" + | "__builtin_ia32_permvardf256_mask" + | "__builtin_ia32_pmulhuw512_mask" + | "__builtin_ia32_pmulhw512_mask" + | "__builtin_ia32_pmulhrsw512_mask" + | "__builtin_ia32_pmaxuw512_mask" + | "__builtin_ia32_pmaxub512_mask" + | "__builtin_ia32_pmaxsw512_mask" + | "__builtin_ia32_pmaxsb512_mask" + | "__builtin_ia32_pminuw512_mask" + | "__builtin_ia32_pminub512_mask" + | "__builtin_ia32_pminsw512_mask" + | "__builtin_ia32_pminsb512_mask" + | "__builtin_ia32_pmaddwd512_mask" + | "__builtin_ia32_pmaddubsw512_mask" + | "__builtin_ia32_packssdw512_mask" + | "__builtin_ia32_packsswb512_mask" + | "__builtin_ia32_packusdw512_mask" + | "__builtin_ia32_packuswb512_mask" + | "__builtin_ia32_pavgw512_mask" + | "__builtin_ia32_pavgb512_mask" + | "__builtin_ia32_psllw512_mask" + | "__builtin_ia32_psllwi512_mask" + | "__builtin_ia32_psllv32hi_mask" + | "__builtin_ia32_psrlw512_mask" + | "__builtin_ia32_psrlwi512_mask" + | "__builtin_ia32_psllv16hi_mask" + | "__builtin_ia32_psllv8hi_mask" + | "__builtin_ia32_psrlv32hi_mask" + | "__builtin_ia32_psraw512_mask" + | "__builtin_ia32_psrawi512_mask" + | "__builtin_ia32_psrlv16hi_mask" + | "__builtin_ia32_psrlv8hi_mask" + | "__builtin_ia32_psrav32hi_mask" + | "__builtin_ia32_permvarhi512_mask" + | "__builtin_ia32_pshufb512_mask" + | "__builtin_ia32_psrav16hi_mask" + | "__builtin_ia32_psrav8hi_mask" + | "__builtin_ia32_permvarhi256_mask" + | "__builtin_ia32_permvarhi128_mask" => { let mut new_args = args.to_vec(); let arg3_type = gcc_func.get_param_type(2); let vector_type = arg3_type.dyncast_vector().expect("vector type"); let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); let num_units = vector_type.get_num_units(); - let first_arg = builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]); new_args.push(first_arg); let arg4_type = gcc_func.get_param_type(3); let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); new_args.push(minus_one); args = new_args.into(); - }, - "__builtin_ia32_dbpsadbw512_mask" | "__builtin_ia32_dbpsadbw256_mask" | "__builtin_ia32_dbpsadbw128_mask" => { + } + "__builtin_ia32_dbpsadbw512_mask" + | "__builtin_ia32_dbpsadbw256_mask" + | "__builtin_ia32_dbpsadbw128_mask" => { let mut new_args = args.to_vec(); let arg4_type = gcc_func.get_param_type(3); let vector_type = arg4_type.dyncast_vector().expect("vector type"); let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); let num_units = vector_type.get_num_units(); - let first_arg = builder.context.new_rvalue_from_vector(None, arg4_type, &vec![zero; num_units]); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg4_type, &vec![zero; num_units]); new_args.push(first_arg); let arg5_type = gcc_func.get_param_type(4); let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1); new_args.push(minus_one); args = new_args.into(); - }, - "__builtin_ia32_vplzcntd_512_mask" | "__builtin_ia32_vplzcntd_256_mask" | "__builtin_ia32_vplzcntd_128_mask" - | "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" | "__builtin_ia32_vplzcntq_128_mask" => { + } + "__builtin_ia32_vplzcntd_512_mask" + | "__builtin_ia32_vplzcntd_256_mask" + | "__builtin_ia32_vplzcntd_128_mask" + | "__builtin_ia32_vplzcntq_512_mask" + | "__builtin_ia32_vplzcntq_256_mask" + | "__builtin_ia32_vplzcntq_128_mask" => { let mut new_args = args.to_vec(); // Remove last arg as it doesn't seem to be used in GCC and is always false. new_args.pop(); @@ -98,37 +189,45 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let vector_type = arg2_type.dyncast_vector().expect("vector type"); let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); let num_units = vector_type.get_num_units(); - let first_arg = builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); new_args.push(first_arg); let arg3_type = gcc_func.get_param_type(2); let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); new_args.push(minus_one); args = new_args.into(); - }, - "__builtin_ia32_vpconflictsi_512_mask" | "__builtin_ia32_vpconflictsi_256_mask" - | "__builtin_ia32_vpconflictsi_128_mask" | "__builtin_ia32_vpconflictdi_512_mask" - | "__builtin_ia32_vpconflictdi_256_mask" | "__builtin_ia32_vpconflictdi_128_mask" => { + } + "__builtin_ia32_vpconflictsi_512_mask" + | "__builtin_ia32_vpconflictsi_256_mask" + | "__builtin_ia32_vpconflictsi_128_mask" + | "__builtin_ia32_vpconflictdi_512_mask" + | "__builtin_ia32_vpconflictdi_256_mask" + | "__builtin_ia32_vpconflictdi_128_mask" => { let mut new_args = args.to_vec(); let arg2_type = gcc_func.get_param_type(1); let vector_type = arg2_type.dyncast_vector().expect("vector type"); let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); let num_units = vector_type.get_num_units(); - let first_arg = builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); new_args.push(first_arg); let arg3_type = gcc_func.get_param_type(2); let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); new_args.push(minus_one); args = new_args.into(); - }, - "__builtin_ia32_pternlogd512_mask" | "__builtin_ia32_pternlogd256_mask" - | "__builtin_ia32_pternlogd128_mask" | "__builtin_ia32_pternlogq512_mask" - | "__builtin_ia32_pternlogq256_mask" | "__builtin_ia32_pternlogq128_mask" => { + } + "__builtin_ia32_pternlogd512_mask" + | "__builtin_ia32_pternlogd256_mask" + | "__builtin_ia32_pternlogd128_mask" + | "__builtin_ia32_pternlogq512_mask" + | "__builtin_ia32_pternlogq256_mask" + | "__builtin_ia32_pternlogq128_mask" => { let mut new_args = args.to_vec(); let arg5_type = gcc_func.get_param_type(4); let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1); new_args.push(minus_one); args = new_args.into(); - }, + } "__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => { let mut new_args = args.to_vec(); @@ -154,24 +253,33 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc } args = new_args.into(); - }, - "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask" - | "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask" - | "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask" - | "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask" - | "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask" - | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" => { + } + "__builtin_ia32_addps512_mask" + | "__builtin_ia32_addpd512_mask" + | "__builtin_ia32_subps512_mask" + | "__builtin_ia32_subpd512_mask" + | "__builtin_ia32_mulps512_mask" + | "__builtin_ia32_mulpd512_mask" + | "__builtin_ia32_divps512_mask" + | "__builtin_ia32_divpd512_mask" + | "__builtin_ia32_maxps512_mask" + | "__builtin_ia32_maxpd512_mask" + | "__builtin_ia32_minps512_mask" + | "__builtin_ia32_minpd512_mask" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); let arg3_type = gcc_func.get_param_type(2); - let undefined = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue(); + let undefined = builder + .current_func() + .new_local(None, arg3_type, "undefined_for_intrinsic") + .to_rvalue(); new_args.push(undefined); let arg4_type = gcc_func.get_param_type(3); let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); new_args.push(minus_one); new_args.push(last_arg); args = new_args.into(); - }, + } "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); @@ -180,54 +288,72 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc new_args.push(minus_one); new_args.push(last_arg); args = new_args.into(); - }, - "__builtin_ia32_vpermi2vard512_mask" | "__builtin_ia32_vpermi2vard256_mask" - | "__builtin_ia32_vpermi2vard128_mask" | "__builtin_ia32_vpermi2varq512_mask" - | "__builtin_ia32_vpermi2varq256_mask" | "__builtin_ia32_vpermi2varq128_mask" - | "__builtin_ia32_vpermi2varps512_mask" | "__builtin_ia32_vpermi2varps256_mask" - | "__builtin_ia32_vpermi2varps128_mask" | "__builtin_ia32_vpermi2varpd512_mask" - | "__builtin_ia32_vpermi2varpd256_mask" | "__builtin_ia32_vpermi2varpd128_mask" | "__builtin_ia32_vpmadd52huq512_mask" - | "__builtin_ia32_vpmadd52luq512_mask" | "__builtin_ia32_vpmadd52huq256_mask" | "__builtin_ia32_vpmadd52luq256_mask" - | "__builtin_ia32_vpmadd52huq128_mask" - => { + } + "__builtin_ia32_vpermi2vard512_mask" + | "__builtin_ia32_vpermi2vard256_mask" + | "__builtin_ia32_vpermi2vard128_mask" + | "__builtin_ia32_vpermi2varq512_mask" + | "__builtin_ia32_vpermi2varq256_mask" + | "__builtin_ia32_vpermi2varq128_mask" + | "__builtin_ia32_vpermi2varps512_mask" + | "__builtin_ia32_vpermi2varps256_mask" + | "__builtin_ia32_vpermi2varps128_mask" + | "__builtin_ia32_vpermi2varpd512_mask" + | "__builtin_ia32_vpermi2varpd256_mask" + | "__builtin_ia32_vpermi2varpd128_mask" + | "__builtin_ia32_vpmadd52huq512_mask" + | "__builtin_ia32_vpmadd52luq512_mask" + | "__builtin_ia32_vpmadd52huq256_mask" + | "__builtin_ia32_vpmadd52luq256_mask" + | "__builtin_ia32_vpmadd52huq128_mask" => { let mut new_args = args.to_vec(); let arg4_type = gcc_func.get_param_type(3); let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); new_args.push(minus_one); args = new_args.into(); - }, - "__builtin_ia32_cvtdq2ps512_mask" | "__builtin_ia32_cvtudq2ps512_mask" - | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => { + } + "__builtin_ia32_cvtdq2ps512_mask" + | "__builtin_ia32_cvtudq2ps512_mask" + | "__builtin_ia32_sqrtps512_mask" + | "__builtin_ia32_sqrtpd512_mask" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); let arg2_type = gcc_func.get_param_type(1); - let undefined = builder.current_func().new_local(None, arg2_type, "undefined_for_intrinsic").to_rvalue(); + let undefined = builder + .current_func() + .new_local(None, arg2_type, "undefined_for_intrinsic") + .to_rvalue(); new_args.push(undefined); let arg3_type = gcc_func.get_param_type(2); let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); new_args.push(minus_one); new_args.push(last_arg); args = new_args.into(); - }, + } "__builtin_ia32_stmxcsr" => { args = vec![].into(); - }, - "__builtin_ia32_addcarryx_u64" | "__builtin_ia32_sbb_u64" | "__builtin_ia32_addcarryx_u32" | "__builtin_ia32_sbb_u32" => { + } + "__builtin_ia32_addcarryx_u64" + | "__builtin_ia32_sbb_u64" + | "__builtin_ia32_addcarryx_u32" + | "__builtin_ia32_sbb_u32" => { let mut new_args = args.to_vec(); let arg2_type = gcc_func.get_param_type(1); let variable = builder.current_func().new_local(None, arg2_type, "addcarryResult"); new_args.push(variable.get_address(None)); args = new_args.into(); - }, - "__builtin_ia32_vpermt2varqi512_mask" | "__builtin_ia32_vpermt2varqi256_mask" - | "__builtin_ia32_vpermt2varqi128_mask" | "__builtin_ia32_vpermt2varhi512_mask" - | "__builtin_ia32_vpermt2varhi256_mask" | "__builtin_ia32_vpermt2varhi128_mask" - => { + } + "__builtin_ia32_vpermt2varqi512_mask" + | "__builtin_ia32_vpermt2varqi256_mask" + | "__builtin_ia32_vpermt2varqi128_mask" + | "__builtin_ia32_vpermt2varhi512_mask" + | "__builtin_ia32_vpermt2varhi256_mask" + | "__builtin_ia32_vpermt2varhi128_mask" => { let new_args = args.to_vec(); let arg4_type = gcc_func.get_param_type(3); let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); args = vec![new_args[1], new_args[0], new_args[2], minus_one].into(); - }, + } "__builtin_ia32_xrstor" | "__builtin_ia32_xsavec" => { let new_args = args.to_vec(); let thirty_two = builder.context.new_rvalue_from_int(new_args[1].get_type(), 32); @@ -235,22 +361,25 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let arg2_type = gcc_func.get_param_type(1); let arg2 = builder.context.new_cast(None, arg2, arg2_type); args = vec![new_args[0], arg2].into(); - }, + } // These builtins are sent one more argument than needed. "__builtin_prefetch" => { let mut new_args = args.to_vec(); new_args.pop(); args = new_args.into(); - }, + } // The GCC version returns one value of the tuple through a pointer. "__builtin_ia32_rdrand64_step" => { - let arg = builder.current_func().new_local(None, builder.ulonglong_type, "return_rdrand_arg"); + let arg = builder.current_func().new_local( + None, + builder.ulonglong_type, + "return_rdrand_arg", + ); args = vec![arg.get_address(None)].into(); - }, + } _ => (), } - } - else { + } else { match &*func_name { "__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => { let new_args = args.to_vec(); @@ -259,7 +388,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let arg4_type = gcc_func.get_param_type(3); let arg4 = builder.context.new_bitcast(None, new_args[2], arg4_type); args = vec![new_args[0], new_args[1], arg3, arg4, new_args[3], new_args[5]].into(); - }, + } // NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors. // FIXME: the intrinsics like _mm_mask_fmadd_sd should probably directly call the GCC // intrinsic to avoid this. @@ -272,7 +401,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 4]); let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 4]); args = vec![a, b, c, new_args[3]].into(); - }, + } "__builtin_ia32_vfmaddsd3_round" => { let new_args = args.to_vec(); let arg1_type = gcc_func.get_param_type(0); @@ -282,25 +411,34 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 2]); let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 2]); args = vec![a, b, c, new_args[3]].into(); - }, - "__builtin_ia32_vfmaddsubpd256" | "__builtin_ia32_vfmaddsubps" | "__builtin_ia32_vfmaddsubps256" - | "__builtin_ia32_vfmaddsubpd" => { + } + "__builtin_ia32_vfmaddsubpd256" + | "__builtin_ia32_vfmaddsubps" + | "__builtin_ia32_vfmaddsubps256" + | "__builtin_ia32_vfmaddsubpd" => { if let Some(original_function_name) = original_function_name { match &**original_function_name { - "llvm.x86.fma.vfmsubadd.pd.256" | "llvm.x86.fma.vfmsubadd.ps" | "llvm.x86.fma.vfmsubadd.ps.256" - | "llvm.x86.fma.vfmsubadd.pd" => { + "llvm.x86.fma.vfmsubadd.pd.256" + | "llvm.x86.fma.vfmsubadd.ps" + | "llvm.x86.fma.vfmsubadd.ps.256" + | "llvm.x86.fma.vfmsubadd.pd" => { // NOTE: since both llvm.x86.fma.vfmsubadd.ps and llvm.x86.fma.vfmaddsub.ps maps to // __builtin_ia32_vfmaddsubps, only add minus if this comes from a // subadd LLVM intrinsic, e.g. _mm256_fmsubadd_pd. let mut new_args = args.to_vec(); let arg3 = &mut new_args[2]; - *arg3 = builder.context.new_unary_op(None, UnaryOp::Minus, arg3.get_type(), *arg3); + *arg3 = builder.context.new_unary_op( + None, + UnaryOp::Minus, + arg3.get_type(), + *arg3, + ); args = new_args.into(); - }, + } _ => (), } } - }, + } "__builtin_ia32_ldmxcsr" => { // The builtin __builtin_ia32_ldmxcsr takes an integer value while llvm.x86.sse.ldmxcsr takes a pointer, // so dereference the pointer. @@ -309,23 +447,31 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let arg1 = builder.context.new_cast(None, args[0], uint_ptr_type); new_args[0] = arg1.dereference(None).to_rvalue(); args = new_args.into(); - }, - "__builtin_ia32_rcp14sd_mask" | "__builtin_ia32_rcp14ss_mask" | "__builtin_ia32_rsqrt14sd_mask" - | "__builtin_ia32_rsqrt14ss_mask" => { + } + "__builtin_ia32_rcp14sd_mask" + | "__builtin_ia32_rcp14ss_mask" + | "__builtin_ia32_rsqrt14sd_mask" + | "__builtin_ia32_rsqrt14ss_mask" => { let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2], new_args[3]].into(); - }, + } "__builtin_ia32_sqrtsd_mask_round" | "__builtin_ia32_sqrtss_mask_round" => { let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2], new_args[3], new_args[4]].into(); - }, - "__builtin_ia32_vpshrdv_v8di" | "__builtin_ia32_vpshrdv_v4di" | "__builtin_ia32_vpshrdv_v2di" | - "__builtin_ia32_vpshrdv_v16si" | "__builtin_ia32_vpshrdv_v8si" | "__builtin_ia32_vpshrdv_v4si" | - "__builtin_ia32_vpshrdv_v32hi" | "__builtin_ia32_vpshrdv_v16hi" | "__builtin_ia32_vpshrdv_v8hi" => { + } + "__builtin_ia32_vpshrdv_v8di" + | "__builtin_ia32_vpshrdv_v4di" + | "__builtin_ia32_vpshrdv_v2di" + | "__builtin_ia32_vpshrdv_v16si" + | "__builtin_ia32_vpshrdv_v8si" + | "__builtin_ia32_vpshrdv_v4si" + | "__builtin_ia32_vpshrdv_v32hi" + | "__builtin_ia32_vpshrdv_v16hi" + | "__builtin_ia32_vpshrdv_v8hi" => { // The first two arguments are reversed, compared to LLVM. let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2]].into(); - }, + } _ => (), } } @@ -333,16 +479,27 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc args } -pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, mut return_value: RValue<'gcc>, func_name: &str, args: &[RValue<'gcc>], args_adjusted: bool, orig_args: &[RValue<'gcc>]) -> RValue<'gcc> { +pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( + builder: &Builder<'a, 'gcc, 'tcx>, + mut return_value: RValue<'gcc>, + func_name: &str, + args: &[RValue<'gcc>], + args_adjusted: bool, + orig_args: &[RValue<'gcc>], +) -> RValue<'gcc> { match func_name { "__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => { - #[cfg(feature="master")] + #[cfg(feature = "master")] { let zero = builder.context.new_rvalue_zero(builder.int_type); - return_value = builder.context.new_vector_access(None, return_value, zero).to_rvalue(); + return_value = + builder.context.new_vector_access(None, return_value, zero).to_rvalue(); } - }, - "__builtin_ia32_addcarryx_u64" | "__builtin_ia32_sbb_u64" | "__builtin_ia32_addcarryx_u32" | "__builtin_ia32_sbb_u32" => { + } + "__builtin_ia32_addcarryx_u64" + | "__builtin_ia32_sbb_u64" + | "__builtin_ia32_addcarryx_u32" + | "__builtin_ia32_sbb_u32" => { // Both llvm.x86.addcarry.32 and llvm.x86.addcarryx.u32 points to the same GCC builtin, // but only the former requires adjusting the return value. // Those 2 LLVM intrinsics differ by their argument count, that's why we check if the @@ -351,10 +508,16 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, let last_arg = args.last().expect("last arg"); let field1 = builder.context.new_field(None, builder.u8_type, "carryFlag"); let field2 = builder.context.new_field(None, args[1].get_type(), "carryResult"); - let struct_type = builder.context.new_struct_type(None, "addcarryResult", &[field1, field2]); - return_value = builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[return_value, last_arg.dereference(None).to_rvalue()]); + let struct_type = + builder.context.new_struct_type(None, "addcarryResult", &[field1, field2]); + return_value = builder.context.new_struct_constructor( + None, + struct_type.as_type(), + None, + &[return_value, last_arg.dereference(None).to_rvalue()], + ); } - }, + } "__builtin_ia32_stmxcsr" => { // The builtin __builtin_ia32_stmxcsr returns a value while llvm.x86.sse.stmxcsr writes // the result in its pointer argument. @@ -366,20 +529,24 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, // The return value was assigned to the result pointer above. In order to not call the // builtin twice, we overwrite the return value with a dummy value. return_value = builder.context.new_rvalue_zero(builder.int_type); - }, + } "__builtin_ia32_rdrand64_step" => { let random_number = args[0].dereference(None).to_rvalue(); - let success_variable = builder.current_func().new_local(None, return_value.get_type(), "success"); + let success_variable = + builder.current_func().new_local(None, return_value.get_type(), "success"); builder.llbb().add_assignment(None, success_variable, return_value); let field1 = builder.context.new_field(None, random_number.get_type(), "random_number"); let field2 = builder.context.new_field(None, return_value.get_type(), "success"); - let struct_type = builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]); - return_value = builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[ - random_number, - success_variable.to_rvalue(), - ]); - }, + let struct_type = + builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]); + return_value = builder.context.new_struct_constructor( + None, + struct_type.as_type(), + None, + &[random_number, success_variable.to_rvalue()], + ); + } _ => (), } @@ -391,23 +558,33 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool { match func_name { // NOTE: these intrinsics have missing parameters before the last one, so ignore the // last argument type check. - "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask" - | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" | "__builtin_ia32_sqrtps512_mask" - | "__builtin_ia32_sqrtpd512_mask" | "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask" - | "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask" - | "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask" - | "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask" - | "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" - | "__builtin_ia32_cvtdq2ps512_mask" | "__builtin_ia32_cvtudq2ps512_mask" => { - if index == args_len - 1 { - return true; - } - }, + "__builtin_ia32_maxps512_mask" + | "__builtin_ia32_maxpd512_mask" + | "__builtin_ia32_minps512_mask" + | "__builtin_ia32_minpd512_mask" + | "__builtin_ia32_sqrtps512_mask" + | "__builtin_ia32_sqrtpd512_mask" + | "__builtin_ia32_addps512_mask" + | "__builtin_ia32_addpd512_mask" + | "__builtin_ia32_subps512_mask" + | "__builtin_ia32_subpd512_mask" + | "__builtin_ia32_mulps512_mask" + | "__builtin_ia32_mulpd512_mask" + | "__builtin_ia32_divps512_mask" + | "__builtin_ia32_divpd512_mask" + | "__builtin_ia32_vfmaddsubps512_mask" + | "__builtin_ia32_vfmaddsubpd512_mask" + | "__builtin_ia32_cvtdq2ps512_mask" + | "__builtin_ia32_cvtudq2ps512_mask" => { + if index == args_len - 1 { + return true; + } + } "__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => { if index == 2 || index == 3 { return true; } - }, + } "__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => { // Since there are two LLVM intrinsics that map to each of these GCC builtins and only // one of them has a missing parameter before the last one, we check the number of @@ -415,49 +592,50 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool { if args_len == 4 && index == args_len - 1 { return true; } - }, + } // NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors. "__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => return true, - "__builtin_ia32_vplzcntd_512_mask" | "__builtin_ia32_vplzcntd_256_mask" | "__builtin_ia32_vplzcntd_128_mask" - | "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" | "__builtin_ia32_vplzcntq_128_mask" => { + "__builtin_ia32_vplzcntd_512_mask" + | "__builtin_ia32_vplzcntd_256_mask" + | "__builtin_ia32_vplzcntd_128_mask" + | "__builtin_ia32_vplzcntq_512_mask" + | "__builtin_ia32_vplzcntq_256_mask" + | "__builtin_ia32_vplzcntq_128_mask" => { if index == args_len - 1 { return true; } - }, + } _ => (), } false } -#[cfg(not(feature="master"))] +#[cfg(not(feature = "master"))] pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> { - let gcc_name = - match name { - "llvm.x86.sse2.pause" => { - // NOTE: pause is only a hint, so we use a dummy built-in because target built-ins - // are not supported in libgccjit 12. - "__builtin_inff" - }, - "llvm.x86.xgetbv" => { - "__builtin_trap" - }, - _ => unimplemented!("unsupported LLVM intrinsic {}", name), - }; + let gcc_name = match name { + "llvm.x86.sse2.pause" => { + // NOTE: pause is only a hint, so we use a dummy built-in because target built-ins + // are not supported in libgccjit 12. + "__builtin_inff" + } + "llvm.x86.xgetbv" => "__builtin_trap", + _ => unimplemented!("unsupported LLVM intrinsic {}", name), + }; let func = cx.context.get_builtin_function(gcc_name); cx.functions.borrow_mut().insert(gcc_name.to_string(), func); return func; } -#[cfg(feature="master")] +#[cfg(feature = "master")] pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> { match name { "llvm.prefetch" => { let gcc_name = "__builtin_prefetch"; let func = cx.context.get_builtin_function(gcc_name); cx.functions.borrow_mut().insert(gcc_name.to_string(), func); - return func - }, + return func; + } _ => (), } diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 0849c6266f19b..22176ab9cd7a2 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -1,43 +1,48 @@ pub mod llvm; mod simd; -#[cfg(feature="master")] +#[cfg(feature = "master")] use std::iter; -#[cfg(feature="master")] +#[cfg(feature = "master")] use gccjit::FunctionType; use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; -use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::common::IntPredicate; +use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; -use rustc_codegen_ssa::traits::{ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; -#[cfg(feature="master")] +use rustc_codegen_ssa::traits::{ + ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods, +}; +#[cfg(feature = "master")] use rustc_codegen_ssa::traits::{BaseTypeMethods, MiscMethods}; -use rustc_codegen_ssa::errors::InvalidMonomorphization; +use rustc_codegen_ssa::MemFlags; use rustc_middle::bug; -use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; -#[cfg(feature="master")] +#[cfg(feature = "master")] use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use rustc_span::{Span, Symbol, symbol::kw, sym}; -use rustc_target::abi::HasDataLayout; +use rustc_middle::ty::{self, Instance, Ty}; +use rustc_span::{sym, symbol::kw, Span, Symbol}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::PanicStrategy; -#[cfg(feature="master")] +use rustc_target::abi::HasDataLayout; +#[cfg(feature = "master")] use rustc_target::spec::abi::Abi; +use rustc_target::spec::PanicStrategy; -use crate::abi::GccType; -#[cfg(feature="master")] +#[cfg(feature = "master")] use crate::abi::FnAbiGccExt; +use crate::abi::GccType; use crate::builder::Builder; use crate::common::{SignType, TypeReflection}; use crate::context::CodegenCx; -use crate::type_of::LayoutGccExt; use crate::intrinsic::simd::generic_simd_intrinsic; +use crate::type_of::LayoutGccExt; -fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> Option> { +fn get_simple_intrinsic<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + name: Symbol, +) -> Option> { let gcc_name = match name { sym::sqrtf32 => "sqrtf", sym::sqrtf64 => "sqrt", @@ -90,7 +95,14 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> } impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { - fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) -> Result<(), Instance<'tcx>> { + fn codegen_intrinsic_call( + &mut self, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OperandRef<'tcx, RValue<'gcc>>], + llresult: RValue<'gcc>, + span: Span, + ) -> Result<(), Instance<'tcx>> { let tcx = self.tcx; let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); @@ -110,268 +122,274 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); - let llval = - match name { - _ if simple.is_some() => { - // FIXME(antoyo): remove this cast when the API supports function. - let func = unsafe { std::mem::transmute(simple.expect("simple")) }; - self.call(self.type_void(), None, None, func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) - }, - sym::likely => { - self.expect(args[0].immediate(), true) - } - sym::unlikely => { - self.expect(args[0].immediate(), false) - } - sym::is_val_statically_known => { - let a = args[0].immediate(); - let builtin = self.context.get_builtin_function("__builtin_constant_p"); - let res = self.context.new_call(None, builtin, &[a]); - self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) - } - kw::Try => { - try_intrinsic( - self, - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - llresult, - ); - return Ok(()); - } - sym::breakpoint => { - unimplemented!(); - } - sym::va_copy => { - unimplemented!(); - } - sym::va_arg => { - unimplemented!(); - } + let llval = match name { + _ if simple.is_some() => { + // FIXME(antoyo): remove this cast when the API supports function. + let func = unsafe { std::mem::transmute(simple.expect("simple")) }; + self.call( + self.type_void(), + None, + None, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + None, + ) + } + sym::likely => self.expect(args[0].immediate(), true), + sym::unlikely => self.expect(args[0].immediate(), false), + sym::is_val_statically_known => { + let a = args[0].immediate(); + let builtin = self.context.get_builtin_function("__builtin_constant_p"); + let res = self.context.new_call(None, builtin, &[a]); + self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) + } + kw::Try => { + try_intrinsic( + self, + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + llresult, + ); + return Ok(()); + } + sym::breakpoint => { + unimplemented!(); + } + sym::va_copy => { + unimplemented!(); + } + sym::va_arg => { + unimplemented!(); + } - sym::volatile_load | sym::unaligned_volatile_load => { - let tp_ty = fn_args.type_at(0); - let ptr = args[0].immediate(); - let load = - if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode { - let gcc_ty = ty.gcc_type(self); - self.volatile_load(gcc_ty, ptr) + sym::volatile_load | sym::unaligned_volatile_load => { + let tp_ty = fn_args.type_at(0); + let ptr = args[0].immediate(); + let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode { + let gcc_ty = ty.gcc_type(self); + self.volatile_load(gcc_ty, ptr) + } else { + self.volatile_load(self.layout_of(tp_ty).gcc_type(self), ptr) + }; + // TODO(antoyo): set alignment. + self.to_immediate(load, self.layout_of(tp_ty)) + } + sym::volatile_store => { + let dst = args[0].deref(self.cx()); + args[1].val.volatile_store(self, dst); + return Ok(()); + } + sym::unaligned_volatile_store => { + let dst = args[0].deref(self.cx()); + args[1].val.unaligned_volatile_store(self, dst); + return Ok(()); + } + sym::prefetch_read_data + | sym::prefetch_write_data + | sym::prefetch_read_instruction + | sym::prefetch_write_instruction => { + unimplemented!(); + } + sym::ctlz + | sym::ctlz_nonzero + | sym::cttz + | sym::cttz_nonzero + | sym::ctpop + | sym::bswap + | sym::bitreverse + | sym::rotate_left + | sym::rotate_right + | sym::saturating_add + | sym::saturating_sub => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, self) { + Some((width, signed)) => match name { + sym::ctlz | sym::cttz => { + let func = self.current_func.borrow().expect("func"); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + + let arg = args[0].immediate(); + let result = func.new_local(None, arg.get_type(), "zeros"); + let zero = self.cx.gcc_zero(arg.get_type()); + let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + let zero_result = self.cx.gcc_uint(arg.get_type(), width); + then_block.add_assignment(None, result, zero_result); + then_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place + // count_leading_zeroes() does not expect, the current block + // in the state need to be updated. + self.switch_to_block(else_block); + + let zeros = match name { + sym::ctlz => self.count_leading_zeroes(width, arg), + sym::cttz => self.count_trailing_zeroes(width, arg), + _ => unreachable!(), + }; + self.llbb().add_assignment(None, result, zeros); + self.llbb().end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current block in the state need to be updated. + self.switch_to_block(after_block); + + result.to_rvalue() } - else { - self.volatile_load(self.layout_of(tp_ty).gcc_type(self), ptr) - }; - // TODO(antoyo): set alignment. - self.to_immediate(load, self.layout_of(tp_ty)) - } - sym::volatile_store => { - let dst = args[0].deref(self.cx()); - args[1].val.volatile_store(self, dst); - return Ok(()); - } - sym::unaligned_volatile_store => { - let dst = args[0].deref(self.cx()); - args[1].val.unaligned_volatile_store(self, dst); - return Ok(()); - } - sym::prefetch_read_data - | sym::prefetch_write_data - | sym::prefetch_read_instruction - | sym::prefetch_write_instruction => { - unimplemented!(); - } - sym::ctlz - | sym::ctlz_nonzero - | sym::cttz - | sym::cttz_nonzero - | sym::ctpop - | sym::bswap - | sym::bitreverse - | sym::rotate_left - | sym::rotate_right - | sym::saturating_add - | sym::saturating_sub => { - let ty = arg_tys[0]; - match int_type_width_signed(ty, self) { - Some((width, signed)) => match name { - sym::ctlz | sym::cttz => { - let func = self.current_func.borrow().expect("func"); - let then_block = func.new_block("then"); - let else_block = func.new_block("else"); - let after_block = func.new_block("after"); - - let arg = args[0].immediate(); - let result = func.new_local(None, arg.get_type(), "zeros"); - let zero = self.cx.gcc_zero(arg.get_type()); - let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); - self.llbb().end_with_conditional(None, cond, then_block, else_block); - - let zero_result = self.cx.gcc_uint(arg.get_type(), width); - then_block.add_assignment(None, result, zero_result); - then_block.end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place - // count_leading_zeroes() does not expect, the current block - // in the state need to be updated. - self.switch_to_block(else_block); - - let zeros = - match name { - sym::ctlz => self.count_leading_zeroes(width, arg), - sym::cttz => self.count_trailing_zeroes(width, arg), - _ => unreachable!(), - }; - self.llbb().add_assignment(None, result, zeros); - self.llbb().end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place rustc does not - // expect, the current block in the state need to be updated. - self.switch_to_block(after_block); - - result.to_rvalue() - } - sym::ctlz_nonzero => { - self.count_leading_zeroes(width, args[0].immediate()) - }, - sym::cttz_nonzero => { - self.count_trailing_zeroes(width, args[0].immediate()) - } - sym::ctpop => self.pop_count(args[0].immediate()), - sym::bswap => { - if width == 8 { - args[0].immediate() // byte swap a u8/i8 is just a no-op - } - else { - self.gcc_bswap(args[0].immediate(), width) - } - }, - sym::bitreverse => self.bit_reverse(width, args[0].immediate()), - sym::rotate_left | sym::rotate_right => { - // TODO(antoyo): implement using algorithm from: - // https://blog.regehr.org/archives/1063 - // for other platforms. - let is_left = name == sym::rotate_left; - let val = args[0].immediate(); - let raw_shift = args[1].immediate(); - if is_left { - self.rotate_left(val, raw_shift, width) - } - else { - self.rotate_right(val, raw_shift, width) - } - }, - sym::saturating_add => { - self.saturating_add(args[0].immediate(), args[1].immediate(), signed, width) - }, - sym::saturating_sub => { - self.saturating_sub(args[0].immediate(), args[1].immediate(), signed, width) - }, - _ => bug!(), - }, - None => { - tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); - return Ok(()); + sym::ctlz_nonzero => self.count_leading_zeroes(width, args[0].immediate()), + sym::cttz_nonzero => self.count_trailing_zeroes(width, args[0].immediate()), + sym::ctpop => self.pop_count(args[0].immediate()), + sym::bswap => { + if width == 8 { + args[0].immediate() // byte swap a u8/i8 is just a no-op + } else { + self.gcc_bswap(args[0].immediate(), width) } } - } - - sym::raw_eq => { - use rustc_target::abi::Abi::*; - let tp_ty = fn_args.type_at(0); - let layout = self.layout_of(tp_ty).layout; - let _use_integer_compare = match layout.abi() { - Scalar(_) | ScalarPair(_, _) => true, - Uninhabited | Vector { .. } => false, - Aggregate { .. } => { - // For rusty ABIs, small aggregates are actually passed - // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), - // so we re-use that same threshold here. - layout.size() <= self.data_layout().pointer_size * 2 + sym::bitreverse => self.bit_reverse(width, args[0].immediate()), + sym::rotate_left | sym::rotate_right => { + // TODO(antoyo): implement using algorithm from: + // https://blog.regehr.org/archives/1063 + // for other platforms. + let is_left = name == sym::rotate_left; + let val = args[0].immediate(); + let raw_shift = args[1].immediate(); + if is_left { + self.rotate_left(val, raw_shift, width) + } else { + self.rotate_right(val, raw_shift, width) + } } - }; - - let a = args[0].immediate(); - let b = args[1].immediate(); - if layout.size().bytes() == 0 { - self.const_bool(true) - } - /*else if use_integer_compare { - let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits. - let ptr_ty = self.type_ptr_to(integer_ty); - let a_ptr = self.bitcast(a, ptr_ty); - let a_val = self.load(integer_ty, a_ptr, layout.align.abi); - let b_ptr = self.bitcast(b, ptr_ty); - let b_val = self.load(integer_ty, b_ptr, layout.align.abi); - self.icmp(IntPredicate::IntEQ, a_val, b_val) - }*/ - else { - let void_ptr_type = self.context.new_type::<*const ()>(); - let a_ptr = self.bitcast(a, void_ptr_type); - let b_ptr = self.bitcast(b, void_ptr_type); - let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type); - let builtin = self.context.get_builtin_function("memcmp"); - let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); - self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) + sym::saturating_add => self.saturating_add( + args[0].immediate(), + args[1].immediate(), + signed, + width, + ), + sym::saturating_sub => self.saturating_sub( + args[0].immediate(), + args[1].immediate(), + signed, + width, + ), + _ => bug!(), + }, + None => { + tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { + span, + name, + ty, + }); + return Ok(()); } } + } - sym::compare_bytes => { - let a = args[0].immediate(); - let b = args[1].immediate(); - let n = args[2].immediate(); + sym::raw_eq => { + use rustc_target::abi::Abi::*; + let tp_ty = fn_args.type_at(0); + let layout = self.layout_of(tp_ty).layout; + let _use_integer_compare = match layout.abi() { + Scalar(_) | ScalarPair(_, _) => true, + Uninhabited | Vector { .. } => false, + Aggregate { .. } => { + // For rusty ABIs, small aggregates are actually passed + // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), + // so we re-use that same threshold here. + layout.size() <= self.data_layout().pointer_size * 2 + } + }; + let a = args[0].immediate(); + let b = args[1].immediate(); + if layout.size().bytes() == 0 { + self.const_bool(true) + } + /*else if use_integer_compare { + let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits. + let ptr_ty = self.type_ptr_to(integer_ty); + let a_ptr = self.bitcast(a, ptr_ty); + let a_val = self.load(integer_ty, a_ptr, layout.align.abi); + let b_ptr = self.bitcast(b, ptr_ty); + let b_val = self.load(integer_ty, b_ptr, layout.align.abi); + self.icmp(IntPredicate::IntEQ, a_val, b_val) + }*/ + else { let void_ptr_type = self.context.new_type::<*const ()>(); let a_ptr = self.bitcast(a, void_ptr_type); let b_ptr = self.bitcast(b, void_ptr_type); - - // Here we assume that the `memcmp` provided by the target is a NOP for size 0. + let n = self.context.new_cast( + None, + self.const_usize(layout.size().bytes()), + self.sizet_type, + ); let builtin = self.context.get_builtin_function("memcmp"); let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); - self.sext(cmp, self.type_ix(32)) + self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) } + } - sym::black_box => { - args[0].val.store(self, result); + sym::compare_bytes => { + let a = args[0].immediate(); + let b = args[1].immediate(); + let n = args[2].immediate(); - let block = self.llbb(); - let extended_asm = block.add_extended_asm(None, ""); - extended_asm.add_input_operand(None, "r", result.llval); - extended_asm.add_clobber("memory"); - extended_asm.set_volatile_flag(true); + let void_ptr_type = self.context.new_type::<*const ()>(); + let a_ptr = self.bitcast(a, void_ptr_type); + let b_ptr = self.bitcast(b, void_ptr_type); - // We have copied the value to `result` already. - return Ok(()); - } + // Here we assume that the `memcmp` provided by the target is a NOP for size 0. + let builtin = self.context.get_builtin_function("memcmp"); + let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); + self.sext(cmp, self.type_ix(32)) + } - sym::ptr_mask => { - let usize_type = self.context.new_type::(); - let void_ptr_type = self.context.new_type::<*const ()>(); + sym::black_box => { + args[0].val.store(self, result); - let ptr = args[0].immediate(); - let mask = args[1].immediate(); + let block = self.llbb(); + let extended_asm = block.add_extended_asm(None, ""); + extended_asm.add_input_operand(None, "r", result.llval); + extended_asm.add_clobber("memory"); + extended_asm.set_volatile_flag(true); - let addr = self.bitcast(ptr, usize_type); - let masked = self.and(addr, mask); - self.bitcast(masked, void_ptr_type) - }, + // We have copied the value to `result` already. + return Ok(()); + } - _ if name_str.starts_with("simd_") => { - match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { - Ok(llval) => llval, - Err(()) => return Ok(()), - } + sym::ptr_mask => { + let usize_type = self.context.new_type::(); + let void_ptr_type = self.context.new_type::<*const ()>(); + + let ptr = args[0].immediate(); + let mask = args[1].immediate(); + + let addr = self.bitcast(ptr, usize_type); + let masked = self.and(addr, mask); + self.bitcast(masked, void_ptr_type) + } + + _ if name_str.starts_with("simd_") => { + match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { + Ok(llval) => llval, + Err(()) => return Ok(()), } + } - // Fall back to default body - _ => return Err(Instance::new(instance.def_id(), instance.args)), - }; + // Fall back to default body + _ => return Err(Instance::new(instance.def_id(), instance.args)), + }; if !fn_abi.ret.is_ignore() { if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr = self.pointercast(result.llval, ptr_llty); self.store(llval, ptr, result.align); - } - else { + } else { OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) .val .store(self, result); @@ -423,11 +441,21 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { - fn store_fn_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>) { + fn store_fn_arg( + &mut self, + arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, + idx: &mut usize, + dst: PlaceRef<'tcx, Self::Value>, + ) { arg_abi.store_fn_arg(self, idx, dst) } - fn store_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) { + fn store_arg( + &mut self, + arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, + val: RValue<'gcc>, + dst: PlaceRef<'tcx, RValue<'gcc>>, + ) { arg_abi.store(self, val, dst) } @@ -438,8 +466,18 @@ impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { pub trait ArgAbiExt<'gcc, 'tcx> { fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; - fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>); - fn store_fn_arg(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>); + fn store( + &self, + bx: &mut Builder<'_, 'gcc, 'tcx>, + val: RValue<'gcc>, + dst: PlaceRef<'tcx, RValue<'gcc>>, + ); + fn store_fn_arg( + &self, + bx: &mut Builder<'_, 'gcc, 'tcx>, + idx: &mut usize, + dst: PlaceRef<'tcx, RValue<'gcc>>, + ); } impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { @@ -453,17 +491,20 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { /// place for the original Rust type of this argument/return. /// Can be used for both storing formal arguments into Rust variables /// or results of call/invoke instructions into their destinations. - fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) { + fn store( + &self, + bx: &mut Builder<'_, 'gcc, 'tcx>, + val: RValue<'gcc>, + dst: PlaceRef<'tcx, RValue<'gcc>>, + ) { if self.is_ignore() { return; } if self.is_sized_indirect() { OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) - } - else if self.is_unsized_indirect() { + } else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); - } - else if let PassMode::Cast { ref cast, .. } = self.mode { + } else if let PassMode::Cast { ref cast, .. } = self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false; @@ -471,8 +512,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx)); let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty); bx.store(val, cast_dst, self.layout.align.abi); - } - else { + } else { // The actual return type is a struct, but the ABI // adaptation code has cast it into some scalar type. The // code that follows is the only reliable way I have @@ -508,35 +548,44 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { bx.lifetime_end(llscratch, scratch_size); } - } - else { + } else { OperandValue::Immediate(val).store(bx, dst); } } - fn store_fn_arg<'a>(&self, bx: &mut Builder<'a, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>) { + fn store_fn_arg<'a>( + &self, + bx: &mut Builder<'a, 'gcc, 'tcx>, + idx: &mut usize, + dst: PlaceRef<'tcx, RValue<'gcc>>, + ) { let mut next = || { let val = bx.current_func().get_param(*idx as i32); *idx += 1; val.to_rvalue() }; match self.mode { - PassMode::Ignore => {}, + PassMode::Ignore => {} PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); - }, + } PassMode::Indirect { meta_attrs: Some(_), .. } => { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); - }, - PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } | PassMode::Cast { .. } => { + } + PassMode::Direct(_) + | PassMode::Indirect { meta_attrs: None, .. } + | PassMode::Cast { .. } => { let next_arg = next(); self.store(bx, next_arg, dst); - }, + } } } } -fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -> Option<(u64, bool)> { +fn int_type_width_signed<'gcc, 'tcx>( + ty: Ty<'tcx>, + cx: &CodegenCx<'gcc, 'tcx>, +) -> Option<(u64, bool)> { match ty.kind() { ty::Int(t) => Some(( match t { @@ -570,82 +619,76 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let typ = result_type.to_unsigned(self.cx); let value = - if result_type.is_signed(self.cx) { - self.gcc_int_cast(value, typ) - } - else { - value - }; + if result_type.is_signed(self.cx) { self.gcc_int_cast(value, typ) } else { value }; let context = &self.cx.context; - let result = - match width { - 8 | 16 | 32 | 64 => { - let mask = ((1u128 << width) - 1) as u64; - let (m0, m1, m2) = if width > 16 { - ( - context.new_rvalue_from_long(typ, (0x5555555555555555u64 & mask) as i64), - context.new_rvalue_from_long(typ, (0x3333333333333333u64 & mask) as i64), - context.new_rvalue_from_long(typ, (0x0f0f0f0f0f0f0f0fu64 & mask) as i64), - ) - } else { - ( - context.new_rvalue_from_int(typ, (0x5555u64 & mask) as i32), - context.new_rvalue_from_int(typ, (0x3333u64 & mask) as i32), - context.new_rvalue_from_int(typ, (0x0f0fu64 & mask) as i32), - ) - }; - let one = context.new_rvalue_from_int(typ, 1); - let two = context.new_rvalue_from_int(typ, 2); - let four = context.new_rvalue_from_int(typ, 4); - - // First step. - let left = self.lshr(value, one); - let left = self.and(left, m0); - let right = self.and(value, m0); - let right = self.shl(right, one); - let step1 = self.or(left, right); - - // Second step. - let left = self.lshr(step1, two); - let left = self.and(left, m1); - let right = self.and(step1, m1); - let right = self.shl(right, two); - let step2 = self.or(left, right); - - // Third step. - let left = self.lshr(step2, four); - let left = self.and(left, m2); - let right = self.and(step2, m2); - let right = self.shl(right, four); - let step3 = self.or(left, right); - - // Fourth step. - if width == 8 { - step3 - } else { - self.gcc_bswap(step3, width) - } - }, - 128 => { - // TODO(antoyo): find a more efficient implementation? - let sixty_four = self.gcc_int(typ, 64); - let right_shift = self.gcc_lshr(value, sixty_four); - let high = self.gcc_int_cast(right_shift, self.u64_type); - let low = self.gcc_int_cast(value, self.u64_type); - - let reversed_high = self.bit_reverse(64, high); - let reversed_low = self.bit_reverse(64, low); - - let new_low = self.gcc_int_cast(reversed_high, typ); - let new_high = self.shl(self.gcc_int_cast(reversed_low, typ), sixty_four); - - self.gcc_or(new_low, new_high, self.loc) - }, - _ => { - panic!("cannot bit reverse with width = {}", width); - }, - }; + let result = match width { + 8 | 16 | 32 | 64 => { + let mask = ((1u128 << width) - 1) as u64; + let (m0, m1, m2) = if width > 16 { + ( + context.new_rvalue_from_long(typ, (0x5555555555555555u64 & mask) as i64), + context.new_rvalue_from_long(typ, (0x3333333333333333u64 & mask) as i64), + context.new_rvalue_from_long(typ, (0x0f0f0f0f0f0f0f0fu64 & mask) as i64), + ) + } else { + ( + context.new_rvalue_from_int(typ, (0x5555u64 & mask) as i32), + context.new_rvalue_from_int(typ, (0x3333u64 & mask) as i32), + context.new_rvalue_from_int(typ, (0x0f0fu64 & mask) as i32), + ) + }; + let one = context.new_rvalue_from_int(typ, 1); + let two = context.new_rvalue_from_int(typ, 2); + let four = context.new_rvalue_from_int(typ, 4); + + // First step. + let left = self.lshr(value, one); + let left = self.and(left, m0); + let right = self.and(value, m0); + let right = self.shl(right, one); + let step1 = self.or(left, right); + + // Second step. + let left = self.lshr(step1, two); + let left = self.and(left, m1); + let right = self.and(step1, m1); + let right = self.shl(right, two); + let step2 = self.or(left, right); + + // Third step. + let left = self.lshr(step2, four); + let left = self.and(left, m2); + let right = self.and(step2, m2); + let right = self.shl(right, four); + let step3 = self.or(left, right); + + // Fourth step. + if width == 8 { + step3 + } else { + self.gcc_bswap(step3, width) + } + } + 128 => { + // TODO(antoyo): find a more efficient implementation? + let sixty_four = self.gcc_int(typ, 64); + let right_shift = self.gcc_lshr(value, sixty_four); + let high = self.gcc_int_cast(right_shift, self.u64_type); + let low = self.gcc_int_cast(value, self.u64_type); + + let reversed_high = self.bit_reverse(64, high); + let reversed_low = self.bit_reverse(64, low); + + let new_low = self.gcc_int_cast(reversed_high, typ); + let new_high = self.shl(self.gcc_int_cast(reversed_low, typ), sixty_four); + + self.gcc_or(new_low, new_high, self.location) + } + _ => { + panic!("cannot bit reverse with width = {}", width); + } + }; self.gcc_int_cast(result, result_type) } @@ -685,56 +728,54 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let first_elem = self.context.new_array_access(None, result, zero); let first_value = self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), arg_type); self.llbb() - .add_assignment(self.loc, first_elem, first_value); + .add_assignment(self.location, first_elem, first_value); - let second_elem = self.context.new_array_access(self.loc, result, one); - let cast = self.gcc_int_cast(self.context.new_call(self.loc, clzll, &[low]), arg_type); + let second_elem = self.context.new_array_access(self.location, result, one); + let cast = self.gcc_int_cast(self.context.new_call(self.location, clzll, &[low]), arg_type); let second_value = self.add(cast, sixty_four); self.llbb() - .add_assignment(self.loc, second_elem, second_value); + .add_assignment(self.location, second_elem, second_value); - let third_elem = self.context.new_array_access(self.loc, result, two); + let third_elem = self.context.new_array_access(self.location, result, two); let third_value = self.const_uint(arg_type, 128); self.llbb() - .add_assignment(self.loc, third_elem, third_value); + .add_assignment(self.location, third_elem, third_value); - let not_high = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, high); - let not_low = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, low); let not_low_and_not_high = not_low & not_high; let index = not_high + not_low_and_not_high; // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in // gcc. // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the // compilation stage. - let index = self.context.new_cast(self.loc, index, self.i32_type); + let index = self.context.new_cast(self.location, index, self.i32_type); - let res = self.context.new_array_access(self.loc, result, index); + let res = self.context.new_array_access(self.location, result, index); return self.gcc_int_cast(res.to_rvalue(), arg_type); } else { let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); - let arg = self.context.new_cast(self.loc, arg, self.ulonglong_type); + let arg = self.context.new_cast(self.location, arg, self.ulonglong_type); let diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64; let diff = self.context.new_rvalue_from_long(self.int_type, diff * 8); - let res = self.context.new_call(self.loc, count_leading_zeroes, &[arg]) - diff; - return self.context.new_cast(self.loc, res, arg_type); + let res = self.context.new_call(self.location, count_leading_zeroes, &[arg]) - diff; + return self.context.new_cast(self.location, res, arg_type); }; let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes); - let res = self.context.new_call(self.loc, count_leading_zeroes, &[arg]); - self.context.new_cast(self.loc, res, arg_type) + let res = self.context.new_call(self.location, count_leading_zeroes, &[arg]); + self.context.new_cast(self.location, res, arg_type) } fn count_trailing_zeroes(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { let result_type = arg.get_type(); - let arg = - if result_type.is_signed(self.cx) { - let new_type = result_type.to_unsigned(self.cx); - self.gcc_int_cast(arg, new_type) - } - else { - arg - }; + let arg = if result_type.is_signed(self.cx) { + let new_type = result_type.to_unsigned(self.cx); + self.gcc_int_cast(arg, new_type) + } else { + arg + }; let arg_type = arg.get_type(); let (count_trailing_zeroes, expected_type) = // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here @@ -766,58 +807,56 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let ctzll = self.context.get_builtin_function("__builtin_ctzll"); - let first_elem = self.context.new_array_access(self.loc, result, zero); - let first_value = self.gcc_int_cast(self.context.new_call(self.loc, ctzll, &[low]), arg_type); + let first_elem = self.context.new_array_access(self.location, result, zero); + let first_value = self.gcc_int_cast(self.context.new_call(self.location, ctzll, &[low]), arg_type); self.llbb() - .add_assignment(self.loc, first_elem, first_value); + .add_assignment(self.location, first_elem, first_value); - let second_elem = self.context.new_array_access(self.loc, result, one); - let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(self.loc, ctzll, &[high]), arg_type), sixty_four); + let second_elem = self.context.new_array_access(self.location, result, one); + let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(self.location, ctzll, &[high]), arg_type), sixty_four); self.llbb() - .add_assignment(self.loc, second_elem, second_value); + .add_assignment(self.location, second_elem, second_value); - let third_elem = self.context.new_array_access(self.loc, result, two); + let third_elem = self.context.new_array_access(self.location, result, two); let third_value = self.gcc_int(arg_type, 128); self.llbb() - .add_assignment(self.loc, third_elem, third_value); + .add_assignment(self.location, third_elem, third_value); - let not_low = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, low); - let not_high = self.context.new_unary_op(self.loc, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, high); let not_low_and_not_high = not_low & not_high; let index = not_low + not_low_and_not_high; // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in // gcc. // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the // compilation stage. - let index = self.context.new_cast(self.loc, index, self.i32_type); + let index = self.context.new_cast(self.location, index, self.i32_type); - let res = self.context.new_array_access(self.loc, result, index); + let res = self.context.new_array_access(self.location, result, index); return self.gcc_int_cast(res.to_rvalue(), result_type); } else { let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll"); let arg_size = arg_type.get_size(); - let casted_arg = self.context.new_cast(self.loc, arg, self.ulonglong_type); + let casted_arg = self.context.new_cast(self.location, arg, self.ulonglong_type); let byte_diff = self.ulonglong_type.get_size() as i64 - arg_size as i64; let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8); let mask = self.context.new_rvalue_from_long(arg_type, -1); // To get the value with all bits set. - let masked = mask & self.context.new_unary_op(self.loc, UnaryOp::BitwiseNegate, arg_type, arg); - let cond = self.context.new_comparison(self.loc, ComparisonOp::Equals, masked, mask); - let diff = diff * self.context.new_cast(self.loc, cond, self.int_type); - let res = self.context.new_call(self.loc, count_trailing_zeroes, &[casted_arg]) - diff; - return self.context.new_cast(self.loc, res, result_type); + let masked = mask & self.context.new_unary_op(self.location, UnaryOp::BitwiseNegate, arg_type, arg); + let cond = self.context.new_comparison(self.location, ComparisonOp::Equals, masked, mask); + let diff = diff * self.context.new_cast(self.location, cond, self.int_type); + let res = self.context.new_call(self.location, count_trailing_zeroes, &[casted_arg]) - diff; + return self.context.new_cast(self.location, res, result_type); }; let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes); - let arg = - if arg_type != expected_type { - self.context.new_cast(self.loc, arg, expected_type) - } - else { - arg - }; - let res = self.context.new_call(self.loc, count_trailing_zeroes, &[arg]); - self.context.new_cast(self.loc, res, result_type) + let arg = if arg_type != expected_type { + self.context.new_cast(self.location, arg, expected_type) + } else { + arg + }; + let res = self.context.new_call(self.location, count_trailing_zeroes, &[arg]); + self.context.new_cast(self.location, res, result_type) } fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> { @@ -825,13 +864,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result_type = value.get_type(); let value_type = result_type.to_unsigned(self.cx); - let value = - if result_type.is_signed(self.cx) { - self.gcc_int_cast(value, value_type) - } - else { - value - }; + let value = if result_type.is_signed(self.cx) { + self.gcc_int_cast(value, value_type) + } else { + value + }; // only break apart 128-bit ints if they're not natively supported // TODO(antoyo): remove this if/when native 128-bit integers land in libgccjit @@ -859,8 +896,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let counter = self.current_func().new_local(None, counter_type, "popcount_counter"); let val = self.current_func().new_local(None, value_type, "popcount_value"); let zero = self.gcc_zero(counter_type); - self.llbb().add_assignment(self.loc, counter, zero); - self.llbb().add_assignment(self.loc, val, value); + self.llbb().add_assignment(self.location, counter, zero); + self.llbb().add_assignment(self.location, val, value); self.br(loop_head); // check if value isn't zero @@ -874,12 +911,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let one = self.gcc_int(value_type, 1); let sub = self.gcc_sub(val.to_rvalue(), one); let op = self.gcc_and(val.to_rvalue(), sub); - loop_body.add_assignment(self.loc, val, op); + loop_body.add_assignment(self.location, val, op); // counter += 1 let one = self.gcc_int(counter_type, 1); let op = self.gcc_add(counter.to_rvalue(), one); - loop_body.add_assignment(self.loc, counter, op); + loop_body.add_assignment(self.location, counter, op); self.br(loop_head); // end of loop @@ -888,66 +925,70 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } // Algorithm from: https://blog.regehr.org/archives/1063 - fn rotate_left(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> { + fn rotate_left( + &mut self, + value: RValue<'gcc>, + shift: RValue<'gcc>, + width: u64, + ) -> RValue<'gcc> { let max = self.const_uint(shift.get_type(), width); let shift = self.urem(shift, max); let lhs = self.shl(value, shift); let result_neg = self.neg(shift); - let result_and = - self.and( - result_neg, - self.const_uint(shift.get_type(), width - 1), - ); + let result_and = self.and(result_neg, self.const_uint(shift.get_type(), width - 1)); let rhs = self.lshr(value, result_and); self.or(lhs, rhs) } // Algorithm from: https://blog.regehr.org/archives/1063 - fn rotate_right(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> { + fn rotate_right( + &mut self, + value: RValue<'gcc>, + shift: RValue<'gcc>, + width: u64, + ) -> RValue<'gcc> { let max = self.const_uint(shift.get_type(), width); let shift = self.urem(shift, max); let lhs = self.lshr(value, shift); let result_neg = self.neg(shift); - let result_and = - self.and( - result_neg, - self.const_uint(shift.get_type(), width - 1), - ); + let result_and = self.and(result_neg, self.const_uint(shift.get_type(), width - 1)); let rhs = self.shl(value, result_and); self.or(lhs, rhs) } - fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> { + fn saturating_add( + &mut self, + lhs: RValue<'gcc>, + rhs: RValue<'gcc>, + signed: bool, + width: u64, + ) -> RValue<'gcc> { let result_type = lhs.get_type(); if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 let func = self.current_func.borrow().expect("func"); - let res = func.new_local(self.loc, result_type, "saturating_sum"); + let res = func.new_local(self.location, result_type, "saturating_sum"); let supports_native_type = self.is_native_int_type(result_type); - let overflow = - if supports_native_type { - let func_name = - match width { - 8 => "__builtin_add_overflow", - 16 => "__builtin_add_overflow", - 32 => "__builtin_sadd_overflow", - 64 => "__builtin_saddll_overflow", - 128 => "__builtin_add_overflow", - _ => unreachable!(), - }; - let overflow_func = self.context.get_builtin_function(func_name); - self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.loc)], None) - } - else { - let func_name = - match width { - 128 => "__rust_i128_addo", - _ => unreachable!(), - }; - let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); - self.llbb().add_assignment(self.loc, res, int_result); - overflow + let overflow = if supports_native_type { + let func_name = match width { + 8 => "__builtin_add_overflow", + 16 => "__builtin_add_overflow", + 32 => "__builtin_sadd_overflow", + 64 => "__builtin_saddll_overflow", + 128 => "__builtin_add_overflow", + _ => unreachable!(), + }; + let overflow_func = self.context.get_builtin_function(func_name); + self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.location)], None) + } else { + let func_name = match width { + 128 => "__rust_i128_addo", + _ => unreachable!(), }; + let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); + self.llbb().add_assignment(self.location, res, int_result); + overflow + }; let then_block = func.new_block("then"); let after_block = func.new_block("after"); @@ -955,61 +996,69 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Return `result_type`'s maximum or minimum value on overflow // NOTE: convert the type to unsigned to have an unsigned shift. let unsigned_type = result_type.to_unsigned(&self.cx); - let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1)); + let shifted = self.gcc_lshr( + self.gcc_int_cast(lhs, unsigned_type), + self.gcc_int(unsigned_type, width as i64 - 1), + ); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); - then_block.add_assignment(self.loc, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); - then_block.end_with_jump(self.loc, after_block); + then_block.add_assignment( + self.location, + res, + self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type), + ); + then_block.end_with_jump(self.location, after_block); - self.llbb().end_with_conditional(self.loc, overflow, then_block, after_block); + self.llbb().end_with_conditional(self.location, overflow, then_block, after_block); // NOTE: since jumps were added in a place rustc does not // expect, the current block in the state need to be updated. self.switch_to_block(after_block); res.to_rvalue() - } - else { + } else { // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/ let res = self.gcc_add(lhs, rhs); let cond = self.gcc_icmp(IntPredicate::IntULT, res, lhs); let value = self.gcc_neg(self.gcc_int_cast(cond, result_type)); - self.gcc_or(res, value, self.loc) + self.gcc_or(res, value, self.location) } } // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/ - fn saturating_sub(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> { + fn saturating_sub( + &mut self, + lhs: RValue<'gcc>, + rhs: RValue<'gcc>, + signed: bool, + width: u64, + ) -> RValue<'gcc> { let result_type = lhs.get_type(); if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 let func = self.current_func.borrow().expect("func"); - let res = func.new_local(self.loc, result_type, "saturating_diff"); + let res = func.new_local(self.location, result_type, "saturating_diff"); let supports_native_type = self.is_native_int_type(result_type); - let overflow = - if supports_native_type { - let func_name = - match width { - 8 => "__builtin_sub_overflow", - 16 => "__builtin_sub_overflow", - 32 => "__builtin_ssub_overflow", - 64 => "__builtin_ssubll_overflow", - 128 => "__builtin_sub_overflow", - _ => unreachable!(), - }; - let overflow_func = self.context.get_builtin_function(func_name); - self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.loc)], None) - } - else { - let func_name = - match width { - 128 => "__rust_i128_subo", - _ => unreachable!(), - }; - let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); - self.llbb().add_assignment(self.loc, res, int_result); - overflow + let overflow = if supports_native_type { + let func_name = match width { + 8 => "__builtin_sub_overflow", + 16 => "__builtin_sub_overflow", + 32 => "__builtin_ssub_overflow", + 64 => "__builtin_ssubll_overflow", + 128 => "__builtin_sub_overflow", + _ => unreachable!(), + }; + let overflow_func = self.context.get_builtin_function(func_name); + self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.location)], None) + } else { + let func_name = match width { + 128 => "__rust_i128_subo", + _ => unreachable!(), }; + let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs); + self.llbb().add_assignment(self.location, res, int_result); + overflow + }; let then_block = func.new_block("then"); let after_block = func.new_block("after"); @@ -1017,21 +1066,27 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Return `result_type`'s maximum or minimum value on overflow // NOTE: convert the type to unsigned to have an unsigned shift. let unsigned_type = result_type.to_unsigned(&self.cx); - let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1)); + let shifted = self.gcc_lshr( + self.gcc_int_cast(lhs, unsigned_type), + self.gcc_int(unsigned_type, width as i64 - 1), + ); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); - then_block.add_assignment(self.loc, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type)); - then_block.end_with_jump(self.loc, after_block); + then_block.add_assignment( + self.location, + res, + self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type), + ); + then_block.end_with_jump(self.location, after_block); - self.llbb().end_with_conditional(self.loc, overflow, then_block, after_block); + self.llbb().end_with_conditional(self.location, overflow, then_block, after_block); // NOTE: since jumps were added in a place rustc does not // expect, the current block in the state need to be updated. self.switch_to_block(after_block); res.to_rvalue() - } - else { + } else { let res = self.gcc_sub(lhs, rhs); let comparison = self.gcc_icmp(IntPredicate::IntULE, res, lhs); let value = self.gcc_neg(self.gcc_int_cast(comparison, result_type)); @@ -1040,21 +1095,25 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } -fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { +fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( + bx: &'b mut Builder<'a, 'gcc, 'tcx>, + try_func: RValue<'gcc>, + data: RValue<'gcc>, + _catch_func: RValue<'gcc>, + dest: RValue<'gcc>, +) { if bx.sess().panic_strategy() == PanicStrategy::Abort { bx.call(bx.type_void(), None, None, try_func, &[data], None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. let ret_align = bx.tcx.data_layout.i32_align.abi; bx.store(bx.const_i32(0), dest, ret_align); - } - else if wants_msvc_seh(bx.sess()) { + } else if wants_msvc_seh(bx.sess()) { unimplemented!(); - } - else { - #[cfg(feature="master")] + } else { + #[cfg(feature = "master")] codegen_gnu_try(bx, try_func, data, _catch_func, dest); - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] unimplemented!(); } } @@ -1070,8 +1129,14 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_fu // function calling it, and that function may already have other personality // functions in play. By calling a shim we're guaranteed that our shim will have // the right personality function. -#[cfg(feature="master")] -fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>, data: RValue<'gcc>, catch_func: RValue<'gcc>, dest: RValue<'gcc>) { +#[cfg(feature = "master")] +fn codegen_gnu_try<'gcc>( + bx: &mut Builder<'_, 'gcc, '_>, + try_func: RValue<'gcc>, + data: RValue<'gcc>, + catch_func: RValue<'gcc>, + dest: RValue<'gcc>, +) { let cx: &CodegenCx<'gcc, '_> = bx.cx; let (llty, func) = get_rust_try_fn(cx, &mut |mut bx| { // Codegens the shims described above: @@ -1130,36 +1195,44 @@ fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>, bx.store(ret, dest, i32_align); } - // Helper function used to get a handle to the `__rust_try` function used to // catch exceptions. // // This function is only generated once and is then cached. -#[cfg(feature="master")] -fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) { +#[cfg(feature = "master")] +fn get_rust_try_fn<'a, 'gcc, 'tcx>( + cx: &'a CodegenCx<'gcc, 'tcx>, + codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>), +) -> (Type<'gcc>, Function<'gcc>) { if let Some(llfn) = cx.rust_try_fn.get() { return llfn; } // Define the type up front for the signature of the rust_try function. let tcx = cx.tcx; - let i8p = Ty::new_mut_ptr(tcx,tcx.types.i8); + let i8p = Ty::new_mut_ptr(tcx, tcx.types.i8); // `unsafe fn(*mut i8) -> ()` - let try_fn_ty = Ty::new_fn_ptr(tcx,ty::Binder::dummy(tcx.mk_fn_sig( - iter::once(i8p), - Ty::new_unit(tcx,), - false, - rustc_hir::Unsafety::Unsafe, - Abi::Rust, - ))); + let try_fn_ty = Ty::new_fn_ptr( + tcx, + ty::Binder::dummy(tcx.mk_fn_sig( + iter::once(i8p), + Ty::new_unit(tcx), + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + )), + ); // `unsafe fn(*mut i8, *mut i8) -> ()` - let catch_fn_ty = Ty::new_fn_ptr(tcx,ty::Binder::dummy(tcx.mk_fn_sig( - [i8p, i8p].iter().cloned(), - Ty::new_unit(tcx,), - false, - rustc_hir::Unsafety::Unsafe, - Abi::Rust, - ))); + let catch_fn_ty = Ty::new_fn_ptr( + tcx, + ty::Binder::dummy(tcx.mk_fn_sig( + [i8p, i8p].iter().cloned(), + Ty::new_unit(tcx), + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + )), + ); // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32` let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig( [try_fn_ty, i8p, catch_fn_ty], @@ -1175,8 +1248,13 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut // Helper function to give a Block to a closure to codegen a shim function. // This is currently primarily used for the `try` intrinsic functions above. -#[cfg(feature="master")] -fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) { +#[cfg(feature = "master")] +fn gen_fn<'a, 'gcc, 'tcx>( + cx: &'a CodegenCx<'gcc, 'tcx>, + name: &str, + rust_fn_sig: ty::PolyFnSig<'tcx>, + codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>), +) -> (Type<'gcc>, Function<'gcc>) { let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty()); let return_type = fn_abi.gcc_type(cx).return_type; // FIXME(eddyb) find a nicer way to do this. diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index cecc982bb1f80..052b368ecb649 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -21,10 +21,10 @@ use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::Align; use crate::builder::Builder; -#[cfg(feature = "master")] -use crate::context::CodegenCx; #[cfg(not(feature = "master"))] use crate::common::SignType; +#[cfg(feature = "master")] +use crate::context::CodegenCx; pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bx: &mut Builder<'a, 'gcc, 'tcx>, @@ -176,7 +176,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( #[cfg(not(feature = "master"))] let shuffled = { - let new_elements: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) + let new_elements: Vec<_> = shuffle_indices + .chunks_exact(elem_size_bytes as _) .flat_map(|x| x.iter().rev()) .map(|&i| { let index = bx.context.new_rvalue_from_long(bx.u64_type, i as _); @@ -188,7 +189,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( }; #[cfg(feature = "master")] let shuffled = { - let indices: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _) + let indices: Vec<_> = shuffle_indices + .chunks_exact(elem_size_bytes as _) .flat_map(|x| x.iter().rev()) .map(|&i| bx.context.new_rvalue_from_int(bx.u8_type, i as _)) .collect(); @@ -202,12 +204,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( if name == sym::simd_bswap || name == sym::simd_bitreverse { require!( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, - InvalidMonomorphization::UnsupportedOperation { - span, - name, - in_ty, - in_elem, - } + InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem } ); } @@ -245,23 +242,27 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( .map(|x| bx.context.new_rvalue_from_int(bx.u8_type, x.reverse_bits() as _)) .chain((16..byte_vector_type_size).map(|_| zero_byte)) .collect(); - let hi_nibble = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &hi_nibble_elements); + let hi_nibble = + bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &hi_nibble_elements); let lo_nibble_elements: Vec<_> = (0u8..16) .map(|x| bx.context.new_rvalue_from_int(bx.u8_type, (x.reverse_bits() >> 4) as _)) .chain((16..byte_vector_type_size).map(|_| zero_byte)) .collect(); - let lo_nibble = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &lo_nibble_elements); + let lo_nibble = + bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &lo_nibble_elements); let mask = bx.context.new_rvalue_from_vector( None, long_byte_vector_type, - &vec![bx.context.new_rvalue_from_int(bx.u8_type, 0x0f); byte_vector_type_size as _]); + &vec![bx.context.new_rvalue_from_int(bx.u8_type, 0x0f); byte_vector_type_size as _], + ); let four_vec = bx.context.new_rvalue_from_vector( None, long_byte_vector_type, - &vec![bx.context.new_rvalue_from_int(bx.u8_type, 4); byte_vector_type_size as _]); + &vec![bx.context.new_rvalue_from_int(bx.u8_type, 4); byte_vector_type_size as _], + ); // Step 2: Byte-swap the input. let swapped = simd_bswap(bx, args[0].immediate()); @@ -294,7 +295,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // Step 5: Combine the results of the shuffle back together and cast back to the original type. let result = hi | lo; - let cast_ty = bx.context.new_vector_type(elem_type, byte_vector_type_size / (elem_size_bytes as u64)); + let cast_ty = + bx.context.new_vector_type(elem_type, byte_vector_type_size / (elem_size_bytes as u64)); // we might need to truncate if sizeof(v_type) < sizeof(cast_type) if type_size_bytes < byte_vector_type_size { @@ -305,7 +307,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bx.extract_element(cast_result, idx) }) .collect(); - return Ok(bx.context.new_rvalue_from_vector(None, v_type, &elems)) + return Ok(bx.context.new_rvalue_from_vector(None, v_type, &elems)); } else { // avoid the unnecessary truncation as an optimization. return Ok(bx.context.new_bitcast(None, result, v_type)); @@ -702,7 +704,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( invert: bool, ) -> RValue<'gcc> { let vector_type = default.get_type(); - let elem_type = vector_type.unqualified().dyncast_vector().expect("vector type").get_element_type(); + let elem_type = + vector_type.unqualified().dyncast_vector().expect("vector type").get_element_type(); let mut values = Vec::with_capacity(in_len as usize); for i in 0..in_len { @@ -724,7 +727,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( mask_types.push(bx.context.new_field(None, bx.i32_type, "m")); let mask_value = bx.context.new_vector_access(None, mask, index).to_rvalue(); let mask_value_cast = bx.context.new_cast(None, mask_value, bx.i32_type); - let masked = bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value_cast; + let masked = + bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value_cast; let value = index + masked; mask_values.push(value); } @@ -965,14 +969,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } } - let result = gather( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - bx, - in_len, - true, - ); + let result = + gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), bx, in_len, true); let pointers = args[1].immediate(); diff --git a/src/lib.rs b/src/lib.rs index 1c1f82c3221cc..0f57465591d5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ hash_raw_entry )] #![allow(broken_intra_doc_links)] -#![recursion_limit="256"] +#![recursion_limit = "256"] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![deny(clippy::pattern_type_mismatch)] @@ -40,7 +40,7 @@ extern crate rustc_fluent_macro; extern crate rustc_fs_util; extern crate rustc_hir; extern crate rustc_index; -#[cfg(feature="master")] +#[cfg(feature = "master")] extern crate rustc_interface; extern crate rustc_macros; extern crate rustc_metadata; @@ -80,36 +80,40 @@ mod type_of; use std::any::Any; use std::fmt::Debug; -use std::sync::Arc; -use std::sync::Mutex; -#[cfg(not(feature="master"))] +#[cfg(not(feature = "master"))] use std::sync::atomic::AtomicBool; -#[cfg(not(feature="master"))] +#[cfg(not(feature = "master"))] use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::sync::Mutex; +use errors::LTONotSupported; +#[cfg(not(feature = "master"))] +use gccjit::CType; use gccjit::{Context, OptimizationLevel}; -#[cfg(feature="master")] +#[cfg(feature = "master")] use gccjit::{TargetInfo, Version}; -#[cfg(not(feature="master"))] -use gccjit::CType; -use errors::LTONotSupported; use rustc_ast::expand::allocator::AllocatorKind; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; -use rustc_codegen_ssa::base::codegen_crate; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, +}; +use rustc_codegen_ssa::base::codegen_crate; +use rustc_codegen_ssa::traits::{ + CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods, +}; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; -use rustc_errors::{ErrorGuaranteed, DiagCtxt}; +use rustc_errors::{DiagCtxt, ErrorGuaranteed}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::util::Providers; use rustc_middle::ty::TyCtxt; +use rustc_middle::util::Providers; use rustc_session::config::{Lto, OptLevel, OutputFilenames}; use rustc_session::Session; -use rustc_span::Symbol; use rustc_span::fatal_error::FatalError; +use rustc_span::Symbol; use tempfile::TempDir; use crate::back::lto::ModuleBuffer; @@ -127,13 +131,13 @@ impl String> Drop for PrintOnPanic { } } -#[cfg(not(feature="master"))] +#[cfg(not(feature = "master"))] #[derive(Debug)] pub struct TargetInfo { supports_128bit_integers: AtomicBool, } -#[cfg(not(feature="master"))] +#[cfg(not(feature = "master"))] impl TargetInfo { fn cpu_supports(&self, _feature: &str) -> bool { false @@ -176,7 +180,7 @@ impl CodegenBackend for GccCodegenBackend { } fn init(&self, sess: &Session) { - #[cfg(feature="master")] + #[cfg(feature = "master")] { let target_cpu = target_cpu(sess); @@ -189,13 +193,13 @@ impl CodegenBackend for GccCodegenBackend { **self.target_info.info.lock().expect("lock") = context.get_target_info(); } - #[cfg(feature="master")] + #[cfg(feature = "master")] gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); if sess.lto() == Lto::Thin { sess.dcx().emit_warn(LTONotSupported {}); } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] { let temp_dir = TempDir::new().expect("cannot create temporary directory"); let temp_file = temp_dir.into_path().join("result.asm"); @@ -203,39 +207,62 @@ impl CodegenBackend for GccCodegenBackend { check_context.set_print_errors_to_stderr(false); let _int128_ty = check_context.new_c_type(CType::UInt128t); // NOTE: we cannot just call compile() as this would require other files than libgccjit.so. - check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str")); - self.target_info.info.lock().expect("lock").supports_128bit_integers.store(check_context.get_last_error() == Ok(None), Ordering::SeqCst); + check_context.compile_to_file( + gccjit::OutputKind::Assembler, + temp_file.to_str().expect("path to str"), + ); + self.target_info + .info + .lock() + .expect("lock") + .supports_128bit_integers + .store(check_context.get_last_error() == Ok(None), Ordering::SeqCst); } } fn provide(&self, providers: &mut Providers) { - providers.global_backend_features = - |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true) + providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true) } - fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box { + fn codegen_crate<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + metadata: EncodedMetadata, + need_metadata_module: bool, + ) -> Box { let target_cpu = target_cpu(tcx.sess); - let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module); + let res = codegen_crate( + self.clone(), + tcx, + target_cpu.to_string(), + metadata, + need_metadata_module, + ); Box::new(res) } - fn join_codegen(&self, ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames) -> (CodegenResults, FxIndexMap) { + fn join_codegen( + &self, + ongoing_codegen: Box, + sess: &Session, + _outputs: &OutputFilenames, + ) -> (CodegenResults, FxIndexMap) { ongoing_codegen .downcast::>() .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") .join(sess) } - fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> { + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + outputs: &OutputFilenames, + ) -> Result<(), ErrorGuaranteed> { use rustc_codegen_ssa::back::link::link_binary; - link_binary( - sess, - &crate::archive::ArArchiveBuilderBuilder, - &codegen_results, - outputs, - ) + link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs) } fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec { @@ -248,14 +275,15 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" { context.add_command_line_option("-masm=intel"); } - #[cfg(feature="master")] + #[cfg(feature = "master")] { context.set_allow_special_chars_in_func_names(true); let version = Version::get(); let version = format!("{}.{}.{}", version.major, version.minor, version.patch); - context.set_output_ident(&format!("rustc version {} with libgccjit {}", - rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), - version, + context.set_output_ident(&format!( + "rustc version {} with libgccjit {}", + rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), + version, )); } // TODO(antoyo): check if this should only be added when using -Cforce-unwind-tables=n. @@ -264,26 +292,41 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { + fn codegen_allocator<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + module_name: &str, + kind: AllocatorKind, + alloc_error_handler_kind: AllocatorKind, + ) -> Self::Module { let mut mods = GccContext { context: new_context(tcx), should_combine_object_files: false, temp_dir: None, }; - unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } + unsafe { + allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); + } mods } - fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen, u64) { + fn compile_codegen_unit( + &self, + tcx: TyCtxt<'_>, + cgu_name: Symbol, + ) -> (ModuleCodegen, u64) { base::compile_codegen_unit(tcx, cgu_name, self.target_info.clone()) } - fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn { + fn target_machine_factory( + &self, + _sess: &Session, + _opt_level: OptLevel, + _features: &[String], + ) -> TargetMachineFactoryFn { // TODO(antoyo): set opt level. - Arc::new(|_| { - Ok(()) - }) + Arc::new(|_| Ok(())) } } @@ -314,11 +357,19 @@ impl WriteBackendMethods for GccCodegenBackend { type ThinData = (); type ThinBuffer = ThinBuffer; - fn run_fat_lto(cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result, FatalError> { + fn run_fat_lto( + cgcx: &CodegenContext, + modules: Vec>, + cached_modules: Vec<(SerializedModule, WorkProduct)>, + ) -> Result, FatalError> { back::lto::run_fat(cgcx, modules, cached_modules) } - fn run_thin_lto(_cgcx: &CodegenContext, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result<(Vec>, Vec), FatalError> { + fn run_thin_lto( + _cgcx: &CodegenContext, + _modules: Vec<(String, Self::ThinBuffer)>, + _cached_modules: Vec<(SerializedModule, WorkProduct)>, + ) -> Result<(Vec>, Vec), FatalError> { unimplemented!(); } @@ -330,21 +381,37 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!() } - unsafe fn optimize(_cgcx: &CodegenContext, _dcx: &DiagCtxt, module: &ModuleCodegen, config: &ModuleConfig) -> Result<(), FatalError> { + unsafe fn optimize( + _cgcx: &CodegenContext, + _dcx: &DiagCtxt, + module: &ModuleCodegen, + config: &ModuleConfig, + ) -> Result<(), FatalError> { module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); Ok(()) } - fn optimize_fat(_cgcx: &CodegenContext, _module: &mut ModuleCodegen) -> Result<(), FatalError> { + fn optimize_fat( + _cgcx: &CodegenContext, + _module: &mut ModuleCodegen, + ) -> Result<(), FatalError> { // TODO(antoyo) Ok(()) } - unsafe fn optimize_thin(_cgcx: &CodegenContext, _thin: ThinModule) -> Result, FatalError> { + unsafe fn optimize_thin( + _cgcx: &CodegenContext, + _thin: ThinModule, + ) -> Result, FatalError> { unimplemented!(); } - unsafe fn codegen(cgcx: &CodegenContext, dcx: &DiagCtxt, module: ModuleCodegen, config: &ModuleConfig) -> Result { + unsafe fn codegen( + cgcx: &CodegenContext, + dcx: &DiagCtxt, + module: ModuleCodegen, + config: &ModuleConfig, + ) -> Result { back::write::codegen(cgcx, dcx, module, config) } @@ -356,7 +423,11 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!(); } - fn run_link(cgcx: &CodegenContext, dcx: &DiagCtxt, modules: Vec>) -> Result, FatalError> { + fn run_link( + cgcx: &CodegenContext, + dcx: &DiagCtxt, + modules: Vec>, + ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) } } @@ -364,55 +435,56 @@ impl WriteBackendMethods for GccCodegenBackend { /// This is the entrypoint for a hot plugged rustc_codegen_gccjit #[no_mangle] pub fn __rustc_codegen_backend() -> Box { - #[cfg(feature="master")] + #[cfg(feature = "master")] let info = { // Check whether the target supports 128-bit integers. let context = Context::default(); Arc::new(Mutex::new(IntoDynSyncSend(context.get_target_info()))) }; - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] let info = Arc::new(Mutex::new(IntoDynSyncSend(TargetInfo { supports_128bit_integers: AtomicBool::new(false), }))); - Box::new(GccCodegenBackend { - target_info: LockedTargetInfo { info }, - }) + Box::new(GccCodegenBackend { target_info: LockedTargetInfo { info } }) } fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { match optlevel { None => OptimizationLevel::None, - Some(level) => { - match level { - OptLevel::No => OptimizationLevel::None, - OptLevel::Less => OptimizationLevel::Limited, - OptLevel::Default => OptimizationLevel::Standard, - OptLevel::Aggressive => OptimizationLevel::Aggressive, - OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited, - } + Some(level) => match level { + OptLevel::No => OptimizationLevel::None, + OptLevel::Less => OptimizationLevel::Limited, + OptLevel::Default => OptimizationLevel::Standard, + OptLevel::Aggressive => OptimizationLevel::Aggressive, + OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited, }, } } -pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &LockedTargetInfo) -> Vec { - sess - .target +pub fn target_features( + sess: &Session, + allow_unstable: bool, + target_info: &LockedTargetInfo, +) -> Vec { + sess.target .supported_target_features() .iter() - .filter_map( - |&(feature, gate)| { - if sess.is_nightly_build() || allow_unstable || gate.is_stable() { Some(feature) } else { None } - }, - ) + .filter_map(|&(feature, gate)| { + if sess.is_nightly_build() || allow_unstable || gate.is_stable() { + Some(feature) + } else { + None + } + }) .filter(|_feature| { target_info.cpu_supports(_feature) /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, - avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, - bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, - sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves - */ + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, + avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, + bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, + sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves + */ }) .map(|feature| Symbol::intern(feature)) .collect() diff --git a/src/mono_item.rs b/src/mono_item.rs index fdeb2f96fe2c9..2f75cec69e925 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -1,11 +1,11 @@ -#[cfg(feature="master")] -use gccjit::{VarAttribute, FnAttribute}; +#[cfg(feature = "master")] +use gccjit::{FnAttribute, VarAttribute}; use rustc_codegen_ssa::traits::PreDefineMethods; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use crate::attributes; use crate::base; @@ -13,8 +13,14 @@ use crate::context::CodegenCx; use crate::type_of::LayoutGccExt; impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - #[cfg_attr(not(feature="master"), allow(unused_variables))] - fn predefine_static(&self, def_id: DefId, _linkage: Linkage, visibility: Visibility, symbol_name: &str) { + #[cfg_attr(not(feature = "master"), allow(unused_variables))] + fn predefine_static( + &self, + def_id: DefId, + _linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ) { let attrs = self.tcx.codegen_fn_attrs(def_id); let instance = Instance::mono(self.tcx, def_id); let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); @@ -22,15 +28,21 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section); - #[cfg(feature="master")] + #[cfg(feature = "master")] global.add_string_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); // TODO(antoyo): set linkage. self.instances.borrow_mut().insert(instance, global); } - #[cfg_attr(not(feature="master"), allow(unused_variables))] - fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) { + #[cfg_attr(not(feature = "master"), allow(unused_variables))] + fn predefine_fn( + &self, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ) { assert!(!instance.args.has_infer()); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); @@ -48,11 +60,10 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { && linkage != Linkage::Private && self.tcx.is_compiler_builtins(LOCAL_CRATE) { - #[cfg(feature="master")] + #[cfg(feature = "master")] decl.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - } - else { - #[cfg(feature="master")] + } else { + #[cfg(feature = "master")] decl.add_attribute(FnAttribute::Visibility(base::visibility_to_gcc(visibility))); } diff --git a/src/type_.rs b/src/type_.rs index 7a89fe81d3844..f5e2ace725c1b 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -1,8 +1,8 @@ use gccjit::{RValue, Struct, Type}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods}; use rustc_codegen_ssa::common::TypeKind; -use rustc_middle::{bug, ty}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods}; use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::{bug, ty}; use rustc_target::abi::{AddressSpace, Align, Integer, Size}; use crate::common::TypeReflection; @@ -135,12 +135,16 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if let Some(typ) = self.struct_types.borrow().get(fields) { return typ.clone(); } - let fields: Vec<_> = fields.iter().enumerate() - .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index))) + let fields: Vec<_> = fields + .iter() + .enumerate() + .map(|(index, field)| { + self.context.new_field(None, *field, &format!("field{}_TODO", index)) + }) .collect(); let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); if packed { - #[cfg(feature="master")] + #[cfg(feature = "master")] typ.set_packed(); } self.struct_types.borrow_mut().insert(types, typ); @@ -150,17 +154,13 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { if self.is_int_type_or_bool(typ) { TypeKind::Integer - } - else if typ.is_compatible_with(self.float_type) { + } else if typ.is_compatible_with(self.float_type) { TypeKind::Float - } - else if typ.is_compatible_with(self.double_type) { + } else if typ.is_compatible_with(self.double_type) { TypeKind::Double - } - else if typ.is_vector() { + } else if typ.is_vector() { TypeKind::Vector - } - else { + } else { // TODO(antoyo): support other types. TypeKind::Void } @@ -177,14 +177,11 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> { if let Some(typ) = ty.dyncast_array() { typ - } - else if let Some(vector_type) = ty.dyncast_vector() { + } else if let Some(vector_type) = ty.dyncast_vector() { vector_type.get_element_type() - } - else if let Some(typ) = ty.get_pointee() { + } else if let Some(typ) = ty.get_pointee() { typ - } - else { + } else { unreachable!() } } @@ -198,11 +195,9 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let f64 = self.context.new_type::(); if typ.is_compatible_with(f32) { 32 - } - else if typ.is_compatible_with(f64) { + } else if typ.is_compatible_with(f64) { 64 - } - else { + } else { panic!("Cannot get width of float type {:?}", typ); } // TODO(antoyo): support other sizes. @@ -216,9 +211,9 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { value.get_type() } - #[cfg_attr(feature="master", allow(unused_mut))] + #[cfg_attr(feature = "master", allow(unused_mut))] fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] if let Some(struct_type) = ty.is_struct() { if struct_type.get_field_count() == 0 { // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a @@ -242,12 +237,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], packed: bool) { - let fields: Vec<_> = fields.iter().enumerate() + let fields: Vec<_> = fields + .iter() + .enumerate() .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index))) .collect(); typ.set_fields(None, &fields); if packed { - #[cfg(feature="master")] + #[cfg(feature = "master")] typ.as_type().set_packed(); } } @@ -257,7 +254,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec>, bool) { +pub fn struct_fields<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + layout: TyAndLayout<'tcx>, +) -> (Vec>, bool) { let field_count = layout.fields.count(); let mut packed = false; @@ -295,5 +295,4 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout (result, packed) } -impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> { -} +impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {} diff --git a/src/type_of.rs b/src/type_of.rs index 25149b8020162..04220d8b1dc00 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -1,13 +1,16 @@ use std::fmt::Write; -use gccjit::{Struct, Type}; use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; +use gccjit::{Struct, Type}; use rustc_middle::bug; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; +use rustc_target::abi::{ + self, Abi, Align, FieldsShape, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface, + Variants, F32, F64, +}; use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType}; use crate::context::CodegenCx; @@ -25,7 +28,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } - #[cfg(feature="master")] + #[cfg(feature = "master")] pub fn type_int_from_ty(&self, t: ty::IntTy) -> Type<'gcc> { match t { ty::IntTy::Isize => self.type_isize(), @@ -37,7 +40,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } - #[cfg(feature="master")] + #[cfg(feature = "master")] pub fn type_uint_from_ty(&self, t: ty::UintTy) -> Type<'gcc> { match t { ty::UintTy::Usize => self.type_isize(), @@ -56,7 +59,11 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { } } -fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> { +fn uncached_gcc_type<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + layout: TyAndLayout<'tcx>, + defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>, +) -> Type<'gcc> { match layout.abi { Abi::Scalar(_) => bug!("handled elsewhere"), Abi::Vector { ref element, count } => { @@ -70,7 +77,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout element }; return cx.context.new_vector_type(element, count); - }, + } Abi::ScalarPair(..) => { return cx.type_struct( &[ @@ -87,7 +94,12 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str + ty::Adt(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Foreign(..) + | ty::Coroutine(..) + | ty::Str if !cx.sess().fewer_names() => { let mut name = with_no_trimmed_paths!(layout.ty.to_string()); @@ -125,22 +137,21 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout let gcc_type = cx.type_named_struct(name); cx.set_struct_body(gcc_type, &[fill], packed); gcc_type.as_type() - }, + } } } FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx), count), - FieldsShape::Arbitrary { .. } => - match name { - None => { - let (gcc_fields, packed) = struct_fields(cx, layout); - cx.type_struct(&gcc_fields, packed) - }, - Some(ref name) => { - let gcc_type = cx.type_named_struct(name); - *defer = Some((gcc_type, layout)); - gcc_type.as_type() - }, - }, + FieldsShape::Arbitrary { .. } => match name { + None => { + let (gcc_fields, packed) = struct_fields(cx, layout); + cx.type_struct(&gcc_fields, packed) + } + Some(ref name) => { + let gcc_type = cx.type_named_struct(name); + *defer = Some((gcc_type, layout)); + gcc_type.as_type() + } + }, } } @@ -149,10 +160,23 @@ pub trait LayoutGccExt<'tcx> { fn is_gcc_scalar_pair(&self) -> bool; fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; - fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; - fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc>; + fn scalar_gcc_type_at<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + scalar: &abi::Scalar, + offset: Size, + ) -> Type<'gcc>; + fn scalar_pair_element_gcc_type<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + index: usize, + ) -> Type<'gcc>; fn gcc_field_index(&self, index: usize) -> u64; - fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option; + fn pointee_info_at<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + offset: Size, + ) -> Option; } impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { @@ -192,24 +216,24 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { return ty; } - let ty = - match *self.ty.kind() { - // NOTE: we cannot remove this match like in the LLVM codegen because the call - // to fn_ptr_backend_type handle the on-stack attribute. - // TODO(antoyo): find a less hackish way to hande the on-stack attribute. - ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())), - _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), - }; + let ty = match *self.ty.kind() { + // NOTE: we cannot remove this match like in the LLVM codegen because the call + // to fn_ptr_backend_type handle the on-stack attribute. + // TODO(antoyo): find a less hackish way to hande the on-stack attribute. + ty::FnPtr(sig) => { + cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) + } + _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), + }; cx.scalar_types.borrow_mut().insert(self.ty, ty); return ty; } // Check the cache. - let variant_index = - match self.variants { - Variants::Single { index } => Some(index), - _ => None, - }; + let variant_index = match self.variants { + Variants::Single { index } => Some(index), + _ => None, + }; let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned(); if let Some(ty) = cached_type { return ty; @@ -222,17 +246,15 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { let normal_ty = cx.tcx.erase_regions(self.ty); let mut defer = None; - let ty = - if self.ty != normal_ty { - let mut layout = cx.layout_of(normal_ty); - if let Some(v) = variant_index { - layout = layout.for_variant(cx, v); - } - layout.gcc_type(cx) + let ty = if self.ty != normal_ty { + let mut layout = cx.layout_of(normal_ty); + if let Some(v) = variant_index { + layout = layout.for_variant(cx, v); } - else { - uncached_gcc_type(cx, *self, &mut defer) - }; + layout.gcc_type(cx) + } else { + uncached_gcc_type(cx, *self, &mut defer) + }; cx.types.borrow_mut().insert((self.ty, variant_index), ty); @@ -253,7 +275,12 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { self.gcc_type(cx) } - fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> { + fn scalar_gcc_type_at<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + scalar: &abi::Scalar, + offset: Size, + ) -> Type<'gcc> { match scalar.primitive() { Int(i, true) => cx.type_from_integer(i), Int(i, false) => cx.type_from_unsigned_integer(i), @@ -261,19 +288,21 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { F64 => cx.type_f64(), Pointer(address_space) => { // If we know the alignment, pick something better than i8. - let pointee = - if let Some(pointee) = self.pointee_info_at(cx, offset) { - cx.type_pointee_for_align(pointee.align) - } - else { - cx.type_i8() - }; + let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { + cx.type_pointee_for_align(pointee.align) + } else { + cx.type_i8() + }; cx.type_ptr_to_ext(pointee, address_space) } } } - fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc> { + fn scalar_pair_element_gcc_type<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + index: usize, + ) -> Type<'gcc> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. @@ -294,13 +323,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { return cx.type_i1(); } - let offset = - if index == 0 { - Size::ZERO - } - else { - a.size(cx).align_to(b.align(cx).abi) - }; + let offset = if index == 0 { Size::ZERO } else { a.size(cx).align_to(b.align(cx).abi) }; self.scalar_gcc_type_at(cx, scalar, offset) } @@ -355,7 +378,12 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { layout.gcc_field_index(index) } - fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, _immediate: bool) -> Type<'gcc> { + fn scalar_pair_element_backend_type( + &self, + layout: TyAndLayout<'tcx>, + index: usize, + _immediate: bool, + ) -> Type<'gcc> { layout.scalar_pair_element_gcc_type(self, index) } @@ -373,12 +401,7 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { // FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`? - let FnAbiGcc { - return_type, - arguments_type, - is_c_variadic, - .. - } = fn_abi.gcc_type(self); + let FnAbiGcc { return_type, arguments_type, is_c_variadic, .. } = fn_abi.gcc_type(self); self.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic) } } diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 4cc429cfa456f..67629a3c95a8a 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -5,9 +5,9 @@ use std::{ process::Command, }; +use boml::Toml; use lang_tester::LangTester; use tempfile::TempDir; -use boml::Toml; /// Controls the compile options (e.g., optimization level) used to compile /// test code. @@ -21,8 +21,7 @@ pub fn main_inner(profile: Profile) { let tempdir = TempDir::new().expect("temp dir"); let current_dir = current_dir().expect("current dir"); let current_dir = current_dir.to_str().expect("current dir").to_string(); - let toml = Toml::parse(include_str!("../config.toml")) - .expect("Failed to parse `config.toml`"); + let toml = Toml::parse(include_str!("../config.toml")).expect("Failed to parse `config.toml`"); let gcc_path = if let Ok(gcc_path) = toml.get_string("gcc-path") { PathBuf::from(gcc_path.to_string()) } else { @@ -42,12 +41,12 @@ pub fn main_inner(profile: Profile) { filename.extension().expect("extension").to_str().expect("to_str") == "rs" } - #[cfg(feature="master")] + #[cfg(feature = "master")] fn filter(filename: &Path) -> bool { rust_filter(filename) } - #[cfg(not(feature="master"))] + #[cfg(not(feature = "master"))] fn filter(filename: &Path) -> bool { if let Some(filename) = filename.to_str() { if filename.ends_with("gep.rs") { @@ -61,13 +60,13 @@ pub fn main_inner(profile: Profile) { .test_dir("tests/run") .test_file_filter(filter) .test_extract(|source| { - let lines = - source.lines() - .skip_while(|l| !l.starts_with("//")) - .take_while(|l| l.starts_with("//")) - .map(|l| &l[2..]) - .collect::>() - .join("\n"); + let lines = source + .lines() + .skip_while(|l| !l.starts_with("//")) + .take_while(|l| l.starts_with("//")) + .map(|l| &l[2..]) + .collect::>() + .join("\n"); Some(lines) }) .test_cmds(move |path| { @@ -78,10 +77,13 @@ pub fn main_inner(profile: Profile) { let mut compiler = Command::new("rustc"); compiler.args(&[ &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir), - "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir), + "--sysroot", + &format!("{}/build_sysroot/sysroot/", current_dir), "-Zno-parallel-llvm", - "-C", "link-arg=-lc", - "-o", exe.to_str().expect("to_str"), + "-C", + "link-arg=-lc", + "-o", + exe.to_str().expect("to_str"), path.to_str().expect("to_str"), ]); @@ -105,10 +107,7 @@ pub fn main_inner(profile: Profile) { match profile { Profile::Debug => {} Profile::Release => { - compiler.args(&[ - "-C", "opt-level=3", - "-C", "lto=no", - ]); + compiler.args(&["-C", "opt-level=3", "-C", "lto=no"]); } } // Test command 2: run `tempdir/x`. @@ -130,18 +129,10 @@ pub fn main_inner(profile: Profile) { runtime.args(&["chroot", vm_dir, "qemu-m68k-static"]); runtime.arg(inside_vm_exe_path); runtime.current_dir(vm_parent_dir); - vec![ - ("Compiler", compiler), - ("Copy", copy), - ("Run-time", runtime), - ] - } - else { + vec![("Compiler", compiler), ("Copy", copy), ("Run-time", runtime)] + } else { let runtime = Command::new(exe); - vec![ - ("Compiler", compiler), - ("Run-time", runtime), - ] + vec![("Compiler", compiler), ("Run-time", runtime)] } }) .run(); From aeffc2fcaa719a052eb832212855d9c400277edb Mon Sep 17 00:00:00 2001 From: tempdragon <645703113@qq.com> Date: Thu, 29 Feb 2024 10:33:11 +0800 Subject: [PATCH 173/192] fix(fmt/style): Clippy-generated Code Correction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modifications to Commit: Modified: src/allocator.rs Modified: src/asm.rs Modified: src/back/lto.rs Modified: src/consts.rs Modified: src/debuginfo.rs Modified: src/intrinsic/mod.rs Modified: src/lib.rs Modified: src/mono_item.rs Modified: src/type_.rs Modified: tests/lang_tests_common.rs --- src/allocator.rs | 6 +++--- src/asm.rs | 6 +++--- src/back/lto.rs | 9 ++++----- src/consts.rs | 12 ++++-------- src/debuginfo.rs | 1 - src/intrinsic/mod.rs | 9 +++++---- src/lib.rs | 12 ++++++------ src/mono_item.rs | 2 +- src/type_.rs | 8 ++++---- tests/lang_tests_common.rs | 16 ++++++++-------- 10 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 5cfd654a2049d..deeb55e9d128e 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -63,7 +63,7 @@ pub(crate) unsafe fn codegen( tcx, context, "__rust_alloc_error_handler", - &alloc_error_handler_name(alloc_error_handler_kind), + alloc_error_handler_name(alloc_error_handler_kind), &[usize, usize], None, ); @@ -93,7 +93,7 @@ fn create_wrapper_function( let args: Vec<_> = types .iter() .enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) .collect(); let func = context.new_function( None, @@ -115,7 +115,7 @@ fn create_wrapper_function( let args: Vec<_> = types .iter() .enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) .collect(); let callee = context.new_function( None, diff --git a/src/asm.rs b/src/asm.rs index bded806cafdeb..a237f3e6490cb 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -96,7 +96,7 @@ impl AsmOutOperand<'_, '_, '_> { res.push('&'); } - res.push_str(&self.constraint); + res.push_str(self.constraint); res } } @@ -304,7 +304,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { tmp_var.set_register_name(reg_name); outputs.push(AsmOutOperand { - constraint: "r".into(), + constraint: "r", rust_idx, late, readwrite: false, @@ -343,7 +343,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { tmp_var.set_register_name(reg_name); outputs.push(AsmOutOperand { - constraint: "r".into(), + constraint: "r", rust_idx, late, readwrite: false, diff --git a/src/back/lto.rs b/src/back/lto.rs index 42837a57bade8..61e0f203ee0b2 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -106,11 +106,10 @@ fn prepare_lto( if !crate_type_allows_lto(*crate_type) { dcx.emit_err(LtoDisallowed); return Err(FatalError); - } else if *crate_type == CrateType::Dylib { - if !cgcx.opts.unstable_opts.dylib_lto { - dcx.emit_err(LtoDylib); - return Err(FatalError); - } + } + if *crate_type == CrateType::Dylib && !cgcx.opts.unstable_opts.dylib_lto { + dcx.emit_err(LtoDylib); + return Err(FatalError); } } diff --git a/src/consts.rs b/src/consts.rs index 1c66ad8cc5a12..327c9bdada924 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -77,10 +77,8 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { // boolean SSA values are i1, but they have to be stored in i8 slots, // otherwise some LLVM optimization passes don't work as expected let val_llty = self.val_ty(value); - let value = if val_llty == self.type_i1() { + if val_llty == self.type_i1() { unimplemented!(); - } else { - value }; let instance = Instance::mono(self.tcx, def_id); @@ -94,11 +92,9 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. - if !is_mutable { - if self.type_is_freeze(ty) { - #[cfg(feature = "master")] - global.global_set_readonly(); - } + if !is_mutable && self.type_is_freeze(ty) { + #[cfg(feature = "master")] + global.global_set_readonly(); } if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/src/debuginfo.rs b/src/debuginfo.rs index a072a5092a798..aed15769025f1 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -255,7 +255,6 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _variable_kind: VariableKind, _span: Span, ) -> Self::DIVariable { - () } fn dbg_scope_fn( diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 22176ab9cd7a2..0fd91fc10f186 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -1065,7 +1065,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Return `result_type`'s maximum or minimum value on overflow // NOTE: convert the type to unsigned to have an unsigned shift. - let unsigned_type = result_type.to_unsigned(&self.cx); + let unsigned_type = result_type.to_unsigned(self.cx); let shifted = self.gcc_lshr( self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1), @@ -1108,9 +1108,10 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( // we can never unwind. let ret_align = bx.tcx.data_layout.i32_align.abi; bx.store(bx.const_i32(0), dest, ret_align); - } else if wants_msvc_seh(bx.sess()) { - unimplemented!(); } else { + if wants_msvc_seh(bx.sess()) { + unimplemented!(); + } #[cfg(feature = "master")] codegen_gnu_try(bx, try_func, data, _catch_func, dest); #[cfg(not(feature = "master"))] @@ -1160,7 +1161,7 @@ fn codegen_gnu_try<'gcc>( let catch_func = func.get_param(2).to_rvalue(); let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void()); - let current_block = bx.block.clone(); + let current_block = bx.block; bx.switch_to_block(then); bx.ret(bx.const_i32(0)); diff --git a/src/lib.rs b/src/lib.rs index 0f57465591d5e..ab029ca4ce596 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -187,7 +187,7 @@ impl CodegenBackend for GccCodegenBackend { // Get the second TargetInfo with the correct CPU features by setting the arch. let context = Context::default(); if target_cpu != "generic" { - context.add_command_line_option(&format!("-march={}", target_cpu)); + context.add_command_line_option(format!("-march={}", target_cpu)); } **self.target_info.info.lock().expect("lock") = context.get_target_info(); @@ -224,9 +224,9 @@ impl CodegenBackend for GccCodegenBackend { providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true) } - fn codegen_crate<'tcx>( + fn codegen_crate( &self, - tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'_>, metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box { @@ -292,9 +292,9 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>( + fn codegen_allocator( &self, - tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'_>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, @@ -486,6 +486,6 @@ pub fn target_features( sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves */ }) - .map(|feature| Symbol::intern(feature)) + .map(Symbol::intern) .collect() } diff --git a/src/mono_item.rs b/src/mono_item.rs index 2f75cec69e925..e56c49686c012 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -47,7 +47,7 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); - let decl = self.declare_fn(symbol_name, &fn_abi); + let decl = self.declare_fn(symbol_name, fn_abi); //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); attributes::from_fn_attrs(self, decl, instance); diff --git a/src/type_.rs b/src/type_.rs index f5e2ace725c1b..0465d0bbdfe29 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -133,13 +133,13 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { let types = fields.to_vec(); if let Some(typ) = self.struct_types.borrow().get(fields) { - return typ.clone(); + return *typ; } let fields: Vec<_> = fields .iter() .enumerate() .map(|(index, field)| { - self.context.new_field(None, *field, &format!("field{}_TODO", index)) + self.context.new_field(None, *field, format!("field{}_TODO", index)) }) .collect(); let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); @@ -240,7 +240,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let fields: Vec<_> = fields .iter() .enumerate() - .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index))) + .map(|(index, field)| self.context.new_field(None, *field, format!("field_{}", index))) .collect(); typ.set_fields(None, &fields); if packed { @@ -265,7 +265,7 @@ pub fn struct_fields<'gcc, 'tcx>( let mut prev_effective_align = layout.align.abi; let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2); for i in layout.fields.index_by_increasing_offset() { - let target_offset = layout.fields.offset(i as usize); + let target_offset = layout.fields.offset(i); let field = layout.field(cx, i); let effective_field_align = layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset); diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 67629a3c95a8a..f89ad650af590 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -75,7 +75,7 @@ pub fn main_inner(profile: Profile) { exe.push(&tempdir); exe.push(path.file_stem().expect("file_stem")); let mut compiler = Command::new("rustc"); - compiler.args(&[ + compiler.args([ &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir), "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir), @@ -90,7 +90,7 @@ pub fn main_inner(profile: Profile) { // TODO(antoyo): find a way to send this via a cli argument. let test_target = std::env::var("CG_GCC_TEST_TARGET"); if let Ok(ref target) = test_target { - compiler.args(&["--target", &target]); + compiler.args(["--target", target]); let linker = format!("{}-gcc", target); compiler.args(&[format!("-Clinker={}", linker)]); let mut env_path = std::env::var("PATH").unwrap_or_default(); @@ -101,32 +101,32 @@ pub fn main_inner(profile: Profile) { if let Some(flags) = option_env!("TEST_FLAGS") { for flag in flags.split_whitespace() { - compiler.arg(&flag); + compiler.arg(flag); } } match profile { Profile::Debug => {} Profile::Release => { - compiler.args(&["-C", "opt-level=3", "-C", "lto=no"]); + compiler.args(["-C", "opt-level=3", "-C", "lto=no"]); } } // Test command 2: run `tempdir/x`. if test_target.is_ok() { let vm_parent_dir = std::env::var("CG_GCC_VM_DIR") - .map(|dir| PathBuf::from(dir)) + .map(PathBuf::from) .unwrap_or_else(|_| std::env::current_dir().unwrap()); let vm_dir = "vm"; let exe_filename = exe.file_name().unwrap(); let vm_home_dir = vm_parent_dir.join(vm_dir).join("home"); let vm_exe_path = vm_home_dir.join(exe_filename); // FIXME(antoyo): panicking here makes the test pass. - let inside_vm_exe_path = PathBuf::from("/home").join(&exe_filename); + let inside_vm_exe_path = PathBuf::from("/home").join(exe_filename); let mut copy = Command::new("sudo"); copy.arg("cp"); - copy.args(&[&exe, &vm_exe_path]); + copy.args([&exe, &vm_exe_path]); let mut runtime = Command::new("sudo"); - runtime.args(&["chroot", vm_dir, "qemu-m68k-static"]); + runtime.args(["chroot", vm_dir, "qemu-m68k-static"]); runtime.arg(inside_vm_exe_path); runtime.current_dir(vm_parent_dir); vec![("Compiler", compiler), ("Copy", copy), ("Run-time", runtime)] From 6f54eeb07096645c6b92fc766ffec752c770b594 Mon Sep 17 00:00:00 2001 From: r01and Date: Thu, 29 Feb 2024 23:13:09 +0800 Subject: [PATCH 174/192] Remove unused structs --- src/errors.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 62be9e9b379a1..6b781f1099893 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,10 +1,8 @@ use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, - IntoDiagnosticArg, Level, + DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; -use std::borrow::Cow; use crate::fluent_generated as fluent; @@ -32,18 +30,6 @@ pub(crate) enum PossibleFeature<'a> { None, } -struct ExitCode(Option); - -impl IntoDiagnosticArg for ExitCode { - fn into_diagnostic_arg(self) -> DiagnosticArgValue { - let ExitCode(exit_code) = self; - match exit_code { - Some(t) => t.into_diagnostic_arg(), - None => DiagnosticArgValue::Str(Cow::Borrowed("")), - } - } -} - #[derive(Diagnostic)] #[diag(codegen_gcc_lto_not_supported)] pub(crate) struct LTONotSupported; @@ -81,12 +67,6 @@ pub(crate) struct CopyBitcode { #[note] pub(crate) struct DynamicLinkingWithLTO; -#[derive(Diagnostic)] -#[diag(codegen_gcc_load_bitcode)] -pub(crate) struct LoadBitcode { - name: String, -} - #[derive(Diagnostic)] #[diag(codegen_gcc_lto_disallowed)] pub(crate) struct LtoDisallowed; From 1b124a9bbd3637d23f1c1a8e41fcb2594a26a077 Mon Sep 17 00:00:00 2001 From: r01and Date: Thu, 29 Feb 2024 23:26:34 +0800 Subject: [PATCH 175/192] Format codes --- src/errors.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 6b781f1099893..58d74ca733be0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,4 @@ -use rustc_errors::{ - DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, -}; +use rustc_errors::{DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; From 7e4b53e45b71abdc1da2960beeb87765330b6340 Mon Sep 17 00:00:00 2001 From: r01and Date: Fri, 1 Mar 2024 09:50:33 +0800 Subject: [PATCH 176/192] Remove unused fluent messages --- messages.ftl | 2 -- 1 file changed, 2 deletions(-) diff --git a/messages.ftl b/messages.ftl index 5ca0a2e1b6db4..0235384445e71 100644 --- a/messages.ftl +++ b/messages.ftl @@ -20,8 +20,6 @@ codegen_gcc_dynamic_linking_with_lto = cannot prefer dynamic linking when performing LTO .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO -codegen_gcc_load_bitcode = failed to load bitcode of module "{$name}" - codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto` From 56dc8de1db5510ccc0545238f556e38b7cc3933f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 1 Mar 2024 12:20:59 -0500 Subject: [PATCH 177/192] Switch to the new set_special_chars_allowed_in_func_names API --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- libgccjit.version | 2 +- src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c004c7b992f7d..ffbd4ee39de8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#af31863f5f2a32f1c805444bfb6e8c174d6da8f4" +source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e" dependencies = [ "gccjit_sys", ] @@ -88,7 +88,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#af31863f5f2a32f1c805444bfb6e8c174d6da8f4" +source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index 85ad69e00fdef..e23aaeab97778 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,4 +59,4 @@ opt-level = 0 debug = false [package.metadata.rust-analyzer] -rustc_private = true \ No newline at end of file +rustc_private = true diff --git a/libgccjit.version b/libgccjit.version index ad2c3b12b874a..41bec6df5d95c 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -cf9554126 +b6f163f52 diff --git a/src/lib.rs b/src/lib.rs index 0f57465591d5e..19e441bae96ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,7 +277,7 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { } #[cfg(feature = "master")] { - context.set_allow_special_chars_in_func_names(true); + context.set_special_chars_allowed_in_func_names("$.*"); let version = Version::get(); let version = format!("{}.{}.{}", version.major, version.minor, version.patch); context.set_output_ident(&format!( From 4baadb7859b6de4e5bf7addcbba253d24d70f52a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 1 Mar 2024 17:28:57 -0500 Subject: [PATCH 178/192] Update lang_tester so that panicking in a test results in the test failing --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- tests/lang_tests_common.rs | 13 +++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffbd4ee39de8a..ab2c7ca8a47c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,9 +70,9 @@ checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "fm" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68fda3cff2cce84c19e5dfa5179a4b35d2c0f18b893f108002b8a6a54984acca" +checksum = "21bcf4db620a804cf7e9d84fbcb5d4ac83a8c43396203b2507d62ea31814dfd4" dependencies = [ "regex", ] @@ -110,9 +110,9 @@ checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "lang_tester" -version = "0.3.13" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090" +checksum = "9af8149dbb3ed7d8e529fcb141fe033b1c26ed54cbffc6762d3a86483c485d23" dependencies = [ "fm", "getopts", diff --git a/Cargo.toml b/Cargo.toml index e23aaeab97778..100c10ef1d7af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } tempfile = "3.7.1" [dev-dependencies] -lang_tester = "0.3.9" +lang_tester = "0.8.0" tempfile = "3.1.0" boml = "0.3.1" diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 67629a3c95a8a..d116daab7c43b 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -37,8 +37,8 @@ pub fn main_inner(profile: Profile) { .to_string(); env::set_var("LD_LIBRARY_PATH", gcc_path); - fn rust_filter(filename: &Path) -> bool { - filename.extension().expect("extension").to_str().expect("to_str") == "rs" + fn rust_filter(path: &Path) -> bool { + path.is_file() && path.extension().expect("extension").to_str().expect("to_str") == "rs" } #[cfg(feature = "master")] @@ -58,16 +58,17 @@ pub fn main_inner(profile: Profile) { LangTester::new() .test_dir("tests/run") - .test_file_filter(filter) - .test_extract(|source| { - let lines = source + .test_path_filter(filter) + .test_extract(|path| { + let lines = std::fs::read_to_string(path) + .expect("read file") .lines() .skip_while(|l| !l.starts_with("//")) .take_while(|l| l.starts_with("//")) .map(|l| &l[2..]) .collect::>() .join("\n"); - Some(lines) + lines }) .test_cmds(move |path| { // Test command 1: Compile `x.rs` into `tempdir/x`. From b76515708b5aab54fc69c50babc03ab92daaff08 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 5 Mar 2024 08:23:27 -0500 Subject: [PATCH 179/192] Workaround for linker error about missing -lLLVM-18-rust-1.78.0-nightly --- build.rs | 6 ++++++ deps/libLLVM-18-rust-1.78.0-nightly.so | 1 + 2 files changed, 7 insertions(+) create mode 100644 build.rs create mode 100644 deps/libLLVM-18-rust-1.78.0-nightly.so diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000000..b93c17793bf37 --- /dev/null +++ b/build.rs @@ -0,0 +1,6 @@ +// TODO: remove this file and deps/libLLVM-18-rust-1.78.0-nightly.so when +// https://github.com/rust-lang/rust/pull/121967 is merged. +fn main() { + println!("cargo:rerun-if-changed=deps/libLLVM-18-rust-1.78.0-nightly.so"); + println!("cargo:rustc-link-search=deps"); +} diff --git a/deps/libLLVM-18-rust-1.78.0-nightly.so b/deps/libLLVM-18-rust-1.78.0-nightly.so new file mode 100644 index 0000000000000..c44ca790b4f8c --- /dev/null +++ b/deps/libLLVM-18-rust-1.78.0-nightly.so @@ -0,0 +1 @@ +INPUT(libLLVM.so.18.1-rust-1.78.0-nightly) From cd75da1f2ce67cf0ee10a4189b13c321f9c6ae4e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 5 Mar 2024 08:33:42 -0500 Subject: [PATCH 180/192] Fix formatting --- src/builder.rs | 22 ++++++++---- src/errors.rs | 4 +-- src/intrinsic/mod.rs | 82 +++++++++++++++++++++++--------------------- src/type_.rs | 4 +-- src/type_of.rs | 31 ++++++++++++++--- 5 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 25eb987d62561..f5cda81f6ab86 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1018,19 +1018,21 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let llty = place.layout.scalar_pair_element_gcc_type(self, i); let load = self.load(llty, llptr, align); scalar_load_metadata(self, load, scalar); - if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } + if scalar.is_bool() { + self.trunc(load, self.type_i1()) + } else { + load + } }; OperandValue::Pair( load(0, a, place.align), load(1, b, place.align.restrict_for_offset(b_offset)), ) - } - else { + } else { OperandValue::Ref(place.llval, None, place.align) }; - OperandRef { val, layout: place.layout } } @@ -2075,7 +2077,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.vector_reduce(src, |a, b, context| context.new_binary_op(loc, op, a.get_type(), a, b)) } - pub fn vector_reduce_fadd_reassoc(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fadd_reassoc( + &mut self, + _acc: RValue<'gcc>, + _src: RValue<'gcc>, + ) -> RValue<'gcc> { unimplemented!(); } @@ -2102,7 +2108,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - pub fn vector_reduce_fmul_reassoc(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fmul_reassoc( + &mut self, + _acc: RValue<'gcc>, + _src: RValue<'gcc>, + ) -> RValue<'gcc> { unimplemented!(); } diff --git a/src/errors.rs b/src/errors.rs index 1d3e09d3f9c5f..f963a153fbaba 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,4 @@ -use rustc_errors::{ - DiagCtxt, Diag, EmissionGuarantee, IntoDiagnostic, Level, -}; +use rustc_errors::{Diag, DiagCtxt, EmissionGuarantee, IntoDiagnostic, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 24d4650e9c2e9..a6c8b72e851b2 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -22,10 +22,10 @@ use rustc_middle::bug; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use rustc_span::{Span, Symbol, sym}; -use rustc_target::abi::HasDataLayout; use rustc_middle::ty::{self, Instance, Ty}; +use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use rustc_target::abi::HasDataLayout; #[cfg(feature = "master")] use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; @@ -122,44 +122,46 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); - let llval = - match name { - _ if simple.is_some() => { - // FIXME(antoyo): remove this cast when the API supports function. - let func = unsafe { std::mem::transmute(simple.expect("simple")) }; - self.call(self.type_void(), None, None, func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) - }, - sym::likely => { - self.expect(args[0].immediate(), true) - } - sym::unlikely => { - self.expect(args[0].immediate(), false) - } - sym::is_val_statically_known => { - let a = args[0].immediate(); - let builtin = self.context.get_builtin_function("__builtin_constant_p"); - let res = self.context.new_call(None, builtin, &[a]); - self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) - } - sym::catch_unwind => { - try_intrinsic( - self, - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - llresult, - ); - return Ok(()); - } - sym::breakpoint => { - unimplemented!(); - } - sym::va_copy => { - unimplemented!(); - } - sym::va_arg => { - unimplemented!(); - } + let llval = match name { + _ if simple.is_some() => { + // FIXME(antoyo): remove this cast when the API supports function. + let func = unsafe { std::mem::transmute(simple.expect("simple")) }; + self.call( + self.type_void(), + None, + None, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + None, + ) + } + sym::likely => self.expect(args[0].immediate(), true), + sym::unlikely => self.expect(args[0].immediate(), false), + sym::is_val_statically_known => { + let a = args[0].immediate(); + let builtin = self.context.get_builtin_function("__builtin_constant_p"); + let res = self.context.new_call(None, builtin, &[a]); + self.icmp(IntPredicate::IntEQ, res, self.const_i32(0)) + } + sym::catch_unwind => { + try_intrinsic( + self, + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + llresult, + ); + return Ok(()); + } + sym::breakpoint => { + unimplemented!(); + } + sym::va_copy => { + unimplemented!(); + } + sym::va_arg => { + unimplemented!(); + } sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = fn_args.type_at(0); diff --git a/src/type_.rs b/src/type_.rs index df091bfde77b8..8fe3328ec55f6 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -123,7 +123,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_f16(&self) -> Type<'gcc> { unimplemented!("f16_f128") } - + fn type_f32(&self) -> Type<'gcc> { self.float_type } @@ -131,7 +131,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_f64(&self) -> Type<'gcc> { self.double_type } - + fn type_f128(&self) -> Type<'gcc> { unimplemented!("f16_f128") } diff --git a/src/type_of.rs b/src/type_of.rs index 27344a1b83db4..8f9bfbbd18fb0 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -5,9 +5,12 @@ use gccjit::{Struct, Type}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_target::abi::{self, Abi, Align, F16, F128, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; +use rustc_target::abi::{ + self, Abi, Align, FieldsShape, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface, + Variants, F128, F16, F32, F64, +}; use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType}; use crate::context::CodegenCx; @@ -157,9 +160,22 @@ pub trait LayoutGccExt<'tcx> { fn is_gcc_scalar_pair(&self) -> bool; fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; - fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; - fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc>; - fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option; + fn scalar_gcc_type_at<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + scalar: &abi::Scalar, + offset: Size, + ) -> Type<'gcc>; + fn scalar_pair_element_gcc_type<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + index: usize, + ) -> Type<'gcc>; + fn pointee_info_at<'gcc>( + &self, + cx: &CodegenCx<'gcc, 'tcx>, + offset: Size, + ) -> Option; } impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { @@ -341,7 +357,12 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { layout.is_gcc_scalar_pair() } - fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, _immediate: bool) -> Type<'gcc> { + fn scalar_pair_element_backend_type( + &self, + layout: TyAndLayout<'tcx>, + index: usize, + _immediate: bool, + ) -> Type<'gcc> { layout.scalar_pair_element_gcc_type(self, index) } From 499d3c229d2516b7ce9f5930ea15339467693580 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 5 Mar 2024 08:42:30 -0500 Subject: [PATCH 181/192] Fix CI --- build_system/src/test.rs | 1 + tests/failing-non-lto-tests.txt | 2 +- tests/failing-ui-tests.txt | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 470bb2431d563..4f9791dde4802 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -912,6 +912,7 @@ fn should_remove_test(file_path: &Path) -> Result { } if [ "// error-pattern:", + "// @error-pattern:", "// build-fail", "// run-fail", "-Cllvm-args", diff --git a/tests/failing-non-lto-tests.txt b/tests/failing-non-lto-tests.txt index 4fd60f2b8e4f0..384dfdc26fb51 100644 --- a/tests/failing-non-lto-tests.txt +++ b/tests/failing-non-lto-tests.txt @@ -5,7 +5,7 @@ tests/ui/lto/lto-many-codegen-units.rs tests/ui/lto/issue-100772.rs tests/ui/lto/lto-rustc-loads-linker-plugin.rs tests/ui/panic-runtime/lto-unwind.rs -tests/ui/sanitize/issue-111184-coroutine-witness.rs +tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs tests/ui/sepcomp/sepcomp-lib-lto.rs tests/ui/lto/lto-opt-level-s.rs tests/ui/lto/lto-opt-level-z.rs diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index e504021bf2ad2..b9ad7ef33cff1 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -76,7 +76,6 @@ tests/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs tests/ui/numbers-arithmetic/divide-by-zero.rs tests/ui/numbers-arithmetic/mod-zero.rs tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs -tests/ui/numbers-arithmetic/overflowing-neg.rs tests/ui/optimization-remark.rs tests/ui/panic-handler/panic-handler-std.rs tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs From 42a0d63238a511fa913fbe7291903fa739c105b2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 5 Mar 2024 15:47:58 +0100 Subject: [PATCH 182/192] Ignore rand tests warnings --- build_system/src/test.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 4f9791dde4802..36d72512dfd02 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -771,11 +771,19 @@ fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { println!("Not using GCC master branch. Skipping `extended_rand_tests`."); return Ok(()); } + let mut env = env.clone(); + // newer aho_corasick versions throw a deprecation warning + let rustflags = format!( + "{} --cap-lints warn", + env.get("RUSTFLAGS").cloned().unwrap_or_default() + ); + env.insert("RUSTFLAGS".to_string(), rustflags); + let path = Path::new(crate::BUILD_DIR).join("rand"); - run_cargo_command(&[&"clean"], Some(&path), env, args)?; + run_cargo_command(&[&"clean"], Some(&path), &env, args)?; // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rust-random/rand"); - run_cargo_command(&[&"test", &"--workspace"], Some(&path), env, args)?; + run_cargo_command(&[&"test", &"--workspace"], Some(&path), &env, args)?; Ok(()) } From 86a2bb760c729fe620a45f35fb55e89abeacfc40 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 5 Mar 2024 10:25:02 -0500 Subject: [PATCH 183/192] Fix CI --- build_system/src/test.rs | 9 +++++---- tests/failing-lto-tests.txt | 5 ----- tests/failing-ui-tests.txt | 33 --------------------------------- 3 files changed, 5 insertions(+), 42 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 36d72512dfd02..a4db2fdebef1e 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -919,10 +919,9 @@ fn should_remove_test(file_path: &Path) -> Result { continue; } if [ - "// error-pattern:", - "// @error-pattern:", - "// build-fail", - "// run-fail", + "//@ error-pattern:", + "//@ build-fail", + "//@ run-fail", "-Cllvm-args", "//~", "thread", @@ -1016,6 +1015,8 @@ where // Tests generating errors. remove_file(&rust_path.join("tests/ui/consts/issue-94675.rs"))?; remove_file(&rust_path.join("tests/ui/mir/mir_heavy_promoted.rs"))?; + remove_file(&rust_path.join("tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs"))?; + remove_file(&rust_path.join("tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs"))?; walk_dir(rust_path.join("tests/ui"), dir_handling, file_handling)?; diff --git a/tests/failing-lto-tests.txt b/tests/failing-lto-tests.txt index 8de45ae0f28b1..6e1ed99c6f7a9 100644 --- a/tests/failing-lto-tests.txt +++ b/tests/failing-lto-tests.txt @@ -21,7 +21,6 @@ tests/ui/fmt/format-args-capture-issue-106408.rs tests/ui/fmt/indoc-issue-106408.rs tests/ui/hygiene/issue-77523-def-site-async-await.rs tests/ui/inherent-impls-overlap-check/no-overlap.rs -tests/ui/annotate-snippet/multispan.rs tests/ui/enum-discriminant/issue-46519.rs tests/ui/issues/issue-45731.rs tests/ui/lint/test-allow-dead-extern-static-no-warning.rs @@ -29,9 +28,5 @@ tests/ui/macros/macro-comma-behavior-rpass.rs tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs tests/ui/macros/stringify.rs -tests/ui/panics/test-panic.rs -tests/ui/panics/test-should-fail-bad-message.rs -tests/ui/panics/test-should-panic-bad-message.rs -tests/ui/panics/test-should-panic-no-message.rs tests/ui/reexport-test-harness-main.rs tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index b9ad7ef33cff1..d13562f8bb01b 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -69,41 +69,8 @@ tests/ui/async-await/deep-futures-are-freeze.rs tests/ui/closures/capture-unsized-by-ref.rs tests/ui/coroutine/resume-after-return.rs tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs -tests/ui/limits/issue-17913.rs -tests/ui/limits/issue-55878.rs -tests/ui/linkage-attr/common-linkage-non-zero-init.rs -tests/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs -tests/ui/numbers-arithmetic/divide-by-zero.rs -tests/ui/numbers-arithmetic/mod-zero.rs -tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs -tests/ui/optimization-remark.rs -tests/ui/panic-handler/panic-handler-std.rs -tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs -tests/ui/panic-runtime/need-unwind-got-abort.rs -tests/ui/panics/issue-47429-short-backtraces.rs -tests/ui/panics/panic-in-cleanup.rs -tests/ui/panics/panic-in-ffi.rs -tests/ui/panics/runtime-switch.rs -tests/ui/panics/short-ice-remove-middle-frames-2.rs -tests/ui/panics/short-ice-remove-middle-frames.rs -tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs tests/ui/simd/masked-load-store.rs tests/ui/simd/repr_packed.rs -tests/ui/type_length_limit.rs tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs -tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs -tests/ui/c-variadic/issue-86053-1.rs -tests/ui/const-ptr/out_of_bounds_read.rs -tests/ui/consts/const_unsafe_unreachable_ub.rs -tests/ui/consts/miri_unleashed/drop.rs -tests/ui/consts/timeout.rs tests/ui/consts/try-operator.rs -tests/ui/coroutine/coroutine-resume-after-panic.rs tests/ui/coroutine/unwind-abort-mix.rs -tests/ui/duplicate/dupe-symbols-7.rs -tests/ui/duplicate/dupe-symbols-8.rs -tests/ui/hygiene/panic-location.rs -tests/ui/invalid/issue-114435-layout-type-err.rs -tests/ui/invalid-compile-flags/invalid-llvm-passes.rs -tests/ui/lto/issue-105637.rs -tests/ui/lto/lto-duplicate-symbols.rs From 3b4c58d7f570f2db6a35e5a3d90167cfada02dd3 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 5 Mar 2024 12:50:14 -0500 Subject: [PATCH 184/192] Fix rand tests --- build_system/src/prepare.rs | 26 +++++++++++++++++++ .../crates/0001-Remove-deny-warnings.patch | 24 +++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 patches/crates/0001-Remove-deny-warnings.patch diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index 4ea334ad8b907..821c793c7e554 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -131,6 +131,30 @@ fn prepare_libcore( )?; } println!("Successfully prepared libcore for building"); + + Ok(()) +} + +// TODO: remove when we can ignore warnings in rustdoc tests. +fn prepare_rand() -> Result<(), String> { + // Apply patch for the rand crate. + let file_path = "patches/crates/0001-Remove-deny-warnings.patch"; + let rand_dir = Path::new("build/rand"); + println!("[GIT] apply `{}`", file_path); + let path = Path::new("../..").join(file_path); + run_command_with_output(&[&"git", &"apply", &path], Some(rand_dir))?; + run_command_with_output(&[&"git", &"add", &"-A"], Some(rand_dir))?; + run_command_with_output( + &[ + &"git", + &"commit", + &"--no-gpg-sign", + &"-m", + &format!("Patch {}", path.display()), + ], + Some(rand_dir), + )?; + Ok(()) } @@ -241,6 +265,8 @@ pub fn run() -> Result<(), String> { for (repo_url, checkout_commit, cb) in to_clone { clone_and_setup(repo_url, checkout_commit, *cb)?; } + + prepare_rand()?; } println!("Successfully ran `prepare`"); diff --git a/patches/crates/0001-Remove-deny-warnings.patch b/patches/crates/0001-Remove-deny-warnings.patch new file mode 100644 index 0000000000000..66ea1df4e1376 --- /dev/null +++ b/patches/crates/0001-Remove-deny-warnings.patch @@ -0,0 +1,24 @@ +From f4a31d2c57cdbd578b778ab70eb2a0cfb248652c Mon Sep 17 00:00:00 2001 +From: Antoni Boucher +Date: Tue, 5 Mar 2024 12:39:44 -0500 +Subject: [PATCH] Remove #[deny(warnings)] + +--- + src/lib.rs | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/lib.rs b/src/lib.rs +index 8ade2881d5..e26c595e38 100644 +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -47,7 +47,6 @@ + )] + #![deny(missing_docs)] + #![deny(missing_debug_implementations)] +-#![doc(test(attr(allow(unused_variables), deny(warnings))))] + #![no_std] + #![cfg_attr(feature = "simd_support", feature(stdsimd, portable_simd))] + #![cfg_attr(doc_cfg, feature(doc_cfg))] +-- +2.44.0 + From e378787a43354ae88473b919bd17dc33e3db375a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 3 Mar 2024 23:00:46 +0100 Subject: [PATCH 185/192] Remove unneeded special case for rust CI --- .../build_system/src/config.rs | 65 +++++++++---------- .../build_system/src/test.rs | 12 +--- 2 files changed, 30 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs index c633ee57d4a34..46621ef3b2141 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/config.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs @@ -128,6 +128,7 @@ pub struct ConfigInfo { // just to set the `gcc_path` field to display it. pub no_download: bool, pub no_default_features: bool, + pub backend: Option, } impl ConfigInfo { @@ -178,6 +179,14 @@ impl ConfigInfo { return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()) } }, + "--use-backend" => match args.next() { + Some(backend) if !backend.is_empty() => self.backend = Some(backend), + _ => { + return Err( + "Expected an argument after `--use-backend`, found nothing".into() + ) + } + }, "--no-default-features" => self.no_default_features = true, _ => return Ok(false), } @@ -377,39 +386,25 @@ impl ConfigInfo { "debug" }; - let has_builtin_backend = env - .get("BUILTIN_BACKEND") - .map(|backend| !backend.is_empty()) - .unwrap_or(false); - let mut rustflags = Vec::new(); - if has_builtin_backend { - // It means we're building inside the rustc testsuite, so some options need to be handled - // a bit differently. - self.cg_backend_path = "gcc".to_string(); - - match env.get("RUSTC_SYSROOT") { - Some(rustc_sysroot) if !rustc_sysroot.is_empty() => { - rustflags.extend_from_slice(&["--sysroot".to_string(), rustc_sysroot.clone()]); - } - _ => {} - } - // This should not be needed, but is necessary for the CI in the rust repository. - // FIXME: Remove when the rust CI switches to the master version of libgccjit. - rustflags.push("-Cpanic=abort".to_string()); + self.cg_backend_path = current_dir + .join("target") + .join(channel) + .join(&format!("librustc_codegen_gcc.{}", self.dylib_ext)) + .display() + .to_string(); + self.sysroot_path = current_dir + .join("build_sysroot/sysroot") + .display() + .to_string(); + if let Some(backend) = &self.backend { + rustflags.push(format!("-Zcodegen-backend={}", backend)); } else { - self.cg_backend_path = current_dir - .join("target") - .join(channel) - .join(&format!("librustc_codegen_gcc.{}", self.dylib_ext)) - .display() - .to_string(); - self.sysroot_path = current_dir - .join("build_sysroot/sysroot") - .display() - .to_string(); - rustflags.extend_from_slice(&["--sysroot".to_string(), self.sysroot_path.clone()]); - }; + rustflags.extend_from_slice(&[ + "--sysroot".to_string(), self.sysroot_path.clone(), + format!("-Zcodegen-backend={}", self.cg_backend_path), + ]); + } // This environment variable is useful in case we want to change options of rustc commands. if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { @@ -427,10 +422,7 @@ impl ConfigInfo { rustflags.push("-Csymbol-mangling-version=v0".to_string()); } - rustflags.extend_from_slice(&[ - "-Cdebuginfo=2".to_string(), - format!("-Zcodegen-backend={}", self.cg_backend_path), - ]); + rustflags.push("-Cdebuginfo=2".to_string()); // Since we don't support ThinLTO, disable LTO completely when not trying to do LTO. // TODO(antoyo): remove when we can handle ThinLTO. @@ -504,7 +496,8 @@ impl ConfigInfo { --config-file : Location of the config file to be used --cg_gcc-path : Location of the rustc_codegen_gcc root folder (used when ran from another directory) - --no-default-features : Add `--no-default-features` flag to cargo commands" + --no-default-features : Add `--no-default-features` flag to cargo commands + --use-backend : Useful only for rustc testsuite" ); } } diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index a4db2fdebef1e..0895dc6bff700 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -93,7 +93,6 @@ fn show_usage() { --features [arg] : Add a new feature [arg] --use-system-gcc : Use system installed libgccjit --build-only : Only build rustc_codegen_gcc then exits - --use-backend : Useful only for rustc testsuite --nb-parts : Used to split rustc_tests (for CI needs) --current-part : Used with `--nb-parts`, allows you to specify which parts to test"# ); @@ -113,7 +112,6 @@ struct TestArg { use_system_gcc: bool, runners: BTreeSet, flags: Vec, - backend: Option, nb_parts: Option, current_part: Option, sysroot_panic_abort: bool, @@ -145,14 +143,6 @@ impl TestArg { test_arg.use_system_gcc = true; } "--build-only" => test_arg.build_only = true, - "--use-backend" => match args.next() { - Some(backend) if !backend.is_empty() => test_arg.backend = Some(backend), - _ => { - return Err( - "Expected an argument after `--use-backend`, found nothing".into() - ) - } - }, "--nb-parts" => { test_arg.nb_parts = Some(get_number_after_arg(&mut args, "--nb-parts")?); } @@ -199,7 +189,7 @@ impl TestArg { } fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> { - if args.backend.is_some() { + if args.config_info.backend.is_some() { return Ok(()); } let mut command: Vec<&dyn AsRef> = vec![&"cargo", &"rustc"]; From 3aefb2e69e87fcc6133754ddb55ffbd935021090 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 5 Mar 2024 20:17:22 +0100 Subject: [PATCH 186/192] Fix cg_gcc build --- compiler/rustc_codegen_gcc/src/type_.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index c8e6ae69bd959..68471b028beb8 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -136,10 +136,6 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { unimplemented!("f16_f128") } - fn type_f128(&self) -> Type<'gcc> { - unimplemented!("f16_f128") - } - fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> { self.context.new_function_pointer_type(None, return_type, params, false) } From 42569283a221ac73a9355e2aef68159450448ece Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 Feb 2024 13:30:04 +0100 Subject: [PATCH 187/192] Correctly handle "master" feature --- compiler/rustc_codegen_gcc/build_system/src/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_codegen_gcc/build_system/src/build.rs b/compiler/rustc_codegen_gcc/build_system/src/build.rs index 0eabd1d897292..c81b02e2183d8 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/build.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/build.rs @@ -107,6 +107,9 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests"); } rustflags.push_str(" -Z force-unstable-if-unmarked"); + if config.no_default_features { + rustflags.push_str(" -Csymbol-mangling-version=v0"); + } let mut env = env.clone(); let mut args: Vec<&dyn AsRef> = vec![&"cargo", &"build", &"--target", &config.target]; From 4bcaa4fe39f310c6ab774eebafd6ebbb6e6bd545 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Mar 2024 16:23:50 +0100 Subject: [PATCH 188/192] Correctly handle `cargo_target_dir` --- compiler/rustc_codegen_gcc/build_system/src/config.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs index 46621ef3b2141..34c92a3485ed6 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/config.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs @@ -446,9 +446,7 @@ impl ConfigInfo { )); let ld_library_path = format!( "{target}:{sysroot}:{gcc_path}", - // FIXME: It's possible to pick another out directory. Would be nice to have a command - // line option to change it. - target = current_dir.join("target/out").display(), + target = self.cargo_target_dir, sysroot = sysroot.display(), gcc_path = self.gcc_path, ); @@ -473,7 +471,7 @@ impl ConfigInfo { self.rustc_command.extend_from_slice(&rustflags); self.rustc_command.extend_from_slice(&[ "-L".to_string(), - "crate=target/out".to_string(), + format!("crate={}", self.cargo_target_dir), "--out-dir".to_string(), self.cargo_target_dir.clone(), ]); From 95b49e7d73ce449b377b4a4f0517ee1254231d89 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 Mar 2024 17:59:12 +0100 Subject: [PATCH 189/192] Build libgccjit in CI --- src/bootstrap/src/core/build_steps/test.rs | 1 - .../dist-x86_64-linux/build-gccjit.sh | 28 +++++++++++++++++++ .../dist-x86_64-linux/libgccjit.version | 1 + .../host-x86_64/x86_64-gnu-tools/Dockerfile | 14 ++++++++-- 4 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh create mode 100644 src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 4a4497e57db14..c8b659903ebbb 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3394,7 +3394,6 @@ impl Step for CodegenGCC { .arg("--out-dir") .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_gcc")) .arg("--release") - .arg("--no-default-features") .arg("--mini-tests") .arg("--std-tests"); cargo.args(builder.config.test_args()); diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh new file mode 100644 index 0000000000000..ec4cb344e050d --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +set -ex + +cd $1 + +# Setting up folders for GCC +git clone https://github.com/antoyo/gcc gcc-src +cd gcc-src +git checkout $(head -1 /scripts/libgccjit.version) + +mkdir ../gcc-build ../gcc-install +cd ../gcc-build + +# Building GCC. +../gcc-src/configure \ + --enable-host-shared \ + --enable-languages=jit \ + --enable-checking=release \ + --disable-bootstrap \ + --disable-multilib \ + --prefix=$(pwd)/../gcc-install +make +make install + +rm -rf ../gcc-src +ln -s /scripts/gcc-install/lib/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so +ln -s /scripts/gcc-install/lib/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so.0 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version b/src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version new file mode 100644 index 0000000000000..41bec6df5d95c --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version @@ -0,0 +1 @@ +b6f163f52 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 82385ea15b7ca..2b66ac718db2f 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -15,7 +15,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ sudo \ xz-utils \ tidy \ - libgccjit-12-dev \ \ # Install dependencies for chromium browser gconf-service \ @@ -57,13 +56,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lsb-release \ xdg-utils \ wget \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -# Make `libgccjit.so` accessible. -RUN ln -s /usr/lib/gcc/x86_64-linux-gnu/12/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so # Fix rustc_codegen_gcc lto issues. ENV GCC_EXEC_PREFIX="/usr/lib/gcc/" @@ -92,6 +95,11 @@ ENV RUST_CONFIGURE_ARGS \ ENV HOST_TARGET x86_64-unknown-linux-gnu +COPY host-x86_64/dist-x86_64-linux/libgccjit.version /scripts/ +COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ + +RUN sh /scripts/build-gccjit.sh /scripts + ENV SCRIPT /tmp/checktools.sh ../x.py && \ NODE_PATH=`npm root -g` python3 ../x.py test tests/rustdoc-gui --stage 2 \ --test-args "'--no-sandbox --jobs 1'" From 379908ef4e61a4d813ecda3e67851d475ef2540e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Mar 2024 10:35:55 +0100 Subject: [PATCH 190/192] Build libgccjit for all CI testsuites using it --- .../host-x86_64/x86_64-gnu-llvm-16/Dockerfile | 12 +++++++++++- .../host-x86_64/x86_64-gnu-llvm-17/Dockerfile | 14 +++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile index f4850715e82e8..4e12a6de781b8 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile @@ -24,7 +24,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ nodejs \ mingw-w64 \ - libgccjit-12-dev \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ && rm -rf /var/lib/apt/lists/* # Note: libgccjit needs to match the default gcc version for the linker to find it. @@ -54,4 +59,9 @@ ENV RUST_CONFIGURE_ARGS \ COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ +COPY host-x86_64/dist-x86_64-linux/libgccjit.version /scripts/ +COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ + +RUN sh /scripts/build-gccjit.sh /scripts + ENV SCRIPT /tmp/script.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile index fe30a95344104..8dd0128895f6b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile @@ -24,11 +24,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ nodejs \ mingw-w64 \ - libgccjit-13-dev \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ && rm -rf /var/lib/apt/lists/* -# Note: libgccjit needs to match the default gcc version for the linker to find it. - # Install powershell (universal package) so we can test x.ps1 on Linux RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ dpkg -i powershell.deb && \ @@ -51,4 +54,9 @@ ENV RUST_CONFIGURE_ARGS \ COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ +COPY host-x86_64/dist-x86_64-linux/libgccjit.version /scripts/ +COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ + +RUN sh /scripts/build-gccjit.sh /scripts + ENV SCRIPT /tmp/script.sh From 1d058a0b061b9651be9031131180e1b9324be7f6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 9 Mar 2024 18:21:13 +0100 Subject: [PATCH 191/192] Fix cg_gcc merge --- compiler/rustc_codegen_gcc/src/asm.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index f8afc5c3eb43a..9b679019e96ce 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -114,7 +114,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, - _catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>, + dest: Option, + _catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>, ) { if options.contains(InlineAsmOptions::MAY_UNWIND) { self.sess().dcx().create_err(UnwindingInlineAsm { span: span[0] }).emit(); @@ -537,8 +538,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) { let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); - let builtin_unreachable: RValue<'gcc> = - unsafe { std::mem::transmute(builtin_unreachable) }; + let builtin_unreachable: RValue<'gcc> = unsafe { + std::mem::transmute(builtin_unreachable) + }; self.call(self.type_void(), None, None, builtin_unreachable, &[], None); } From c5c6729c88b6d00798f46d5c7397e854775d0923 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 9 Mar 2024 18:06:59 +0100 Subject: [PATCH 192/192] Use full commit hash and remove `libgccjit.version` file --- src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh | 3 ++- src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version | 1 - src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile | 1 - src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile | 1 - src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh index ec4cb344e050d..324dd5fac161e 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh @@ -7,7 +7,8 @@ cd $1 # Setting up folders for GCC git clone https://github.com/antoyo/gcc gcc-src cd gcc-src -git checkout $(head -1 /scripts/libgccjit.version) +# This commit hash needs to be updated to use a more recent gcc fork version. +git checkout 78dc50f0e50e6cd1433149520bd512a4e0eaa1bc mkdir ../gcc-build ../gcc-install cd ../gcc-build diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version b/src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version deleted file mode 100644 index 41bec6df5d95c..0000000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/libgccjit.version +++ /dev/null @@ -1 +0,0 @@ -b6f163f52 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile index 4e12a6de781b8..6540a500d3a58 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile @@ -59,7 +59,6 @@ ENV RUST_CONFIGURE_ARGS \ COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ -COPY host-x86_64/dist-x86_64-linux/libgccjit.version /scripts/ COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ RUN sh /scripts/build-gccjit.sh /scripts diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile index 8dd0128895f6b..e10881caf27e7 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile @@ -54,7 +54,6 @@ ENV RUST_CONFIGURE_ARGS \ COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ -COPY host-x86_64/dist-x86_64-linux/libgccjit.version /scripts/ COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ RUN sh /scripts/build-gccjit.sh /scripts diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 2b66ac718db2f..a03577b45112b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -95,7 +95,6 @@ ENV RUST_CONFIGURE_ARGS \ ENV HOST_TARGET x86_64-unknown-linux-gnu -COPY host-x86_64/dist-x86_64-linux/libgccjit.version /scripts/ COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ RUN sh /scripts/build-gccjit.sh /scripts