Merge commit '59a81c2ca1edc88ad3ac4b27a8e03977ffb8e73a' into subtree-update_cg_gcc_2025_01_12

This commit is contained in:
Antoni Boucher 2025-01-13 10:53:58 -05:00
commit 06f0a9bc78
49 changed files with 825 additions and 1519 deletions

View File

@ -22,7 +22,6 @@ jobs:
- { gcc: "gcc-13.deb" }
- { gcc: "gcc-13-without-int128.deb" }
commands: [
"--mini-tests",
"--std-tests",
# FIXME: re-enable asm tests when GCC can emit in the right syntax.
# "--asm-tests",
@ -79,6 +78,7 @@ jobs:
run: |
./y.sh prepare --only-libcore
./y.sh build --sysroot
./y.sh test --mini-tests
cargo test
- name: Run y.sh cargo build
@ -87,7 +87,7 @@ jobs:
- name: Clean
run: |
./y.sh clean all
./y.sh clean all
- name: Prepare dependencies
run: |
@ -95,9 +95,6 @@ jobs:
git config --global user.name "User"
./y.sh prepare
- name: Add more failing tests because the sysroot is not compiled with LTO
run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
- name: Run tests
run: |
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}

View File

@ -90,15 +90,12 @@ jobs:
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
run: ./y.sh prepare
- name: Add more failing tests because the sysroot is not compiled with LTO
run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
- name: Run tests
# TODO: re-enable those tests for libgccjit 12.
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
id: tests
run: |
${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} | tee output_log
${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} 2>&1 | tee output_log
rg --text "test result" output_log >> $GITHUB_STEP_SUMMARY
- name: Run failing ui pattern tests for ICE
@ -106,7 +103,7 @@ jobs:
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
id: ui-tests
run: |
${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --test-failing-ui-pattern-tests ${{ matrix.libgccjit_version.extra }} | tee output_log_ui
${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --test-failing-ui-pattern-tests ${{ matrix.libgccjit_version.extra }} 2>&1 | tee output_log_ui
if grep -q "the compiler unexpectedly panicked" output_log_ui; then
echo "Error: 'the compiler unexpectedly panicked' found in output logs. CI Error!!"
exit 1

View File

@ -82,9 +82,6 @@ jobs:
#- name: Add more failing tests for GCC 12
#run: cat tests/failing-ui-tests12.txt >> tests/failing-ui-tests.txt
#- name: Add more failing tests because the sysroot is not compiled with LTO
#run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
#- name: Run tests
#run: |
#./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features

View File

@ -23,7 +23,6 @@ jobs:
fail-fast: false
matrix:
commands: [
"--mini-tests",
"--std-tests",
# TODO(antoyo): fix those on m68k.
#"--test-libcore",
@ -93,6 +92,7 @@ jobs:
run: |
./y.sh prepare --only-libcore --cross
./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu
./y.sh test --mini-tests
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test
./y.sh clean all
@ -102,9 +102,6 @@ jobs:
git config --global user.name "User"
./y.sh prepare --cross
- name: Add more failing tests because the sysroot is not compiled with LTO
run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
- name: Run tests
run: |
./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }}

View File

@ -13,7 +13,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
fail-fast: false
@ -54,6 +54,7 @@ jobs:
run: |
./y.sh prepare --only-libcore
EMBED_LTO_BITCODE=1 ./y.sh build --sysroot --release --release-sysroot
./y.sh test --mini-tests
cargo test
./y.sh clean all
@ -70,4 +71,9 @@ jobs:
run: |
# FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros.
echo -n 'lto = "fat"' >> build_system/build_sysroot/Cargo.toml
EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }}
EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }}
- name: Run y.sh cargo build
run: |
EMBED_LTO_BITCODE=1 CHANNEL="release" ./y.sh cargo build --release --manifest-path tests/hello-world/Cargo.toml
# TODO: grep the asm output for "call my_func" and fail if it is found.

View File

@ -73,10 +73,6 @@ jobs:
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
if: ${{ !matrix.cargo_runner }}
run: |
@ -92,6 +88,7 @@ jobs:
if: ${{ !matrix.cargo_runner }}
run: |
./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore
cargo test
- name: Run stdarch tests
if: ${{ !matrix.cargo_runner }}

View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "aho-corasick"
@ -11,12 +11,40 @@ dependencies = [
"memchr",
]
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "boml"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "errno"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "fm"
version = "0.2.2"
@ -28,18 +56,18 @@ dependencies = [
[[package]]
name = "gccjit"
version = "2.2.0"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bb376e98c82d9284c3a17fc1d6bf9bc921055418950238d7a553c27a7e1f6ab"
checksum = "72fd91f4adbf02b53cfc73c97bc33c5f253009043f30c56a5ec08dd5c8094dc8"
dependencies = [
"gccjit_sys",
]
[[package]]
name = "gccjit_sys"
version = "0.3.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93b4b1be553b5df790bf25ca2a1d6add81727dc29f8d5c8742468ed306d621d1"
checksum = "0fb7b8f48a75e2cfe78c3d9a980b32771c34ffd12d196021ab3f98c49fbd2f0d"
dependencies = [
"libc",
]
@ -77,9 +105,15 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.150"
version = "0.2.168"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "memchr"
@ -97,6 +131,12 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "regex"
version = "1.8.4"
@ -121,6 +161,20 @@ dependencies = [
"boml",
"gccjit",
"lang_tester",
"tempfile",
]
[[package]]
name = "rustix"
version = "0.38.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
@ -132,6 +186,19 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "tempfile"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
"cfg-if",
"fastrand",
"once_cell",
"rustix",
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.2.0"
@ -205,3 +272,76 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@ -22,15 +22,16 @@ master = ["gccjit/master"]
default = ["master"]
[dependencies]
gccjit = "2.2"
gccjit = "2.4"
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" }
# Local copy.
#gccjit = { path = "../gccjit.rs" }
[dev-dependencies]
lang_tester = "0.8.0"
boml = "0.3.1"
lang_tester = "0.8.0"
tempfile = "3.7.1"
[profile.dev]
# By compiling dependencies with optimizations, performing tests gets much faster.

View File

@ -93,6 +93,7 @@ struct TestArg {
sysroot_panic_abort: bool,
config_info: ConfigInfo,
sysroot_features: Vec<String>,
keep_lto_tests: bool,
}
impl TestArg {
@ -128,6 +129,9 @@ impl TestArg {
"--sysroot-panic-abort" => {
test_arg.sysroot_panic_abort = true;
}
"--keep-lto-tests" => {
test_arg.keep_lto_tests = true;
}
"--sysroot-features" => match args.next() {
Some(feature) if !feature.is_empty() => {
test_arg.sysroot_features.push(feature);
@ -194,7 +198,7 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> {
}
fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
let _ = std::fs::remove_dir_all(&args.config_info.cargo_target_dir);
let _ = remove_dir_all(&args.config_info.cargo_target_dir);
let path = Path::new(&args.config_info.cargo_target_dir).join("gccjit");
create_dir(&path)
}
@ -641,7 +645,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
//failing test is fixed upstream.
//"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/time-rs/time", // FIXME: one test fails (https://github.com/time-rs/time/issues/719).
"https://github.com/rust-lang/log",
"https://github.com/bitflags/bitflags",
//"https://github.com/serde-rs/serde", // FIXME: one test fails.
@ -835,8 +839,7 @@ fn valid_ui_error_pattern_test(file: &str) -> bool {
.any(|to_ignore| file.ends_with(to_ignore))
}
#[rustfmt::skip]
fn contains_ui_error_patterns(file_path: &Path) -> Result<bool, String> {
fn contains_ui_error_patterns(file_path: &Path, keep_lto_tests: bool) -> Result<bool, String> {
// Tests generating errors.
let file = File::open(file_path)
.map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?;
@ -849,22 +852,38 @@ fn contains_ui_error_patterns(file_path: &Path) -> Result<bool, String> {
"//@ error-pattern:",
"//@ build-fail",
"//@ run-fail",
"//@ known-bug",
"-Cllvm-args",
"//~",
"thread",
]
.iter()
.any(|check| line.contains(check))
.iter()
.any(|check| line.contains(check))
{
return Ok(true);
}
if !keep_lto_tests
&& (line.contains("-Clto")
|| line.contains("-C lto")
|| line.contains("compile-flags: -Clinker-plugin-lto"))
&& !line.contains("-Clto=thin")
{
return Ok(true);
}
if line.contains("//[") && line.contains("]~") {
return Ok(true);
}
}
if file_path.display().to_string().contains("ambiguous-4-extern.rs") {
let file_path = file_path.display().to_string();
if file_path.contains("ambiguous-4-extern.rs") {
eprintln!("nothing found for {file_path:?}");
}
// The files in this directory contain errors.
if file_path.contains("/error-emitter/") {
return Ok(true);
}
Ok(false)
}
@ -903,7 +922,7 @@ where
rust_path.join("tests/ui"),
&mut |_dir| Ok(()),
&mut |file_path| {
if contains_ui_error_patterns(file_path)? {
if contains_ui_error_patterns(file_path, args.keep_lto_tests)? {
Ok(())
} else {
remove_file(file_path).map_err(|e| e.to_string())
@ -928,7 +947,7 @@ where
.iter()
.any(|name| *name == dir_name)
{
std::fs::remove_dir_all(dir).map_err(|error| {
remove_dir_all(dir).map_err(|error| {
format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
})?;
}
@ -940,27 +959,42 @@ where
// These two functions are used to remove files that are known to not be working currently
// with the GCC backend to reduce noise.
fn dir_handling(dir: &Path) -> Result<(), String> {
if dir.file_name().map(|name| name == "auxiliary").unwrap_or(true) {
return Ok(());
}
fn dir_handling(keep_lto_tests: bool) -> impl Fn(&Path) -> Result<(), String> {
move |dir| {
if dir.file_name().map(|name| name == "auxiliary").unwrap_or(true) {
return Ok(());
}
walk_dir(dir, &mut dir_handling, &mut file_handling, false)
}
fn file_handling(file_path: &Path) -> Result<(), String> {
if !file_path.extension().map(|extension| extension == "rs").unwrap_or(false) {
return Ok(());
walk_dir(
dir,
&mut dir_handling(keep_lto_tests),
&mut file_handling(keep_lto_tests),
false,
)
}
let path_str = file_path.display().to_string().replace("\\", "/");
if valid_ui_error_pattern_test(&path_str) {
return Ok(());
} else if contains_ui_error_patterns(file_path)? {
return remove_file(&file_path);
}
Ok(())
}
walk_dir(rust_path.join("tests/ui"), &mut dir_handling, &mut file_handling, false)?;
fn file_handling(keep_lto_tests: bool) -> impl Fn(&Path) -> Result<(), String> {
move |file_path| {
if !file_path.extension().map(|extension| extension == "rs").unwrap_or(false) {
return Ok(());
}
let path_str = file_path.display().to_string().replace("\\", "/");
if valid_ui_error_pattern_test(&path_str) {
return Ok(());
} else if contains_ui_error_patterns(file_path, keep_lto_tests)? {
return remove_file(&file_path);
}
Ok(())
}
}
walk_dir(
rust_path.join("tests/ui"),
&mut dir_handling(args.keep_lto_tests),
&mut file_handling(args.keep_lto_tests),
false,
)?;
}
let nb_parts = args.nb_parts.unwrap_or(0);
if nb_parts > 0 {
@ -1173,7 +1207,7 @@ fn remove_files_callback<'a>(
files.split('\n').map(|line| line.trim()).filter(|line| !line.is_empty())
{
let path = rust_path.join(file);
if let Err(e) = std::fs::remove_dir_all(&path) {
if let Err(e) = remove_dir_all(&path) {
println!("Failed to remove directory `{}`: {}", path.display(), e);
}
}

View File

@ -170,6 +170,14 @@ impl Add for usize {
}
}
impl Add for isize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
#[lang = "sub"]
pub trait Sub<RHS = Self> {
type Output;

View File

@ -1 +1 @@
e744a9459d33864067214741daf5c5bc2a7b88c6
45648c2edd4ecd862d9f08196d3d6c6ccba79f07

View File

@ -1,7 +1,7 @@
From 18793c6109890493ceb3ff36549849a36e3d8022 Mon Sep 17 00:00:00 2001
From af0e237f056fa838c77463381a19b0dc993c0a35 Mon Sep 17 00:00:00 2001
From: None <none@example.com>
Date: Sun, 1 Sep 2024 11:42:17 -0400
Subject: [PATCH] [core] Disable not compiling tests
Subject: [PATCH] Disable not compiling tests
---
library/core/tests/Cargo.toml | 14 ++++++++++++++
@ -30,14 +30,15 @@ index 0000000..ca326ac
+rand = { version = "0.8.5", default-features = false }
+rand_xorshift = { version = "0.3.0", default-features = false }
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 1e336bf..5800ebb 100644
index a4a7946..ecfe43f 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -1,4 +1,5 @@
// tidy-alphabetical-start
+#![cfg(test)]
#![cfg_attr(bootstrap, feature(offset_of_nested))]
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_match))]
--
2.46.0
#![feature(alloc_layout_extra)]
--
2.47.1

View File

@ -27,5 +27,4 @@ index b71786c..cf484d5 100644
mod slice;
mod str;
mod str_lossy;
--
2.45.2
-- 2.45.2

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2024-08-11"
channel = "nightly-2025-01-12"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View File

@ -1,6 +1,6 @@
#[cfg(feature = "master")]
use gccjit::FnAttribute;
use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type};
#[cfg(feature = "master")]
use gccjit::{FnAttribute, VarAttribute};
use rustc_ast::expand::allocator::{
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
alloc_error_handler_name, default_fn_name, global_fn_name,
@ -10,6 +10,8 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::config::OomStrategy;
use crate::GccContext;
#[cfg(feature = "master")]
use crate::base::symbol_visibility_to_gcc;
pub(crate) unsafe fn codegen(
tcx: TyCtxt<'_>,
@ -70,12 +72,20 @@ pub(crate) unsafe fn codegen(
let name = OomStrategy::SYMBOL.to_string();
let global = context.new_global(None, GlobalKind::Exported, i8, name);
#[cfg(feature = "master")]
global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
tcx.sess.default_visibility(),
)));
let value = tcx.sess.opts.unstable_opts.oom.should_panic();
let value = context.new_rvalue_from_int(i8, value as i32);
global.global_set_initializer_rvalue(value);
let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
let global = context.new_global(None, GlobalKind::Exported, i8, name);
#[cfg(feature = "master")]
global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
tcx.sess.default_visibility(),
)));
let value = context.new_rvalue_from_int(i8, 0);
global.global_set_initializer_rvalue(value);
}
@ -105,15 +115,9 @@ fn create_wrapper_function(
);
#[cfg(feature = "master")]
match tcx.sess.default_visibility() {
rustc_target::spec::SymbolVisibility::Hidden => {
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden))
}
rustc_target::spec::SymbolVisibility::Protected => {
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Protected))
}
rustc_target::spec::SymbolVisibility::Interposable => {}
}
func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc(
tcx.sess.default_visibility(),
)));
if tcx.sess.must_emit_unwind_tables() {
// TODO(antoyo): emit unwind tables.

View File

@ -35,16 +35,13 @@ use rustc_middle::bug;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
use rustc_session::config::{CrateType, Lto};
use rustc_target::spec::RelocModel;
use tempfile::{TempDir, tempdir};
use crate::back::write::save_temp_bitcode;
use crate::errors::{DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib};
use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
/// We keep track of the computed LTO cache keys from the previous
/// session to determine which CGUs we can reuse.
//pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
match crate_type {
CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
@ -54,7 +51,7 @@ pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
struct LtoData {
// TODO(antoyo): use symbols_below_threshold.
//symbols_below_threshold: Vec<CString>,
//symbols_below_threshold: Vec<String>,
upstream_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
tmp_path: TempDir,
}
@ -83,7 +80,7 @@ fn prepare_lto(
let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
if info.level.is_below_threshold(export_threshold) || info.used {
Some(CString::new(name.as_str()).unwrap())
Some(name.clone())
} else {
None
}
@ -91,7 +88,7 @@ fn prepare_lto(
let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
let mut symbols_below_threshold = {
let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold");
exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<CString>>()
exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<String>>()
};
info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
@ -159,11 +156,7 @@ fn prepare_lto(
}
}
Ok(LtoData {
//symbols_below_threshold,
upstream_modules,
tmp_path,
})
Ok(LtoData { upstream_modules, tmp_path })
}
fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> {
@ -191,7 +184,7 @@ pub(crate) fn run_fat(
cached_modules,
lto_data.upstream_modules,
lto_data.tmp_path,
//&symbols_below_threshold,
//&lto_data.symbols_below_threshold,
)
}
@ -202,7 +195,7 @@ fn fat_lto(
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
tmp_path: TempDir,
//symbols_below_threshold: &[*const libc::c_char],
//symbols_below_threshold: &[String],
) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module");
info!("going for a fat lto");
@ -327,6 +320,7 @@ fn fat_lto(
ptr as *const *const libc::c_char,
symbols_below_threshold.len() as libc::size_t,
);*/
save_temp_bitcode(cgcx, &module, "lto.after-restriction");
//}
}
@ -363,8 +357,6 @@ pub(crate) fn run_thin(
let dcx = cgcx.create_dcx();
let dcx = dcx.handle();
let lto_data = prepare_lto(cgcx, dcx)?;
/*let symbols_below_threshold =
symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
if cgcx.opts.cg.linker_plugin_lto.enabled() {
unreachable!(
"We should never reach this case if the LTO step \
@ -377,7 +369,8 @@ pub(crate) fn run_thin(
modules,
lto_data.upstream_modules,
lto_data.tmp_path,
cached_modules, /*, &symbols_below_threshold*/
cached_modules,
//&lto_data.symbols_below_threshold,
)
}
@ -428,7 +421,7 @@ fn thin_lto(
serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
tmp_path: TempDir,
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
//symbols_below_threshold: &[*const libc::c_char],
//_symbols_below_threshold: &[String],
) -> Result<(Vec<LtoModuleCodegen<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> {
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis");
info!("going for that thin, thin LTO");
@ -640,7 +633,13 @@ pub unsafe fn optimize_thin_module(
}
};
let module = ModuleCodegen {
module_llvm: GccContext { context, should_combine_object_files, temp_dir: None },
module_llvm: GccContext {
context,
should_combine_object_files,
// TODO(antoyo): use the correct relocation model here.
relocation_model: RelocModel::Pic,
temp_dir: None,
},
name: thin_module.name().to_string(),
kind: ModuleKind::Regular,
};

View File

@ -1,6 +1,6 @@
use std::{env, fs};
use gccjit::OutputKind;
use gccjit::{Context, OutputKind};
use rustc_codegen_ssa::back::link::ensure_removed;
use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
@ -10,6 +10,7 @@ use rustc_session::config::OutputType;
use rustc_span::fatal_error::FatalError;
use rustc_target::spec::SplitDebuginfo;
use crate::base::add_pic_option;
use crate::errors::CopyBitcode;
use crate::{GccCodegenBackend, GccContext};
@ -31,51 +32,87 @@ pub(crate) unsafe fn codegen(
// NOTE: Only generate object files with GIMPLE when this environment variable is set for
// now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit).
// TODO: remove this environment variable.
// TODO(antoyo): remove this environment variable.
let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1");
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
if config.bitcode_needed() && fat_lto {
let _timer = cgcx
.prof
.generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
// TODO(antoyo)
/*if let Some(bitcode_filename) = bc_out.file_name() {
cgcx.prof.artifact_size(
"llvm_bitcode",
bitcode_filename.to_string_lossy(),
data.len() as u64,
);
}*/
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
if config.bitcode_needed() {
if fat_lto {
let _timer = cgcx
.prof
.generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name);
context.add_command_line_option("-flto=auto");
context.add_command_line_option("-flto-partition=one");
// TODO: remove since we don't want fat objects when it is for Bitcode only.
context.add_command_line_option("-ffat-lto-objects");
context
.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
}
.generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
let _timer = cgcx
.prof
.generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name);
// TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
//embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
// TODO(antoyo)
/*if let Some(bitcode_filename) = bc_out.file_name() {
cgcx.prof.artifact_size(
"llvm_bitcode",
bitcode_filename.to_string_lossy(),
data.len() as u64,
);
}*/
context.add_command_line_option("-flto=auto");
context.add_command_line_option("-flto-partition=one");
context.add_command_line_option("-ffat-lto-objects");
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
context
.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
let _timer = cgcx.prof.generic_activity_with_arg(
"GCC_module_codegen_emit_bitcode",
&*module.name,
);
context.add_command_line_option("-flto=auto");
context.add_command_line_option("-flto-partition=one");
// TODO(antoyo): remove since we don't want fat objects when it is for Bitcode only.
context.add_command_line_option("-ffat-lto-objects");
context.compile_to_file(
OutputKind::ObjectFile,
bc_out.to_str().expect("path to str"),
);
}
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
let _timer = cgcx.prof.generic_activity_with_arg(
"GCC_module_codegen_embed_bitcode",
&*module.name,
);
// TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
//embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
context.add_command_line_option("-flto=auto");
context.add_command_line_option("-flto-partition=one");
context.add_command_line_option("-ffat-lto-objects");
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
context.compile_to_file(
OutputKind::ObjectFile,
bc_out.to_str().expect("path to str"),
);
}
} else {
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
let _timer = cgcx.prof.generic_activity_with_arg(
"GCC_module_codegen_emit_bitcode",
&*module.name,
);
context.compile_to_file(
OutputKind::ObjectFile,
bc_out.to_str().expect("path to str"),
);
}
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
// TODO(antoyo): we might want to emit to emit an error here, saying to set the
// environment variable EMBED_LTO_BITCODE.
let _timer = cgcx.prof.generic_activity_with_arg(
"GCC_module_codegen_embed_bitcode",
&*module.name,
);
// TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
//embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
context.compile_to_file(
OutputKind::ObjectFile,
bc_out.to_str().expect("path to str"),
);
}
}
}
@ -123,6 +160,8 @@ pub(crate) unsafe fn codegen(
// NOTE: without -fuse-linker-plugin, we get the following error:
// lto1: internal compiler error: decompressed stream: Destination buffer is too small
// TODO(antoyo): since we do not do LTO when the linker is invoked anymore, perhaps
// the following flag is not necessary anymore.
context.add_driver_option("-fuse-linker-plugin");
}
@ -131,11 +170,43 @@ pub(crate) unsafe fn codegen(
// /usr/bin/ld: cannot find -lgcc_s: No such file or directory
context.add_driver_option("-nostdlib");
// NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o.
context.compile_to_file(
OutputKind::Executable,
obj_out.to_str().expect("path to str"),
);
let path = obj_out.to_str().expect("path to str");
if fat_lto {
let lto_path = format!("{}.lto", path);
// FIXME(antoyo): The LTO frontend generates the following warning:
// ../build_sysroot/sysroot_src/library/core/src/num/dec2flt/lemire.rs:150:15: warning: type of _ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E does not match original declaration [-Wlto-type-mismatch]
// 150 | let (lo5, hi5) = POWER_OF_FIVE_128[index];
// | ^
// lto1: note: _ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E was previously declared here
//
// This option is to mute it to make the UI tests pass with LTO enabled.
context.add_driver_option("-Wno-lto-type-mismatch");
// NOTE: this doesn't actually generate an executable. With the above
// flags, it combines the .o files together in another .o.
context.compile_to_file(OutputKind::Executable, &lto_path);
let context = Context::default();
if cgcx.target_arch == "x86" || cgcx.target_arch == "x86_64" {
// NOTE: it seems we need to use add_driver_option instead of
// add_command_line_option here because we use the LTO frontend via gcc.
context.add_driver_option("-masm=intel");
}
// NOTE: these two options are needed to invoke LTO to produce an object file.
// We need to initiate a second compilation because the arguments "-x lto"
// needs to be at the very beginning.
context.add_driver_option("-x");
context.add_driver_option("lto");
add_pic_option(&context, module.module_llvm.relocation_model);
context.add_driver_option(lto_path);
context.compile_to_file(OutputKind::ObjectFile, path);
} else {
// NOTE: this doesn't actually generate an executable. With the above
// flags, it combines the .o files together in another .o.
context.compile_to_file(OutputKind::Executable, path);
}
} else {
context.compile_to_file(
OutputKind::ObjectFile,

View File

@ -3,7 +3,7 @@ use std::env;
use std::sync::Arc;
use std::time::Instant;
use gccjit::{CType, FunctionType, GlobalKind};
use gccjit::{CType, Context, FunctionType, GlobalKind};
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::DebugInfoCodegenMethods;
@ -15,21 +15,32 @@ use rustc_middle::mir::mono::Visibility;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
use rustc_span::Symbol;
use rustc_target::spec::PanicStrategy;
#[cfg(feature = "master")]
use rustc_target::spec::SymbolVisibility;
use rustc_target::spec::{PanicStrategy, RelocModel};
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::{GccContext, LockedTargetInfo, SyncContext, gcc_util, new_context};
#[cfg(feature = "master")]
pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility {
match linkage {
pub fn visibility_to_gcc(visibility: Visibility) -> gccjit::Visibility {
match visibility {
Visibility::Default => gccjit::Visibility::Default,
Visibility::Hidden => gccjit::Visibility::Hidden,
Visibility::Protected => gccjit::Visibility::Protected,
}
}
#[cfg(feature = "master")]
pub fn symbol_visibility_to_gcc(visibility: SymbolVisibility) -> gccjit::Visibility {
match visibility {
SymbolVisibility::Hidden => gccjit::Visibility::Hidden,
SymbolVisibility::Protected => gccjit::Visibility::Protected,
SymbolVisibility::Interposable => gccjit::Visibility::Default,
}
}
pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
match linkage {
Linkage::External => GlobalKind::Imported,
@ -140,9 +151,7 @@ pub fn compile_codegen_unit(
});
}
if tcx.sess.relocation_model() == rustc_target::spec::RelocModel::Static {
context.add_command_line_option("-fno-pie");
}
add_pic_option(&context, tcx.sess.relocation_model());
let target_cpu = gcc_util::target_cpu(tcx.sess);
if target_cpu != "generic" {
@ -199,12 +208,13 @@ pub fn compile_codegen_unit(
let f32_type_supported = target_info.supports_target_dependent_type(CType::Float32);
let f64_type_supported = target_info.supports_target_dependent_type(CType::Float64);
let f128_type_supported = target_info.supports_target_dependent_type(CType::Float128);
let u128_type_supported = target_info.supports_target_dependent_type(CType::UInt128t);
// TODO: improve this to avoid passing that many arguments.
let cx = CodegenCx::new(
&context,
cgu,
tcx,
target_info.supports_128bit_int(),
u128_type_supported,
f16_type_supported,
f32_type_supported,
f64_type_supported,
@ -235,6 +245,7 @@ pub fn compile_codegen_unit(
name: cgu_name.to_string(),
module_llvm: GccContext {
context: Arc::new(SyncContext::new(context)),
relocation_model: tcx.sess.relocation_model(),
should_combine_object_files: false,
temp_dir: None,
},
@ -244,3 +255,24 @@ pub fn compile_codegen_unit(
(module, cost)
}
pub fn add_pic_option<'gcc>(context: &Context<'gcc>, relocation_model: RelocModel) {
match relocation_model {
rustc_target::spec::RelocModel::Static => {
context.add_command_line_option("-fno-pie");
context.add_driver_option("-fno-pie");
}
rustc_target::spec::RelocModel::Pic => {
context.add_command_line_option("-fPIC");
// NOTE: we use both add_command_line_option and add_driver_option because the usage in
// this module (compile_codegen_unit) requires add_command_line_option while the usage
// in the back::write module (codegen) requires add_driver_option.
context.add_driver_option("-fPIC");
}
rustc_target::spec::RelocModel::Pie => {
context.add_command_line_option("-fPIE");
context.add_driver_option("-fPIE");
}
model => eprintln!("Unsupported relocation model: {:?}", model),
}
}

View File

@ -1102,18 +1102,24 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
val: RValue<'gcc>,
ptr: RValue<'gcc>,
align: Align,
_flags: MemFlags,
flags: MemFlags,
) -> RValue<'gcc> {
let ptr = self.check_store(val, ptr);
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.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.
let align = if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() };
let mut modified_destination_type = destination_type.get_aligned(align);
if flags.contains(MemFlags::VOLATILE) {
modified_destination_type = modified_destination_type.make_volatile();
}
let modified_ptr =
self.cx.context.new_cast(self.location, ptr, modified_destination_type.make_pointer());
let modified_destination = modified_ptr.dereference(self.location);
self.llbb().add_assignment(self.location, modified_destination, val);
// TODO(antoyo): handle `MemFlags::NONTEMPORAL`.
// NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
// When adding support for NONTEMPORAL, make sure to not just emit MOVNT on x86; see the
// LLVM backend for details.
@ -1236,13 +1242,13 @@ 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());
let usize_value = self.cx.context.new_cast(None, value, self.cx.type_isize());
self.intcast(usize_value, dest_ty, false)
}
fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
let usize_value = self.intcast(value, self.cx.type_isize(), false);
self.cx.const_bitcast(usize_value, dest_ty)
self.cx.context.new_cast(None, usize_value, dest_ty)
}
fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
@ -1901,6 +1907,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
v2: RValue<'gcc>,
mask: RValue<'gcc>,
) -> RValue<'gcc> {
// NOTE: if the `mask` is a constant value, the following code will copy it in many places,
// which will make GCC create a lot (+4000) local variables in some cases.
// So we assign it to an explicit local variable once to avoid this.
let func = self.current_func();
let mask_var = func.new_local(self.location, mask.get_type(), "mask");
let block = self.block;
block.add_assignment(self.location, mask_var, mask);
let mask = mask_var.to_rvalue();
// TODO(antoyo): use a recursive unqualified() here.
let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");
let element_type = vector_type.get_element_type();
@ -1917,18 +1932,35 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
self.int_type
};
let vector_type =
mask.get_type().dyncast_vector().expect("simd_shuffle mask should be of vector type");
let mask_num_units = vector_type.get_num_units();
let mut mask_elements = vec![];
for i in 0..mask_num_units {
let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
mask_elements.push(self.context.new_cast(
self.location,
self.extract_element(mask, index).to_rvalue(),
mask_element_type,
));
}
// NOTE: this condition is needed because we call shuffle_vector in the implementation of
// simd_gather.
let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() {
let mask_num_units = vector_type.get_num_units();
let mut mask_elements = vec![];
for i in 0..mask_num_units {
let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
mask_elements.push(self.context.new_cast(
self.location,
self.extract_element(mask, index).to_rvalue(),
mask_element_type,
));
}
mask_elements
} else {
let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
let mask_num_units = struct_type.get_field_count();
let mut mask_elements = vec![];
for i in 0..mask_num_units {
let field = struct_type.get_field(i as i32);
mask_elements.push(self.context.new_cast(
self.location,
mask.access_field(self.location, field).to_rvalue(),
mask_element_type,
));
}
mask_elements
};
let mask_num_units = mask_elements.len();
// NOTE: the mask needs to be the same length as the input vectors, so add the missing
// elements in the mask if needed.

View File

@ -72,95 +72,74 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
attributes::from_fn_attrs(cx, func, instance);
let instance_def_id = instance.def_id();
#[cfg(feature = "master")]
{
let instance_def_id = instance.def_id();
// TODO(antoyo): set linkage and attributes.
// TODO(antoyo): set linkage and attributes.
// Apply an appropriate linkage/visibility value to our item that we
// just declared.
//
// This is sort of subtle. Inside our codegen unit we started off
// compilation by predefining all our own `MonoItem` instances. That
// is, everything we're codegenning ourselves is already defined. That
// means that anything we're actually codegenning in this codegen unit
// will have hit the above branch in `get_declared_value`. As a result,
// we're guaranteed here that we're declaring a symbol that won't get
// defined, or in other words we're referencing a value from another
// codegen unit or even another crate.
//
// So because this is a foreign value we blanket apply an external
// linkage directive because it's coming from a different object file.
// The visibility here is where it gets tricky. This symbol could be
// referencing some foreign crate or foreign library (an `extern`
// block) in which case we want to leave the default visibility. We may
// also, though, have multiple codegen units. It could be a
// monomorphization, in which case its expected visibility depends on
// whether we are sharing generics or not. The important thing here is
// that the visibility we apply to the declaration is the same one that
// has been applied to the definition (wherever that definition may be).
let is_generic = instance.args.non_erasable_generics().next().is_some();
// Apply an appropriate linkage/visibility value to our item that we
// just declared.
//
// This is sort of subtle. Inside our codegen unit we started off
// compilation by predefining all our own `MonoItem` instances. That
// is, everything we're codegenning ourselves is already defined. That
// means that anything we're actually codegenning in this codegen unit
// will have hit the above branch in `get_declared_value`. As a result,
// we're guaranteed here that we're declaring a symbol that won't get
// defined, or in other words we're referencing a value from another
// codegen unit or even another crate.
//
// So because this is a foreign value we blanket apply an external
// linkage directive because it's coming from a different object file.
// The visibility here is where it gets tricky. This symbol could be
// referencing some foreign crate or foreign library (an `extern`
// block) in which case we want to leave the default visibility. We may
// also, though, have multiple codegen units. It could be a
// monomorphization, in which case its expected visibility depends on
// whether we are sharing generics or not. The important thing here is
// that the visibility we apply to the declaration is the same one that
// has been applied to the definition (wherever that definition may be).
let is_generic = instance.args.non_erasable_generics().next().is_some();
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)
let is_hidden = if is_generic {
// This is a monomorphization of a generic function.
if !(cx.tcx.sess.opts.share_generics()
|| tcx.codegen_fn_attrs(instance_def_id).inline
== rustc_attr_parsing::InlineAttr::Never)
{
// When not sharing generics, all instances are in the same
// crate and have hidden visibility.
true
} else if let Some(instance_def_id) = instance_def_id.as_local() {
// This is a monomorphization of a generic function
// defined in the current crate. It is hidden if:
// - the definition is unreachable for downstream
// crates, or
// - the current crate does not re-export generics
// (because the crate is a C library or executable)
cx.tcx.is_unreachable_local_definition(instance_def_id)
|| !cx.tcx.local_crate_exports_generics()
{
#[cfg(feature = "master")]
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
}
} else {
// This is a monomorphization of a generic function
// defined in an upstream crate.
if instance.upstream_monomorphization(tcx).is_some() {
// This is instantiated in another crate. It cannot
// be `hidden`.
} else {
// This is a local instantiation of an upstream definition.
// If the current crate does not re-export it
// (because it is a C library or an executable), it
// will have been declared `hidden`.
if !cx.tcx.local_crate_exports_generics() {
#[cfg(feature = "master")]
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
}
}
// defined in an upstream crate. It is hidden if:
// - it is instantiated in this crate, and
// - the current crate does not re-export generics
instance.upstream_monomorphization(tcx).is_none()
&& !cx.tcx.local_crate_exports_generics()
}
} else {
// When not sharing generics, all instances are in the same
// crate and have hidden visibility
#[cfg(feature = "master")]
// This is a non-generic function. It is hidden if:
// - it is instantiated in the local crate, and
// - it is defined an upstream crate (non-local), or
// - it is not reachable
cx.tcx.is_codegened_item(instance_def_id)
&& (!instance_def_id.is_local()
|| !cx.tcx.is_reachable_non_generic(instance_def_id))
};
if is_hidden {
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
}
} else {
// This is a non-generic function
if cx.tcx.is_codegened_item(instance_def_id) {
// This is a function that is instantiated in the local crate
if instance_def_id.is_local() {
// This is function that is defined in the local crate.
// If it is not reachable, it is hidden.
if !cx.tcx.is_reachable_non_generic(instance_def_id) {
#[cfg(feature = "master")]
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
}
} else {
// This is a function from an upstream crate that has
// been instantiated here. These are always hidden.
#[cfg(feature = "master")]
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
}
}
}
func

