Skip to content
Merged
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
590bfc6
Don't pass --target in cargo.sh
bjorn3 Mar 26, 2022
3888aaf
Merge commit '39683d8eb7a32a74bea96ecbf1e87675d3338506' into sync_cg_…
bjorn3 Mar 26, 2022
14c33f5
Merge pull request #147 from bjorn3/misc_improvements
antoyo Mar 26, 2022
02970a6
Add support for target builtins
antoyo Feb 6, 2022
13ab1ab
Merge pull request #129 from rust-lang/feature/simd
antoyo Mar 30, 2022
267e5e1
Add support for target builtins
antoyo Feb 6, 2022
a445bcb
Merge pull request #149 from rust-lang/missing-comments
antoyo Mar 30, 2022
927eea3
Add support for packed struct
antoyo Mar 29, 2022
74edcb8
Spellchecking some comments
nyurik Mar 30, 2022
c519b85
Spellchecking compiler code
nyurik Mar 30, 2022
81083b9
Rollup merge of #95461 - nyurik:spelling, r=lcnr
Dylan-DPC Mar 30, 2022
9bb797c
Add missing vendor intrinsics
bjorn3 Mar 27, 2022
76cf7c2
Merge pull request #150 from bjorn3/bootstrap_missing_vendor_intrinsics
antoyo Mar 30, 2022
f537564
Merge pull request #148 from rust-lang/feature/packed-struct
antoyo Mar 30, 2022
3970825
Add intrinsic translation for x86 arch
GuillaumeGomez Mar 30, 2022
0237d95
Merge pull request #151 from GuillaumeGomez/x86-intrinsics
antoyo Mar 30, 2022
68ac3a4
Generate all listed architectures from llvmint
GuillaumeGomez Mar 30, 2022
dac3595
Merge pull request #152 from GuillaumeGomez/more-intrinsics
antoyo Mar 30, 2022
ef1a6d7
Fix error related to var tracking assignments
antoyo Mar 31, 2022
403e198
Merge pull request #154 from rust-lang/fix/error-var-tracking
antoyo Mar 31, 2022
035ac03
Add intrinsics not bound to a specific arch
GuillaumeGomez Mar 30, 2022
341b9f2
Merge pull request #153 from GuillaumeGomez/general-intrinsics
antoyo Mar 31, 2022
56983cf
test: Remove redundant code from `tests/run/int.rs`
yvt Apr 1, 2022
88c058b
make memcmp return a value of c_int_width instead of i32
drmorr0 Nov 11, 2021
6ce5ce8
Cleanup after some refactoring in rustc_target
Urgau Apr 3, 2022
d71f633
Mark scalar layout unions so that backends that do not support partia…
oli-obk Mar 3, 2022
249d3e9
Use WrappingRange::full instead of hand-rolling it
oli-obk Apr 5, 2022
837a446
test: Test more integer types and checked arithmetic in `tests/run/in…
yvt Apr 5, 2022
00677e5
Implement `saturating_{add, sub}` for non-native integer types
yvt Apr 1, 2022
5061e3a
Remove redundant assertions
yvt Apr 6, 2022
a7a09d5
Wrap numbers with `black_box` in-line, remove `one`
yvt Apr 6, 2022
d69ada6
Merge pull request #156 from yvt/fix-int-ops
antoyo Apr 6, 2022
c59b01f
simplify a self-profiling activity call in the cg_gcc backend
lqd Apr 1, 2022
4d7de81
Add feature for future libgccjit 12 release
antoyo Apr 13, 2022
3301275
Don't assume /bin/bash is available on every system.
Apr 14, 2022
c35f4e8
Merge pull request #158 from rust-lang/feature/gcc12
antoyo Apr 14, 2022
f927795
Add set -v as we can't pass command line argument with /usr/bin/env
MikaelUrankar Apr 15, 2022
0e31b92
Add codegen for global_asm! sym operands
Amanieu Mar 1, 2022
4210fd4
Merge pull request #160 from MikaelUrankar/master
antoyo Apr 15, 2022
21be9da
Auto merge of #95689 - lqd:self-profiler, r=wesleywiser
bors Apr 16, 2022
52cd51f
asm: Add a kreg0 register class on x86 which includes k0
Amanieu Apr 6, 2022
63e9911
Rollup merge of #95740 - Amanieu:kreg0, r=nagisa
Dylan-DPC Apr 19, 2022
889c402
Fix test.sh --build
antoyo Apr 23, 2022
b30a8f3
Merge pull request #162 from rust-lang/fix/test-script
antoyo Apr 24, 2022
a0742bd
Don't emit `.intel_syntax` for non-x86 targets
yvt Mar 27, 2022
1d62e95
Merge pull request #164 from yvt/no-intel-syntax
antoyo Apr 24, 2022
5d25b8f
Convert inline assembly `sym` operands into GCC input operands
yvt Apr 23, 2022
63ffdfd
Add compilation tests with optimization enabled
yvt Apr 25, 2022
dc8da94
Add rustfmt config to disable formatting
antoyo Apr 30, 2022
248c1c5
Merge pull request #168 from rust-lang/config/no-fmt
antoyo Apr 30, 2022
0405aa0
Merge pull request #163 from yvt/fix-asm-sym
antoyo Apr 30, 2022
758a7da
Rename run_lto_pass_manager to optimize_fat and remove thin parameter
bjorn3 Apr 30, 2022
e2f645d
Let LtoModuleCodegen::optimize take self by value
bjorn3 Apr 30, 2022
c00ecf5
Remove config parameter of optimize_fat and avoid interior mutability…
bjorn3 Apr 30, 2022
dc82445
Merge new_metadata into codegen_allocator
bjorn3 Apr 30, 2022
a225f0a
Pass a pointee type to `<Builder as BuilderMethods>::load` when calli…
yvt May 3, 2022
351c683
Use the given pointee type in `<Builder as BuilderMethods>::load`
yvt May 2, 2022
37892fc
Merge pull request #170 from yvt/fix-internal-load-calls
antoyo May 3, 2022
af9149a
Add tool to generate intrinsics conversion automatically
GuillaumeGomez May 3, 2022
ed0ba31
Update intrinsics
GuillaumeGomez May 3, 2022
19d8617
Generate intrinsics translations from llvmint as well
GuillaumeGomez May 3, 2022
f402cfe
Update intrinsics
GuillaumeGomez May 3, 2022
618ba48
Handle a syntax corner case where a def does not end with a `;`
GuillaumeGomez May 3, 2022
6e1bf49
Give priority to intrinsics translations from llvm
GuillaumeGomez May 3, 2022
852735d
Merge pull request #171 from GuillaumeGomez/update-intrinsics
antoyo May 3, 2022
5088fb3
Cast arguments in SIMD function
antoyo Apr 24, 2022
4636c59
Add more SIMD
antoyo Apr 30, 2022
ddc152b
Add more SIMD
antoyo May 1, 2022
a654186
Implement simd_select_bitmask
antoyo May 1, 2022
ace3250
Fix shuffle_vector
antoyo May 1, 2022
6bfe2b0
Support more SIMD intrinsics
antoyo May 3, 2022
eba654c
Support more SIMD intrinsics
antoyo May 3, 2022
4b40ac7
Support more SIMD intrinsics and refactor argument adjustment
antoyo May 4, 2022
41807a3
Support more SIMD intrinsics
antoyo May 4, 2022
d4ab681
Add comments
antoyo May 5, 2022
603d342
Feature-gate for libgccjit 12
antoyo May 5, 2022
e7df0a4
Simplify get() after contains()
antoyo May 5, 2022
4a97440
Feature gate call to get_size() for libgccjit 12
antoyo May 5, 2022
e062c37
Merge pull request #172 from rust-lang/feature/more-simd
antoyo May 5, 2022
be960e1
Update llvmint
GuillaumeGomez May 15, 2022
e25e2c3
Regenerate JSON file for llvmint every time
GuillaumeGomez May 15, 2022
bac878c
Add instrinsics from aweinstock314's llvmint as well
GuillaumeGomez May 15, 2022
cede919
Add tools/llvmint-2 to ignored entries
GuillaumeGomez May 15, 2022
e6dbecd
Merge pull request #175 from GuillaumeGomez/llvmint-update
antoyo May 15, 2022
084d2d7
Handle tmm_reg in rustc_codegen_gcc
chorman0773 May 17, 2022
8f0f6e3
rustc_codegen_ssa: cleanup `AtomicOrdering`
tmiasko May 24, 2022
4620b9f
rustc_codegen_ssa: derive copy and clone for various enums
tmiasko May 24, 2022
f26eb5a
Update `gccjit`
yvt May 25, 2022
a513b2a
Finish bumping stage0
Mark-Simulacrum May 20, 2022
10a9c0e
Mark immutable globals as read-only with `LValue::global_set_readonly`
yvt May 25, 2022
7e0a42b
Merge pull request #165 from yvt/fix-const-memattr
antoyo May 28, 2022
bafdded
Merge branch 'master' into sync_from_rust2
antoyo Jun 7, 2022
8697dec
Update toolchain
antoyo Jun 7, 2022
fb69f73
Fix exactudiv
antoyo Jun 7, 2022
e8dca3e
Merge pull request #179 from rust-lang/sync_from_rust2
antoyo Jun 7, 2022
3fac982
Merge commit 'e8dca3e87d164d2806098c462c6ce41301341f68' into sync_fro…
antoyo Jun 7, 2022
80cbaa3
Remove unused macro rule
antoyo Jun 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion compiler/rustc_codegen_gcc/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
libgccjit_version: ["libgccjit.so", "libgccjit_without_int128.so"]
libgccjit_version: ["libgccjit.so", "libgccjit_without_int128.so", "libgccjit12.so"]

steps:
- uses: actions/checkout@v2
@@ -78,12 +78,21 @@ jobs:
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}

- name: Build
if: matrix.libgccjit_version != 'libgccjit12.so'
run: |
./prepare_build.sh
./build.sh
cargo test
./clean_all.sh
- name: Build
if: matrix.libgccjit_version == 'libgccjit12.so'
run: |
./prepare_build.sh
./build.sh --no-default-features
cargo test --no-default-features
./clean_all.sh
- name: Prepare dependencies
run: |
git config --global user.email "[email protected]"
@@ -98,6 +107,7 @@ jobs:
args: --release

- name: Test
if: matrix.libgccjit_version != 'libgccjit12.so'
run: |
# Enable backtraces for easier debugging
export RUST_BACKTRACE=1
@@ -107,3 +117,15 @@ jobs:
export RUN_RUNS=2
./test.sh --release
- name: Test
if: matrix.libgccjit_version == 'libgccjit12.so'
run: |
# Enable backtraces for easier debugging
export RUST_BACKTRACE=1
# Reduce amount of benchmark runs as they are slow
export COMPILE_RUNS=2
export RUN_RUNS=2
./test.sh --release --no-default-features
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_gcc/.gitignore
Original file line number Diff line number Diff line change
@@ -13,9 +13,13 @@ perf.data.old
/rust
/simple-raytracer
/regex
/rand
gimple*
*asm
res
test-backend
gcc_path
benchmarks
tools/llvm-project
tools/llvmint
tools/llvmint-2
1 change: 1 addition & 0 deletions compiler/rustc_codegen_gcc/.rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
disable_all_formatting = true
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/Cargo.lock
Original file line number Diff line number Diff line change
@@ -41,15 +41,15 @@ dependencies = [
[[package]]
name = "gccjit"
version = "1.0.0"
source = "git+https://github.com/antoyo/gccjit.rs#bdecdecfb8a02ec861a39a350f990faa33bd31c3"
source = "git+https://github.com/antoyo/gccjit.rs#bdb86fb5092895ff5589726b33250010c64d93f6"
dependencies = [
"gccjit_sys",
]

[[package]]
name = "gccjit_sys"
version = "0.0.1"
source = "git+https://github.com/antoyo/gccjit.rs#bdecdecfb8a02ec861a39a350f990faa33bd31c3"
source = "git+https://github.com/antoyo/gccjit.rs#bdb86fb5092895ff5589726b33250010c64d93f6"
dependencies = [
"libc 0.1.12",
]
12 changes: 10 additions & 2 deletions compiler/rustc_codegen_gcc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -9,9 +9,17 @@ license = "MIT OR Apache-2.0"
crate-type = ["dylib"]

[[test]]
name = "lang_tests"
path = "tests/lib.rs"
name = "lang_tests_debug"
path = "tests/lang_tests_debug.rs"
harness = false
[[test]]
name = "lang_tests_release"
path = "tests/lang_tests_release.rs"
harness = false

[features]
default = ["master"]
master = ["gccjit/master"]

[dependencies]
gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
25 changes: 14 additions & 11 deletions compiler/rustc_codegen_gcc/build.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#!/bin/bash
#!/usr/bin/env bash

#set -x
set -e

codegen_channel=debug
sysroot_channel=debug

flags=

while [[ $# -gt 0 ]]; do
case $1 in
--release)
@@ -16,6 +18,15 @@ while [[ $# -gt 0 ]]; do
sysroot_channel=release
shift
;;
--no-default-features)
flags="$flags --no-default-features"
shift
;;
--features)
shift
flags="$flags --features $1"
shift
;;
*)
echo "Unknown option $1"
exit 1
@@ -33,21 +44,13 @@ fi
export LD_LIBRARY_PATH="$GCC_PATH"
export LIBRARY_PATH="$GCC_PATH"

features=

if [[ "$1" == "--features" ]]; then
shift
features="--features $1"
shift
fi

if [[ "$codegen_channel" == "release" ]]; then
export CHANNEL='release'
CARGO_INCREMENTAL=1 cargo rustc --release $features
CARGO_INCREMENTAL=1 cargo rustc --release $flags
else
echo $LD_LIBRARY_PATH
export CHANNEL='debug'
cargo rustc $features
cargo rustc $flags
fi

source config.sh
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash

# Requires the CHANNEL env var to be set to `debug` or `release.`

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
cd $(dirname "$0")

4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/cargo.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash

if [ -z $CHANNEL ]; then
export CHANNEL='debug'
@@ -20,4 +20,4 @@ fi
cmd=$1
shift

RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@
RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd $@
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_gcc/clean_all.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/bin/bash --verbose
#!/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/
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/config.sh
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ set -e

export CARGO_INCREMENTAL=0

if [ -f ./gcc_path ]; then
if [ -f ./gcc_path ]; then
export GCC_PATH=$(cat gcc_path)
else
echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
@@ -38,7 +38,7 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
fi
fi

export RUSTFLAGS="$linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
export RUSTFLAGS="$CG_RUSTFLAGS $linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"

# FIXME(antoyo): remove once the atomic shim is gone
if [[ `uname` == 'Darwin' ]]; then
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
From a8fb97120d71252538b6b026695df40d02696bdb Mon Sep 17 00:00:00 2001
From: bjorn3 <[email protected]>
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
58 changes: 33 additions & 25 deletions compiler/rustc_codegen_gcc/example/std_example.rs
Original file line number Diff line number Diff line change
@@ -93,9 +93,10 @@ fn main() {

println!("{:?}", std::intrinsics::caller_location());

/*unsafe {
#[cfg(feature="master")]
unsafe {
test_simd();
}*/
}

Box::pin(move |mut _task_context| {
yield ();
@@ -104,15 +105,16 @@ fn main() {
println!("End");
}

/*#[target_feature(enable = "sse2")]
#[cfg(feature="master")]
#[target_feature(enable = "sse2")]
unsafe fn test_simd() {
let x = _mm_setzero_si128();
let y = _mm_set1_epi16(7);
let or = _mm_or_si128(x, y);
let cmp_eq = _mm_cmpeq_epi8(y, y);
let cmp_lt = _mm_cmplt_epi8(y, y);

/*assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);

@@ -124,14 +126,15 @@ unsafe fn test_simd() {
test_mm_cvtepi8_epi16();
test_mm_cvtsi128_si64();

// FIXME(#666) implement `#[rustc_arg_required_const(..)]` support
//test_mm_extract_epi8();
test_mm_extract_epi8();
test_mm_insert_epi16();

