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 );
53 allocation
54 .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
55 .map_err(|e| e.stable(tables))?;
56 allocation.stable(tables)
57 }
58 ConstValue::ZeroSized => new_empty_allocation(layout.align.abi),
59 ConstValue::Slice { data, meta } => {
60 let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data);
61 let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
62 let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
63 let scalar_meta =
64 rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
65 let mut allocation = rustc_middle::mir::interpret::Allocation::new(
66 layout.size,
67 layout.align.abi,
68 AllocInit::Uninit,
69 (),
70 );
71 allocation
72 .write_scalar(
73 &tables.tcx,
74 alloc_range(Size::ZERO, tables.tcx.data_layout.pointer_size),
75 scalar_ptr,
76 )
77 .map_err(|e| e.stable(tables))?;
78 allocation
79 .write_scalar(
80 &tables.tcx,
81 alloc_range(tables.tcx.data_layout.pointer_size, scalar_meta.size()),
82 scalar_meta,
83 )
84 .map_err(|e| e.stable(tables))?;
85 allocation.stable(tables)
86 }
87 ConstValue::Indirect { alloc_id, offset } => {
88 let alloc = tables.tcx.global_alloc(alloc_id).unwrap_memory();
89 allocation_filter(&alloc.0, alloc_range(offset, layout.size), tables)
90 }
91 })
92}
93
94pub(super) fn allocation_filter<'tcx>(
96 alloc: &rustc_middle::mir::interpret::Allocation,
97 alloc_range: AllocRange,
98 tables: &mut Tables<'tcx>,
99) -> Allocation {
100 let mut bytes: Vec<Option<u8>> = alloc
101 .inspect_with_uninit_and_ptr_outside_interpreter(
102 alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(),
103 )
104 .iter()
105 .copied()
106 .map(Some)
107 .collect();
108 for (i, b) in bytes.iter_mut().enumerate() {
109 if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) {
110 *b = None;
111 }
112 }
113 let mut ptrs = Vec::new();
114 for (offset, prov) in alloc
115 .provenance()
116 .ptrs()
117 .iter()
118 .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end())
119 {
120 ptrs.push((
121 offset.bytes_usize() - alloc_range.start.bytes_usize(),
122 tables.prov(prov.alloc_id()),
123 ));
124 }
125 Allocation {
126 bytes,
127 provenance: ProvenanceMap { ptrs },
128 align: alloc.align.bytes(),
129 mutability: alloc.mutability.stable(tables),
130 }
131}