View File

@ -240,14 +240,14 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
};
let ptr_type = base_addr.get_type();
let base_addr = self.const_bitcast(base_addr, self.usize_type);
let base_addr = self.context.new_cast(None, base_addr, self.usize_type);
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);
let ptr = self.context.new_cast(None, base_addr + offset, ptr_type);
if !matches!(layout.primitive(), Pointer(_)) {
self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
} else {
self.const_bitcast(ptr, ty)
self.context.new_cast(None, ptr, ty)
}
}
}

View File

@ -252,7 +252,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
let global = self.declare_global(
sym,
gcc_type,
GlobalKind::Exported,
GlobalKind::Imported,
is_tls,
fn_attrs.link_section,
);
@ -404,7 +404,6 @@ fn check_and_apply_linkage<'gcc, 'tcx>(
// TODO(antoyo): set linkage.
let value = cx.const_ptrcast(global1.get_address(None), gcc_type);
global2.global_set_initializer_rvalue(value);
// TODO(antoyo): use global_set_initializer() when it will work.
global2
} else {
// Generate an external declaration.

View File

@ -386,6 +386,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
type Value = RValue<'gcc>;
type Metadata = RValue<'gcc>;
// TODO(antoyo): change to Function<'gcc>.
type Function = RValue<'gcc>;
type BasicBlock = Block<'gcc>;

View File

@ -40,10 +40,6 @@ pub(crate) enum PossibleFeature<'a> {
None,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_lto_not_supported)]
pub(crate) struct LTONotSupported;
#[derive(Diagnostic)]
#[diag(codegen_gcc_unwinding_inline_asm)]
pub(crate) struct UnwindingInlineAsm {

View File

@ -66,16 +66,14 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
// We do the equivalent above in `target_features_cfg`.
// See <https://github.com/rust-lang/rust/issues/134792>.
all_rust_features.push((false, feature));
} else if !feature.is_empty() {
if diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
}
} else if !feature.is_empty() && diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
}
}
// Remove features that are meant for rustc, not codegen.
all_rust_features.retain(|(_, feature)| {
all_rust_features.retain(|&(_, feature)| {
// Retain if it is not a rustc feature
!RUSTC_SPECIFIC_FEATURES.contains(feature)
!RUSTC_SPECIFIC_FEATURES.contains(&feature)
});
// Check feature validity.
@ -103,7 +101,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
};
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
Some(&(_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
@ -165,29 +163,25 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
);
// Translate this into GCC features.
let feats = all_rust_features
.iter()
.filter_map(|&(enable, feature)| {
let feats =
all_rust_features.iter().flat_map(|&(enable, feature)| {
let enable_disable = if enable { '+' } else { '-' };
// We run through `to_gcc_features` when
// passing requests down to GCC. This means that all in-language
// features also work on the command line instead of having two
// different names when the GCC name and the Rust name differ.
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::<Vec<_>>(),
)
})
.flatten();
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::<Vec<_>>()
});
features.extend(feats);
if diagnostics {

View File

@ -90,7 +90,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
}
}
}
} else if a_type.is_vector() && a_type.is_vector() {
} else if a_type.is_vector() && b_type.is_vector() {
a >> b
} else if a_native && !b_native {
self.gcc_lshr(a, self.gcc_int_cast(b, a_type))
@ -660,7 +660,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
}
}
}
} else if a_type.is_vector() && a_type.is_vector() {
} else if a_type.is_vector() && b_type.is_vector() {
a << b
} else if a_native && !b_native {
self.gcc_shl(a, self.gcc_int_cast(b, a_type))

View File

@ -421,7 +421,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
| "__builtin_ia32_xsaveopt64" => {
let new_args = args.to_vec();
let thirty_two = builder.context.new_rvalue_from_int(new_args[1].get_type(), 32);
let arg2 = new_args[1] << thirty_two | new_args[2];
let arg2 = (new_args[1] << thirty_two) | new_args[2];
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();

View File

@ -13,15 +13,16 @@ use rustc_codegen_ssa::common::IntPredicate;
use rustc_codegen_ssa::errors::InvalidMonomorphization;
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
#[cfg(feature = "master")]
use rustc_codegen_ssa::traits::MiscCodegenMethods;
use rustc_codegen_ssa::traits::{
ArgAbiBuilderMethods, BuilderMethods, ConstCodegenMethods, IntrinsicCallBuilderMethods,
};
#[cfg(feature = "master")]
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, MiscCodegenMethods};
use rustc_middle::bug;
use rustc_middle::ty::layout::LayoutOf;
#[cfg(feature = "master")]
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
use rustc_middle::ty::{self, Instance, Ty};
use rustc_span::{Span, Symbol, sym};
use rustc_target::abi::HasDataLayout;
@ -139,6 +140,18 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
)
}
sym::fmaf16 => {
// TODO(antoyo): use the correct builtin for f16.
let func = self.cx.context.get_builtin_function("fmaf");
let args: Vec<_> = args
.iter()
.map(|arg| {
self.cx.context.new_cast(self.location, arg.immediate(), self.cx.type_f32())
})
.collect();
let result = self.cx.context.new_call(self.location, func, &args);
self.cx.context.new_cast(self.location, result, self.cx.type_f16())
}
sym::is_val_statically_known => {
let a = args[0].immediate();
let builtin = self.context.get_builtin_function("__builtin_constant_p");

View File

@ -379,7 +379,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
// Make sure this is actually a SIMD vector.
let idx_ty = args[2].layout.ty;
let n: u64 = if idx_ty.is_simd()
&& matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
&& matches!(*idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
{
idx_ty.simd_size_and_type(bx.cx.tcx).0
} else {
@ -829,6 +829,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
| sym::simd_flog
| sym::simd_floor
| sym::simd_fma
| sym::simd_relaxed_fma
| sym::simd_fpow
| sym::simd_fpowi
| sym::simd_fsin

View File

@ -27,6 +27,8 @@
// Some "regular" crates we want to share with rustc
extern crate object;
extern crate smallvec;
// FIXME(antoyo): clippy bug: remove the #[allow] when it's fixed.
#[allow(unused_extern_crates)]
extern crate tempfile;
#[macro_use]
extern crate tracing;
@ -88,7 +90,6 @@ use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};
use back::lto::{ThinBuffer, ThinData};
use errors::LTONotSupported;
use gccjit::{CType, Context, OptimizationLevel};
#[cfg(feature = "master")]
use gccjit::{TargetInfo, Version};
@ -109,9 +110,10 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::ty::TyCtxt;
use rustc_middle::util::Providers;
use rustc_session::Session;
use rustc_session::config::{Lto, OptLevel, OutputFilenames};
use rustc_session::config::{OptLevel, OutputFilenames};
use rustc_span::Symbol;
use rustc_span::fatal_error::FatalError;
use rustc_target::spec::RelocModel;
use tempfile::TempDir;
use crate::back::lto::ModuleBuffer;
@ -141,11 +143,15 @@ impl TargetInfo {
false
}
fn supports_128bit_int(&self) -> bool {
self.supports_128bit_integers.load(Ordering::SeqCst)
}
fn supports_target_dependent_type(&self, _typ: CType) -> bool {
fn supports_target_dependent_type(&self, typ: CType) -> bool {
match typ {
CType::UInt128t | CType::Int128t => {
if self.supports_128bit_integers.load(Ordering::SeqCst) {
return true;
}
}
_ => (),
}
false
}
}
@ -166,10 +172,6 @@ impl LockedTargetInfo {
self.info.lock().expect("lock").cpu_supports(feature)
}
fn supports_128bit_int(&self) -> bool {
self.info.lock().expect("lock").supports_128bit_int()
}
fn supports_target_dependent_type(&self, typ: CType) -> bool {
self.info.lock().expect("lock").supports_target_dependent_type(typ)
}
@ -202,10 +204,6 @@ impl CodegenBackend for GccCodegenBackend {
#[cfg(feature = "master")]
gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
if sess.lto() == Lto::Thin {
sess.dcx().emit_warn(LTONotSupported {});
}
#[cfg(not(feature = "master"))]
{
let temp_dir = TempDir::new().expect("cannot create temporary directory");
@ -297,6 +295,7 @@ impl ExtraBackendMethods for GccCodegenBackend {
) -> Self::Module {
let mut mods = GccContext {
context: Arc::new(SyncContext::new(new_context(tcx))),
relocation_model: tcx.sess.relocation_model(),
should_combine_object_files: false,
temp_dir: None,
};
@ -328,6 +327,9 @@ impl ExtraBackendMethods for GccCodegenBackend {
pub struct GccContext {
context: Arc<SyncContext>,
/// This field is needed in order to be able to set the flag -fPIC when necessary when doing
/// LTO.
relocation_model: RelocModel,
should_combine_object_files: bool,
// Temporary directory used by LTO. We keep it here so that it's not removed before linking.
temp_dir: Option<TempDir>,
@ -492,10 +494,10 @@ fn target_features_cfg(
sess.target
.rust_target_features()
.iter()
.filter(|(_, gate, _)| gate.in_cfg())
.filter_map(|(feature, gate, _)| {
.filter(|&&(_, gate, _)| gate.in_cfg())
.filter_map(|&(feature, gate, _)| {
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
Some(*feature)
Some(feature)
} else {
None
}

View File

@ -1,11 +0,0 @@
tests/ui/issues/issue-44056.rs
tests/ui/lto/fat-lto.rs
tests/ui/lto/debuginfo-lto.rs
tests/ui/lto/lto-many-codegen-units.rs
tests/ui/lto/issue-100772.rs
tests/ui/lto/lto-rustc-loads-linker-plugin.rs
tests/ui/panic-runtime/lto-unwind.rs
tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs
tests/ui/sepcomp/sepcomp-lib-lto.rs
tests/ui/lto/lto-opt-level-s.rs
tests/ui/lto/lto-opt-level-z.rs

View File

@ -69,20 +69,22 @@ tests/ui/mir/mir_heavy_promoted.rs
tests/ui/consts/const_cmp_type_id.rs
tests/ui/consts/issue-73976-monomorphic.rs
tests/ui/consts/issue-94675.rs
tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs
tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
tests/ui/traits/const-traits/const-drop-fail.rs
tests/ui/traits/const-traits/const-drop.rs
tests/ui/runtime/on-broken-pipe/child-processes.rs
tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs
tests/ui/sanitizer/cfi-async-closures.rs
tests/ui/sanitizer/cfi-closures.rs
tests/ui/sanitizer/cfi-complex-receiver.rs
tests/ui/sanitizer/cfi-coroutine.rs
tests/ui/sanitizer/cfi-drop-in-place.rs
tests/ui/sanitizer/cfi-drop-no-principal.rs
tests/ui/sanitizer/cfi-fn-ptr.rs
tests/ui/sanitizer/cfi-self-ref.rs
tests/ui/sanitizer/cfi-supertraits.rs
tests/ui/sanitizer/cfi-virtual-auto.rs
tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
tests/ui/sanitizer/cfi/async-closures.rs
tests/ui/sanitizer/cfi/closures.rs
tests/ui/sanitizer/cfi/complex-receiver.rs
tests/ui/sanitizer/cfi/coroutine.rs
tests/ui/sanitizer/cfi/drop-in-place.rs
tests/ui/sanitizer/cfi/drop-no-principal.rs
tests/ui/sanitizer/cfi/fn-ptr.rs
tests/ui/sanitizer/cfi/self-ref.rs
tests/ui/sanitizer/cfi/supertraits.rs
tests/ui/sanitizer/cfi/virtual-auto.rs
tests/ui/sanitizer/cfi/sized-associated-ty.rs
tests/ui/sanitizer/cfi/can-reveal-opaques.rs
tests/ui/sanitizer/kcfi-mangling.rs
tests/ui/statics/const_generics.rs
tests/ui/backtrace/dylib-dep.rs
@ -91,6 +93,7 @@ tests/ui/delegation/fn-header.rs
tests/ui/consts/zst_no_llvm_alloc.rs
tests/ui/consts/const-eval/parse_ints.rs
tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
tests/ui/simd/intrinsic/generic-as.rs
tests/ui/backtrace/backtrace.rs
tests/ui/lifetimes/tail-expr-lock-poisoning.rs
tests/ui/runtime/rt-explody-panic-payloads.rs
@ -118,5 +121,4 @@ tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
tests/ui/sanitizer/cfi-sized-associated-ty.rs
tests/ui/sanitizer/cfi-can-reveal-opaques.rs
tests/ui/simd/simd-bitmask-notpow2.rs

View File

@ -11,7 +11,6 @@ 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
tests/ui/simd/intrinsic/generic-cast-pointer-width.rs
tests/ui/simd/intrinsic/generic-comparison-pass.rs

View File

@ -0,0 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "hello_world"
version = "0.0.0"
dependencies = [
"mylib",
]
[[package]]
name = "mylib"
version = "0.1.0"

View File

@ -1,4 +1,12 @@
[package]
name = "hello_world"
edition = "2024"
[dependencies]
mylib = { path = "mylib" }
[profile.dev]
lto = "thin"
[profile.release]
lto = "fat"

View File

@ -0,0 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "mylib"
version = "0.1.0"

View File

@ -0,0 +1,9 @@
[package]
name = "mylib"
version = "0.1.0"
authors = ["Antoni Boucher <bouanto@zoho.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,7 @@
pub fn my_func(a: i32, b: i32) -> i32 {
let mut res = a;
for i in a..b {
res += i;
}
res
}

View File

@ -1,3 +1,5 @@
use mylib::my_func;
fn main() {
println!("Hello, world!");
println!("{}", my_func(5, 10));
}

View File

@ -22,14 +22,20 @@ 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 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("build/libgccjit").join(commit)
};
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let gcc_path = std::fs::read_to_string(manifest_dir.join("config.toml"))
.ok()
.and_then(|v| {
let toml = Toml::parse(&v).expect("Failed to parse `config.toml`");
toml.get_string("gcc-path").map(PathBuf::from).ok()
})
.unwrap_or_else(|| {
// then we try to retrieve it from the `target` folder.
let commit = include_str!("../libgccjit.version").trim();
Path::new("build/libgccjit").join(commit)
});
let gcc_path = Path::new(&gcc_path)
.canonicalize()
@ -83,6 +89,8 @@ pub fn main_inner(profile: Profile) {
&format!("{}/build/build_sysroot/sysroot/", current_dir),
"-C",
"link-arg=-lc",
"--extern",
"mini_core=target/out/libmini_core.rlib",
"-o",
exe.to_str().expect("to_str"),
path.to_str().expect("to_str"),

View File

@ -7,38 +7,12 @@
// 5
// 10
#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
#![allow(internal_features)]
#![feature(no_core, start)]
#![no_std]
#![no_core]
/*
* Core
*/
// Because we don't have core yet.
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
trait Copy {
}
impl Copy for isize {}
impl Copy for usize {}
impl Copy for i32 {}
impl Copy for u8 {}
impl Copy for i8 {}
impl Copy for i16 {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "receiver"]
trait Receiver {
}
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
extern crate mini_core;
mod libc {
#[link(name = "c")]
@ -48,182 +22,6 @@ mod libc {
}
}
#[lang = "index"]
pub trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
impl<T> Index<usize> for [T; 3] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
impl<T> Index<usize> for [T] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.
drop_in_place(to_drop);
}
#[lang = "panic"]
#[track_caller]
#[no_mangle]
pub fn panic(_msg: &'static str) -> ! {
unsafe {
libc::puts("Panicking\0" as *const str as *const u8);
intrinsics::abort();
}
}
#[lang = "panic_location"]
struct PanicLocation {
file: &'static str,
line: u32,
column: u32,
}
#[lang = "panic_bounds_check"]
#[track_caller]
#[no_mangle]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
intrinsics::abort();
}
}
mod intrinsics {
#[rustc_nounwind]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub fn abort() -> ! {
loop {}
}
}
#[lang = "add"]
trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
impl Add for u8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i32 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for usize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for isize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
#[lang = "sub"]
pub trait Sub<RHS = Self> {
type Output;
fn sub(self, rhs: RHS) -> Self::Output;
}
impl Sub for usize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for isize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for u8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i16 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
#[track_caller]
#[lang = "panic_const_add_overflow"]
pub fn panic_const_add_overflow() -> ! {
panic("attempt to add with overflow");
}
#[track_caller]
#[lang = "panic_const_sub_overflow"]
pub fn panic_const_sub_overflow() -> ! {
panic("attempt to subtract with overflow");
}
/*
* Code
*/
static mut ONE: usize = 1;
fn make_array() -> [u8; 3] {

View File

@ -8,200 +8,20 @@
// Int argument: 2
// Both args: 11
#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics,
unboxed_closures, rustc_attrs)]
#![allow(internal_features)]
#![feature(no_core, start)]
#![no_std]
#![no_core]
/*
* Core
*/
// Because we don't have core yet.
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
trait Copy {
}
impl Copy for isize {}
impl Copy for usize {}
impl Copy for i32 {}
impl Copy for u32 {}
impl Copy for u8 {}
impl Copy for i8 {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "receiver"]
trait Receiver {
}
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
extern crate mini_core;
mod libc {
#[link(name = "c")]
extern "C" {
pub fn puts(s: *const u8) -> i32;
pub fn printf(format: *const i8, ...) -> i32;
}
}
#[lang = "index"]
pub trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
impl<T> Index<usize> for [T; 3] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
impl<T> Index<usize> for [T] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.
drop_in_place(to_drop);
}
#[lang = "panic_location"]
struct PanicLocation {
file: &'static str,
line: u32,
column: u32,
}
#[lang = "panic_bounds_check"]
#[track_caller]
#[no_mangle]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
intrinsics::abort();
}
}
mod intrinsics {
#[rustc_nounwind]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub fn abort() -> ! {
loop {}
}
}
#[lang = "tuple_trait"]
pub trait Tuple {}
#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {}
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {}
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
#[lang = "fn_once"]
#[rustc_paren_sugar]
pub trait FnOnce<Args: Tuple> {
#[lang = "fn_once_output"]
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
#[lang = "fn_mut"]
#[rustc_paren_sugar]
pub trait FnMut<Args: Tuple>: FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
#[lang = "add"]
trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
impl Add for u8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i32 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for usize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for isize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
#[lang = "panic"]
#[track_caller]
#[no_mangle]
pub fn panic(_msg: &'static str) -> ! {
unsafe {
libc::puts("Panicking\0" as *const str as *const u8);
intrinsics::abort();
}
}
#[track_caller]
#[lang = "panic_const_add_overflow"]
pub fn panic_const_add_overflow() -> ! {
panic("attempt to add with overflow");
}
/*
* Code
*/
#[start]
fn main(mut argc: isize, _argv: *const *const u8) -> isize {
let string = "Arg: %d\n\0";

View File

@ -5,304 +5,20 @@
// stdout: true
// 1
#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
#![allow(internal_features)]
#![feature(no_core, start)]
#![no_std]
#![no_core]
/*
* Core
*/
// Because we don't have core yet.
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
trait Copy {
}
impl Copy for isize {}
impl Copy for usize {}
impl Copy for u64 {}
impl Copy for i32 {}
impl Copy for u32 {}
impl Copy for bool {}
impl Copy for u16 {}
impl Copy for i16 {}
impl Copy for char {}
impl Copy for i8 {}
impl Copy for u8 {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "receiver"]
trait Receiver {
}
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
extern crate mini_core;
mod libc {
#[link(name = "c")]
extern "C" {
pub fn printf(format: *const i8, ...) -> i32;
pub fn puts(s: *const u8) -> i32;
}
}
#[lang = "index"]
pub trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
impl<T> Index<usize> for [T; 3] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
impl<T> Index<usize> for [T] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.
drop_in_place(to_drop);
}
#[lang = "panic"]
#[track_caller]
#[no_mangle]
pub fn panic(_msg: &'static str) -> ! {
unsafe {
libc::puts("Panicking\0" as *const str as *const u8);
intrinsics::abort();
}
}
#[lang = "panic_location"]
struct PanicLocation {
file: &'static str,
line: u32,
column: u32,
}
#[lang = "panic_bounds_check"]
#[track_caller]
#[no_mangle]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
intrinsics::abort();
}
}
mod intrinsics {
#[rustc_nounwind]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub fn abort() -> ! {
loop {}
}
}
#[lang = "add"]
trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
impl Add for u8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i32 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for usize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for isize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
#[lang = "sub"]
pub trait Sub<RHS = Self> {
type Output;
fn sub(self, rhs: RHS) -> Self::Output;
}
impl Sub for usize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for isize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for u8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i16 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
#[lang = "eq"]
pub trait PartialEq<Rhs: ?Sized = Self> {
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool;
}
impl PartialEq for u8 {
fn eq(&self, other: &u8) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &u8) -> bool {
(*self) != (*other)
}
}
impl PartialEq for u16 {
fn eq(&self, other: &u16) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &u16) -> bool {
(*self) != (*other)
}
}
impl PartialEq for u32 {
fn eq(&self, other: &u32) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &u32) -> bool {
(*self) != (*other)
}
}
impl PartialEq for u64 {
fn eq(&self, other: &u64) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &u64) -> bool {
(*self) != (*other)
}
}
impl PartialEq for usize {
fn eq(&self, other: &usize) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &usize) -> bool {
(*self) != (*other)
}
}
impl PartialEq for i8 {
fn eq(&self, other: &i8) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &i8) -> bool {
(*self) != (*other)
}
}
impl PartialEq for i32 {
fn eq(&self, other: &i32) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &i32) -> bool {
(*self) != (*other)
}
}
impl PartialEq for isize {
fn eq(&self, other: &isize) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &isize) -> bool {
(*self) != (*other)
}
}
impl PartialEq for char {
fn eq(&self, other: &char) -> bool {
(*self) == (*other)
}
fn ne(&self, other: &char) -> bool {
(*self) != (*other)
}
}
/*
* Code
*/
#[start]
fn main(argc: isize, _argv: *const *const u8) -> isize {
unsafe {

View File

@ -4,212 +4,20 @@
// status: 0
// stdout: 1
#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
#![allow(internal_features)]
#![feature(no_core, start)]
#![no_std]
#![no_core]
/*
* Core
*/
// Because we don't have core yet.
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
trait Copy {
}
impl Copy for isize {}
impl Copy for usize {}
impl Copy for i32 {}
impl Copy for u8 {}
impl Copy for i8 {}
impl Copy for i16 {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "receiver"]
trait Receiver {
}
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
extern crate mini_core;
mod libc {
#[link(name = "c")]
extern "C" {
pub fn printf(format: *const i8, ...) -> i32;
pub fn puts(s: *const u8) -> i32;
}
}
#[lang = "index"]
pub trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
impl<T> Index<usize> for [T; 3] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
impl<T> Index<usize> for [T] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.
drop_in_place(to_drop);
}
#[lang = "panic"]
#[track_caller]
#[no_mangle]
pub fn panic(_msg: &'static str) -> ! {
unsafe {
libc::puts("Panicking\0" as *const str as *const u8);
intrinsics::abort();
}
}
#[lang = "panic_location"]
struct PanicLocation {
file: &'static str,
line: u32,
column: u32,
}
#[lang = "panic_bounds_check"]
#[track_caller]
#[no_mangle]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
intrinsics::abort();
}
}
mod intrinsics {
#[rustc_nounwind]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub fn abort() -> ! {
loop {}
}
}
#[lang = "add"]
trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
impl Add for u8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i32 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for usize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for isize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
#[lang = "sub"]
pub trait Sub<RHS = Self> {
type Output;
fn sub(self, rhs: RHS) -> Self::Output;
}
impl Sub for usize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for isize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for u8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i16 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
/*
* Code
*/
fn i16_as_i8(a: i16) -> i8 {
a as i8
}