let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
assert_eq!(mask1, 1);*/
}*/
assert_eq!(mask1, 1);
}

/*#[target_feature(enable = "sse2")]
#[cfg(feature="master")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_slli_si128() {
#[rustfmt::skip]
let a = _mm_setr_epi8(
@@ -155,22 +158,10 @@ unsafe fn test_mm_slli_si128() {
);
let r = _mm_slli_si128(a, 16);
assert_eq_m128i(r, _mm_set1_epi8(0));
#[rustfmt::skip]
let a = _mm_setr_epi8(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
);
let r = _mm_slli_si128(a, -1);
assert_eq_m128i(_mm_set1_epi8(0), r);
#[rustfmt::skip]
let a = _mm_setr_epi8(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
);
let r = _mm_slli_si128(a, -0x80000000);
assert_eq_m128i(r, _mm_set1_epi8(0));
}


#[cfg(feature="master")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_movemask_epi8() {
#[rustfmt::skip]
@@ -184,6 +175,7 @@ unsafe fn test_mm_movemask_epi8() {
assert_eq!(r, 0b10100100_00100101);
}

#[cfg(feature="master")]
#[target_feature(enable = "avx2")]
unsafe fn test_mm256_movemask_epi8() {
let a = _mm256_set1_epi8(-1);
@@ -192,6 +184,7 @@ unsafe fn test_mm256_movemask_epi8() {
assert_eq!(r, e);
}

#[cfg(feature="master")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_epi8() {
let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
@@ -207,6 +200,7 @@ unsafe fn test_mm_add_epi8() {
assert_eq_m128i(r, e);
}

#[cfg(feature="master")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_pd() {
let a = _mm_setr_pd(1.0, 2.0);
@@ -215,25 +209,29 @@ unsafe fn test_mm_add_pd() {
assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
}

#[cfg(feature="master")]
fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
unsafe {
assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
}
}

#[cfg(feature="master")]
#[target_feature(enable = "sse2")]
pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
panic!("{:?} != {:?}", a, b);
}
}

#[cfg(feature="master")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_cvtsi128_si64() {
let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
assert_eq!(r, 5);
}

#[cfg(feature="master")]
#[target_feature(enable = "sse4.1")]
unsafe fn test_mm_cvtepi8_epi16() {
let a = _mm_set1_epi8(10);
@@ -246,6 +244,7 @@ unsafe fn test_mm_cvtepi8_epi16() {
assert_eq_m128i(r, e);
}

#[cfg(feature="master")]
#[target_feature(enable = "sse4.1")]
unsafe fn test_mm_extract_epi8() {
#[rustfmt::skip]
@@ -254,10 +253,19 @@ unsafe fn test_mm_extract_epi8() {
8, 9, 10, 11, 12, 13, 14, 15
);
let r1 = _mm_extract_epi8(a, 0);
let r2 = _mm_extract_epi8(a, 19);
let r2 = _mm_extract_epi8(a, 3);
assert_eq!(r1, 0xFF);
assert_eq!(r2, 3);
}*/
}

