Skip to content

Commit 637daf2

Browse files
committed
Changes to constant handling - faster deduplication, more compact represtntation
1 parent 6ba33f5 commit 637daf2

File tree

3 files changed

+83
-23
lines changed

3 files changed

+83
-23
lines changed

src/common.rs

Lines changed: 67 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,58 @@ 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 alaways using an array of bytes, use an array of larger intgers of target endianess
49+
// if possible.
50+
match bytes.len() % 8 {
51+
0 => {
52+
let context = &cx.context;
53+
let byte_type = context.new_type::<u64>();
54+
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 8);
55+
let elements: Vec<_> = bytes
56+
.chunks_exact(8)
57+
.map(|arr| {
58+
let arr: [u8; 8] = arr.try_into().unwrap();
59+
context.new_rvalue_from_long(
60+
byte_type,
61+
match cx.sess().target.options.endian {
62+
rustc_abi::Endian::Little => u64::from_le_bytes(arr) as i64,
63+
rustc_abi::Endian::Big => u64::from_be_bytes(arr) as i64,
64+
},
65+
)
66+
})
67+
.collect();
68+
context.new_array_constructor(None, typ, &elements)
69+
}
70+
4 => {
71+
let context = &cx.context;
72+
let byte_type = context.new_type::<u32>();
73+
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 4);
74+
let elements: Vec<_> = bytes
75+
.chunks_exact(4)
76+
.map(|arr| {
77+
let arr: [u8; 4] = arr.try_into().unwrap();
78+
context.new_rvalue_from_int(
79+
byte_type,
80+
match cx.sess().target.options.endian {
81+
rustc_abi::Endian::Little => u32::from_le_bytes(arr) as i32,
82+
rustc_abi::Endian::Big => u32::from_be_bytes(arr) as i32,
83+
},
84+
)
85+
})
86+
.collect();
87+
context.new_array_constructor(None, typ, &elements)
88+
}
89+
_ => {
90+
let context = cx.context;
91+
let byte_type = context.new_type::<u8>();
92+
let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
93+
let elements: Vec<_> = bytes
94+
.iter()
95+
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
96+
.collect();
97+
context.new_array_constructor(None, typ, &elements)
98+
}
99+
}
55100
}
56101

57102
pub fn type_is_pointer(typ: Type<'_>) -> bool {
@@ -212,7 +257,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
212257
let alloc_id = prov.alloc_id();
213258
let base_addr = match self.tcx.global_alloc(alloc_id) {
214259
GlobalAlloc::Memory(alloc) => {
215-
let init = const_alloc_to_gcc(self, alloc);
260+
let init = self.const_data_from_alloc(alloc);
216261
let alloc = alloc.inner();
217262
let value = match alloc.mutability {
218263
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
@@ -234,7 +279,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
234279
}),
235280
)))
236281
.unwrap_memory();
237-
let init = const_alloc_to_gcc(self, alloc);
282+
let init = self.const_data_from_alloc(alloc);
238283
self.static_addr_of(init, alloc.inner().align, None)
239284
}
240285
GlobalAlloc::Static(def_id) => {
@@ -257,7 +302,19 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
257302
}
258303

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

263320
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_unchached<'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),

0 commit comments

Comments
 (0)