View File

@ -38,8 +38,8 @@ pub trait Deref {
fn deref(&self) -> &Self::Target;
}
#[lang = "receiver"]
trait Receiver {
#[lang = "legacy_receiver"]
trait LegacyReceiver {
}
#[lang = "freeze"]

View File

@ -4,212 +4,20 @@
// status: 0
// stdout: 1
#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
#![allow(internal_features)]
#![feature(no_core, start)]
#![no_std]
#![no_core]
/*
* Core
*/
// Because we don't have core yet.
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
trait Copy {
}
impl Copy for isize {}
impl Copy for usize {}
impl Copy for i32 {}
impl Copy for u8 {}
impl Copy for i8 {}
impl Copy for i16 {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "receiver"]
trait Receiver {
}
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
extern crate mini_core;
mod libc {
#[link(name = "c")]
extern "C" {
pub fn printf(format: *const i8, ...) -> i32;
pub fn puts(s: *const u8) -> i32;
}
}
#[lang = "index"]
pub trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
impl<T> Index<usize> for [T; 3] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
impl<T> Index<usize> for [T] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.
drop_in_place(to_drop);
}
#[lang = "panic"]
#[track_caller]
#[no_mangle]
pub fn panic(_msg: &'static str) -> ! {
unsafe {
libc::puts("Panicking\0" as *const str as *const u8);
intrinsics::abort();
}
}
#[lang = "panic_location"]
struct PanicLocation {
file: &'static str,
line: u32,
column: u32,
}
#[lang = "panic_bounds_check"]
#[track_caller]
#[no_mangle]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
intrinsics::abort();
}
}
mod intrinsics {
#[rustc_nounwind]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub fn abort() -> ! {
loop {}
}
}
#[lang = "add"]
trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
impl Add for u8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i32 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for usize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for isize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
#[lang = "sub"]
pub trait Sub<RHS = Self> {
type Output;
fn sub(self, rhs: RHS) -> Self::Output;
}
impl Sub for usize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for isize {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for u8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i16 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
/*
* Code
*/
static mut ONE: usize = 1;
fn make_array() -> [u8; 3] {

View File

@ -15,18 +15,18 @@
#[lang = "copy"]
pub unsafe trait Copy {}
unsafe impl Copy for bool {}
unsafe impl Copy for u8 {}
unsafe impl Copy for u16 {}
unsafe impl Copy for u32 {}
unsafe impl Copy for u64 {}
unsafe impl Copy for usize {}
unsafe impl Copy for i8 {}
unsafe impl Copy for i16 {}
unsafe impl Copy for i32 {}
unsafe impl Copy for isize {}
unsafe impl Copy for f32 {}
unsafe impl Copy for char {}
impl Copy for bool {}
impl Copy for u8 {}
impl Copy for u16 {}
impl Copy for u32 {}
impl Copy for u64 {}
impl Copy for usize {}
impl Copy for i8 {}
impl Copy for i16 {}
impl Copy for i32 {}
impl Copy for isize {}
impl Copy for f32 {}
impl Copy for char {}
mod libc {
#[link(name = "c")]
@ -43,8 +43,8 @@ mod libc {
#[lang = "sized"]
pub trait Sized {}
#[lang = "receiver"]
trait Receiver {
#[lang = "legacy_receiver"]
trait LegacyReceiver {
}
#[lang = "freeze"]

View File

@ -4,36 +4,12 @@
// status: 0
// stdout: 5
#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
#![allow(internal_features)]
#![feature(no_core, start)]
#![no_std]
#![no_core]
/*
* Core
*/
// Because we don't have core yet.
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
trait Copy {
}
impl Copy for isize {}
impl Copy for usize {}
impl Copy for i32 {}
impl Copy for u32 {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "receiver"]
trait Receiver {
}
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
extern crate mini_core;
mod libc {
#[link(name = "c")]
@ -42,79 +18,6 @@ mod libc {
}
}
#[lang = "index"]
pub trait Index<Idx: ?Sized> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
impl<T> Index<usize> for [T; 3] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
impl<T> Index<usize> for [T] {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self[index]
}
}
#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {}
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {}
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.
drop_in_place(to_drop);
}
#[lang = "panic_location"]
struct PanicLocation {
file: &'static str,
line: u32,
column: u32,
}
#[lang = "panic_bounds_check"]
#[track_caller]
#[no_mangle]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
intrinsics::abort();
}
}
mod intrinsics {
use super::Sized;
#[rustc_nounwind]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub fn abort() -> ! {
loop {}
}
}
/*
* Code
*/
static mut TWO: usize = 2;
fn index_slice(s: &[u32]) -> u32 {

View File

@ -0,0 +1,113 @@
// Compiler:
//
// Run-time:
// status: 0
mod libc {
#[link(name = "c")]
extern "C" {
pub fn puts(s: *const u8) -> i32;
pub fn sigaction(signum: i32, act: *const sigaction, oldact: *mut sigaction) -> i32;
pub fn mmap(addr: *mut (), len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut ();
pub fn mprotect(addr: *mut (), len: usize, prot: i32) -> i32;
}
pub const PROT_READ: i32 = 1;
pub const PROT_WRITE: i32 = 2;
pub const MAP_PRIVATE: i32 = 0x0002;
pub const MAP_ANONYMOUS: i32 = 0x0020;
pub const MAP_FAILED: *mut u8 = !0 as *mut u8;
/// glibc sigaction
#[repr(C)]
pub struct sigaction {
pub sa_sigaction: Option<unsafe extern "C" fn(i32, *mut (), *mut ())>,
pub sa_mask: [u32; 32],
pub sa_flags: i32,
pub sa_restorer: Option<unsafe extern "C" fn()>,
}
pub const SA_SIGINFO: i32 = 0x00000004;
pub const SIGSEGV: i32 = 11;
}
static mut COUNT: u32 = 0;
static mut STORAGE: *mut u8 = core::ptr::null_mut();
const PAGE_SIZE: usize = 1 << 15;
fn main() {
unsafe {
// Register a segfault handler
libc::sigaction(
libc::SIGSEGV,
&libc::sigaction {
sa_sigaction: Some(segv_handler),
sa_flags: libc::SA_SIGINFO,
..core::mem::zeroed()
},
core::ptr::null_mut(),
);
STORAGE = libc::mmap(
core::ptr::null_mut(),
PAGE_SIZE * 2,
0,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
-1,
0,
).cast();
if STORAGE == libc::MAP_FAILED {
panic!("error: mmap failed");
}
let p_count = (&mut COUNT) as *mut u32;
p_count.write_volatile(0);
// Trigger segfaults
STORAGE.add(0).write_volatile(1);
STORAGE.add(PAGE_SIZE).write_volatile(1);
STORAGE.add(0).write_volatile(1);
STORAGE.add(PAGE_SIZE).write_volatile(1);
STORAGE.add(0).write_volatile(1);
STORAGE.add(PAGE_SIZE).write_volatile(1);
STORAGE.add(0).read_volatile();
STORAGE.add(PAGE_SIZE).read_volatile();
STORAGE.add(0).read_volatile();
STORAGE.add(PAGE_SIZE).read_volatile();
STORAGE.add(0).read_volatile();
STORAGE.add(PAGE_SIZE).read_volatile();
STORAGE.add(0).write_volatile(1);
STORAGE.add(PAGE_SIZE).write_volatile(1);
// The segfault handler should have been called for every `write_volatile` and
// `read_volatile` in `STORAGE`. If the compiler ignores volatility, some of these writes
// will be combined, causing a different number of segfaults.
//
// This `p_count` read is done by a volatile read. If the compiler
// ignores volatility, the compiler will speculate that `*p_count` is
// unchanged and remove this check, failing the test.
if p_count.read_volatile() != 14 {
panic!("error: segfault count mismatch: {}", p_count.read_volatile());
}
}
}
unsafe extern "C" fn segv_handler(_: i32, _: *mut (), _: *mut ()) {
let p_count = (&mut COUNT) as *mut u32;
p_count.write_volatile(p_count.read_volatile() + 1);
let count = p_count.read_volatile();
// Toggle the protected page so that the handler will be called for
// each `write_volatile`
libc::mprotect(
STORAGE.cast(),
PAGE_SIZE,
if count % 2 == 1 { libc::PROT_READ | libc::PROT_WRITE } else { 0 },
);
libc::mprotect(
STORAGE.add(PAGE_SIZE).cast(),
PAGE_SIZE,
if count % 2 == 0 { libc::PROT_READ | libc::PROT_WRITE } else { 0 },
);
}