#[cfg(all(feature="master", target_arch = "x86_64"))]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_insert_epi16() {
let a = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
let r = _mm_insert_epi16(a, 9, 0);
let e = _mm_setr_epi16(9, 1, 2, 3, 4, 5, 6, 7);
assert_eq_m128i(r, e);
}

#[derive(PartialEq)]
enum LoopState {
Original file line number Diff line number Diff line change
@@ -7,167 +7,6 @@ Subject: [PATCH] [core] Disable portable-simd test
library/core/tests/lib.rs | 1 -
1 file changed, 1 deletion(-)

diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index aa1ad93..95fbf55 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -398,23 +398,4 @@ pub mod arch {
}
}

-// Pull in the `core_simd` crate directly into libcore. The contents of
-// `core_simd` are in a different repository: rust-lang/portable-simd.
-//
-// `core_simd` depends on libcore, but the contents of this module are
-// set up in such a way that directly pulling it here works such that the
-// crate uses this crate as its libcore.
-#[path = "../../portable-simd/crates/core_simd/src/mod.rs"]
-#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
-#[allow(rustdoc::bare_urls)]
-#[unstable(feature = "portable_simd", issue = "86656")]
-mod core_simd;
-
-#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
-#[unstable(feature = "portable_simd", issue = "86656")]
-pub mod simd {
- #[unstable(feature = "portable_simd", issue = "86656")]
- pub use crate::core_simd::simd::*;
-}
-
include!("primitive_docs.rs");
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index cd38c3a..ad632dc 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -17,6 +17,5 @@ use crate::ptr;
use crate::result::Result;
use crate::result::Result::{Err, Ok};
-use crate::simd::{self, Simd};
use crate::slice;

#[unstable(
@@ -3475,121 +3474,6 @@ impl<T> [T] {
}
}

- /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
- ///
- /// This is a safe wrapper around [`slice::align_to`], so has the same weak
- /// postconditions as that method. You're only assured that
- /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
- ///
- /// Notably, all of the following are possible:
- /// - `prefix.len() >= LANES`.
- /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
- /// - `suffix.len() >= LANES`.
- ///
- /// That said, this is a safe method, so if you're only writing safe code,
- /// then this can at most cause incorrect logic, not unsoundness.
- ///
- /// # Panics
- ///
- /// This will panic if the size of the SIMD type is different from
- /// `LANES` times that of the scalar.
- ///
- /// At the time of writing, the trait restrictions on `Simd<T, LANES>` keeps
- /// that from ever happening, as only power-of-two numbers of lanes are
- /// supported. It's possible that, in the future, those restrictions might
- /// be lifted in a way that would make it possible to see panics from this
- /// method for something like `LANES == 3`.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(portable_simd)]
- ///
- /// let short = &[1, 2, 3];
- /// let (prefix, middle, suffix) = short.as_simd::<4>();
- /// assert_eq!(middle, []); // Not enough elements for anything in the middle
- ///
- /// // They might be split in any possible way between prefix and suffix
- /// let it = prefix.iter().chain(suffix).copied();
- /// assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);
- ///
- /// fn basic_simd_sum(x: &[f32]) -> f32 {
- /// use std::ops::Add;
- /// use std::simd::f32x4;
- /// let (prefix, middle, suffix) = x.as_simd();
- /// let sums = f32x4::from_array([
- /// prefix.iter().copied().sum(),
- /// 0.0,
- /// 0.0,
- /// suffix.iter().copied().sum(),
- /// ]);
- /// let sums = middle.iter().copied().fold(sums, f32x4::add);
- /// sums.reduce_sum()
- /// }
- ///
- /// let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
- /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
- /// ```
- #[unstable(feature = "portable_simd", issue = "86656")]
- pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
- where
- Simd<T, LANES>: AsRef<[T; LANES]>,
- T: simd::SimdElement,
- simd::LaneCount<LANES>: simd::SupportedLaneCount,
- {
- // These are expected to always match, as vector types are laid out like
- // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
- // might as well double-check since it'll optimize away anyhow.
- assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
-
- // SAFETY: The simd types have the same layout as arrays, just with
- // potentially-higher alignment, so the de-facto transmutes are sound.
- unsafe { self.align_to() }
- }
-
- /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
- ///
- /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak
- /// postconditions as that method. You're only assured that
- /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
- ///
- /// Notably, all of the following are possible:
- /// - `prefix.len() >= LANES`.
- /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
- /// - `suffix.len() >= LANES`.
- ///
- /// That said, this is a safe method, so if you're only writing safe code,
- /// then this can at most cause incorrect logic, not unsoundness.
- ///
- /// This is the mutable version of [`slice::as_simd`]; see that for examples.
- ///
- /// # Panics
- ///
- /// This will panic if the size of the SIMD type is different from
- /// `LANES` times that of the scalar.
- ///
- /// At the time of writing, the trait restrictions on `Simd<T, LANES>` keeps
- /// that from ever happening, as only power-of-two numbers of lanes are
- /// supported. It's possible that, in the future, those restrictions might
- /// be lifted in a way that would make it possible to see panics from this
- /// method for something like `LANES == 3`.
- #[unstable(feature = "portable_simd", issue = "86656")]
- pub fn as_simd_mut<const LANES: usize>(&mut self) -> (&mut [T], &mut [Simd<T, LANES>], &mut [T])
- where
- Simd<T, LANES>: AsMut<[T; LANES]>,
- T: simd::SimdElement,
- simd::LaneCount<LANES>: simd::SupportedLaneCount,
- {
- // These are expected to always match, as vector types are laid out like
- // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
- // might as well double-check since it'll optimize away anyhow.
- assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
-
- // SAFETY: The simd types have the same layout as arrays, just with
- // potentially-higher alignment, so the de-facto transmutes are sound.
- unsafe { self.align_to_mut() }
- }
-
/// Checks if the elements of this slice are sorted.
///
/// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 06c7be0..359e2e7 100644
--- a/library/core/tests/lib.rs
@@ -188,41 +27,3 @@ index 06c7be0..359e2e7 100644
mod slice;
mod str;
mod str_lossy;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5dc586d..b6fc48f 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -312,6 +312,5 @@
#![feature(panic_can_unwind)]
#![feature(panic_unwind)]
#![feature(platform_intrinsics)]
-#![feature(portable_simd)]
#![feature(prelude_import)]
#![feature(ptr_as_uninit)]
@@ -508,23 +508,6 @@ pub mod time;
#[unstable(feature = "once_cell", issue = "74465")]
pub mod lazy;

