Skip to content

Commit 721ac5a

Browse files
committed
Merge branch 'master' into sync_from_rust_2025_05_21
2 parents e58e697 + 9aec231 commit 721ac5a

File tree

11 files changed

+145
-74
lines changed

11 files changed

+145
-74
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ jobs:
115115
- uses: actions/checkout@v4
116116
- run: python tools/check_intrinsics_duplicates.py
117117

118+
spell_check:
119+
runs-on: ubuntu-24.04
120+
steps:
121+
- uses: actions/checkout@v4
122+
- uses: crate-ci/[email protected]
123+
118124
build_system:
119125
runs-on: ubuntu-24.04
120126
steps:

_typos.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[default.extend-words]
2+
ba = "ba"
3+
hsa = "hsa"
4+
olt = "olt"
5+
seh = "seh"
6+
typ = "typ"
7+
8+
[files]
9+
extend-exclude = ["src/intrinsic/archs.rs"]

example/std_example.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,18 @@ fn main() {
7777
assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
7878

7979
// Check that all u/i128 <-> float casts work correctly.
80-
let houndred_u128 = 100u128;
81-
let houndred_i128 = 100i128;
82-
let houndred_f32 = 100.0f32;
83-
let houndred_f64 = 100.0f64;
84-
assert_eq!(houndred_u128 as f32, 100.0);
85-
assert_eq!(houndred_u128 as f64, 100.0);
86-
assert_eq!(houndred_f32 as u128, 100);
87-
assert_eq!(houndred_f64 as u128, 100);
88-
assert_eq!(houndred_i128 as f32, 100.0);
89-
assert_eq!(houndred_i128 as f64, 100.0);
90-
assert_eq!(houndred_f32 as i128, 100);
91-
assert_eq!(houndred_f64 as i128, 100);
80+
let hundred_u128 = 100u128;
81+
let hundred_i128 = 100i128;
82+
let hundred_f32 = 100.0f32;
83+
let hundred_f64 = 100.0f64;
84+
assert_eq!(hundred_u128 as f32, 100.0);
85+
assert_eq!(hundred_u128 as f64, 100.0);
86+
assert_eq!(hundred_f32 as u128, 100);
87+
assert_eq!(hundred_f64 as u128, 100);
88+
assert_eq!(hundred_i128 as f32, 100.0);
89+
assert_eq!(hundred_i128 as f64, 100.0);
90+
assert_eq!(hundred_f32 as i128, 100);
91+
assert_eq!(hundred_f64 as i128, 100);
9292

9393
let _a = 1u32 << 2u8;
9494

src/allocator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ fn create_wrapper_function(
152152
if output.is_some() {
153153
block.end_with_return(None, ret);
154154
} else {
155+
block.add_eval(None, ret);
155156
block.end_with_void_return(None);
156157
}
157158

src/archive.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use std::path::Path;
2+
3+
use rustc_codegen_ssa::back::archive::{
4+
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
5+
};
6+
use rustc_session::Session;
7+
8+
pub(crate) struct ArArchiveBuilderBuilder;
9+
10+
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
11+
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
12+
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
13+
}
14+
15+
fn create_dll_import_lib(
16+
&self,
17+
_sess: &Session,
18+
_lib_name: &str,
19+
_import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
20+
_output_path: &Path,
21+
) {
22+
unimplemented!("creating dll imports is not yet supported");
23+
}
24+
}

src/attributes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::gcc_util::to_gcc_features;
1616
/// Checks if the function `instance` is recursively inline.
1717
/// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive.
1818
#[cfg(feature = "master")]
19-
fn resursively_inline<'gcc, 'tcx>(
19+
fn recursively_inline<'gcc, 'tcx>(
2020
cx: &CodegenCx<'gcc, 'tcx>,
2121
instance: ty::Instance<'tcx>,
2222
) -> bool {
@@ -61,7 +61,7 @@ fn inline_attr<'gcc, 'tcx>(
6161
//
6262
// That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost.
6363
// We *only* need to check all the terminators of a function marked with this attribute.
64-
if resursively_inline(cx, instance) {
64+
if recursively_inline(cx, instance) {
6565
Some(FnAttribute::Inline)
6666
} else {
6767
Some(FnAttribute::AlwaysInline)

src/common.rs

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use rustc_middle::mir::Mutability;
99
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
1010
use rustc_middle::ty::layout::LayoutOf;
1111

12-
use crate::consts::const_alloc_to_gcc;
1312
use crate::context::CodegenCx;
1413
use crate::type_of::LayoutGccExt;
1514

@@ -46,12 +45,65 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
4645
}
4746

4847
pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
49-
let context = &cx.context;
50-
let byte_type = context.new_type::<u8>();
51-
let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
52-
let elements: Vec<_> =
53-
bytes.iter().map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)).collect();
54-
context.new_array_constructor(None, typ, &elements)
48+
// Instead of always using an array of bytes, use an array of larger integers of target endianness
49+
// if possible. This reduces the amount of `rvalues` we use, which reduces memory usage significantly.
50+
//
51+
// FIXME(FractalFir): Consider using `global_set_initializer` instead. Before this is done, we need to confirm that
52+
// `global_set_initializer` is more memory efficient than the current solution.
53+
// `global_set_initializer` calls `global_set_initializer_rvalue` under the hood - does it generate an array of rvalues,
54+
// or is it using a more efficient representation?
55+
match bytes.len() % 8 {
56+
0 => {
57+
let context = &cx.context;
58+
let byte_type = context.new_type::<u64>();
59+
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 8);
60+
let elements: Vec<_> = bytes
61+
.chunks_exact(8)
62+
.map(|arr| {
63+
let arr: [u8; 8] = arr.try_into().unwrap();
64+
context.new_rvalue_from_long(
65+
byte_type,
66+
// Since we are representing arbitrary byte runs as integers, we need to follow the target
67+
// endianness.
68+
match cx.sess().target.options.endian {
69+
rustc_abi::Endian::Little => u64::from_le_bytes(arr) as i64,
70+
rustc_abi::Endian::Big => u64::from_be_bytes(arr) as i64,
71+
},
72+
)
73+
})
74+
.collect();
75+
context.new_array_constructor(None, typ, &elements)
76+
}
77+
4 => {
78+
let context = &cx.context;
79+
let byte_type = context.new_type::<u32>();
80+
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 4);
81+
let elements: Vec<_> = bytes
82+
.chunks_exact(4)
83+
.map(|arr| {
84+
let arr: [u8; 4] = arr.try_into().unwrap();
85+
context.new_rvalue_from_int(
86+
byte_type,
87+
match cx.sess().target.options.endian {
88+
rustc_abi::Endian::Little => u32::from_le_bytes(arr) as i32,
89+
rustc_abi::Endian::Big => u32::from_be_bytes(arr) as i32,
90+
},
91+
)
92+
})
93+
.collect();
94+
context.new_array_constructor(None, typ, &elements)
95+
}
96+
_ => {
97+
let context = cx.context;
98+
let byte_type = context.new_type::<u8>();
99+
let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
100+
let elements: Vec<_> = bytes
101+
.iter()
102+
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
103+
.collect();
104+
context.new_array_constructor(None, typ, &elements)
105+
}
106+
}
55107
}
56108

57109
pub fn type_is_pointer(typ: Type<'_>) -> bool {
@@ -212,7 +264,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
212264
let alloc_id = prov.alloc_id();
213265
let base_addr = match self.tcx.global_alloc(alloc_id) {
214266
GlobalAlloc::Memory(alloc) => {
215-
let init = const_alloc_to_gcc(self, alloc);
267+
let init = self.const_data_from_alloc(alloc);
216268
let alloc = alloc.inner();
217269
let value = match alloc.mutability {
218270
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
@@ -234,7 +286,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
234286
}),
235287
)))
236288
.unwrap_memory();
237-
let init = const_alloc_to_gcc(self, alloc);
289+
let init = self.const_data_from_alloc(alloc);
238290
self.static_addr_of(init, alloc.inner().align, None)
239291
}
240292
GlobalAlloc::Static(def_id) => {
@@ -257,7 +309,19 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
257309
}
258310

259311
fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value {
260-
const_alloc_to_gcc(self, alloc)
312+
// We ignore the alignment for the purpose of deduping RValues
313+
// The alignment is not handled / used in any way by `const_alloc_to_gcc`,
314+
// so it is OK to overwrite it here.
315+
let mut mock_alloc = alloc.inner().clone();
316+
mock_alloc.align = rustc_abi::Align::MAX;
317+
// Check if the rvalue is already in the cache - if so, just return it directly.
318+
if let Some(res) = self.const_cache.borrow().get(&mock_alloc) {
319+
return *res;
320+
}
321+
// Rvalue not in the cache - convert and add it.
322+
let res = crate::consts::const_alloc_to_gcc_uncached(self, alloc);
323+
self.const_cache.borrow_mut().insert(mock_alloc, res);
324+
res
261325
}
262326

