]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | //! Handling of `static`s, `const`s and promoted allocations |
2 | ||
17df50a5 | 3 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
29967ef6 XL |
4 | use rustc_errors::ErrorReported; |
5 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; | |
6 | use rustc_middle::mir::interpret::{ | |
136023e0 | 7 | read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar, |
29967ef6 | 8 | }; |
6a06907d | 9 | use rustc_middle::ty::ConstKind; |
136023e0 | 10 | use rustc_span::DUMMY_SP; |
29967ef6 XL |
11 | |
12 | use cranelift_codegen::ir::GlobalValueData; | |
13 | use cranelift_module::*; | |
14 | ||
15 | use crate::prelude::*; | |
16 | ||
29967ef6 XL |
17 | pub(crate) struct ConstantCx { |
18 | todo: Vec<TodoItem>, | |
19 | done: FxHashSet<DataId>, | |
17df50a5 | 20 | anon_allocs: FxHashMap<AllocId, DataId>, |
29967ef6 XL |
21 | } |
22 | ||
23 | #[derive(Copy, Clone, Debug)] | |
24 | enum TodoItem { | |
25 | Alloc(AllocId), | |
26 | Static(DefId), | |
27 | } | |
28 | ||
29 | impl ConstantCx { | |
17df50a5 XL |
30 | pub(crate) fn new() -> Self { |
31 | ConstantCx { todo: vec![], done: FxHashSet::default(), anon_allocs: FxHashMap::default() } | |
32 | } | |
33 | ||
6a06907d | 34 | pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) { |
29967ef6 XL |
35 | //println!("todo {:?}", self.todo); |
36 | define_all_allocs(tcx, module, &mut self); | |
37 | //println!("done {:?}", self.done); | |
38 | self.done.clear(); | |
39 | } | |
40 | } | |
41 | ||
6a06907d XL |
42 | pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { |
43 | let mut all_constants_ok = true; | |
29967ef6 | 44 | for constant in &fx.mir.required_consts { |
6a06907d XL |
45 | let const_ = match fx.monomorphize(constant.literal) { |
46 | ConstantKind::Ty(ct) => ct, | |
47 | ConstantKind::Val(..) => continue, | |
48 | }; | |
29967ef6 XL |
49 | match const_.val { |
50 | ConstKind::Value(_) => {} | |
cdc7bbd5 | 51 | ConstKind::Unevaluated(unevaluated) => { |
29967ef6 | 52 | if let Err(err) = |
cdc7bbd5 | 53 | fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) |
29967ef6 | 54 | { |
6a06907d | 55 | all_constants_ok = false; |
29967ef6 XL |
56 | match err { |
57 | ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => { | |
6a06907d | 58 | fx.tcx.sess.span_err(constant.span, "erroneous constant encountered"); |
29967ef6 XL |
59 | } |
60 | ErrorHandled::TooGeneric => { | |
61 | span_bug!( | |
62 | constant.span, | |
63 | "codgen encountered polymorphic constant: {:?}", | |
64 | err | |
65 | ); | |
66 | } | |
67 | } | |
68 | } | |
69 | } | |
70 | ConstKind::Param(_) | |
71 | | ConstKind::Infer(_) | |
72 | | ConstKind::Bound(_, _) | |
73 | | ConstKind::Placeholder(_) | |
74 | | ConstKind::Error(_) => unreachable!("{:?}", const_), | |
75 | } | |
76 | } | |
6a06907d | 77 | all_constants_ok |
29967ef6 XL |
78 | } |
79 | ||
17df50a5 XL |
80 | pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) { |
81 | let mut constants_cx = ConstantCx::new(); | |
29967ef6 | 82 | constants_cx.todo.push(TodoItem::Static(def_id)); |
17df50a5 | 83 | constants_cx.finalize(tcx, module); |
29967ef6 XL |
84 | } |
85 | ||
86 | pub(crate) fn codegen_tls_ref<'tcx>( | |
6a06907d | 87 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
88 | def_id: DefId, |
89 | layout: TyAndLayout<'tcx>, | |
90 | ) -> CValue<'tcx> { | |
17df50a5 XL |
91 | let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); |
92 | let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); | |
cdc7bbd5 XL |
93 | if fx.clif_comments.enabled() { |
94 | fx.add_comment(local_data_id, format!("tls {:?}", def_id)); | |
95 | } | |
29967ef6 XL |
96 | let tls_ptr = fx.bcx.ins().tls_value(fx.pointer_type, local_data_id); |
97 | CValue::by_val(tls_ptr, layout) | |
98 | } | |
99 | ||
100 | fn codegen_static_ref<'tcx>( | |
6a06907d | 101 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
102 | def_id: DefId, |
103 | layout: TyAndLayout<'tcx>, | |
104 | ) -> CPlace<'tcx> { | |
17df50a5 XL |
105 | let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); |
106 | let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); | |
cdc7bbd5 XL |
107 | if fx.clif_comments.enabled() { |
108 | fx.add_comment(local_data_id, format!("{:?}", def_id)); | |
109 | } | |
29967ef6 XL |
110 | let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id); |
111 | assert!(!layout.is_unsized(), "unsized statics aren't supported"); | |
112 | assert!( | |
5869c6ff XL |
113 | matches!( |
114 | fx.bcx.func.global_values[local_data_id], | |
115 | GlobalValueData::Symbol { tls: false, .. } | |
116 | ), | |
29967ef6 XL |
117 | "tls static referenced without Rvalue::ThreadLocalRef" |
118 | ); | |
119 | CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout) | |
120 | } | |
121 | ||
122 | pub(crate) fn codegen_constant<'tcx>( | |
6a06907d | 123 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
124 | constant: &Constant<'tcx>, |
125 | ) -> CValue<'tcx> { | |
6a06907d XL |
126 | let const_ = match fx.monomorphize(constant.literal) { |
127 | ConstantKind::Ty(ct) => ct, | |
128 | ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty), | |
129 | }; | |
29967ef6 XL |
130 | let const_val = match const_.val { |
131 | ConstKind::Value(const_val) => const_val, | |
c295e0f8 | 132 | ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => { |
94222f64 XL |
133 | assert!(uv.substs(fx.tcx).is_empty()); |
134 | assert!(uv.promoted.is_none()); | |
29967ef6 | 135 | |
94222f64 | 136 | return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx); |
29967ef6 | 137 | } |
cdc7bbd5 XL |
138 | ConstKind::Unevaluated(unevaluated) => { |
139 | match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { | |
29967ef6 XL |
140 | Ok(const_val) => const_val, |
141 | Err(_) => { | |
6a06907d | 142 | span_bug!(constant.span, "erroneous constant not captured by required_consts"); |
29967ef6 XL |
143 | } |
144 | } | |
145 | } | |
146 | ConstKind::Param(_) | |
147 | | ConstKind::Infer(_) | |
148 | | ConstKind::Bound(_, _) | |
149 | | ConstKind::Placeholder(_) | |
150 | | ConstKind::Error(_) => unreachable!("{:?}", const_), | |
151 | }; | |
152 | ||
153 | codegen_const_value(fx, const_val, const_.ty) | |
154 | } | |
155 | ||
156 | pub(crate) fn codegen_const_value<'tcx>( | |
6a06907d | 157 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
158 | const_val: ConstValue<'tcx>, |
159 | ty: Ty<'tcx>, | |
160 | ) -> CValue<'tcx> { | |
161 | let layout = fx.layout_of(ty); | |
162 | assert!(!layout.is_unsized(), "sized const value"); | |
163 | ||
164 | if layout.is_zst() { | |
fc512014 | 165 | return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout); |
29967ef6 XL |
166 | } |
167 | ||
168 | match const_val { | |
136023e0 XL |
169 | ConstValue::Scalar(x) => match x { |
170 | Scalar::Int(int) => { | |
171 | if fx.clif_type(layout.ty).is_some() { | |
172 | return CValue::const_val(fx, layout, int); | |
173 | } else { | |
174 | let raw_val = int.to_bits(int.size()).unwrap(); | |
175 | let val = match int.size().bytes() { | |
176 | 1 => fx.bcx.ins().iconst(types::I8, raw_val as i64), | |
177 | 2 => fx.bcx.ins().iconst(types::I16, raw_val as i64), | |
178 | 4 => fx.bcx.ins().iconst(types::I32, raw_val as i64), | |
179 | 8 => fx.bcx.ins().iconst(types::I64, raw_val as i64), | |
180 | 16 => { | |
181 | let lsb = fx.bcx.ins().iconst(types::I64, raw_val as u64 as i64); | |
182 | let msb = | |
183 | fx.bcx.ins().iconst(types::I64, (raw_val >> 64) as u64 as i64); | |
184 | fx.bcx.ins().iconcat(lsb, msb) | |
29967ef6 | 185 | } |
136023e0 | 186 | _ => unreachable!(), |
29967ef6 | 187 | }; |
136023e0 XL |
188 | |
189 | let place = CPlace::new_stack_slot(fx, layout); | |
190 | place.to_ptr().store(fx, val, MemFlags::trusted()); | |
191 | place.to_cvalue(fx) | |
29967ef6 XL |
192 | } |
193 | } | |
136023e0 XL |
194 | Scalar::Ptr(ptr, _size) => { |
195 | let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative | |
196 | let alloc_kind = fx.tcx.get_global_alloc(alloc_id); | |
197 | let base_addr = match alloc_kind { | |
198 | Some(GlobalAlloc::Memory(alloc)) => { | |
199 | let data_id = data_id_for_alloc_id( | |
200 | &mut fx.constants_cx, | |
201 | fx.module, | |
202 | alloc_id, | |
203 | alloc.mutability, | |
204 | ); | |
205 | let local_data_id = | |
206 | fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); | |
207 | if fx.clif_comments.enabled() { | |
208 | fx.add_comment(local_data_id, format!("{:?}", alloc_id)); | |
209 | } | |
210 | fx.bcx.ins().global_value(fx.pointer_type, local_data_id) | |
211 | } | |
212 | Some(GlobalAlloc::Function(instance)) => { | |
213 | let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); | |
214 | let local_func_id = | |
215 | fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); | |
216 | fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) | |
217 | } | |
218 | Some(GlobalAlloc::Static(def_id)) => { | |
219 | assert!(fx.tcx.is_static(def_id)); | |
220 | let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); | |
221 | let local_data_id = | |
222 | fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); | |
223 | if fx.clif_comments.enabled() { | |
224 | fx.add_comment(local_data_id, format!("{:?}", def_id)); | |
225 | } | |
226 | fx.bcx.ins().global_value(fx.pointer_type, local_data_id) | |
227 | } | |
228 | None => bug!("missing allocation {:?}", alloc_id), | |
229 | }; | |
230 | let val = if offset.bytes() != 0 { | |
231 | fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap()) | |
232 | } else { | |
233 | base_addr | |
234 | }; | |
235 | CValue::by_val(val, layout) | |
236 | } | |
237 | }, | |
29967ef6 XL |
238 | ConstValue::ByRef { alloc, offset } => CValue::by_ref( |
239 | pointer_for_allocation(fx, alloc) | |
240 | .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), | |
241 | layout, | |
242 | ), | |
243 | ConstValue::Slice { data, start, end } => { | |
244 | let ptr = pointer_for_allocation(fx, data) | |
245 | .offset_i64(fx, i64::try_from(start).unwrap()) | |
246 | .get_addr(fx); | |
6a06907d XL |
247 | let len = fx |
248 | .bcx | |
249 | .ins() | |
250 | .iconst(fx.pointer_type, i64::try_from(end.checked_sub(start).unwrap()).unwrap()); | |
29967ef6 XL |
251 | CValue::by_val_pair(ptr, len, layout) |
252 | } | |
253 | } | |
254 | } | |
255 | ||
136023e0 | 256 | pub(crate) fn pointer_for_allocation<'tcx>( |
6a06907d | 257 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
258 | alloc: &'tcx Allocation, |
259 | ) -> crate::pointer::Pointer { | |
260 | let alloc_id = fx.tcx.create_memory_alloc(alloc); | |
17df50a5 XL |
261 | let data_id = |
262 | data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability); | |
29967ef6 | 263 | |
17df50a5 | 264 | let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); |
cdc7bbd5 XL |
265 | if fx.clif_comments.enabled() { |
266 | fx.add_comment(local_data_id, format!("{:?}", alloc_id)); | |
267 | } | |
29967ef6 XL |
268 | let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id); |
269 | crate::pointer::Pointer::new(global_ptr) | |
270 | } | |
271 | ||
136023e0 | 272 | pub(crate) fn data_id_for_alloc_id( |
17df50a5 | 273 | cx: &mut ConstantCx, |
6a06907d | 274 | module: &mut dyn Module, |
29967ef6 XL |
275 | alloc_id: AllocId, |
276 | mutability: rustc_hir::Mutability, | |
277 | ) -> DataId { | |
136023e0 | 278 | cx.todo.push(TodoItem::Alloc(alloc_id)); |
17df50a5 XL |
279 | *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { |
280 | module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap() | |
281 | }) | |
29967ef6 XL |
282 | } |
283 | ||
284 | fn data_id_for_static( | |
285 | tcx: TyCtxt<'_>, | |
6a06907d | 286 | module: &mut dyn Module, |
29967ef6 XL |
287 | def_id: DefId, |
288 | definition: bool, | |
289 | ) -> DataId { | |
290 | let rlinkage = tcx.codegen_fn_attrs(def_id).linkage; | |
291 | let linkage = if definition { | |
292 | crate::linkage::get_static_linkage(tcx, def_id) | |
293 | } else if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak) | |
294 | || rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny) | |
295 | { | |
296 | Linkage::Preemptible | |
297 | } else { | |
298 | Linkage::Import | |
299 | }; | |
300 | ||
301 | let instance = Instance::mono(tcx, def_id).polymorphize(tcx); | |
302 | let symbol_name = tcx.symbol_name(instance).name; | |
303 | let ty = instance.ty(tcx, ParamEnv::reveal_all()); | |
304 | let is_mutable = if tcx.is_mutable_static(def_id) { | |
305 | true | |
306 | } else { | |
307 | !ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) | |
308 | }; | |
6a06907d | 309 | let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes(); |
29967ef6 XL |
310 | |
311 | let attrs = tcx.codegen_fn_attrs(def_id); | |
312 | ||
313 | let data_id = module | |
314 | .declare_data( | |
315 | &*symbol_name, | |
316 | linkage, | |
317 | is_mutable, | |
318 | attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL), | |
319 | ) | |
320 | .unwrap(); | |
321 | ||
322 | if rlinkage.is_some() { | |
323 | // Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141 | |
324 | // Declare an internal global `extern_with_linkage_foo` which | |
325 | // is initialized with the address of `foo`. If `foo` is | |
326 | // discarded during linking (for example, if `foo` has weak | |
327 | // linkage and there are no definitions), then | |
328 | // `extern_with_linkage_foo` will instead be initialized to | |
329 | // zero. | |
330 | ||
331 | let ref_name = format!("_rust_extern_with_linkage_{}", symbol_name); | |
6a06907d | 332 | let ref_data_id = module.declare_data(&ref_name, Linkage::Local, false, false).unwrap(); |
29967ef6 XL |
333 | let mut data_ctx = DataContext::new(); |
334 | data_ctx.set_align(align); | |
335 | let data = module.declare_data_in_data(data_id, &mut data_ctx); | |
6a06907d | 336 | data_ctx.define(std::iter::repeat(0).take(pointer_ty(tcx).bytes() as usize).collect()); |
29967ef6 XL |
337 | data_ctx.write_data_addr(0, data, 0); |
338 | match module.define_data(ref_data_id, &data_ctx) { | |
339 | // Every time the static is referenced there will be another definition of this global, | |
340 | // so duplicate definitions are expected and allowed. | |
341 | Err(ModuleError::DuplicateDefinition(_)) => {} | |
342 | res => res.unwrap(), | |
343 | } | |
344 | ref_data_id | |
345 | } else { | |
346 | data_id | |
347 | } | |
348 | } | |
349 | ||
6a06907d | 350 | fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) { |
29967ef6 XL |
351 | while let Some(todo_item) = cx.todo.pop() { |
352 | let (data_id, alloc, section_name) = match todo_item { | |
353 | TodoItem::Alloc(alloc_id) => { | |
354 | //println!("alloc_id {}", alloc_id); | |
355 | let alloc = match tcx.get_global_alloc(alloc_id).unwrap() { | |
356 | GlobalAlloc::Memory(alloc) => alloc, | |
357 | GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(), | |
358 | }; | |
136023e0 XL |
359 | let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { |
360 | module | |
361 | .declare_anonymous_data( | |
362 | alloc.mutability == rustc_hir::Mutability::Mut, | |
363 | false, | |
364 | ) | |
365 | .unwrap() | |
366 | }); | |
29967ef6 XL |
367 | (data_id, alloc, None) |
368 | } | |
369 | TodoItem::Static(def_id) => { | |
370 | //println!("static {:?}", def_id); | |
371 | ||
a2a8927a | 372 | let section_name = tcx.codegen_fn_attrs(def_id).link_section; |
29967ef6 XL |
373 | |
374 | let alloc = tcx.eval_static_initializer(def_id).unwrap(); | |
375 | ||
376 | let data_id = data_id_for_static(tcx, module, def_id, true); | |
377 | (data_id, alloc, section_name) | |
378 | } | |
379 | }; | |
380 | ||
381 | //("data_id {}", data_id); | |
382 | if cx.done.contains(&data_id) { | |
383 | continue; | |
384 | } | |
385 | ||
386 | let mut data_ctx = DataContext::new(); | |
387 | data_ctx.set_align(alloc.align.bytes()); | |
388 | ||
389 | if let Some(section_name) = section_name { | |
17df50a5 | 390 | let (segment_name, section_name) = if tcx.sess.target.is_like_osx { |
a2a8927a | 391 | let section_name = section_name.as_str(); |
17df50a5 XL |
392 | if let Some(names) = section_name.split_once(',') { |
393 | names | |
394 | } else { | |
395 | tcx.sess.fatal(&format!( | |
396 | "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma", | |
397 | section_name | |
398 | )); | |
399 | } | |
400 | } else { | |
a2a8927a | 401 | ("", section_name.as_str()) |
17df50a5 XL |
402 | }; |
403 | data_ctx.set_segment_section(segment_name, section_name); | |
29967ef6 XL |
404 | } |
405 | ||
6a06907d | 406 | let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); |
29967ef6 XL |
407 | data_ctx.define(bytes.into_boxed_slice()); |
408 | ||
136023e0 | 409 | for &(offset, alloc_id) in alloc.relocations().iter() { |
29967ef6 XL |
410 | let addend = { |
411 | let endianness = tcx.data_layout.endian; | |
412 | let offset = offset.bytes() as usize; | |
413 | let ptr_size = tcx.data_layout.pointer_size; | |
414 | let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter( | |
415 | offset..offset + ptr_size.bytes() as usize, | |
416 | ); | |
417 | read_target_uint(endianness, bytes).unwrap() | |
418 | }; | |
419 | ||
136023e0 | 420 | let reloc_target_alloc = tcx.get_global_alloc(alloc_id).unwrap(); |
29967ef6 XL |
421 | let data_id = match reloc_target_alloc { |
422 | GlobalAlloc::Function(instance) => { | |
423 | assert_eq!(addend, 0); | |
424 | let func_id = crate::abi::import_function(tcx, module, instance); | |
425 | let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx); | |
426 | data_ctx.write_function_addr(offset.bytes() as u32, local_func_id); | |
427 | continue; | |
428 | } | |
429 | GlobalAlloc::Memory(target_alloc) => { | |
136023e0 | 430 | data_id_for_alloc_id(cx, module, alloc_id, target_alloc.mutability) |
29967ef6 XL |
431 | } |
432 | GlobalAlloc::Static(def_id) => { | |
6a06907d | 433 | if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) |
29967ef6 XL |
434 | { |
435 | tcx.sess.fatal(&format!( | |
436 | "Allocation {:?} contains reference to TLS value {:?}", | |
437 | alloc, def_id | |
438 | )); | |
439 | } | |
440 | ||
441 | // Don't push a `TodoItem::Static` here, as it will cause statics used by | |
442 | // multiple crates to be duplicated between them. It isn't necessary anyway, | |
443 | // as it will get pushed by `codegen_static` when necessary. | |
444 | data_id_for_static(tcx, module, def_id, false) | |
445 | } | |
446 | }; | |
447 | ||
448 | let global_value = module.declare_data_in_data(data_id, &mut data_ctx); | |
449 | data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64); | |
450 | } | |
451 | ||
17df50a5 | 452 | module.define_data(data_id, &data_ctx).unwrap(); |
29967ef6 XL |
453 | cx.done.insert(data_id); |
454 | } | |
455 | ||
456 | assert!(cx.todo.is_empty(), "{:?}", cx.todo); | |
457 | } | |
458 | ||
459 | pub(crate) fn mir_operand_get_const_val<'tcx>( | |
6a06907d | 460 | fx: &FunctionCx<'_, '_, 'tcx>, |
29967ef6 | 461 | operand: &Operand<'tcx>, |
6a06907d | 462 | ) -> Option<ConstValue<'tcx>> { |
29967ef6 | 463 | match operand { |
6a06907d XL |
464 | Operand::Constant(const_) => match const_.literal { |
465 | ConstantKind::Ty(const_) => { | |
466 | fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value() | |
467 | } | |
468 | ConstantKind::Val(val, _) => Some(val), | |
469 | }, | |
17df50a5 XL |
470 | // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored |
471 | // inside a temporary before being passed to the intrinsic requiring the const argument. | |
472 | // This code tries to find a single constant defining definition of the referenced local. | |
473 | Operand::Copy(place) | Operand::Move(place) => { | |
474 | if !place.projection.is_empty() { | |
475 | return None; | |
476 | } | |
477 | let mut computed_const_val = None; | |
478 | for bb_data in fx.mir.basic_blocks() { | |
479 | for stmt in &bb_data.statements { | |
480 | match &stmt.kind { | |
481 | StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => { | |
482 | match &local_and_rvalue.1 { | |
483 | Rvalue::Cast(CastKind::Misc, operand, ty) => { | |
484 | if computed_const_val.is_some() { | |
485 | return None; // local assigned twice | |
486 | } | |
487 | if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) { | |
488 | return None; | |
489 | } | |
490 | let const_val = mir_operand_get_const_val(fx, operand)?; | |
491 | if fx.layout_of(ty).size | |
492 | != const_val.try_to_scalar_int()?.size() | |
493 | { | |
494 | return None; | |
495 | } | |
496 | computed_const_val = Some(const_val); | |
497 | } | |
498 | Rvalue::Use(operand) => { | |
499 | computed_const_val = mir_operand_get_const_val(fx, operand) | |
500 | } | |
501 | _ => return None, | |
502 | } | |
503 | } | |
504 | StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ } | |
505 | if &**stmt_place == place => | |
506 | { | |
507 | return None; | |
508 | } | |
509 | StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => { | |
510 | return None; | |
511 | } // conservative handling | |
512 | StatementKind::Assign(_) | |
513 | | StatementKind::FakeRead(_) | |
514 | | StatementKind::SetDiscriminant { .. } | |
515 | | StatementKind::StorageLive(_) | |
516 | | StatementKind::StorageDead(_) | |
517 | | StatementKind::Retag(_, _) | |
518 | | StatementKind::AscribeUserType(_, _) | |
519 | | StatementKind::Coverage(_) | |
520 | | StatementKind::Nop => {} | |
521 | } | |
522 | } | |
523 | match &bb_data.terminator().kind { | |
524 | TerminatorKind::Goto { .. } | |
525 | | TerminatorKind::SwitchInt { .. } | |
526 | | TerminatorKind::Resume | |
527 | | TerminatorKind::Abort | |
528 | | TerminatorKind::Return | |
529 | | TerminatorKind::Unreachable | |
530 | | TerminatorKind::Drop { .. } | |
531 | | TerminatorKind::Assert { .. } => {} | |
532 | TerminatorKind::DropAndReplace { .. } | |
533 | | TerminatorKind::Yield { .. } | |
534 | | TerminatorKind::GeneratorDrop | |
535 | | TerminatorKind::FalseEdge { .. } | |
536 | | TerminatorKind::FalseUnwind { .. } => unreachable!(), | |
537 | TerminatorKind::InlineAsm { .. } => return None, | |
538 | TerminatorKind::Call { destination: Some((call_place, _)), .. } | |
539 | if call_place == place => | |
540 | { | |
541 | return None; | |
542 | } | |
543 | TerminatorKind::Call { .. } => {} | |
544 | } | |
545 | } | |
546 | computed_const_val | |
547 | } | |
29967ef6 XL |
548 | } |
549 | } |