-// Pull in `std_float` crate into libstd. The contents of
-// `std_float` are in a different repository: rust-lang/portable-simd.
-#[path = "../../portable-simd/crates/std_float/src/lib.rs"]
-#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
-#[allow(rustdoc::bare_urls)]
-#[unstable(feature = "portable_simd", issue = "86656")]
-mod std_float;
-
-#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
-#[unstable(feature = "portable_simd", issue = "86656")]
-pub mod simd {
- #[doc(inline)]
- pub use crate::std_float::StdFloat;
- #[doc(inline)]
- pub use core::simd::*;
-}
-
#[stable(feature = "futures_api", since = "1.36.0")]
pub mod task {
//! Types and Traits for working with asynchronous tasks.
--
2.26.2.7.g19db9cfb68

10 changes: 9 additions & 1 deletion compiler/rustc_codegen_gcc/prepare.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#!/bin/bash --verbose
#!/usr/bin/env bash
set -e
set -v

source prepare_build.sh

cargo install hyperfine || echo "Skipping hyperfine install"

git clone https://github.com/rust-random/rand.git || echo "rust-random/rand has already been cloned"
pushd rand
git checkout -- .
git checkout 0f933f9c7176e53b2a3c7952ded484e1783f0bf1
git am ../crate_patches/*-rand-*.patch
popd

git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned"
pushd regex
git checkout -- .
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_gcc/prepare_build.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/bash --verbose
#!/usr/bin/env bash
set -e
set -v

./build_sysroot/prepare_sysroot_src.sh
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/rust-toolchain
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2022-03-26"
channel = "nightly-2022-06-06"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
14 changes: 14 additions & 0 deletions compiler/rustc_codegen_gcc/rustc_patches/compile_test.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 887d27fd6dca4..2c2239f2b83d1 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
cfg: Option<&str>,
) -> test::TestDesc {
let mut ignore = false;
#[cfg(not(bootstrap))]
- let ignore_message: Option<String> = None;
+ let ignore_message: Option<&str> = None;
let mut should_fail = false;

let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/rustup.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash

set -e

39 changes: 27 additions & 12 deletions compiler/rustc_codegen_gcc/src/asm.rs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ use std::borrow::Cow;
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::type_of::LayoutGccExt;
use crate::callee::get_fn;


// Rust asm! and GCC Extended Asm semantics differ substantially.
@@ -116,7 +117,6 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX);

// GCC index of an output operand equals its position in the array
let mut outputs = vec![];
@@ -348,9 +348,24 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
// processed in the previous pass
}

InlineAsmOperandRef::Const { .. }
| InlineAsmOperandRef::SymFn { .. }
| InlineAsmOperandRef::SymStatic { .. } => {
InlineAsmOperandRef::SymFn { instance } => {
inputs.push(AsmInOperand {
constraint: "X".into(),
rust_idx,
val: self.cx.rvalue_as_function(get_fn(self.cx, instance))
.get_address(None),
});
}

InlineAsmOperandRef::SymStatic { def_id } => {
inputs.push(AsmInOperand {
constraint: "X".into(),
rust_idx,
val: self.cx.get_static(def_id).get_address(None),
});
}

InlineAsmOperandRef::Const { .. } => {
// processed in the previous pass
}
}
@@ -359,7 +374,7 @@ 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));
if !intel_dialect {
if att_dialect {
template_str.push_str(ATT_SYNTAX_INS);
}

@@ -444,7 +459,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
}
}

if !intel_dialect {
if att_dialect {
template_str.push_str(INTEL_SYNTAX_INS);
}

@@ -588,7 +603,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
InlineAsmRegClass::X86(
@@ -672,8 +687,8 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
let asm_arch = self.tcx.sess.asm_arch.unwrap();

// Default to Intel syntax on x86
let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
&& !options.contains(InlineAsmOptions::ATT_SYNTAX);
let att_dialect = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
&& options.contains(InlineAsmOptions::ATT_SYNTAX);

// Build the template string
let mut template_str = String::new();
@@ -723,11 +738,11 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}

let template_str =
if intel_syntax {
format!("{}\n\t.intel_syntax noprefix", template_str)
if att_dialect {
format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str)
}
else {
format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str)
template_str
};
// NOTE: seems like gcc will put the asm in the wrong section, so set it to .text manually.
let template_str = format!(".pushsection .text\n{}\n.popsection", template_str);
10 changes: 10 additions & 0 deletions compiler/rustc_codegen_gcc/src/base.rs
Original file line number Diff line number Diff line change
@@ -78,9 +78,19 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol, supports_
let context = Context::default();
// TODO(antoyo): only set on x86 platforms.
context.add_command_line_option("-masm=intel");
// TODO(antoyo): only add the following cli argument if the feature is supported.
context.add_command_line_option("-msse2");
context.add_command_line_option("-mavx2");
context.add_command_line_option("-msha");
context.add_command_line_option("-mpclmul");
// FIXME(antoyo): the following causes an illegal instruction on vmovdqu64 in std_example on my CPU.
// Only add if the CPU supports it.
//context.add_command_line_option("-mavx512f");
for arg in &tcx.sess.opts.cg.llvm_args {
context.add_command_line_option(arg);
}
// NOTE: This is needed to compile the file src/intrinsic/archs.rs during a bootstrap of rustc.
context.add_command_line_option("-fno-var-tracking-assignments");
// NOTE: an optimization (https://github.com/rust-lang/rustc_codegen_gcc/issues/53).
context.add_command_line_option("-fno-semantic-interposition");
// NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292).
251 changes: 222 additions & 29 deletions compiler/rustc_codegen_gcc/src/builder.rs

Large diffs are not rendered by default.

82 changes: 78 additions & 4 deletions compiler/rustc_codegen_gcc/src/common.rs
Original file line number Diff line number Diff line change
@@ -121,8 +121,8 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
unimplemented!();
}

fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> {
unimplemented!();
fn const_real(&self, typ: Type<'gcc>, val: f64) -> RValue<'gcc> {
self.context.new_rvalue_from_double(typ, val)
}

fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
@@ -279,6 +279,21 @@ impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
else if self.is_u128(cx) {
cx.i128_type
}
else if self.is_uchar(cx) {
cx.char_type
}
else if self.is_ushort(cx) {
cx.short_type
}
else if self.is_uint(cx) {
cx.int_type
}
else if self.is_ulong(cx) {
cx.long_type
}
else if self.is_ulonglong(cx) {
cx.longlong_type
}
else {
self.clone()
}
@@ -300,6 +315,21 @@ impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
else if self.is_i128(cx) {
cx.u128_type
}
else if self.is_char(cx) {
cx.uchar_type
}
else if self.is_short(cx) {
cx.ushort_type
}
else if self.is_int(cx) {
cx.uint_type
}
else if self.is_long(cx) {
cx.ulong_type
}
else if self.is_longlong(cx) {
cx.ulonglong_type
}
else {
self.clone()
}
@@ -312,6 +342,11 @@ pub trait TypeReflection<'gcc, 'tcx> {
fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;

fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
@@ -326,15 +361,17 @@ pub trait TypeReflection<'gcc, 'tcx> {

fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;

fn is_vector(&self) -> bool;
}

impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.u8_type
self.unqualified() == cx.uchar_type
}

fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.u16_type
self.unqualified() == cx.ushort_type
}

fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
@@ -349,6 +386,26 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
self.unqualified() == cx.ulonglong_type
}

fn is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.char_type
}

fn is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.short_type
}

fn is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.int_type
}

fn is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.long_type
}

fn is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.longlong_type
}

fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.i8_type
}
@@ -396,4 +453,21 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.context.new_type::<f64>()
}

fn is_vector(&self) -> bool {
let mut typ = self.clone();
loop {
if typ.dyncast_vector().is_some() {
return true;
}

let old_type = typ;
typ = typ.unqualified();
if old_type == typ {
break;
}
}

false
}
}
25 changes: 13 additions & 12 deletions compiler/rustc_codegen_gcc/src/consts.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
}
}
}
self.context.new_bitcast(None, value, typ)
// NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some
// SIMD builtins require a constant value.
self.bitcast_if_needed(value, typ)
}
}

@@ -45,7 +47,10 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
}
}
let global_value = self.static_addr_of_mut(cv, align, kind);
// TODO(antoyo): set global constant.
#[cfg(feature = "master")]
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);
global_value
}
@@ -79,20 +84,15 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {

// TODO(antoyo): set alignment.

let value =
if value.get_type() != gcc_type {
self.context.new_bitcast(None, value, gcc_type)
}
else {
value
};
let value = self.bitcast_if_needed(value, gcc_type);
global.global_set_initializer_rvalue(value);

// 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) {
// TODO(antoyo): set global constant.
#[cfg(feature = "master")]
global.global_set_readonly();
}
}

@@ -171,8 +171,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
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.
// TODO(antoyo): set alignment here as well.
let global = self.declare_private_global(&name[..], self.val_ty(cv));

let typ = self.val_ty(cv).get_aligned(align.bytes());
let global = self.declare_private_global(&name[..], typ);
global
}
_ => {
42 changes: 38 additions & 4 deletions compiler/rustc_codegen_gcc/src/context.rs
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
pub normal_function_addresses: RefCell<FxHashSet<RValue<'gcc>>>,

pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
pub intrinsics: RefCell<FxHashMap<String, Function<'gcc>>>,

pub tls_model: gccjit::TlsModel,

@@ -53,10 +54,15 @@ pub struct CodegenCx<'gcc, 'tcx> {
pub u128_type: Type<'gcc>,
pub usize_type: Type<'gcc>,

pub char_type: Type<'gcc>,
pub uchar_type: Type<'gcc>,
pub short_type: Type<'gcc>,
pub ushort_type: Type<'gcc>,
pub int_type: Type<'gcc>,
pub uint_type: Type<'gcc>,
pub long_type: Type<'gcc>,
pub ulong_type: Type<'gcc>,
pub longlong_type: Type<'gcc>,
pub ulonglong_type: Type<'gcc>,
pub sizet_type: Type<'gcc>,

@@ -145,10 +151,15 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
let float_type = context.new_type::<f32>();
let double_type = context.new_type::<f64>();

let char_type = context.new_c_type(CType::Char);
let uchar_type = context.new_c_type(CType::UChar);
let short_type = context.new_c_type(CType::Short);
let ushort_type = context.new_c_type(CType::UShort);
let int_type = context.new_c_type(CType::Int);
let uint_type = context.new_c_type(CType::UInt);
let long_type = context.new_c_type(CType::Long);
let ulong_type = context.new_c_type(CType::ULong);
let longlong_type = context.new_c_type(CType::LongLong);
let ulonglong_type = context.new_c_type(CType::ULongLong);
let sizet_type = context.new_c_type(CType::SizeT);

@@ -184,6 +195,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
current_func: RefCell::new(None),
normal_function_addresses: Default::default(),
functions: RefCell::new(functions),
intrinsics: RefCell::new(FxHashMap::default()),

tls_model,

@@ -200,10 +212,15 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
u32_type,
u64_type,
u128_type,
char_type,
uchar_type,
short_type,
ushort_type,
int_type,
uint_type,
long_type,
ulong_type,
longlong_type,
ulonglong_type,
sizet_type,

@@ -269,16 +286,25 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
}

pub fn is_native_int_type_or_bool(&self, typ: Type<'gcc>) -> bool {
self.is_native_int_type(typ) || typ == self.bool_type
self.is_native_int_type(typ) || typ.is_compatible_with(self.bool_type)
}

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 == 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) -> &Session {
&self.tcx.sess
}

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 {
value
}
}
}

impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
@@ -306,8 +332,16 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}

fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
let func = get_fn(self, instance);
let func = self.rvalue_as_function(func);
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 {
let func = get_fn(self, instance);
self.rvalue_as_function(func)
};
let ptr = func.get_address(None);

// TODO(antoyo): don't do this twice: i.e. in declare_fn and here.
8 changes: 5 additions & 3 deletions compiler/rustc_codegen_gcc/src/declare.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ 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<Symbol>) -> LValue<'gcc> {
if self.globals.borrow().contains_key(name) {
let typ = self.globals.borrow().get(name).expect("global").get_type();
let typ = self.globals.borrow()[name].get_type();
let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
if is_tls {
global.set_tls_model(self.tls_model);
@@ -103,11 +103,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
/// 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> {
if name.starts_with("llvm.") {
return llvm::intrinsic(name, cx);
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().get(name).expect("function")
cx.functions.borrow()[name]
}
else {
let params: Vec<_> = param_types.into_iter().enumerate()
18 changes: 15 additions & 3 deletions compiler/rustc_codegen_gcc/src/int.rs
Original file line number Diff line number Diff line change
@@ -153,8 +153,15 @@ 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) {
if a.get_type() != b.get_type() {
b = self.context.new_cast(None, b, a.get_type());
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(None, b, a.get_type());
}
else {
b = self.context.new_cast(None, b, a.get_type());
}
}
self.context.new_binary_op(None, operation, a_type, a, b)
}
@@ -593,7 +600,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
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_native && b_native {
if a_type.is_vector() && b_type.is_vector() {
self.context.new_binary_op(None, 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);
}
@@ -639,6 +649,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
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.

// TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
self.context.new_bitcast(None, value, dest_typ)
}
}
5,722 changes: 5,722 additions & 0 deletions compiler/rustc_codegen_gcc/src/intrinsic/archs.rs

Large diffs are not rendered by default.

264 changes: 246 additions & 18 deletions compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,250 @@
use gccjit::Function;
use std::borrow::Cow;

use crate::context::CodegenCx;
use gccjit::{Function, FunctionPtrType, RValue, ToRValue};

pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
let _gcc_name =
match name {
"llvm.x86.xgetbv" => {
let gcc_name = "__builtin_trap";
let func = cx.context.get_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
return func;
use crate::{context::CodegenCx, builder::Builder};

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) -> 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 {
"__builtin_ia32_pmuldq512_mask" | "__builtin_ia32_pmuludq512_mask"
// FIXME(antoyo): the following intrinsics has 4 (or 5) arguments according to the doc, but is defined with 2 (or 3) arguments in library/stdarch/crates/core_arch/src/x86/avx512f.rs.
| "__builtin_ia32_pmaxsd512_mask" | "__builtin_ia32_pmaxsq512_mask" | "__builtin_ia32_pmaxsq256_mask"
| "__builtin_ia32_pmaxsq128_mask" | "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask"
| "__builtin_ia32_pmaxud512_mask" | "__builtin_ia32_pmaxuq512_mask" | "__builtin_ia32_pmaxuq256_mask"
| "__builtin_ia32_pmaxuq128_mask"
| "__builtin_ia32_pminsd512_mask" | "__builtin_ia32_pminsq512_mask" | "__builtin_ia32_pminsq256_mask"
| "__builtin_ia32_pminsq128_mask" | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask"
| "__builtin_ia32_pminud512_mask" | "__builtin_ia32_pminuq512_mask" | "__builtin_ia32_pminuq256_mask"
| "__builtin_ia32_pminuq128_mask" | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask"
=> {
// TODO: refactor by separating those intrinsics outside of this branch.
let add_before_last_arg =
match &*func_name {
"__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask"
| "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask"
| "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => true,
_ => false,
};
let new_first_arg_is_zero =
match &*func_name {
"__builtin_ia32_pmaxuq256_mask" | "__builtin_ia32_pmaxuq128_mask"
| "__builtin_ia32_pminuq256_mask" | "__builtin_ia32_pminuq128_mask" => true,
_ => false
};
let arg3_index =
match &*func_name {
"__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => 1,
_ => 2,
};
let mut new_args = args.to_vec();
let arg3_type = gcc_func.get_param_type(arg3_index);
let first_arg =
if new_first_arg_is_zero {
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();
builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units])
}
else {
builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue()
};
if add_before_last_arg {
new_args.insert(new_args.len() - 1, first_arg);
}
else {
new_args.push(first_arg);
}
let arg4_index =
match &*func_name {
"__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => 2,
_ => 3,
};
let arg4_type = gcc_func.get_param_type(arg4_index);
let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
if add_before_last_arg {
new_args.insert(new_args.len() - 1, minus_one);
}
else {
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" => {
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();

let mut last_arg = None;
if args.len() == 4 {
last_arg = new_args.pop();
}

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);

if args.len() == 3 {
// Both llvm.fma.v16f32 and llvm.x86.avx512.vfmadd.ps.512 maps to
// the same GCC intrinsic, but the former has 3 parameters and the
// latter has 4 so it doesn't require this additional argument.
let arg5_type = gcc_func.get_param_type(4);
new_args.push(builder.context.new_rvalue_from_int(arg5_type, 4));
}

if let Some(last_arg) = last_arg {
new_args.push(last_arg);
}

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" => {
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();
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");
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();
},
_ => (),
}
}

args
}

pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool {
// NOTE: these intrinsics have missing parameters before the last one, so ignore the
// last argument type check.
// FIXME(antoyo): find a way to refactor in order to avoid this hack.
match func_name {
"__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" => {
if index == args_len - 1 {
return true;
}
},
// NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
"llvm.x86.sse2.cmp.pd" => "__builtin_ia32_cmppd",
"llvm.x86.sse2.movmsk.pd" => "__builtin_ia32_movmskpd",
"llvm.x86.sse2.pmovmskb.128" => "__builtin_ia32_pmovmskb128",
_ => unimplemented!("unsupported LLVM intrinsic {}", name)
};

unimplemented!();
"__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
// arguments to distinguish those cases.
if args_len == 4 && index == args_len - 1 {
return true;
}
},
_ => (),
}

false
}

#[cfg(not(feature="master"))]
pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
match name {
"llvm.x86.xgetbv" => {
let gcc_name = "__builtin_trap";
let func = cx.context.get_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
return func;
},
_ => unimplemented!("unsupported LLVM intrinsic {}", name),
}
}

#[cfg(feature="master")]
pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
let gcc_name = match name {
"llvm.x86.xgetbv" => "__builtin_ia32_xgetbv",
// NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
"llvm.sqrt.v2f64" => "__builtin_ia32_sqrtpd",
"llvm.x86.avx512.pmul.dq.512" => "__builtin_ia32_pmuldq512_mask",
"llvm.x86.avx512.pmulu.dq.512" => "__builtin_ia32_pmuludq512_mask",
"llvm.x86.avx512.mask.pmaxs.q.256" => "__builtin_ia32_pmaxsq256_mask",
"llvm.x86.avx512.mask.pmaxs.q.128" => "__builtin_ia32_pmaxsq128_mask",
"llvm.x86.avx512.max.ps.512" => "__builtin_ia32_maxps512_mask",
"llvm.x86.avx512.max.pd.512" => "__builtin_ia32_maxpd512_mask",
"llvm.x86.avx512.mask.pmaxu.q.256" => "__builtin_ia32_pmaxuq256_mask",
"llvm.x86.avx512.mask.pmaxu.q.128" => "__builtin_ia32_pmaxuq128_mask",
"llvm.x86.avx512.mask.pmins.q.256" => "__builtin_ia32_pminsq256_mask",
"llvm.x86.avx512.mask.pmins.q.128" => "__builtin_ia32_pminsq128_mask",
"llvm.x86.avx512.min.ps.512" => "__builtin_ia32_minps512_mask",
"llvm.x86.avx512.min.pd.512" => "__builtin_ia32_minpd512_mask",
"llvm.x86.avx512.mask.pminu.q.256" => "__builtin_ia32_pminuq256_mask",
"llvm.x86.avx512.mask.pminu.q.128" => "__builtin_ia32_pminuq128_mask",
"llvm.fma.v16f32" => "__builtin_ia32_vfmaddps512_mask",
"llvm.fma.v8f64" => "__builtin_ia32_vfmaddpd512_mask",
"llvm.x86.avx512.vfmaddsub.ps.512" => "__builtin_ia32_vfmaddsubps512_mask",
"llvm.x86.avx512.vfmaddsub.pd.512" => "__builtin_ia32_vfmaddsubpd512_mask",
"llvm.x86.avx512.pternlog.d.512" => "__builtin_ia32_pternlogd512_mask",
"llvm.x86.avx512.pternlog.d.256" => "__builtin_ia32_pternlogd256_mask",
"llvm.x86.avx512.pternlog.d.128" => "__builtin_ia32_pternlogd128_mask",
"llvm.x86.avx512.pternlog.q.512" => "__builtin_ia32_pternlogq512_mask",
"llvm.x86.avx512.pternlog.q.256" => "__builtin_ia32_pternlogq256_mask",
"llvm.x86.avx512.pternlog.q.128" => "__builtin_ia32_pternlogq128_mask",
"llvm.x86.avx512.add.ps.512" => "__builtin_ia32_addps512_mask",
"llvm.x86.avx512.add.pd.512" => "__builtin_ia32_addpd512_mask",
"llvm.x86.avx512.sub.ps.512" => "__builtin_ia32_subps512_mask",
"llvm.x86.avx512.sub.pd.512" => "__builtin_ia32_subpd512_mask",
"llvm.x86.avx512.mul.ps.512" => "__builtin_ia32_mulps512_mask",
"llvm.x86.avx512.mul.pd.512" => "__builtin_ia32_mulpd512_mask",
"llvm.x86.avx512.div.ps.512" => "__builtin_ia32_divps512_mask",
"llvm.x86.avx512.div.pd.512" => "__builtin_ia32_divpd512_mask",
"llvm.x86.avx512.vfmadd.ps.512" => "__builtin_ia32_vfmaddps512_mask",
"llvm.x86.avx512.vfmadd.pd.512" => "__builtin_ia32_vfmaddpd512_mask",

// The above doc points to unknown builtins for the following, so override them:
"llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gathersiv4si",
"llvm.x86.avx2.gather.d.d.256" => "__builtin_ia32_gathersiv8si",
"llvm.x86.avx2.gather.d.ps" => "__builtin_ia32_gathersiv4sf",
"llvm.x86.avx2.gather.d.ps.256" => "__builtin_ia32_gathersiv8sf",
"llvm.x86.avx2.gather.d.q" => "__builtin_ia32_gathersiv2di",
"llvm.x86.avx2.gather.d.q.256" => "__builtin_ia32_gathersiv4di",
"llvm.x86.avx2.gather.d.pd" => "__builtin_ia32_gathersiv2df",
"llvm.x86.avx2.gather.d.pd.256" => "__builtin_ia32_gathersiv4df",
"llvm.x86.avx2.gather.q.d" => "__builtin_ia32_gatherdiv4si",
"llvm.x86.avx2.gather.q.d.256" => "__builtin_ia32_gatherdiv4si256",
"llvm.x86.avx2.gather.q.ps" => "__builtin_ia32_gatherdiv4sf",
"llvm.x86.avx2.gather.q.ps.256" => "__builtin_ia32_gatherdiv4sf256",
"llvm.x86.avx2.gather.q.q" => "__builtin_ia32_gatherdiv2di",
"llvm.x86.avx2.gather.q.q.256" => "__builtin_ia32_gatherdiv4di",
"llvm.x86.avx2.gather.q.pd" => "__builtin_ia32_gatherdiv2df",
"llvm.x86.avx2.gather.q.pd.256" => "__builtin_ia32_gatherdiv4df",
"" => "",
// NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py
_ => include!("archs.rs"),
};

let func = cx.context.get_target_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
func
}
90 changes: 55 additions & 35 deletions compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
@@ -967,34 +967,55 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
}

fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
let func = self.current_func.borrow().expect("func");

let result_type = lhs.get_type();
if signed {
// Algorithm from: https://stackoverflow.com/a/56531252/389119
let after_block = func.new_block("after");
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);
let result_type = lhs.get_type();
// 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 overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None);
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(None)], None)
}
else {
let func_name =
match width {
128 => "__rust_i128_addo",
_ => unreachable!(),
};
let param_a = self.context.new_parameter(None, result_type, "a");
let param_b = self.context.new_parameter(None, result_type, "b");
let result_field = self.context.new_field(None, result_type, "result");
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
let result = self.context.new_call(None, func, &[lhs, rhs]);
let overflow = result.access_field(None, overflow_field);
let int_result = result.access_field(None, result_field);
self.llbb().add_assignment(None, res, int_result);
overflow
};

let then_block = func.new_block("then");
let after_block = func.new_block("after");

let unsigned_type = self.context.new_int_type(width as i32 / 8, false);
let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1);
let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type,
self.context.new_rvalue_from_int(unsigned_type, 0)
);
let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type);
then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type));
// 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 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);

self.llbb().end_with_conditional(None, overflow, then_block, after_block);
@@ -1007,19 +1028,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
}
else {
// Algorithm from: http://locklessinc.com/articles/sat_arithmetic/
let res = lhs + rhs;
let res_type = res.get_type();
let cond = self.context.new_comparison(None, ComparisonOp::LessThan, res, lhs);
let value = self.context.new_unary_op(None, UnaryOp::Minus, res_type, self.context.new_cast(None, cond, res_type));
res | value
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)
}
}

// 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> {
let result_type = lhs.get_type();
if signed {
// Also based on algorithm from: https://stackoverflow.com/a/56531252/389119
let result_type = lhs.get_type();
// 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 supports_native_type = self.is_native_int_type(result_type);
@@ -1059,6 +1079,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let then_block = func.new_block("then");
let after_block = func.new_block("after");

// 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));
@@ -1076,11 +1097,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
res.to_rvalue()
}
else {
let res = lhs - rhs;
let comparison = self.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs);
let comparison = self.context.new_cast(None, comparison, lhs.get_type());
let unary_op = self.context.new_unary_op(None, UnaryOp::Minus, comparison.get_type(), comparison);
self.and(res, unary_op)
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));
self.gcc_and(res, value)
}
}
}
574 changes: 568 additions & 6 deletions compiler/rustc_codegen_gcc/src/intrinsic/simd.rs

Large diffs are not rendered by default.

19 changes: 17 additions & 2 deletions compiler/rustc_codegen_gcc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -203,7 +203,7 @@ impl WriteBackendMethods for GccCodegenBackend {
fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
// TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
// NOTE: implemented elsewhere.
// TODO: what is implemented elsewhere ^ ?
// TODO(antoyo): what is implemented elsewhere ^ ?
let module =
match modules.remove(0) {
FatLTOInput::InMemory(module) => module,
@@ -301,7 +301,22 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
)
.filter(|_feature| {
// TODO(antoyo): implement a way to get enabled feature in libgccjit.
false
// Probably using the equivalent of __builtin_cpu_supports.
#[cfg(feature="master")]
{
_feature.contains("sse") || _feature.contains("avx")
}
#[cfg(not(feature="master"))]
{
false
}
/*
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512gfni,
avx512ifma, avx512pf, avx512vaes, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpclmulqdq,
avx512vpopcntdq, bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, xsave, xsavec, xsaveopt, xsaves
*/
//false
})
.map(|feature| Symbol::intern(feature))
.collect()
40 changes: 31 additions & 9 deletions compiler/rustc_codegen_gcc/src/type_.rs
Original file line number Diff line number Diff line change
@@ -3,10 +3,11 @@ use std::convert::TryInto;
use gccjit::{RValue, Struct, Type};
use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
use rustc_codegen_ssa::common::TypeKind;
use rustc_middle::bug;
use rustc_middle::{bug, ty};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_target::abi::{AddressSpace, Align, Integer, Size};

