@@ -9,7 +9,7 @@ use itertools::Itertools as _;
99use rspirv:: spirv:: Word ;
1010use rustc_abi:: { self as abi, AddressSpace , Float , HasDataLayout , Integer , Primitive , Size } ;
1111use rustc_codegen_ssa:: traits:: { ConstCodegenMethods , MiscCodegenMethods , StaticCodegenMethods } ;
12- use rustc_middle:: mir:: interpret:: { ConstAllocation , GlobalAlloc , Scalar , alloc_range} ;
12+ use rustc_middle:: mir:: interpret:: { AllocError , ConstAllocation , GlobalAlloc , Scalar , alloc_range} ;
1313use rustc_middle:: ty:: layout:: LayoutOf ;
1414use rustc_span:: { DUMMY_SP , Span } ;
1515
@@ -298,24 +298,7 @@ impl ConstCodegenMethods for CodegenCx<'_> {
298298 ( self . get_static ( def_id) , AddressSpace :: DATA )
299299 }
300300 } ;
301- let value = if offset. bytes ( ) == 0 {
302- base_addr
303- } else {
304- self . tcx
305- . dcx ( )
306- . fatal ( "Non-zero scalar_to_backend ptr.offset not supported" )
307- // let offset = self.constant_bit64(ptr.offset.bytes());
308- // self.gep(base_addr, once(offset))
309- } ;
310- if let Primitive :: Pointer ( _) = layout. primitive ( ) {
311- assert_ty_eq ! ( self , value. ty, ty) ;
312- value
313- } else {
314- self . tcx
315- . dcx ( )
316- . fatal ( "Non-pointer-typed scalar_to_backend Scalar::Ptr not supported" ) ;
317- // unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
318- }
301+ self . const_bitcast ( self . const_ptr_byte_offset ( base_addr, offset) , ty)
319302 }
320303 }
321304 }
@@ -448,18 +431,82 @@ impl<'tcx> CodegenCx<'tcx> {
448431 SpirvType :: Pointer { .. } => Primitive :: Pointer ( AddressSpace :: DATA ) ,
449432 _ => unreachable ! ( ) ,
450433 } ;
451- let value = match alloc. inner ( ) . read_scalar (
452- self ,
453- alloc_range ( offset, size) ,
454- matches ! ( primitive, Primitive :: Pointer ( _) ) ,
455- ) {
434+
435+ let range = alloc_range ( offset, size) ;
436+ let read_provenance = matches ! ( primitive, Primitive :: Pointer ( _) ) ;
437+
438+ let mut primitive = primitive;
439+ let mut read_result = alloc. inner ( ) . read_scalar ( self , range, read_provenance) ;
440+
441+ // HACK(eddyb) while reading a pointer as an integer will fail,
442+ // the pointer itself can be read as a pointer, and then passed
443+ // to `scalar_to_backend`, which will `const_bitcast` it to `ty`.
444+ if read_result. is_err ( )
445+ && !read_provenance
446+ && let read_ptr_result @ Ok ( Scalar :: Ptr ( ptr, _) ) = alloc
447+ . inner ( )
448+ . read_scalar ( self , range, /* read_provenance */ true )
449+ {
450+ let ( prov, _offset) = ptr. into_parts ( ) ;
451+ primitive = Primitive :: Pointer (
452+ self . tcx . global_alloc ( prov. alloc_id ( ) ) . address_space ( self ) ,
453+ ) ;
454+ read_result = read_ptr_result;
455+ }
456+
457+ let scalar_or_zombie = match read_result {
456458 Ok ( scalar) => {
457- self . scalar_to_backend ( scalar, self . primitive_to_scalar ( primitive) , ty)
459+ Ok ( self . scalar_to_backend ( scalar, self . primitive_to_scalar ( primitive) , ty) )
458460 }
459- // FIXME(eddyb) this is really unsound, could be an error!
460- _ => self . undef ( ty) ,
461+
462+ // FIXME(eddyb) could some of these use e.g. `const_bitcast`?
463+ // (or, in general, assembling one constant out of several)
464+ Err ( err) => match err {
465+ // The scalar is only `undef` if the entire byte range
466+ // it covers is completely uninitialized - all other
467+ // failure modes of `read_scalar` are various errors.
468+ AllocError :: InvalidUninitBytes ( _) => {
469+ let uninit_range = alloc
470+ . inner ( )
471+ . init_mask ( )
472+ . is_range_initialized ( range)
473+ . unwrap_err ( ) ;
474+ let uninit_size = {
475+ let [ start, end] = [ uninit_range. start , uninit_range. end ( ) ]
476+ . map ( |x| x. clamp ( range. start , range. end ( ) ) ) ;
477+ end - start
478+ } ;
479+ if uninit_size == size {
480+ Ok ( self . undef ( ty) )
481+ } else {
482+ Err ( format ! (
483+ "overlaps {} uninitialized bytes" ,
484+ uninit_size. bytes( )
485+ ) )
486+ }
487+ }
488+ AllocError :: ReadPointerAsInt ( _) => Err ( "overlaps pointer bytes" . into ( ) ) ,
489+ AllocError :: ReadPartialPointer ( _) => {
490+ Err ( "partially overlaps another pointer" . into ( ) )
491+ }
492+
493+ // HACK(eddyb) these should never happen when using
494+ // `read_scalar`, but better not outright crash.
495+ AllocError :: ScalarSizeMismatch ( _)
496+ | AllocError :: OverwritePartialPointer ( _) => {
497+ Err ( format ! ( "unrecognized `AllocError::{err:?}`" ) )
498+ }
499+ } ,
461500 } ;
462- ( value, size)
501+ let result = scalar_or_zombie. unwrap_or_else ( |reason| {
502+ let result = self . undef ( ty) ;
503+ self . zombie_no_span (
504+ result. def_cx ( self ) ,
505+ & format ! ( "unsupported `{}` constant: {reason}" , self . debug_type( ty) , ) ,
506+ ) ;
507+ result
508+ } ) ;
509+ ( result, size)
463510 }
464511 SpirvType :: Adt {
465512 field_types,
0 commit comments