Rollup merge of #152622 - GuillaumeGomez:subtree-update_cg_gcc_2026-02-14, r=GuillaumeGomez

Update GCC subtree

cc @antoyo
r? ghost
This commit is contained in:
Jonathan Brouwer 2026-02-14 22:11:52 +01:00 committed by GitHub
commit 0318407e30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 1790 additions and 1641 deletions

View file

@ -18,6 +18,7 @@
], ],
"ignorePaths": [ "ignorePaths": [
"src/intrinsic/archs.rs", "src/intrinsic/archs.rs",
"src/intrinsic/old_archs.rs",
"src/intrinsic/llvm.rs" "src/intrinsic/llvm.rs"
], ],
"ignoreRegExpList": [ "ignoreRegExpList": [

View file

@ -113,6 +113,10 @@ jobs:
git config --global user.name "User" git config --global user.name "User"
./y.sh prepare ./y.sh prepare
- name: Add more failing tests for GCC without 128-bit integers support
if: ${{ matrix.libgccjit_version.gcc == 'gcc-15-without-int128.deb' }}
run: cat tests/failing-ui-tests-without-128bit-integers.txt >> tests/failing-ui-tests.txt
- name: Run tests - name: Run tests
run: | run: |
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}

View file

@ -83,7 +83,7 @@ jobs:
run: | run: |
./y.sh prepare --only-libcore --cross ./y.sh prepare --only-libcore --cross
./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build -Zjson-target-spec --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
./y.sh clean all ./y.sh clean all
- name: Build - name: Build

View file

@ -56,18 +56,18 @@ dependencies = [
[[package]] [[package]]
name = "gccjit" name = "gccjit"
version = "3.1.1" version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff80f4d6d0749eab3a69122210b3a1fdd52edb6162781aadd7c4842e26983683" checksum = "26b73d18b642ce16378af78f89664841d7eeafa113682ff5d14573424eb0232a"
dependencies = [ dependencies = [
"gccjit_sys", "gccjit_sys",
] ]
[[package]] [[package]]
name = "gccjit_sys" name = "gccjit_sys"
version = "1.1.2" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f81d901767ddba371a619fa9bba657066a4d3c5607ee69bbb557c1c5ba9bf85" checksum = "ee689456c013616942d5aef9a84d613cefcc3b335340d036f3650fc1a7459e15"
dependencies = [ dependencies = [
"libc", "libc",
] ]

View file

@ -24,7 +24,7 @@ default = ["master"]
[dependencies] [dependencies]
object = { version = "0.37.0", default-features = false, features = ["std", "read"] } object = { version = "0.37.0", default-features = false, features = ["std", "read"] }
tempfile = "3.20" tempfile = "3.20"
gccjit = { version = "3.1.1", features = ["dlopen"] } gccjit = { version = "3.3.0", features = ["dlopen"] }
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs", branch = "error-dlopen", features = ["dlopen"] } #gccjit = { git = "https://github.com/rust-lang/gccjit.rs", branch = "error-dlopen", features = ["dlopen"] }
# Local copy. # Local copy.

View file

@ -45,12 +45,12 @@ The default configuration (see below in the [Quick start](#quick-start) section)
./y.sh test --release ./y.sh test --release
``` ```
If don't need to test GCC patches you wrote in our GCC fork, then the default configuration should If you don't need to test GCC patches you wrote in our GCC fork, then the default configuration should
be all you need. You can update the `rustc_codegen_gcc` without worrying about GCC. be all you need. You can update the `rustc_codegen_gcc` without worrying about GCC.
### Building with your own GCC version ### Building with your own GCC version
If you wrote a patch for GCC and want to test it without this backend, you will need If you wrote a patch for GCC and want to test it with this backend, you will need
to do a few more things. to do a few more things.
To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue): To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue):
@ -127,7 +127,7 @@ You have to run these commands, in the corresponding order:
$ ./y.sh prepare $ ./y.sh prepare
$ ./y.sh build --sysroot $ ./y.sh build --sysroot
``` ```
To check if all is working correctly, run: To check if all is working correctly, run:
```bash ```bash
$ ./y.sh cargo build --manifest-path tests/hello-world/Cargo.toml $ ./y.sh cargo build --manifest-path tests/hello-world/Cargo.toml

View file

@ -6,4 +6,4 @@ seh = "seh"
typ = "typ" typ = "typ"
[files] [files]
extend-exclude = ["src/intrinsic/archs.rs"] extend-exclude = ["src/intrinsic/archs.rs", "src/intrinsic/old_archs.rs"]

View file

@ -141,6 +141,10 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
} }
let mut args: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"build", &"--target", &config.target]; let mut args: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"build", &"--target", &config.target];
if config.target.ends_with(".json") {
args.push(&"-Zjson-target-spec");
}
for feature in &config.features { for feature in &config.features {
args.push(&"--features"); args.push(&"--features");
args.push(feature); args.push(feature);

View file

@ -679,10 +679,10 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
create_dir(projects_path)?; create_dir(projects_path)?;
let nb_parts = args.nb_parts.unwrap_or(0); let nb_parts = args.nb_parts.unwrap_or(0);
if nb_parts > 0 { if let Some(count) = projects.len().checked_div(nb_parts) {
// We increment the number of tests by one because if this is an odd number, we would skip // We increment the number of tests by one because if this is an odd number, we would skip
// one test. // one test.
let count = projects.len() / nb_parts + 1; let count = count + 1;
let current_part = args.current_part.unwrap(); let current_part = args.current_part.unwrap();
let start = current_part * count; let start = current_part * count;
// We remove the projects we don't want to test. // We remove the projects we don't want to test.

View file

@ -2,9 +2,9 @@
## How to debug GCC LTO ## How to debug GCC LTO
Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. Run the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger.
## How to debug stdarch tests that cannot be ran locally ## How to debug stdarch tests that cannot be run locally
First, run the tests normally: First, run the tests normally:

View file

@ -15,7 +15,7 @@ That can be caused by the fact that you try to compile with `lto = "fat"`, but y
### ld: cannot find crtbegin.o ### ld: cannot find crtbegin.o
When compiling an executable with libgccijt, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors: When compiling an executable with libgccjit, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors:
``` ```
ld: cannot find crtbegin.o: No such file or directory ld: cannot find crtbegin.o: No such file or directory

View file

@ -3,7 +3,7 @@
You can see the full documentation about what GIMPLE is [here](https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html). In this document we will explain how to generate it. You can see the full documentation about what GIMPLE is [here](https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html). In this document we will explain how to generate it.
First, we'll copy the content from `gcc/gcc/testsuite/jit.dg/test-const-attribute.c` into a First, we'll copy the content from `gcc/gcc/testsuite/jit.dg/test-const-attribute.c` into a
file named `local.c` and remove the content we're not interested into: file named `local.c` and remove the content we're not interested in:
```diff ```diff
- /* { dg-do compile { target x86_64-*-* } } */ - /* { dg-do compile { target x86_64-*-* } } */

View file

@ -53,7 +53,7 @@ If you wish to build a custom sysroot, pass the path of your sysroot source to `
### How to use [mem-trace](https://github.com/antoyo/mem-trace) ### How to use [mem-trace](https://github.com/antoyo/mem-trace)
`rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. `rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't have a chance to intercept the calls to `malloc`.
### How to generate GIMPLE ### How to generate GIMPLE

View file

@ -1 +1 @@
0081ca6631abdfa02bf42bc85aaf507b8a0e6beb efdd0a7290c22f5438d7c5380105d353ee3e8518

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2025-12-20" channel = "nightly-2026-02-14"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"] components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -575,9 +575,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
} }
if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) { if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) {
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
let builtin_unreachable: RValue<'gcc> = self.llbb().add_eval(None, self.context.new_call(None, builtin_unreachable, &[]));
unsafe { std::mem::transmute(builtin_unreachable) };
self.call(self.type_void(), None, None, builtin_unreachable, &[], None, None);
} }
// Write results to outputs. // Write results to outputs.

View file

@ -1495,6 +1495,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
#[cfg(not(feature = "master"))] #[cfg(not(feature = "master"))]
fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> { fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> {
use crate::context::new_array_type;
let vector_type = vec let vector_type = vec
.get_type() .get_type()
.unqualified() .unqualified()
@ -1503,7 +1505,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let element_type = vector_type.get_element_type(); let element_type = vector_type.get_element_type();
let vec_num_units = vector_type.get_num_units(); let vec_num_units = vector_type.get_num_units();
let array_type = let array_type =
self.context.new_array_type(self.location, element_type, vec_num_units as u64); new_array_type(self.context, self.location, element_type, vec_num_units as u64);
let array = self.context.new_bitcast(self.location, vec, array_type).to_rvalue(); let array = self.context.new_bitcast(self.location, vec, array_type).to_rvalue();
self.context.new_array_access(self.location, array, idx).to_rvalue() self.context.new_array_access(self.location, array, idx).to_rvalue()
} }
@ -1871,32 +1873,31 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
// On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
// we're rounding towards zero, we just get float_ty::MAX (which is always an integer). // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
// This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
let int_max = |signed: bool, int_width: u64| -> u128 { fn int_max(signed: bool, int_width: u64) -> u128 {
let shift_amount = 128 - int_width; let shift_amount = 128 - int_width;
if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount } if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
}; }
let int_min = |signed: bool, int_width: u64| -> i128 { fn int_min(signed: bool, int_width: u64) -> i128 {
if signed { i128::MIN >> (128 - int_width) } else { 0 } if signed { i128::MIN >> (128 - int_width) } else { 0 }
}; }
let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) { // TODO: rewrite using a generic function with <F: Float>.
let compute_clamp_bounds_half = |signed: bool, int_width: u64| -> (u128, u128) {
let rounded_min = let rounded_min =
ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero); ieee::Half::from_i128_r(int_min(signed, int_width), Round::TowardZero);
assert_eq!(rounded_min.status, Status::OK); //assert_eq!(rounded_min.status, Status::OK);
let rounded_max = let rounded_max =
ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero); ieee::Half::from_u128_r(int_max(signed, int_width), Round::TowardZero);
assert!(rounded_max.value.is_finite()); assert!(rounded_max.value.is_finite());
(rounded_min.value.to_bits(), rounded_max.value.to_bits()) (rounded_min.value.to_bits(), rounded_max.value.to_bits())
}; };
let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) { fn compute_clamp_bounds<F: Float>(signed: bool, int_width: u64) -> (u128, u128) {
let rounded_min = let rounded_min = F::from_i128_r(int_min(signed, int_width), Round::TowardZero);
ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
assert_eq!(rounded_min.status, Status::OK); assert_eq!(rounded_min.status, Status::OK);
let rounded_max = let rounded_max = F::from_u128_r(int_max(signed, int_width), Round::TowardZero);
ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
assert!(rounded_max.value.is_finite()); assert!(rounded_max.value.is_finite());
(rounded_min.value.to_bits(), rounded_max.value.to_bits()) (rounded_min.value.to_bits(), rounded_max.value.to_bits())
}; }
// To implement saturation, we perform the following steps: // To implement saturation, we perform the following steps:
// //
// 1. Cast val to an integer with fpto[su]i. This may result in undef. // 1. Cast val to an integer with fpto[su]i. This may result in undef.
@ -1926,15 +1927,19 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let float_bits_to_llval = |bx: &mut Self, bits| { let float_bits_to_llval = |bx: &mut Self, bits| {
let bits_llval = match float_width { let bits_llval = match float_width {
16 => bx.cx().const_u16(bits as u16),
32 => bx.cx().const_u32(bits as u32), 32 => bx.cx().const_u32(bits as u32),
64 => bx.cx().const_u64(bits as u64), 64 => bx.cx().const_u64(bits as u64),
128 => bx.cx().const_u128(bits),
n => bug!("unsupported float width {}", n), n => bug!("unsupported float width {}", n),
}; };
bx.bitcast(bits_llval, float_ty) bx.bitcast(bits_llval, float_ty)
}; };
let (f_min, f_max) = match float_width { let (f_min, f_max) = match float_width {
32 => compute_clamp_bounds_single(signed, int_width), 16 => compute_clamp_bounds_half(signed, int_width),
64 => compute_clamp_bounds_double(signed, int_width), 32 => compute_clamp_bounds::<ieee::Single>(signed, int_width),
64 => compute_clamp_bounds::<ieee::Double>(signed, int_width),
128 => compute_clamp_bounds::<ieee::Quad>(signed, int_width),
n => bug!("unsupported float width {}", n), n => bug!("unsupported float width {}", n),
}; };
let f_min = float_bits_to_llval(self, f_min); let f_min = float_bits_to_llval(self, f_min);

View file

@ -8,7 +8,7 @@ use rustc_middle::mir::Mutability;
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use crate::context::CodegenCx; use crate::context::{CodegenCx, new_array_type};
use crate::type_of::LayoutGccExt; use crate::type_of::LayoutGccExt;
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@ -20,6 +20,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
bytes_in_context(self, bytes) bytes_in_context(self, bytes)
} }
pub fn const_u16(&self, i: u16) -> RValue<'gcc> {
self.const_uint(self.type_u16(), i as u64)
}
fn global_string(&self, string: &str) -> LValue<'gcc> { fn global_string(&self, string: &str) -> LValue<'gcc> {
// TODO(antoyo): handle non-null-terminated strings. // TODO(antoyo): handle non-null-terminated strings.
let string = self.context.new_string_literal(string); let string = self.context.new_string_literal(string);
@ -55,7 +59,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
0 => { 0 => {
let context = &cx.context; let context = &cx.context;
let byte_type = context.new_type::<u64>(); let byte_type = context.new_type::<u64>();
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 8); let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 8);
let elements: Vec<_> = bytes let elements: Vec<_> = bytes
.chunks_exact(8) .chunks_exact(8)
.map(|arr| { .map(|arr| {
@ -76,7 +80,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
4 => { 4 => {
let context = &cx.context; let context = &cx.context;
let byte_type = context.new_type::<u32>(); let byte_type = context.new_type::<u32>();
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 4); let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 4);
let elements: Vec<_> = bytes let elements: Vec<_> = bytes
.chunks_exact(4) .chunks_exact(4)
.map(|arr| { .map(|arr| {
@ -95,7 +99,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
_ => { _ => {
let context = cx.context; let context = cx.context;
let byte_type = context.new_type::<u8>(); let byte_type = context.new_type::<u8>();
let typ = context.new_array_type(None, byte_type, bytes.len() as u64); let typ = new_array_type(context, None, byte_type, bytes.len() as u64);
let elements: Vec<_> = bytes let elements: Vec<_> = bytes
.iter() .iter()
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))

View file

@ -19,6 +19,8 @@ use rustc_middle::ty::layout::{
}; };
use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt}; use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
use rustc_session::Session; use rustc_session::Session;
#[cfg(feature = "master")]
use rustc_session::config::DebugInfo;
use rustc_span::source_map::respan; use rustc_span::source_map::respan;
use rustc_span::{DUMMY_SP, Span}; use rustc_span::{DUMMY_SP, Span};
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi}; use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi};
@ -145,6 +147,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
supports_f64_type: bool, supports_f64_type: bool,
supports_f128_type: bool, supports_f128_type: bool,
) -> Self { ) -> Self {
#[cfg(feature = "master")]
if tcx.sess.opts.debuginfo != DebugInfo::None {
context.set_filename(codegen_unit.name().as_str());
}
let create_type = |ctype, rust_type| { let create_type = |ctype, rust_type| {
let layout = tcx let layout = tcx
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type)) .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type))
@ -194,8 +201,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
// TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in // TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in
// gcc_jit_context_new_array_constructor (it should not use reinterpret_cast). // gcc_jit_context_new_array_constructor (it should not use reinterpret_cast).
let i128_type = context.new_array_type(None, i64_type, 2)/*.get_aligned(i128_align)*/; let i128_type = new_array_type(context, None, i64_type, 2)/*.get_aligned(i128_align)*/;
let u128_type = context.new_array_type(None, u64_type, 2)/*.get_aligned(u128_align)*/; let u128_type = new_array_type(context, None, u64_type, 2)/*.get_aligned(u128_align)*/;
(i128_type, u128_type) (i128_type, u128_type)
}; };
@ -601,3 +608,17 @@ fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
TlsModel::Emulated => gccjit::TlsModel::GlobalDynamic, TlsModel::Emulated => gccjit::TlsModel::GlobalDynamic,
} }
} }
pub fn new_array_type<'gcc>(
context: &'gcc Context<'gcc>,
location: Option<Location<'gcc>>,
typ: Type<'gcc>,
size: u64,
) -> Type<'gcc> {
#[cfg(feature = "master")]
{
context.new_array_type_u64(location, typ, size)
}
#[cfg(not(feature = "master"))]
context.new_array_type(location, typ, size)
}

View file

@ -942,7 +942,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
fn float_to_int_cast( fn float_to_int_cast(
&self, &self,
signed: bool, signed: bool,
value: RValue<'gcc>, mut value: RValue<'gcc>,
dest_typ: Type<'gcc>, dest_typ: Type<'gcc>,
) -> RValue<'gcc> { ) -> RValue<'gcc> {
let value_type = value.get_type(); let value_type = value.get_type();
@ -951,16 +951,22 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
} }
debug_assert!(dest_typ.dyncast_array().is_some()); debug_assert!(dest_typ.dyncast_array().is_some());
let (dest_type, param_type) = match self.type_kind(value_type) {
TypeKind::Half => (Some(self.float_type), self.float_type),
_ => (None, value_type),
};
let name_suffix = match self.type_kind(value_type) { let name_suffix = match self.type_kind(value_type) {
// cSpell:disable // cSpell:disable
TypeKind::Float => "sfti", // Since we will cast Half to a float, we use sfti for both.
TypeKind::Half | TypeKind::Float => "sfti",
TypeKind::Double => "dfti", TypeKind::Double => "dfti",
TypeKind::FP128 => "tfti",
// cSpell:enable // cSpell:enable
kind => panic!("cannot cast a {:?} to non-native integer", kind), kind => panic!("cannot cast a {:?} to non-native integer", kind),
}; };
let sign = if signed { "" } else { "uns" }; let sign = if signed { "" } else { "uns" };
let func_name = format!("__fix{}{}", sign, name_suffix); let func_name = format!("__fix{}{}", sign, name_suffix);
let param = self.context.new_parameter(None, value_type, "n"); let param = self.context.new_parameter(None, param_type, "n");
let func = self.context.new_function( let func = self.context.new_function(
None, None,
FunctionType::Extern, FunctionType::Extern,
@ -969,6 +975,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
func_name, func_name,
false, false,
); );
if let Some(dest_type) = dest_type {
value = self.context.new_cast(None, value, dest_type);
}
self.context.new_call(None, func, &[value]) self.context.new_call(None, func, &[value])
} }

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ use gccjit::{CType, Context, Field, Function, FunctionPtrType, RValue, ToRValue,
use rustc_codegen_ssa::traits::BuilderMethods; use rustc_codegen_ssa::traits::BuilderMethods;
use crate::builder::Builder; use crate::builder::Builder;
use crate::context::CodegenCx; use crate::context::{CodegenCx, new_array_type};
fn encode_key_128_type<'a, 'gcc, 'tcx>( fn encode_key_128_type<'a, 'gcc, 'tcx>(
builder: &Builder<'a, 'gcc, 'tcx>, builder: &Builder<'a, 'gcc, 'tcx>,
@ -585,7 +585,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
"__builtin_ia32_encodekey128_u32" => { "__builtin_ia32_encodekey128_u32" => {
let mut new_args = args.to_vec(); let mut new_args = args.to_vec();
let m128i = builder.context.new_vector_type(builder.i64_type, 2); let m128i = builder.context.new_vector_type(builder.i64_type, 2);
let array_type = builder.context.new_array_type(None, m128i, 6); let array_type = new_array_type(builder.context, None, m128i, 6);
let result = builder.current_func().new_local(None, array_type, "result"); let result = builder.current_func().new_local(None, array_type, "result");
new_args.push(result.get_address(None)); new_args.push(result.get_address(None));
args = new_args.into(); args = new_args.into();
@ -593,7 +593,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
"__builtin_ia32_encodekey256_u32" => { "__builtin_ia32_encodekey256_u32" => {
let mut new_args = args.to_vec(); let mut new_args = args.to_vec();
let m128i = builder.context.new_vector_type(builder.i64_type, 2); let m128i = builder.context.new_vector_type(builder.i64_type, 2);
let array_type = builder.context.new_array_type(None, m128i, 7); let array_type = new_array_type(builder.context, None, m128i, 7);
let result = builder.current_func().new_local(None, array_type, "result"); let result = builder.current_func().new_local(None, array_type, "result");
new_args.push(result.get_address(None)); new_args.push(result.get_address(None));
args = new_args.into(); args = new_args.into();
@ -620,7 +620,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
let first_value = old_args.swap_remove(0); let first_value = old_args.swap_remove(0);
let element_type = first_value.get_type(); let element_type = first_value.get_type();
let array_type = builder.context.new_array_type(None, element_type, 8); let array_type = new_array_type(builder.context, None, element_type, 8);
let result = builder.current_func().new_local(None, array_type, "result"); let result = builder.current_func().new_local(None, array_type, "result");
new_args.push(result.get_address(None)); new_args.push(result.get_address(None));
@ -869,7 +869,7 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
builder.llbb().add_assignment(None, field1, return_value); builder.llbb().add_assignment(None, field1, return_value);
let field2 = result.access_field(None, field2); let field2 = result.access_field(None, field2);
let field2_type = field2.to_rvalue().get_type(); let field2_type = field2.to_rvalue().get_type();
let array_type = builder.context.new_array_type(None, field2_type, 6); let array_type = new_array_type(builder.context, None, field2_type, 6);
let ptr = builder.context.new_cast(None, args[2], array_type.make_pointer()); let ptr = builder.context.new_cast(None, args[2], array_type.make_pointer());
let field2_ptr = let field2_ptr =
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer()); builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
@ -891,7 +891,7 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
builder.llbb().add_assignment(None, field1, return_value); builder.llbb().add_assignment(None, field1, return_value);
let field2 = result.access_field(None, field2); let field2 = result.access_field(None, field2);
let field2_type = field2.to_rvalue().get_type(); let field2_type = field2.to_rvalue().get_type();
let array_type = builder.context.new_array_type(None, field2_type, 7); let array_type = new_array_type(builder.context, None, field2_type, 7);
let ptr = builder.context.new_cast(None, args[3], array_type.make_pointer()); let ptr = builder.context.new_cast(None, args[3], array_type.make_pointer());
let field2_ptr = let field2_ptr =
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer()); builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
@ -937,7 +937,7 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
builder.llbb().add_assignment(None, field1, return_value); builder.llbb().add_assignment(None, field1, return_value);
let field2 = result.access_field(None, field2); let field2 = result.access_field(None, field2);
let field2_type = field2.to_rvalue().get_type(); let field2_type = field2.to_rvalue().get_type();
let array_type = builder.context.new_array_type(None, field2_type, 8); let array_type = new_array_type(builder.context, None, field2_type, 8);
let ptr = builder.context.new_cast(None, args[0], array_type.make_pointer()); let ptr = builder.context.new_cast(None, args[0], array_type.make_pointer());
let field2_ptr = let field2_ptr =
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer()); builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
@ -1061,7 +1061,18 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
"llvm.x86.xgetbv" => "__builtin_ia32_xgetbv", "llvm.x86.xgetbv" => "__builtin_ia32_xgetbv",
// NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
// FIXME: Should handle other targets than `ia32`.
"llvm.sqrt.v2f64" => "__builtin_ia32_sqrtpd", "llvm.sqrt.v2f64" => "__builtin_ia32_sqrtpd",
// FIXME: Should handle other targets than `ia32`.
"llvm.sqrt.v4f32" => "__builtin_ia32_sqrtps",
"llvm.sqrt.f32" => {
let gcc_name = "__builtin_sqrtf";
let func = cx.context.get_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
return func;
}
// FIXME: Should handle other targets than `ia32`.
"llvm.smax.v4i32" => "__builtin_ia32_pmaxsd128",
"llvm.x86.avx512.pmul.dq.512" => "__builtin_ia32_pmuldq512_mask", "llvm.x86.avx512.pmul.dq.512" => "__builtin_ia32_pmuldq512_mask",
"llvm.x86.avx512.pmulu.dq.512" => "__builtin_ia32_pmuludq512_mask", "llvm.x86.avx512.pmulu.dq.512" => "__builtin_ia32_pmuludq512_mask",
"llvm.x86.avx512.max.ps.512" => "__builtin_ia32_maxps512_mask", "llvm.x86.avx512.max.ps.512" => "__builtin_ia32_maxps512_mask",
@ -1604,5 +1615,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
func func
} }
#[cfg(feature = "master")]
include!("old_archs.rs");
#[cfg(feature = "master")] #[cfg(feature = "master")]
include!("archs.rs"); include!("archs.rs");

View file

@ -208,6 +208,7 @@ fn get_simple_function_f128<'gcc, 'tcx>(
let f128_type = cx.type_f128(); let f128_type = cx.type_f128();
let func_name = match name { let func_name = match name {
sym::ceilf128 => "ceilf128", sym::ceilf128 => "ceilf128",
sym::fabsf128 => "fabsf128",
sym::floorf128 => "floorf128", sym::floorf128 => "floorf128",
sym::truncf128 => "truncf128", sym::truncf128 => "truncf128",
sym::roundf128 => "roundf128", sym::roundf128 => "roundf128",
@ -262,6 +263,7 @@ fn f16_builtin<'gcc, 'tcx>(
let builtin_name = match name { let builtin_name = match name {
sym::ceilf16 => "__builtin_ceilf", sym::ceilf16 => "__builtin_ceilf",
sym::copysignf16 => "__builtin_copysignf", sym::copysignf16 => "__builtin_copysignf",
sym::fabsf16 => "fabsf",
sym::floorf16 => "__builtin_floorf", sym::floorf16 => "__builtin_floorf",
sym::fmaf16 => "fmaf", sym::fmaf16 => "fmaf",
sym::maxnumf16 => "__builtin_fmaxf", sym::maxnumf16 => "__builtin_fmaxf",
@ -328,6 +330,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
} }
sym::ceilf16 sym::ceilf16
| sym::copysignf16 | sym::copysignf16
| sym::fabsf16
| sym::floorf16 | sym::floorf16
| sym::fmaf16 | sym::fmaf16
| sym::maxnumf16 | sym::maxnumf16
@ -648,15 +651,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let fn_ptr = func.get_address(None); let fn_ptr = func.get_address(None);
let fn_ty = fn_ptr.get_type(); let fn_ty = fn_ptr.get_type();
let mut llargs = vec![]; let mut call_args = vec![];
for arg in args { for arg in args {
match arg.val { match arg.val {
OperandValue::ZeroSized => {} OperandValue::ZeroSized => {}
OperandValue::Immediate(_) => llargs.push(arg.immediate()), OperandValue::Immediate(_) => call_args.push(arg.immediate()),
OperandValue::Pair(a, b) => { OperandValue::Pair(a, b) => {
llargs.push(a); call_args.push(a);
llargs.push(b); call_args.push(b);
} }
OperandValue::Ref(op_place_val) => { OperandValue::Ref(op_place_val) => {
let mut llval = op_place_val.llval; let mut llval = op_place_val.llval;
@ -673,13 +676,13 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
// We store bools as `i8` so we need to truncate to `i1`. // We store bools as `i8` so we need to truncate to `i1`.
llval = self.to_immediate_scalar(llval, scalar); llval = self.to_immediate_scalar(llval, scalar);
} }
llargs.push(llval); call_args.push(llval);
} }
} }
} }
// FIXME directly use the llvm intrinsic adjustment functions here // FIXME directly use the llvm intrinsic adjustment functions here
let llret = self.call(fn_ty, None, None, fn_ptr, &llargs, None, None); let llret = self.call(fn_ty, None, None, fn_ptr, &call_args, None, None);
if is_cleanup { if is_cleanup {
self.apply_attrs_to_cleanup_callsite(llret); self.apply_attrs_to_cleanup_callsite(llret);
} }
@ -720,7 +723,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
} }
fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> { fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!(); // TODO(antoyo): implement.
self.context.new_rvalue_from_int(self.int_type, 0)
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -234,6 +234,8 @@ impl CodegenBackend for GccCodegenBackend {
#[cfg(feature = "master")] #[cfg(feature = "master")]
{ {
gccjit::set_lang_name(c"GNU Rust");
let target_cpu = target_cpu(sess); let target_cpu = target_cpu(sess);
// Get the second TargetInfo with the correct CPU features by setting the arch. // Get the second TargetInfo with the correct CPU features by setting the arch.

View file

@ -13,7 +13,7 @@ use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, ty}; use rustc_middle::{bug, ty};
use crate::common::TypeReflection; use crate::common::TypeReflection;
use crate::context::CodegenCx; use crate::context::{CodegenCx, new_array_type};
use crate::type_of::LayoutGccExt; use crate::type_of::LayoutGccExt;
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@ -311,7 +311,7 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> {
len = 0; len = 0;
} }
self.context.new_array_type(None, ty, len) new_array_type(self.context, None, ty, len)
} }
} }

View file

@ -11,4 +11,4 @@ tests/run-make/foreign-exceptions/
tests/run-make/glibc-staticlib-args/ tests/run-make/glibc-staticlib-args/
tests/run-make/lto-smoke-c/ tests/run-make/lto-smoke-c/
tests/run-make/return-non-c-like-enum/ tests/run-make/return-non-c-like-enum/
tests/run-make/short-ice

View file

@ -0,0 +1 @@
tests/ui/simd/intrinsic/splat.rs

View file

@ -89,11 +89,13 @@ tests/ui/thir-print/offset_of.rs
tests/ui/iterators/rangefrom-overflow-debug.rs tests/ui/iterators/rangefrom-overflow-debug.rs
tests/ui/iterators/rangefrom-overflow-overflow-checks.rs tests/ui/iterators/rangefrom-overflow-overflow-checks.rs
tests/ui/iterators/iter-filter-count-debug-check.rs tests/ui/iterators/iter-filter-count-debug-check.rs
tests/ui/eii/codegen_single_crate.rs tests/ui/eii/linking/codegen_single_crate.rs
tests/ui/eii/codegen_cross_crate.rs tests/ui/eii/linking/codegen_cross_crate.rs
tests/ui/eii/default/local_crate.rs tests/ui/eii/default/local_crate.rs
tests/ui/eii/multiple_impls.rs tests/ui/eii/duplicate/multiple_impls.rs
tests/ui/eii/default/call_default.rs tests/ui/eii/default/call_default.rs
tests/ui/eii/same-symbol.rs tests/ui/eii/linking/same-symbol.rs
tests/ui/eii/privacy1.rs tests/ui/eii/privacy1.rs
tests/ui/eii/default/call_impl.rs tests/ui/eii/default/call_impl.rs
tests/ui/c-variadic/copy.rs
tests/ui/asm/x86_64/global_asm_escape.rs

View file

@ -0,0 +1,38 @@
// Compiler:
//
// Run-time:
// status: 0
// FIXME: Remove this test once rustc's `./tests/codegen/riscv-abi/call-llvm-intrinsics.rs`
// stops ignoring GCC backend.
#![feature(link_llvm_intrinsics)]
#![allow(internal_features)]
struct A;
impl Drop for A {
fn drop(&mut self) {
println!("A");
}
}
extern "C" {
#[link_name = "llvm.sqrt.f32"]
fn sqrt(x: f32) -> f32;
}
pub fn do_call() {
let _a = A;
unsafe {
// Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them
// CHECK: store float 4.000000e+00, float* %{{.}}, align 4
// CHECK: call float @llvm.sqrt.f32(float %{{.}}
sqrt(4.0);
}
}
fn main() {
do_call();
}

View file

@ -0,0 +1,102 @@
// Compiler:
//
// Run-time:
// status: 0
// FIXME: Remove this test once <tests/run-make/simd-ffi/simd.rs> stops
// ignoring GCC backend.
#![allow(internal_features, non_camel_case_types)]
// we can compile to a variety of platforms, because we don't need
// cross-compiled standard libraries.
#![feature(no_core, auto_traits)]
#![no_core]
#![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items, rustc_attrs)]
#[derive(Copy)]
#[repr(simd)]
pub struct f32x4([f32; 4]);
extern "C" {
#[link_name = "llvm.sqrt.v4f32"]
fn vsqrt(x: f32x4) -> f32x4;
}
pub fn foo(x: f32x4) -> f32x4 {
unsafe { vsqrt(x) }
}
#[derive(Copy)]
#[repr(simd)]
pub struct i32x4([i32; 4]);
extern "C" {
// _mm_sll_epi32
#[cfg(all(any(target_arch = "x86", target_arch = "x86-64"), target_feature = "sse2"))]
#[link_name = "llvm.x86.sse2.psll.d"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// vmaxq_s32
#[cfg(target_arch = "arm")]
#[link_name = "llvm.arm.neon.vmaxs.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// vmaxq_s32
#[cfg(target_arch = "aarch64")]
#[link_name = "llvm.aarch64.neon.maxs.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// Use a generic LLVM intrinsic to do type checking on other platforms
#[cfg(not(any(
all(any(target_arch = "x86", target_arch = "x86-64"), target_feature = "sse2"),
target_arch = "arm",
target_arch = "aarch64"
)))]
#[link_name = "llvm.smax.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
}
pub fn bar(a: i32x4, b: i32x4) -> i32x4 {
unsafe { integer(a, b) }
}
#[lang = "pointee_sized"]
pub trait PointeeSized {}
#[lang = "meta_sized"]
pub trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized: MetaSized {}
#[lang = "copy"]
pub trait Copy {}
impl Copy for f32 {}
impl Copy for i32 {}
impl Copy for [f32; 4] {}
impl Copy for [i32; 4] {}
pub mod marker {
pub use Copy;
}
#[lang = "freeze"]
auto trait Freeze {}
#[macro_export]
#[rustc_builtin_macro]
macro_rules! Copy {
() => {};
}
#[macro_export]
#[rustc_builtin_macro]
macro_rules! derive {
() => {};
}
#[lang = "start"]
fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
0
}
fn main() {}

View file

@ -0,0 +1,27 @@
// Compiler:
//
// Run-time:
// status: 0
use std::arch::asm;
fn exit_syscall(status: i32) -> ! {
#[cfg(target_arch = "x86_64")]
unsafe {
asm!(
"syscall",
in("rax") 60,
in("rdi") status,
options(noreturn)
);
}
#[cfg(not(target_arch = "x86_64"))]
std::process::exit(status);
}
fn main() {
// Used to crash with rustc_codegen_gcc.
exit_syscall(0);
std::process::exit(1);
}

View file

@ -12,7 +12,7 @@ def run_command(command, cwd=None):
sys.exit(1) sys.exit(1)
def clone_repository(repo_name, path, repo_url, branch="master", sub_paths=None): def clone_repository(repo_name, path, repo_url, sub_paths):
if os.path.exists(path): if os.path.exists(path):
while True: while True:
choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path)) choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path))
@ -21,18 +21,15 @@ def clone_repository(repo_name, path, repo_url, branch="master", sub_paths=None)
return return
elif choice.lower() == "y": elif choice.lower() == "y":
print("Updating repository...") print("Updating repository...")
run_command(["git", "pull", "origin", branch], cwd=path) run_command(["git", "pull", "origin", "main"], cwd=path)
return return
else: else:
print("Didn't understand answer...") print("Didn't understand answer...")
print("Cloning {} repository...".format(repo_name)) print("Cloning {} repository...".format(repo_name))
if sub_paths is None: run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path])
run_command(["git", "clone", repo_url, "--depth", "1", path]) run_command(["git", "sparse-checkout", "init"], cwd=path)
else: run_command(["git", "sparse-checkout", "set", *sub_paths], cwd=path)
run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path]) run_command(["git", "checkout"], cwd=path)
run_command(["git", "sparse-checkout", "init"], cwd=path)
run_command(["git", "sparse-checkout", "set", *sub_paths], cwd=path)
run_command(["git", "checkout"], cwd=path)
def append_intrinsic(array, intrinsic_name, translation): def append_intrinsic(array, intrinsic_name, translation):
@ -45,121 +42,36 @@ def convert_to_string(content):
return content return content
def extract_intrinsics_from_llvm(llvm_path, intrinsics): def extract_intrinsics_from_llvm(llvm_path):
command = ["llvm-tblgen", "llvm/IR/Intrinsics.td"] intrinsics = {}
command = ["llvm-tblgen", "llvm/IR/Intrinsics.td", "--dump-json"]
cwd = os.path.join(llvm_path, "llvm/include") cwd = os.path.join(llvm_path, "llvm/include")
print("=> Running command `{}` from `{}`".format(command, cwd)) print("=> Running command `{}` from `{}`".format(command, cwd))
p = subprocess.Popen(command, cwd=cwd, stdout=subprocess.PIPE) p = subprocess.Popen(command, cwd=cwd, stdout=subprocess.PIPE)
output, err = p.communicate() output, err = p.communicate()
lines = convert_to_string(output).splitlines() content = json.loads(convert_to_string(output))
pos = 0 for intrinsic in content:
while pos < len(lines): data = content[intrinsic]
line = lines[pos] if not isinstance(data, dict):
if not line.startswith("def "):
pos += 1
continue continue
intrinsic = line.split(" ")[1].strip() current_arch = data.get("TargetPrefix")
content = line builtin_name = data.get("ClangBuiltinName")
while pos < len(lines): if current_arch is None or current_arch == "" or builtin_name is None:
line = lines[pos].split(" // ")[0].strip()
content += line
pos += 1
if line == "}":
break
entries = re.findall('string ClangBuiltinName = "(\\w+)";', content)
current_arch = re.findall('string TargetPrefix = "(\\w+)";', content)
if len(entries) == 1 and len(current_arch) == 1:
current_arch = current_arch[0]
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] = []
append_intrinsic(intrinsics[current_arch], intrinsic, entries[0])
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_intrinsics_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 continue
if it["kind"] != "function": intrinsic = intrinsic.split("_")
# We're only looking for functions. if len(intrinsic) < 2 or intrinsic[0] != "int":
continue continue
# if len(it["path"]) == 2: intrinsic[0] = "llvm"
# # This is a "general" intrinsic, not bound to a specific arch. intrinsic = ".".join(intrinsic)
# append_translation(json_data, p, general) if current_arch not in intrinsics:
# continue intrinsics[current_arch] = []
if len(it["path"]) != 3 or it["path"][1] not in archs: append_intrinsic(intrinsics[current_arch], intrinsic, builtin_name)
continue
arch = it["path"][1] return intrinsics
if arch not in intrinsics:
intrinsics[arch] = []
append_translation(json_data, p, intrinsics[arch])
def fill_intrinsics(intrinsics, from_intrinsics, all_intrinsics): def update_intrinsics(llvm_path):
for arch in from_intrinsics: intrinsics = extract_intrinsics_from_llvm(llvm_path)
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_intrinsics_from_llvm(llvm_path, intrinsics_llvm)
extract_intrinsics_from_llvmint(llvmint, intrinsics_llvmint)
extract_intrinsics_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 = [arch for arch in intrinsics]
archs.sort() archs.sort()
@ -173,33 +85,41 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
# Since all intrinsic names start with "llvm.", we skip that prefix. # Since all intrinsic names start with "llvm.", we skip that prefix.
print("Updating content of `{}`...".format(output_file)) print("Updating content of `{}`...".format(output_file))
with open(output_file, "w", encoding="utf8") as out: with open(output_file, "w", encoding="utf8") as out:
out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n") out.write("""// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`
out.write("// DO NOT EDIT IT!\n") // DO NOT EDIT IT!
out.write("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n") /// Translate a given LLVM intrinsic name to an equivalent GCC one.
out.write("fn map_arch_intrinsic(full_name:&str)->&'static str{\n") fn map_arch_intrinsic(full_name:&str)-> &'static str {
out.write('let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };\n') let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };
out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n') let Some((arch, name)) = name.split_once('.') else { unimplemented!("***** unsupported LLVM intrinsic llvm.{}", name) };
out.write("match arch {\n") let old_arch_res = old_archs(arch, name);
if let ArchCheckResult::Ok(res) = old_arch_res {
return res;
}
match arch {""")
for arch in archs: for arch in archs:
if len(intrinsics[arch]) == 0: if len(intrinsics[arch]) == 0:
continue continue
attribute = "#[expect(non_snake_case)]" if arch[0].isupper() else "" attribute = "#[expect(non_snake_case)]" if arch[0].isupper() else ""
out.write("\"{}\" => {{ {} fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch, attribute, arch)) out.write("\"{}\" => {{ {} fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch, attribute, arch))
intrinsics[arch].sort(key=lambda x: (x[0], x[2])) intrinsics[arch].sort(key=lambda x: (x[0], x[1]))
out.write(' // {}\n'.format(arch)) out.write(' // {}\n'.format(arch))
for entry in intrinsics[arch]: for entry in intrinsics[arch]:
llvm_name = entry[0].removeprefix("llvm."); llvm_name = entry[0].removeprefix("llvm.");
llvm_name = llvm_name.removeprefix(arch); llvm_name = llvm_name.removeprefix(arch);
llvm_name = llvm_name.removeprefix("."); llvm_name = llvm_name.removeprefix(".");
if entry[2] is True: # if it is a duplicate if "_round_mask" in entry[1]:
out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
elif "_round_mask" in entry[1]:
out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1])) out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
else: else:
out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1])) out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1]))
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n') out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n')
out.write("}} }} {}(name,full_name) }}\n,".format(arch)) out.write("}} }} {}(name,full_name) }}\n,".format(arch))
out.write(' _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"),\n') out.write(""" _ => {
match old_arch_res {
ArchCheckResult::UnknownIntrinsic => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
ArchCheckResult::UnknownArch => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic: {full_name}"),
ArchCheckResult::Ok(_) => unreachable!(),
}
}""")
out.write("}\n}") out.write("}\n}")
subprocess.call(["rustfmt", output_file]) subprocess.call(["rustfmt", output_file])
print("Done!") print("Done!")
@ -210,35 +130,21 @@ def main():
os.path.dirname(os.path.abspath(__file__)), os.path.dirname(os.path.abspath(__file__)),
"llvm-project", "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. # First, we clone the LLVM repository if it's not already here.
clone_repository( clone_repository(
"llvm-project", "llvm-project",
llvm_path, llvm_path,
"https://github.com/llvm/llvm-project", "https://github.com/llvm/llvm-project",
branch="main", ["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"],
sub_paths=["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"],
) )
clone_repository( update_intrinsics(llvm_path)
"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)
# llvm-tblgen can be built with:
#
# mkdir llvm-tblgen-build && cd llvm-tblgen-build
# cmake -G Ninja -DLLVM_ENABLE_PROJECTS="llvm" -DCMAKE_BUILD_TYPE=Release ../llvm
# ninja llvm-tblgen
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

@ -1 +1 @@
Subproject commit 0081ca6631abdfa02bf42bc85aaf507b8a0e6beb Subproject commit efdd0a7290c22f5438d7c5380105d353ee3e8518