use crate::common::TypeReflection;
use crate::context::CodegenCx;
use crate::type_of::LayoutGccExt;

@@ -60,6 +61,17 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
let ity = Integer::approximate_align(self, align);
self.type_from_integer(ity)
}

pub fn type_vector(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> {
self.context.new_vector_type(ty, len)
}

pub fn type_float_from_ty(&self, t: ty::FloatTy) -> Type<'gcc> {
match t {
ty::FloatTy::F32 => self.type_f32(),
ty::FloatTy::F64 => self.type_f64(),
}
}
}

impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
@@ -103,16 +115,19 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
self.context.new_function_pointer_type(None, return_type, params, false)
}

fn type_struct(&self, fields: &[Type<'gcc>], _packed: bool) -> Type<'gcc> {
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();
}
let fields: Vec<_> = fields.iter().enumerate()
.map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index)))
.collect();
// TODO(antoyo): use packed.
let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
if packed {
#[cfg(feature="master")]
typ.set_packed();
}
self.struct_types.borrow_mut().insert(types, typ);
typ
}
@@ -127,7 +142,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
else if typ.is_compatible_with(self.double_type) {
TypeKind::Double
}
else if typ.dyncast_vector().is_some() {
else if typ.is_vector() {
TypeKind::Vector
}
else {
@@ -141,7 +156,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}

fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
// TODO(antoyo): use address_space
// TODO(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE?
ty.make_pointer()
}

@@ -167,10 +182,10 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn float_width(&self, typ: Type<'gcc>) -> usize {
let f32 = self.context.new_type::<f32>();
let f64 = self.context.new_type::<f64>();
if typ == f32 {
if typ.is_compatible_with(f32) {
32
}
else if typ == f64 {
else if typ.is_compatible_with(f64) {
64
}
else {
@@ -197,12 +212,15 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
self.type_array(self.type_from_integer(unit), size / unit_size)
}

pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) {
// TODO(antoyo): use packed.
pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], packed: bool) {
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")]
typ.as_type().set_packed();
}
}

pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
@@ -229,6 +247,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {

self.context.new_array_type(None, ty, len)
}

pub fn type_bool(&self) -> Type<'gcc> {
self.context.new_type::<bool>()
}
}

pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) {
24 changes: 24 additions & 0 deletions compiler/rustc_codegen_gcc/src/type_of.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,30 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
I128 => self.type_u128(),
}
}

#[cfg(feature="master")]
pub fn type_int_from_ty(&self, t: ty::IntTy) -> Type<'gcc> {
match t {
ty::IntTy::Isize => self.type_isize(),
ty::IntTy::I8 => self.type_i8(),
ty::IntTy::I16 => self.type_i16(),
ty::IntTy::I32 => self.type_i32(),
ty::IntTy::I64 => self.type_i64(),
ty::IntTy::I128 => self.type_i128(),
}
}

