@@ -9,7 +9,6 @@ use rustc_middle::mir::Mutability;
99use rustc_middle:: mir:: interpret:: { ConstAllocation , GlobalAlloc , Scalar } ;
1010use rustc_middle:: ty:: layout:: LayoutOf ;
1111
12- use crate :: consts:: const_alloc_to_gcc;
1312use crate :: context:: CodegenCx ;
1413use crate :: type_of:: LayoutGccExt ;
1514
@@ -46,12 +45,65 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
4645}
4746
4847pub 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
57109pub 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 {
0 commit comments