@@ -9,7 +9,6 @@ use rustc_middle::mir::Mutability;
9
9
use rustc_middle:: mir:: interpret:: { ConstAllocation , GlobalAlloc , Scalar } ;
10
10
use rustc_middle:: ty:: layout:: LayoutOf ;
11
11
12
- use crate :: consts:: const_alloc_to_gcc;
13
12
use crate :: context:: CodegenCx ;
14
13
use crate :: type_of:: LayoutGccExt ;
15
14
@@ -46,12 +45,65 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
46
45
}
47
46
48
47
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
+ }
55
107
}
56
108
57
109
pub fn type_is_pointer ( typ : Type < ' _ > ) -> bool {
@@ -212,7 +264,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
212
264
let alloc_id = prov. alloc_id ( ) ;
213
265
let base_addr = match self . tcx . global_alloc ( alloc_id) {
214
266
GlobalAlloc :: Memory ( alloc) => {
215
- let init = const_alloc_to_gcc ( self , alloc) ;
267
+ let init = self . const_data_from_alloc ( alloc) ;
216
268
let alloc = alloc. inner ( ) ;
217
269
let value = match alloc. mutability {
218
270
Mutability :: Mut => self . static_addr_of_mut ( init, alloc. align , None ) ,
@@ -234,7 +286,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
234
286
} ) ,
235
287
) ) )
236
288
. unwrap_memory ( ) ;
237
- let init = const_alloc_to_gcc ( self , alloc) ;
289
+ let init = self . const_data_from_alloc ( alloc) ;
238
290
self . static_addr_of ( init, alloc. inner ( ) . align , None )
239
291
}
240
292
GlobalAlloc :: Static ( def_id) => {
@@ -257,7 +309,19 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
257
309
}
258
310
259
311
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
261
325
}
262
326
263
327
fn const_ptr_byte_offset ( & self , base_addr : Self :: Value , offset : abi:: Size ) -> Self :: Value {
0 commit comments