#[cfg(feature="master")]
pub fn type_uint_from_ty(&self, t: ty::UintTy) -> Type<'gcc> {
match t {
ty::UintTy::Usize => self.type_isize(),
ty::UintTy::U8 => self.type_i8(),
ty::UintTy::U16 => self.type_i16(),
ty::UintTy::U32 => self.type_i32(),
ty::UintTy::U64 => self.type_i64(),
ty::UintTy::U128 => self.type_i128(),
}
}
}

pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> {
225 changes: 131 additions & 94 deletions compiler/rustc_codegen_gcc/test.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash

# TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed?

@@ -14,25 +14,87 @@ fi
export LD_LIBRARY_PATH="$GCC_PATH"
export LIBRARY_PATH="$GCC_PATH"

features=

if [[ "$1" == "--features" ]]; then
shift
features="--features $1"
shift
fi

if [[ "$1" == "--release" ]]; then
flags=
gcc_master_branch=1
channel="debug"
func=all
build_only=0

while [[ $# -gt 0 ]]; do
case $1 in
--release)
codegen_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
;;
--release)
channel="release"
shift
;;
"--test-rustc")
func=test_rustc
shift
;;

"--test-libcore")
func=test_libcore
shift
;;

"--clean-ui-tests")
func=clean_ui_tests
shift
;;

"--std-tests")
func=std_tests
shift
;;

"--extended-tests")
func=extended_sysroot_tests
shift
;;

"--build-sysroot")
func=build_sysroot
shift
;;
"--build")
build_only=1
shift
;;
*)
echo "Unknown option $1"
exit 1
;;
esac
done

if [[ $channel == "release" ]]; then
export CHANNEL='release'
CARGO_INCREMENTAL=1 cargo rustc --release $features
CARGO_INCREMENTAL=1 cargo rustc --release $flags
shift
else
echo $LD_LIBRARY_PATH
export CHANNEL='debug'
cargo rustc $features
cargo rustc $flags
fi

if [[ "$1" == "--build" ]]; then
if (( $build_only == 1 )); then
exit
fi

@@ -78,7 +140,11 @@ function std_tests() {
$RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)

echo "[AOT] std_example"
$RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE
std_flags="--cfg feature=\"master\""
if (( $gcc_master_branch == 0 )); then
std_flags=""
fi
$RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE $std_flags
$RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE

echo "[AOT] subslice-patterns-const-eval"
@@ -97,25 +163,6 @@ function std_tests() {
#echo "[BUILD] sysroot in release mode"
#./build_sysroot/build_sysroot.sh --release

# TODO(antoyo): uncomment when it works.
#pushd simple-raytracer
#if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
#echo "[BENCH COMPILE] ebobby/simple-raytracer"
#hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "rm -r target/*/debug || true" \
#"RUSTFLAGS='' cargo build --target $TARGET_TRIPLE" \
#"../cargo.sh build"

#echo "[BENCH RUN] ebobby/simple-raytracer"
#cp ./target/*/debug/main ./raytracer_cg_gccjit
#hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_gccjit
#else
#echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
#echo "[COMPILE] ebobby/simple-raytracer"
#../cargo.sh build
#echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
#fi
#popd

function test_libcore() {
pushd build_sysroot/sysroot_src/library/core/tests
echo "[TEST] libcore"
@@ -124,19 +171,6 @@ function test_libcore() {
popd
}

# TODO(antoyo): uncomment when it works.
#pushd regex
#echo "[TEST] rust-lang/regex example shootout-regex-dna"
#../cargo.sh clean
## Make sure `[codegen mono items] start` doesn't poison the diff
#../cargo.sh build --example shootout-regex-dna
#cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt
#diff -u res.txt examples/regexdna-output.txt

#echo "[TEST] rust-lang/regex tests"
#../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options
#popd

#echo
#echo "[BENCH COMPILE] mod_bench"

@@ -153,6 +187,44 @@ function test_libcore() {
#echo "[BENCH RUN] mod_bench"
#hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_*

function extended_sysroot_tests() {
if (( $gcc_master_branch == 0 )); then
return
fi

pushd rand
cargo clean
echo "[TEST] rust-random/rand"
../cargo.sh test --workspace
popd

#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

pushd regex
echo "[TEST] rust-lang/regex example shootout-regex-dna"
cargo clean
export CG_RUSTFLAGS="--cap-lints warn" # newer aho_corasick versions throw a deprecation warning
# Make sure `[codegen mono items] start` doesn't poison the diff
../cargo.sh build --example shootout-regex-dna
cat examples/regexdna-input.txt \
| ../cargo.sh run --example shootout-regex-dna \
| grep -v "Spawned thread" > res.txt
diff -u res.txt examples/regexdna-output.txt

echo "[TEST] rust-lang/regex tests"
../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
popd
}

function test_rustc() {
echo
echo "[TEST] rust-lang/rust"
@@ -165,23 +237,7 @@ function test_rustc() {
git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(')
export RUSTFLAGS=

git apply - <<EOF
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 887d27fd6dca4..2c2239f2b83d1 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
cfg: Option<&str>,
) -> test::TestDesc {
let mut ignore = false;
#[cfg(not(bootstrap))]
- let ignore_message: Option<String> = None;
+ let ignore_message: Option<&str> = None;
let mut should_fail = false;
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
EOF
git apply ../rustc_patches/compile_test.patch || true

rm config.toml || true

@@ -205,7 +261,7 @@ EOF

git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed

rm -r src/test/ui/{abi*,extern/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,simd*,borrowck/,test*,*lto*.rs} || true
rm -r src/test/ui/{abi*,extern/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,test*,*lto*.rs} || true
for test in $(rg --files-with-matches "catch_unwind|should_panic|thread|lto" src/test/ui); do
rm $test
done
@@ -222,33 +278,14 @@ function clean_ui_tests() {
find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -exec rm -rf {} \;
}

case $1 in
"--test-rustc")
test_rustc
;;

"--test-libcore")
test_libcore
;;

"--clean-ui-tests")
clean_ui_tests
;;

"--std-tests")
std_tests
;;

"--build-sysroot")
build_sysroot
;;

*)
clean
mini_tests
build_sysroot
std_tests
test_libcore
test_rustc
;;
esac
function all() {
clean
mini_tests
build_sysroot
std_tests
test_libcore
extended_sysroot_tests
test_rustc
}

