@@ -11,21 +11,70 @@ use rustc_codegen_ssa::traits::*;
1111use rustc_hir:: def_id:: DefId ;
1212use rustc_middle:: middle:: codegen_fn_attrs:: { CodegenFnAttrFlags , CodegenFnAttrs } ;
1313use rustc_middle:: mir:: interpret:: {
14- read_target_uint, Allocation , ErrorHandled , GlobalAlloc , Pointer , Scalar as InterpScalar ,
14+ read_target_uint, Allocation , ErrorHandled , GlobalAlloc , InitChunk , Pointer ,
15+ Scalar as InterpScalar ,
1516} ;
1617use rustc_middle:: mir:: mono:: MonoItem ;
1718use rustc_middle:: ty:: { self , Instance , Ty } ;
1819use rustc_middle:: { bug, span_bug} ;
1920use rustc_target:: abi:: {
2021 AddressSpace , Align , HasDataLayout , LayoutOf , Primitive , Scalar , Size , WrappingRange ,
2122} ;
23+ use std:: ops:: Range ;
2224use tracing:: debug;
2325
2426pub fn const_alloc_to_llvm ( cx : & CodegenCx < ' ll , ' _ > , alloc : & Allocation ) -> & ' ll Value {
2527 let mut llvals = Vec :: with_capacity ( alloc. relocations ( ) . len ( ) + 1 ) ;
2628 let dl = cx. data_layout ( ) ;
2729 let pointer_size = dl. pointer_size . bytes ( ) as usize ;
2830
31+ // Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`,
32+ // so `range` must be within the bounds of `alloc` and not within a relocation.
33+ fn append_chunks_of_init_and_uninit_bytes < ' ll , ' a , ' b > (
34+ llvals : & mut Vec < & ' ll Value > ,
35+ cx : & ' a CodegenCx < ' ll , ' b > ,
36+ alloc : & ' a Allocation ,
37+ range : Range < usize > ,
38+ ) {
39+ /// Allocations larger than this will only be codegen'd as entirely initialized or entirely undef.
40+ /// This avoids compile time regressions when an alloc would have many chunks,
41+ /// e.g. for `[(u64, u8); N]`, which has undef padding in each element.
42+ const MAX_PARTIALLY_UNDEF_SIZE : usize = 1024 ;
43+
44+ let mut chunks = alloc
45+ . init_mask ( )
46+ . range_as_init_chunks ( Size :: from_bytes ( range. start ) , Size :: from_bytes ( range. end ) ) ;
47+
48+ let chunk_to_llval = move |chunk| match chunk {
49+ InitChunk :: Init ( range) => {
50+ let range = ( range. start . bytes ( ) as usize ) ..( range. end . bytes ( ) as usize ) ;
51+ let bytes = alloc. inspect_with_uninit_and_ptr_outside_interpreter ( range) ;
52+ cx. const_bytes ( bytes)
53+ }
54+ InitChunk :: Uninit ( range) => {
55+ let len = range. end . bytes ( ) - range. start . bytes ( ) ;
56+ cx. const_undef ( cx. type_array ( cx. type_i8 ( ) , len) )
57+ }
58+ } ;
59+
60+ if range. len ( ) > MAX_PARTIALLY_UNDEF_SIZE {
61+ let llval = match ( chunks. next ( ) , chunks. next ( ) ) {
62+ ( Some ( chunk) , None ) => {
63+ // exactly one chunk, either fully init or fully uninit
64+ chunk_to_llval ( chunk)
65+ }
66+ _ => {
67+ // partially uninit
68+ let bytes = alloc. inspect_with_uninit_and_ptr_outside_interpreter ( range) ;
69+ cx. const_bytes ( bytes)
70+ }
71+ } ;
72+ llvals. push ( llval) ;
73+ } else {
74+ llvals. extend ( chunks. map ( chunk_to_llval) ) ;
75+ }
76+ }
77+
2978 let mut next_offset = 0 ;
3079 for & ( offset, alloc_id) in alloc. relocations ( ) . iter ( ) {
3180 let offset = offset. bytes ( ) ;
@@ -34,12 +83,8 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
3483 if offset > next_offset {
3584 // This `inspect` is okay since we have checked that it is not within a relocation, it
3685 // is within the bounds of the allocation, and it doesn't affect interpreter execution
37- // (we inspect the result after interpreter execution). Any undef byte is replaced with
38- // some arbitrary byte value.
39- //
40- // FIXME: relay undef bytes to codegen as undef const bytes
41- let bytes = alloc. inspect_with_uninit_and_ptr_outside_interpreter ( next_offset..offset) ;
42- llvals. push ( cx. const_bytes ( bytes) ) ;
86+ // (we inspect the result after interpreter execution).
87+ append_chunks_of_init_and_uninit_bytes ( & mut llvals, cx, alloc, next_offset..offset) ;
4388 }
4489 let ptr_offset = read_target_uint (
4590 dl. endian ,
@@ -70,12 +115,8 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
70115 let range = next_offset..alloc. len ( ) ;
71116 // This `inspect` is okay since we have check that it is after all relocations, it is
72117 // within the bounds of the allocation, and it doesn't affect interpreter execution (we
73- // inspect the result after interpreter execution). Any undef byte is replaced with some
74- // arbitrary byte value.
75- //
76- // FIXME: relay undef bytes to codegen as undef const bytes
77- let bytes = alloc. inspect_with_uninit_and_ptr_outside_interpreter ( range) ;
78- llvals. push ( cx. const_bytes ( bytes) ) ;
118+ // inspect the result after interpreter execution).
119+ append_chunks_of_init_and_uninit_bytes ( & mut llvals, cx, alloc, range) ;
79120 }
80121
81122 cx. const_struct ( & llvals, true )
0 commit comments