263327
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {

src/consts.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,14 @@ fn set_global_alignment<'gcc, 'tcx>(
4242

4343
impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
4444
fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
45-
// TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the
46-
// following:
47-
for (value, variable) in &*self.const_globals.borrow() {
48-
if format!("{:?}", value) == format!("{:?}", cv) {
49-
if let Some(global_variable) = self.global_lvalues.borrow().get(variable) {
50-
let alignment = align.bits() as i32;
51-
if alignment > global_variable.get_alignment() {
52-
global_variable.set_alignment(alignment);
53-
}
45+
if let Some(variable) = self.const_globals.borrow().get(&cv) {
46+
if let Some(global_variable) = self.global_lvalues.borrow().get(variable) {
47+
let alignment = align.bits() as i32;
48+
if alignment > global_variable.get_alignment() {
49+
global_variable.set_alignment(alignment);
5450
}
55-
return *variable;
5651
}
52+
return *variable;
5753
}
5854
let global_value = self.static_addr_of_mut(cv, align, kind);
5955
#[cfg(feature = "master")]
@@ -299,8 +295,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
299295
global
300296
}
301297
}
302-
303-
pub fn const_alloc_to_gcc<'gcc>(
298+
/// Converts a given const alloc to a gcc Rvalue, without any caching or deduplication.
299+
/// YOU SHOULD NOT call this function directly - that may break the semantics of Rust.
300+
/// Use `const_data_from_alloc` instead.
301+
pub(crate) fn const_alloc_to_gcc_uncached<'gcc>(
304302
cx: &CodegenCx<'gcc, '_>,
305303
alloc: ConstAllocation<'_>,
306304
) -> RValue<'gcc> {
@@ -371,7 +369,7 @@ fn codegen_static_initializer<'gcc, 'tcx>(
371369
def_id: DefId,
372370
) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
373371
let alloc = cx.tcx.eval_static_initializer(def_id)?;
374-
Ok((const_alloc_to_gcc(cx, alloc), alloc))
372+
Ok((cx.const_data_from_alloc(alloc), alloc))
375373
}
376374

377375
fn check_and_apply_linkage<'gcc, 'tcx>(

src/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::cell::{Cell, RefCell};
2+
use std::collections::HashMap;
23

34
use gccjit::{
45
Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type,
@@ -9,6 +10,7 @@ use rustc_codegen_ssa::errors as ssa_errors;
910
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods};
1011
use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
1112
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
13+
use rustc_middle::mir::interpret::Allocation;
1214
use rustc_middle::mir::mono::CodegenUnit;
1315
use rustc_middle::span_bug;
1416
use rustc_middle::ty::layout::{
@@ -30,6 +32,8 @@ use crate::common::SignType;
3032

3133
#[cfg_attr(not(feature = "master"), allow(dead_code))]
3234
pub struct CodegenCx<'gcc, 'tcx> {
35+
/// A cache of converted ConstAllocs
36+
pub const_cache: RefCell<HashMap<Allocation, RValue<'gcc>>>,
3337
pub codegen_unit: &'tcx CodegenUnit<'tcx>,
3438
pub context: &'gcc Context<'gcc>,
3539

@@ -222,6 +226,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
222226
}
223227

224228
let mut cx = Self {
229+
const_cache: Default::default(),
225230
codegen_unit,
226231
context,
227232
current_func: RefCell::new(None),

src/intrinsic/mod.rs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -72,44 +72,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
7272
sym::fabsf64 => "fabs",
7373
sym::minnumf32 => "fminf",
7474
sym::minnumf64 => "fmin",
75-
sym::minimumf32 => "fminimumf",
76-
sym::minimumf64 => "fminimum",
77-
sym::minimumf128 => {
78-
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
79-
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html
80-
let f128_type = cx.type_f128();
81-
return Some(cx.context.new_function(
82-
None,
83-
FunctionType::Extern,
84-
f128_type,
85-
&[
86-
cx.context.new_parameter(None, f128_type, "a"),
87-
cx.context.new_parameter(None, f128_type, "b"),
88-
],
89-
"fminimumf128",
90-
false,
91-
));
92-
}
9375
sym::maxnumf32 => "fmaxf",
9476
sym::maxnumf64 => "fmax",
95-
sym::maximumf32 => "fmaximumf",
96-
sym::maximumf64 => "fmaximum",
97-
sym::maximumf128 => {
98-
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
99-
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html
100-
let f128_type = cx.type_f128();
101-
return Some(cx.context.new_function(
102-
None,
103-
FunctionType::Extern,
104-
f128_type,
105-
&[
106-
cx.context.new_parameter(None, f128_type, "a"),
107-
cx.context.new_parameter(None, f128_type, "b"),
108-
],
109-
"fmaximumf128",
110-
false,
111-
));
112-
}
11377
sym::copysignf32 => "copysignf",
11478
sym::copysignf64 => "copysign",
11579
sym::copysignf128 => "copysignl",

src/type_of.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
217217
let ty = match *self.ty.kind() {
218218
// NOTE: we cannot remove this match like in the LLVM codegen because the call
219219
// to fn_ptr_backend_type handle the on-stack attribute.
220-
// TODO(antoyo): find a less hackish way to hande the on-stack attribute.
220+
// TODO(antoyo): find a less hackish way to handle the on-stack attribute.
221221
ty::FnPtr(sig_tys, hdr) => cx
222222
.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig_tys.with(hdr), ty::List::empty())),
223223
_ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),

0 commit comments

Comments
 (0)