rustc_smir/rustc_smir/
alloc.rs1use rustc_abi::{Align, Size};
2use rustc_middle::mir::ConstValue;
3use rustc_middle::mir::interpret::{AllocInit, AllocRange, Pointer, alloc_range};
4use stable_mir::Error;
5use stable_mir::mir::Mutability;
6use stable_mir::ty::{Allocation, ProvenanceMap};
7
8use crate::rustc_smir::{Stable, Tables};
9use crate::stable_mir;
10
11fn new_empty_allocation(align: Align) -> Allocation {
13 Allocation {
14 bytes: Vec::new(),
15 provenance: ProvenanceMap { ptrs: Vec::new() },
16 align: align.bytes(),
17 mutability: Mutability::Not,
18 }
19}
20
21#[allow(rustc::usage_of_qualified_ty)]
25pub(crate) fn new_allocation<'tcx>(
26 ty: rustc_middle::ty::Ty<'tcx>,
27 const_value: ConstValue<'tcx>,
28 tables: &mut Tables<'tcx>,
29) -> Allocation {
30 try_new_allocation(ty, const_value, tables)
31 .unwrap_or_else(|_| panic!("Failed to convert: {const_value:?} to {ty:?}"))
32}
33
34#[allow(rustc::usage_of_qualified_ty)]
35pub(crate) fn try_new_allocation<'tcx>(
36 ty: rustc_middle::ty::Ty<'tcx>,
37 const_value: ConstValue<'tcx>,
38 tables: &mut Tables<'tcx>,
39) -> Result<Allocation, Error> {
40 let layout = tables
41 .tcx
42 .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
43 .map_err(|e| e.stable(tables))?;
44 Ok(match const_value {
45 ConstValue::Scalar(scalar) => {
46 let size = scalar.size();
47 let mut allocation = rustc_middle::mir::interpret::Allocation::new(
48 size,
49 layout.align.abi,
50 AllocInit::Uninit,
51 );
52 allocation
53 .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
54 .map_err(|e| e.stable(tables))?;
55 allocation.stable(tables)
56 }
57 ConstValue::ZeroSized => new_empty_allocation(layout.align.abi),
58 ConstValue::Slice { data, meta } => {
59 let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data);
60 let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
61 let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
62 let scalar_meta =
63 rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
64 let mut allocation = rustc_middle::mir::interpret::Allocation::new(
65 layout.size,
66 layout.align.abi,
67 AllocInit::Uninit,
68 );
69 allocation
70 .write_scalar(
71 &tables.tcx,
72 alloc_range(Size::ZERO, tables.tcx.data_layout.pointer_size),
73 scalar_ptr,
74 )
75 .map_err(|e| e.stable(tables))?;
76 allocation
77 .write_scalar(
78 &tables.tcx,
79 alloc_range(tables.tcx.data_layout.pointer_size, scalar_meta.size()),
80 scalar_meta,
81 )
82 .map_err(|e| e.stable(tables))?;
83 allocation.stable(tables)
84 }
85 ConstValue::Indirect { alloc_id, offset } => {
86 let alloc = tables.tcx.global_alloc(alloc_id).unwrap_memory();
87 allocation_filter(&alloc.0, alloc_range(offset, layout.size), tables)
88 }
89 })
90}
91
92pub(super) fn allocation_filter<'tcx>(
94 alloc: &rustc_middle::mir::interpret::Allocation,
95 alloc_range: AllocRange,
96 tables: &mut Tables<'tcx>,
97) -> Allocation {
98 let mut bytes: Vec<Option<u8>> = alloc
99 .inspect_with_uninit_and_ptr_outside_interpreter(
100 alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(),
101 )
102 .iter()
103 .copied()
104 .map(Some)
105 .collect();
106 for (i, b) in bytes.iter_mut().enumerate() {
107 if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) {
108 *b = None;
109 }
110 }
111 let mut ptrs = Vec::new();
112 for (offset, prov) in alloc
113 .provenance()
114 .ptrs()
115 .iter()
116 .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end())
117 {
118 ptrs.push((
119 offset.bytes_usize() - alloc_range.start.bytes_usize(),
120 tables.prov(prov.alloc_id()),
121 ));
122 }
123 Allocation {
124 bytes,
125 provenance: ProvenanceMap { ptrs },
126 align: alloc.align.bytes(),
127 mutability: alloc.mutability.stable(tables),
128 }
129}