$func
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! The common code for `tests/lang_tests_*.rs`
use std::{
env::{self, current_dir},
path::PathBuf,
@@ -7,7 +8,15 @@ use std::{
use lang_tester::LangTester;
use tempfile::TempDir;

fn main() {
/// Controls the compile options (e.g., optimization level) used to compile
/// test code.
#[allow(dead_code)] // Each test crate picks one variant
pub enum Profile {
Debug,
Release,
}

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();
@@ -42,6 +51,15 @@ fn main() {
"-o", exe.to_str().expect("to_str"),
path.to_str().expect("to_str"),
]);
match profile {
Profile::Debug => {}
Profile::Release => {
compiler.args(&[
"-C", "opt-level=3",
"-C", "lto=no",
]);
}
}
// Test command 2: run `tempdir/x`.
let runtime = Command::new(exe);
vec![("Compiler", compiler), ("Run-time", runtime)]
5 changes: 5 additions & 0 deletions compiler/rustc_codegen_gcc/tests/lang_tests_debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod lang_tests_common;

fn main() {
lang_tests_common::main_inner(lang_tests_common::Profile::Debug);
}
5 changes: 5 additions & 0 deletions compiler/rustc_codegen_gcc/tests/lang_tests_release.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod lang_tests_common;

fn main() {
lang_tests_common::main_inner(lang_tests_common::Profile::Release);
}
451 changes: 319 additions & 132 deletions compiler/rustc_codegen_gcc/tests/run/int.rs

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Compiler:
//
// Run-time:
// stdout: Panicking
// stdout: Success
// status: signal

#![allow(unused_attributes)]
@@ -64,7 +64,9 @@ mod intrinsics {
#[no_mangle]
pub fn panic(_msg: &str) -> ! {
unsafe {
libc::puts("Panicking\0" as *const str as *const u8);
// Panicking is expected iff overflow checking is enabled.
#[cfg(debug_assertions)]
libc::puts("Success\0" as *const str as *const u8);
libc::fflush(libc::stdout);
intrinsics::abort();
}
@@ -124,6 +126,15 @@ impl Add for isize {
#[start]
fn main(mut argc: isize, _argv: *const *const u8) -> isize {
let int = 9223372036854775807isize;
let int = int + argc;
let int = int + argc; // overflow

// If overflow checking is disabled, we should reach here.
#[cfg(not(debug_assertions))]
unsafe {
libc::puts("Success\0" as *const str as *const u8);
libc::fflush(libc::stdout);
intrinsics::abort();
}

int
}
238 changes: 238 additions & 0 deletions compiler/rustc_codegen_gcc/tools/generate_intrinsics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import json
import os
import re
import sys
import subprocess
from os import walk


def run_command(command, cwd=None):
p = subprocess.Popen(command, cwd=cwd)
if p.wait() != 0:
print("command `{}` failed...".format(" ".join(command)))
sys.exit(1)


def clone_repository(repo_name, path, repo_url, sub_path=None):
if os.path.exists(path):
while True:
choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path))
if choice == "" or choice.lower() == "n":
print("Skipping repository update.")
return
elif choice.lower() == "y":
print("Updating repository...")
run_command(["git", "pull", "origin"], cwd=path)
return
else:
print("Didn't understand answer...")
print("Cloning {} repository...".format(repo_name))
if sub_path is None:
run_command(["git", "clone", repo_url, "--depth", "1", path])
else:
run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path])
run_command(["git", "sparse-checkout", "init"], cwd=path)
run_command(["git", "sparse-checkout", "set", "add", sub_path], cwd=path)
run_command(["git", "checkout"], cwd=path)


def append_intrinsic(array, intrinsic_name, translation):
array.append((intrinsic_name, translation))


def extract_instrinsics(intrinsics, file):
print("Extracting intrinsics from `{}`...".format(file))
with open(file, "r", encoding="utf8") as f:
content = f.read()

lines = content.splitlines()
pos = 0
current_arch = None
while pos < len(lines):
line = lines[pos].strip()
if line.startswith("let TargetPrefix ="):
current_arch = line.split('"')[1].strip()
if len(current_arch) == 0:
current_arch = None
elif current_arch is None:
pass
elif line == "}":
current_arch = None
elif line.startswith("def "):
content = ""
while not content.endswith(";") and not content.endswith("}") and pos < len(lines):
line = lines[pos].split(" // ")[0].strip()
content += line
pos += 1
entries = re.findall('GCCBuiltin<"(\\w+)">', content)
if len(entries) > 0:
intrinsic = content.split("def ")[1].strip().split(":")[0].strip()
intrinsic = intrinsic.split("_")
if len(intrinsic) < 2 or intrinsic[0] != "int":
continue
intrinsic[0] = "llvm"
intrinsic = ".".join(intrinsic)
if current_arch not in intrinsics:
intrinsics[current_arch] = []
for entry in entries:
append_intrinsic(intrinsics[current_arch], intrinsic, entry)
continue
pos += 1
continue
print("Done!")


def extract_instrinsics_from_llvm(llvm_path, intrinsics):
files = []
intrinsics_path = os.path.join(llvm_path, "llvm/include/llvm/IR")
for (dirpath, dirnames, filenames) in walk(intrinsics_path):
files.extend([os.path.join(intrinsics_path, f) for f in filenames if f.endswith(".td")])

for file in files:
extract_instrinsics(intrinsics, file)


def append_translation(json_data, p, array):
it = json_data["index"][p]
content = it["docs"].split('`')
if len(content) != 5:
return
append_intrinsic(array, content[1], content[3])


def extract_instrinsics_from_llvmint(llvmint, intrinsics):
archs = [
"AMDGPU",
"aarch64",
"arm",
"cuda",
"hexagon",
"mips",
"nvvm",
"ppc",
"ptx",
"x86",
"xcore",
]

json_file = os.path.join(llvmint, "target/doc/llvmint.json")
# We need to regenerate the documentation!
run_command(
["cargo", "rustdoc", "--", "-Zunstable-options", "--output-format", "json"],
cwd=llvmint,
)
with open(json_file, "r", encoding="utf8") as f:
json_data = json.loads(f.read())
for p in json_data["paths"]:
it = json_data["paths"][p]
if it["crate_id"] != 0:
# This is from an external crate.
continue
if it["kind"] != "function":
# We're only looking for functions.
continue
# if len(it["path"]) == 2:
# # This is a "general" intrinsic, not bound to a specific arch.
# append_translation(json_data, p, general)
# continue
if len(it["path"]) != 3 or it["path"][1] not in archs:
continue
arch = it["path"][1]
if arch not in intrinsics:
intrinsics[arch] = []
append_translation(json_data, p, intrinsics[arch])


def fill_intrinsics(intrinsics, from_intrinsics, all_intrinsics):
for arch in from_intrinsics:
if arch not in intrinsics:
intrinsics[arch] = []
for entry in from_intrinsics[arch]:
if entry[0] in all_intrinsics:
if all_intrinsics[entry[0]] == entry[1]:
# This is a "full" duplicate, both the LLVM instruction and the GCC
# translation are the same.
continue
intrinsics[arch].append((entry[0], entry[1], True))
else:
intrinsics[arch].append((entry[0], entry[1], False))
all_intrinsics[entry[0]] = entry[1]


def update_intrinsics(llvm_path, llvmint, llvmint2):
intrinsics_llvm = {}
intrinsics_llvmint = {}
all_intrinsics = {}

extract_instrinsics_from_llvm(llvm_path, intrinsics_llvm)
extract_instrinsics_from_llvmint(llvmint, intrinsics_llvmint)
extract_instrinsics_from_llvmint(llvmint2, intrinsics_llvmint)

intrinsics = {}
# We give priority to translations from LLVM over the ones from llvmint.
fill_intrinsics(intrinsics, intrinsics_llvm, all_intrinsics)
fill_intrinsics(intrinsics, intrinsics_llvmint, all_intrinsics)

archs = [arch for arch in intrinsics]
archs.sort()

output_file = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"../src/intrinsic/archs.rs",
)
print("Updating content of `{}`...".format(output_file))
with open(output_file, "w", encoding="utf8") as out:
out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
out.write("// DO NOT EDIT IT!\n")
out.write("match name {\n")
for arch in archs:
if len(intrinsics[arch]) == 0:
continue
intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
out.write(' // {}\n'.format(arch))
for entry in intrinsics[arch]:
if entry[2] == True: # if it is a duplicate
out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1]))
else:
out.write(' "{}" => "{}",\n'.format(entry[0], entry[1]))
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
out.write("}\n")
print("Done!")


def main():
llvm_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"llvm-project",
)
llvmint_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"llvmint",
)
llvmint2_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"llvmint-2",
)

# First, we clone the LLVM repository if it's not already here.
clone_repository(
"llvm-project",
llvm_path,
"https://github.com/llvm/llvm-project",
sub_path="llvm/include/llvm/IR",
)
clone_repository(
"llvmint",
llvmint_path,
"https://github.com/GuillaumeGomez/llvmint",
)
clone_repository(
"llvmint2",
llvmint2_path,
"https://github.com/antoyo/llvmint",
)
update_intrinsics(llvm_path, llvmint_path, llvmint2_path)


if __name__ == "__main__":
sys.exit(main())