Merge commit '70ae207ff5' into subtree-update_cg_gcc_2026-02-14
This commit is contained in:
commit
6ea369cfee
33 changed files with 1789 additions and 1640 deletions
|
|
@ -18,6 +18,7 @@
|
|||
],
|
||||
"ignorePaths": [
|
||||
"src/intrinsic/archs.rs",
|
||||
"src/intrinsic/old_archs.rs",
|
||||
"src/intrinsic/llvm.rs"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ jobs:
|
|||
git config --global user.name "User"
|
||||
./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
|
||||
run: |
|
||||
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ jobs:
|
|||
run: |
|
||||
./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
|
||||
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
|
||||
|
||||
- name: Build
|
||||
|
|
|
|||
|
|
@ -56,18 +56,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gccjit"
|
||||
version = "3.1.1"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff80f4d6d0749eab3a69122210b3a1fdd52edb6162781aadd7c4842e26983683"
|
||||
checksum = "26b73d18b642ce16378af78f89664841d7eeafa113682ff5d14573424eb0232a"
|
||||
dependencies = [
|
||||
"gccjit_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gccjit_sys"
|
||||
version = "1.1.2"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f81d901767ddba371a619fa9bba657066a4d3c5607ee69bbb557c1c5ba9bf85"
|
||||
checksum = "ee689456c013616942d5aef9a84d613cefcc3b335340d036f3650fc1a7459e15"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ default = ["master"]
|
|||
[dependencies]
|
||||
object = { version = "0.37.0", default-features = false, features = ["std", "read"] }
|
||||
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"] }
|
||||
|
||||
# Local copy.
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@ The default configuration (see below in the [Quick start](#quick-start) section)
|
|||
./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.
|
||||
|
||||
### 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 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 build --sysroot
|
||||
```
|
||||
To check if all is working correctly, run:
|
||||
To check if all is working correctly, run:
|
||||
|
||||
```bash
|
||||
$ ./y.sh cargo build --manifest-path tests/hello-world/Cargo.toml
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@ seh = "seh"
|
|||
typ = "typ"
|
||||
|
||||
[files]
|
||||
extend-exclude = ["src/intrinsic/archs.rs"]
|
||||
extend-exclude = ["src/intrinsic/archs.rs", "src/intrinsic/old_archs.rs"]
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
if config.target.ends_with(".json") {
|
||||
args.push(&"-Zjson-target-spec");
|
||||
}
|
||||
|
||||
for feature in &config.features {
|
||||
args.push(&"--features");
|
||||
args.push(feature);
|
||||
|
|
|
|||
|
|
@ -679,10 +679,10 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
create_dir(projects_path)?;
|
||||
|
||||
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
|
||||
// one test.
|
||||
let count = projects.len() / nb_parts + 1;
|
||||
let count = count + 1;
|
||||
let current_part = args.current_part.unwrap();
|
||||
let start = current_part * count;
|
||||
// We remove the projects we don't want to test.
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
## 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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
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
|
||||
- /* { dg-do compile { target x86_64-*-* } } */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
`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
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
0081ca6631abdfa02bf42bc85aaf507b8a0e6beb
|
||||
896045775f7c40fafe48c6e398f6c53bf6af889e
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-12-20"
|
||||
channel = "nightly-2026-02-14"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -575,9 +575,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) {
|
||||
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
|
||||
let builtin_unreachable: RValue<'gcc> =
|
||||
unsafe { std::mem::transmute(builtin_unreachable) };
|
||||
self.call(self.type_void(), None, None, builtin_unreachable, &[], None, None);
|
||||
self.llbb().add_eval(None, self.context.new_call(None, builtin_unreachable, &[]));
|
||||
}
|
||||
|
||||
// Write results to outputs.
|
||||
|
|
|
|||
|
|
@ -1495,6 +1495,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
#[cfg(not(feature = "master"))]
|
||||
fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> {
|
||||
use crate::context::new_array_type;
|
||||
|
||||
let vector_type = vec
|
||||
.get_type()
|
||||
.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 vec_num_units = vector_type.get_num_units();
|
||||
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();
|
||||
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
|
||||
// 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.
|
||||
let int_max = |signed: bool, int_width: u64| -> u128 {
|
||||
fn int_max(signed: bool, int_width: u64) -> u128 {
|
||||
let shift_amount = 128 - int_width;
|
||||
if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
|
||||
};
|
||||
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 }
|
||||
};
|
||||
}
|
||||
|
||||
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 =
|
||||
ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
||||
assert_eq!(rounded_min.status, Status::OK);
|
||||
ieee::Half::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
||||
//assert_eq!(rounded_min.status, Status::OK);
|
||||
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());
|
||||
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
|
||||
};
|
||||
let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
|
||||
let rounded_min =
|
||||
ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
||||
fn compute_clamp_bounds<F: Float>(signed: bool, int_width: u64) -> (u128, u128) {
|
||||
let rounded_min = F::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
||||
assert_eq!(rounded_min.status, Status::OK);
|
||||
let rounded_max =
|
||||
ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
|
||||
let rounded_max = F::from_u128_r(int_max(signed, int_width), Round::TowardZero);
|
||||
assert!(rounded_max.value.is_finite());
|
||||
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
|
||||
};
|
||||
}
|
||||
// To implement saturation, we perform the following steps:
|
||||
//
|
||||
// 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 bits_llval = match float_width {
|
||||
16 => bx.cx().const_u16(bits as u16),
|
||||
32 => bx.cx().const_u32(bits as u32),
|
||||
64 => bx.cx().const_u64(bits as u64),
|
||||
128 => bx.cx().const_u128(bits),
|
||||
n => bug!("unsupported float width {}", n),
|
||||
};
|
||||
bx.bitcast(bits_llval, float_ty)
|
||||
};
|
||||
let (f_min, f_max) = match float_width {
|
||||
32 => compute_clamp_bounds_single(signed, int_width),
|
||||
64 => compute_clamp_bounds_double(signed, int_width),
|
||||
16 => compute_clamp_bounds_half(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),
|
||||
};
|
||||
let f_min = float_bits_to_llval(self, f_min);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_middle::mir::Mutability;
|
|||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
|
||||
use crate::context::CodegenCx;
|
||||
use crate::context::{CodegenCx, new_array_type};
|
||||
use crate::type_of::LayoutGccExt;
|
||||
|
||||
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
|
|
@ -20,6 +20,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
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> {
|
||||
// TODO(antoyo): handle non-null-terminated strings.
|
||||
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 => {
|
||||
let context = &cx.context;
|
||||
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
|
||||
.chunks_exact(8)
|
||||
.map(|arr| {
|
||||
|
|
@ -76,7 +80,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
|
|||
4 => {
|
||||
let context = &cx.context;
|
||||
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
|
||||
.chunks_exact(4)
|
||||
.map(|arr| {
|
||||
|
|
@ -95,7 +99,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
|
|||
_ => {
|
||||
let context = cx.context;
|
||||
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
|
||||
.iter()
|
||||
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ use rustc_middle::ty::layout::{
|
|||
};
|
||||
use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::source_map::respan;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi};
|
||||
|
|
@ -145,6 +147,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
supports_f64_type: bool,
|
||||
supports_f128_type: bool,
|
||||
) -> 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 layout = tcx
|
||||
.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
|
||||
// gcc_jit_context_new_array_constructor (it should not use reinterpret_cast).
|
||||
let i128_type = context.new_array_type(None, i64_type, 2)/*.get_aligned(i128_align)*/;
|
||||
let u128_type = context.new_array_type(None, u64_type, 2)/*.get_aligned(u128_align)*/;
|
||||
let i128_type = new_array_type(context, None, i64_type, 2)/*.get_aligned(i128_align)*/;
|
||||
let u128_type = new_array_type(context, None, u64_type, 2)/*.get_aligned(u128_align)*/;
|
||||
(i128_type, u128_type)
|
||||
};
|
||||
|
||||
|
|
@ -601,3 +608,17 @@ fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
|
|||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -942,7 +942,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
fn float_to_int_cast(
|
||||
&self,
|
||||
signed: bool,
|
||||
value: RValue<'gcc>,
|
||||
mut value: RValue<'gcc>,
|
||||
dest_typ: Type<'gcc>,
|
||||
) -> RValue<'gcc> {
|
||||
let value_type = value.get_type();
|
||||
|
|
@ -951,16 +951,22 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
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) {
|
||||
// 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::FP128 => "tfti",
|
||||
// cSpell:enable
|
||||
kind => panic!("cannot cast a {:?} to non-native integer", kind),
|
||||
};
|
||||
let sign = if signed { "" } else { "uns" };
|
||||
let func_name = format!("__fix{}{}", sign, name_suffix);
|
||||
let param = self.context.new_parameter(None, value_type, "n");
|
||||
let param = self.context.new_parameter(None, param_type, "n");
|
||||
let func = self.context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
|
|
@ -969,6 +975,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
func_name,
|
||||
false,
|
||||
);
|
||||
if let Some(dest_type) = dest_type {
|
||||
value = self.context.new_cast(None, value, dest_type);
|
||||
}
|
||||
self.context.new_call(None, func, &[value])
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,7 +4,7 @@ use gccjit::{CType, Context, Field, Function, FunctionPtrType, RValue, ToRValue,
|
|||
use rustc_codegen_ssa::traits::BuilderMethods;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::context::{CodegenCx, new_array_type};
|
||||
|
||||
fn encode_key_128_type<'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" => {
|
||||
let mut new_args = args.to_vec();
|
||||
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");
|
||||
new_args.push(result.get_address(None));
|
||||
args = new_args.into();
|
||||
|
|
@ -593,7 +593,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
|
|||
"__builtin_ia32_encodekey256_u32" => {
|
||||
let mut new_args = args.to_vec();
|
||||
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");
|
||||
new_args.push(result.get_address(None));
|
||||
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 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");
|
||||
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);
|
||||
let field2 = result.access_field(None, field2);
|
||||
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 field2_ptr =
|
||||
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);
|
||||
let field2 = result.access_field(None, field2);
|
||||
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 field2_ptr =
|
||||
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);
|
||||
let field2 = result.access_field(None, field2);
|
||||
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 field2_ptr =
|
||||
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",
|
||||
// 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",
|
||||
// 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.pmulu.dq.512" => "__builtin_ia32_pmuludq512_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
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
include!("old_archs.rs");
|
||||
#[cfg(feature = "master")]
|
||||
include!("archs.rs");
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ fn get_simple_function_f128<'gcc, 'tcx>(
|
|||
let f128_type = cx.type_f128();
|
||||
let func_name = match name {
|
||||
sym::ceilf128 => "ceilf128",
|
||||
sym::fabsf128 => "fabsf128",
|
||||
sym::floorf128 => "floorf128",
|
||||
sym::truncf128 => "truncf128",
|
||||
sym::roundf128 => "roundf128",
|
||||
|
|
@ -262,6 +263,7 @@ fn f16_builtin<'gcc, 'tcx>(
|
|||
let builtin_name = match name {
|
||||
sym::ceilf16 => "__builtin_ceilf",
|
||||
sym::copysignf16 => "__builtin_copysignf",
|
||||
sym::fabsf16 => "fabsf",
|
||||
sym::floorf16 => "__builtin_floorf",
|
||||
sym::fmaf16 => "fmaf",
|
||||
sym::maxnumf16 => "__builtin_fmaxf",
|
||||
|
|
@ -328,6 +330,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
}
|
||||
sym::ceilf16
|
||||
| sym::copysignf16
|
||||
| sym::fabsf16
|
||||
| sym::floorf16
|
||||
| sym::fmaf16
|
||||
| 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_ty = fn_ptr.get_type();
|
||||
|
||||
let mut llargs = vec![];
|
||||
let mut call_args = vec![];
|
||||
|
||||
for arg in args {
|
||||
match arg.val {
|
||||
OperandValue::ZeroSized => {}
|
||||
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
|
||||
OperandValue::Immediate(_) => call_args.push(arg.immediate()),
|
||||
OperandValue::Pair(a, b) => {
|
||||
llargs.push(a);
|
||||
llargs.push(b);
|
||||
call_args.push(a);
|
||||
call_args.push(b);
|
||||
}
|
||||
OperandValue::Ref(op_place_val) => {
|
||||
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`.
|
||||
llval = self.to_immediate_scalar(llval, scalar);
|
||||
}
|
||||
llargs.push(llval);
|
||||
call_args.push(llval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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> {
|
||||
unimplemented!();
|
||||
// TODO(antoyo): implement.
|
||||
self.context.new_rvalue_from_int(self.int_type, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
1390
compiler/rustc_codegen_gcc/src/intrinsic/old_archs.rs
Normal file
1390
compiler/rustc_codegen_gcc/src/intrinsic/old_archs.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -234,6 +234,8 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
gccjit::set_lang_name(c"GNU Rust");
|
||||
|
||||
let target_cpu = target_cpu(sess);
|
||||
|
||||
// Get the second TargetInfo with the correct CPU features by setting the arch.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_middle::ty::layout::TyAndLayout;
|
|||
use rustc_middle::{bug, ty};
|
||||
|
||||
use crate::common::TypeReflection;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::context::{CodegenCx, new_array_type};
|
||||
use crate::type_of::LayoutGccExt;
|
||||
|
||||
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
|
|
@ -311,7 +311,7 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
|||
len = 0;
|
||||
}
|
||||
|
||||
self.context.new_array_type(None, ty, len)
|
||||
new_array_type(self.context, None, ty, len)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ tests/run-make/foreign-exceptions/
|
|||
tests/run-make/glibc-staticlib-args/
|
||||
tests/run-make/lto-smoke-c/
|
||||
tests/run-make/return-non-c-like-enum/
|
||||
|
||||
tests/run-make/short-ice
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
tests/ui/simd/intrinsic/splat.rs
|
||||
|
|
@ -89,11 +89,13 @@ tests/ui/thir-print/offset_of.rs
|
|||
tests/ui/iterators/rangefrom-overflow-debug.rs
|
||||
tests/ui/iterators/rangefrom-overflow-overflow-checks.rs
|
||||
tests/ui/iterators/iter-filter-count-debug-check.rs
|
||||
tests/ui/eii/codegen_single_crate.rs
|
||||
tests/ui/eii/codegen_cross_crate.rs
|
||||
tests/ui/eii/linking/codegen_single_crate.rs
|
||||
tests/ui/eii/linking/codegen_cross_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/same-symbol.rs
|
||||
tests/ui/eii/linking/same-symbol.rs
|
||||
tests/ui/eii/privacy1.rs
|
||||
tests/ui/eii/default/call_impl.rs
|
||||
tests/ui/c-variadic/copy.rs
|
||||
tests/ui/asm/x86_64/global_asm_escape.rs
|
||||
|
|
|
|||
38
compiler/rustc_codegen_gcc/tests/run/call-llvm-intrinsics.rs
Normal file
38
compiler/rustc_codegen_gcc/tests/run/call-llvm-intrinsics.rs
Normal 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();
|
||||
}
|
||||
102
compiler/rustc_codegen_gcc/tests/run/simd-ffi.rs
Normal file
102
compiler/rustc_codegen_gcc/tests/run/simd-ffi.rs
Normal 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() {}
|
||||
27
compiler/rustc_codegen_gcc/tests/run/unreachable-function.rs
Normal file
27
compiler/rustc_codegen_gcc/tests/run/unreachable-function.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ def run_command(command, cwd=None):
|
|||
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):
|
||||
while True:
|
||||
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
|
||||
elif choice.lower() == "y":
|
||||
print("Updating repository...")
|
||||
run_command(["git", "pull", "origin", branch], cwd=path)
|
||||
run_command(["git", "pull", "origin", "main"], cwd=path)
|
||||
return
|
||||
else:
|
||||
print("Didn't understand answer...")
|
||||
print("Cloning {} repository...".format(repo_name))
|
||||
if sub_paths 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", *sub_paths], cwd=path)
|
||||
run_command(["git", "checkout"], cwd=path)
|
||||
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", *sub_paths], cwd=path)
|
||||
run_command(["git", "checkout"], cwd=path)
|
||||
|
||||
|
||||
def append_intrinsic(array, intrinsic_name, translation):
|
||||
|
|
@ -45,121 +42,36 @@ def convert_to_string(content):
|
|||
return content
|
||||
|
||||
|
||||
def extract_intrinsics_from_llvm(llvm_path, intrinsics):
|
||||
command = ["llvm-tblgen", "llvm/IR/Intrinsics.td"]
|
||||
def extract_intrinsics_from_llvm(llvm_path):
|
||||
intrinsics = {}
|
||||
command = ["llvm-tblgen", "llvm/IR/Intrinsics.td", "--dump-json"]
|
||||
cwd = os.path.join(llvm_path, "llvm/include")
|
||||
print("=> Running command `{}` from `{}`".format(command, cwd))
|
||||
p = subprocess.Popen(command, cwd=cwd, stdout=subprocess.PIPE)
|
||||
output, err = p.communicate()
|
||||
lines = convert_to_string(output).splitlines()
|
||||
pos = 0
|
||||
while pos < len(lines):
|
||||
line = lines[pos]
|
||||
if not line.startswith("def "):
|
||||
pos += 1
|
||||
content = json.loads(convert_to_string(output))
|
||||
for intrinsic in content:
|
||||
data = content[intrinsic]
|
||||
if not isinstance(data, dict):
|
||||
continue
|
||||
intrinsic = line.split(" ")[1].strip()
|
||||
content = line
|
||||
while pos < len(lines):
|
||||
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.
|
||||
current_arch = data.get("TargetPrefix")
|
||||
builtin_name = data.get("ClangBuiltinName")
|
||||
if current_arch is None or current_arch == "" or builtin_name is None:
|
||||
continue
|
||||
if it["kind"] != "function":
|
||||
# We're only looking for functions.
|
||||
intrinsic = intrinsic.split("_")
|
||||
if len(intrinsic) < 2 or intrinsic[0] != "int":
|
||||
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])
|
||||
intrinsic[0] = "llvm"
|
||||
intrinsic = ".".join(intrinsic)
|
||||
if current_arch not in intrinsics:
|
||||
intrinsics[current_arch] = []
|
||||
append_intrinsic(intrinsics[current_arch], intrinsic, builtin_name)
|
||||
|
||||
return intrinsics
|
||||
|
||||
|
||||
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_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)
|
||||
def update_intrinsics(llvm_path):
|
||||
intrinsics = extract_intrinsics_from_llvm(llvm_path)
|
||||
|
||||
archs = [arch for arch in intrinsics]
|
||||
archs.sort()
|
||||
|
|
@ -173,33 +85,41 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
|
|||
# Since all intrinsic names start with "llvm.", we skip that prefix.
|
||||
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("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n")
|
||||
out.write("fn map_arch_intrinsic(full_name:&str)->&'static str{\n")
|
||||
out.write('let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };\n')
|
||||
out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n')
|
||||
out.write("match arch {\n")
|
||||
out.write("""// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`
|
||||
// DO NOT EDIT IT!
|
||||
/// Translate a given LLVM intrinsic name to an equivalent GCC one.
|
||||
fn map_arch_intrinsic(full_name:&str)-> &'static str {
|
||||
let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };
|
||||
let Some((arch, name)) = name.split_once('.') else { unimplemented!("***** unsupported LLVM intrinsic llvm.{}", name) };
|
||||
let old_arch_res = old_archs(arch, name);
|
||||
if let ArchCheckResult::Ok(res) = old_arch_res {
|
||||
return res;
|
||||
}
|
||||
match arch {""")
|
||||
for arch in archs:
|
||||
if len(intrinsics[arch]) == 0:
|
||||
continue
|
||||
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))
|
||||
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))
|
||||
for entry in intrinsics[arch]:
|
||||
llvm_name = entry[0].removeprefix("llvm.");
|
||||
llvm_name = llvm_name.removeprefix(arch);
|
||||
llvm_name = llvm_name.removeprefix(".");
|
||||
if entry[2] is True: # if it is a duplicate
|
||||
out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
|
||||
elif "_round_mask" in entry[1]:
|
||||
if "_round_mask" in entry[1]:
|
||||
out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
|
||||
else:
|
||||
out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1]))
|
||||
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n')
|
||||
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}")
|
||||
subprocess.call(["rustfmt", output_file])
|
||||
print("Done!")
|
||||
|
|
@ -210,35 +130,21 @@ def main():
|
|||
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",
|
||||
branch="main",
|
||||
sub_paths=["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"],
|
||||
["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"],
|
||||
)
|
||||
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)
|
||||
update_intrinsics(llvm_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__":
|
||||
sys.exit(main())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue