3 use rustc::mir::interpret::{
4 read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
6 use rustc::ty::{Const, LazyConst};
7 use rustc_mir::interpret::{
8 EvalContext, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer, StackPopCleanup,
11 use cranelift_module::*;
13 use crate::prelude::*;
16 pub struct ConstantCx {
17 todo: HashSet<TodoItem>,
18 done: HashSet<DataId>,
21 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
28 pub fn finalize<'a, 'tcx: 'a, B: Backend>(
30 tcx: TyCtxt<'a, 'tcx, 'tcx>,
31 module: &mut Module<B>,
33 //println!("todo {:?}", self.todo);
34 define_all_allocs(tcx, module, &mut self);
35 //println!("done {:?}", self.done);
40 pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
41 ccx.todo.insert(TodoItem::Static(def_id));
44 pub fn codegen_static_ref<'a, 'tcx: 'a>(
45 fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
46 static_: &Static<'tcx>,
48 let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
49 cplace_for_dataid(fx, static_.ty, data_id)
52 pub fn trans_promoted<'a, 'tcx: 'a>(
53 fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
58 .const_eval(ParamEnv::reveal_all().and(GlobalId {
59 instance: fx.instance,
60 promoted: Some(promoted),
64 trans_const_place(fx, const_)
67 pub fn trans_constant<'a, 'tcx: 'a>(
68 fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
69 constant: &Constant<'tcx>,
71 let const_ = fx.monomorphize(&constant.literal);
72 let const_ = force_eval_const(fx, const_);
73 trans_const_value(fx, const_)
76 pub fn force_eval_const<'a, 'tcx: 'a>(
77 fx: &FunctionCx<'a, 'tcx, impl Backend>,
78 const_: &'tcx LazyConst<'tcx>,
81 LazyConst::Unevaluated(def_id, ref substs) => {
82 let param_env = ParamEnv::reveal_all();
83 let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
88 fx.tcx.const_eval(param_env.and(cid)).unwrap()
90 LazyConst::Evaluated(const_) => const_,
94 fn trans_const_value<'a, 'tcx: 'a>(
95 fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
98 let ty = fx.monomorphize(&const_.ty);
99 let layout = fx.layout_of(ty);
102 let bits = const_.val.try_to_bits(layout.size).unwrap();
103 CValue::const_val(fx, ty, bits as u64 as i64)
106 let bits = const_.val.try_to_bits(layout.size).unwrap();
107 CValue::const_val(fx, ty, bits as u64 as i64)
110 let bits = const_.val.try_to_bits(layout.size).unwrap();
111 CValue::const_val(fx, ty, bits as i128 as i64)
113 ty::FnDef(_def_id, _substs) => {
115 fx.bcx.ins().iconst(fx.pointer_type, 0),
119 _ => trans_const_place(fx, const_).to_cvalue(fx),
123 fn trans_const_place<'a, 'tcx: 'a>(
124 fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
127 // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
128 let result = || -> EvalResult<'tcx, &'tcx Allocation> {
129 let mut ecx = EvalContext::new(
131 ty::ParamEnv::reveal_all(),
132 TransPlaceInterpreter,
134 ecx.push_stack_frame(
139 StackPopCleanup::None { cleanup: false },
142 let op = ecx.eval_operand(
143 &Operand::Constant(Box::new(Constant {
147 literal: fx.tcx.intern_lazy_const(LazyConst::Evaluated(const_)),
151 let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
152 ecx.copy_op(op, ptr.into())?;
153 let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
154 Ok(fx.tcx.intern_const_alloc(alloc.clone()))
156 let alloc = result().expect("unable to convert ConstValue to Allocation");
158 //println!("const value: {:?} allocation: {:?}", value, alloc);
159 let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
160 fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
161 let data_id = data_id_for_alloc_id(fx.module, alloc_id);
162 cplace_for_dataid(fx, const_.ty, data_id)
165 fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
167 .declare_data(&format!("__alloc_{}", alloc_id.0), Linkage::Local, false)
171 fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
172 tcx: TyCtxt<'a, 'tcx, 'tcx>,
173 module: &mut Module<B>,
177 let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
178 let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
182 .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
185 .declare_data(&*symbol_name, linkage, is_mutable)
189 fn cplace_for_dataid<'a, 'tcx: 'a>(
190 fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
194 let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
195 let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
196 let layout = fx.layout_of(fx.monomorphize(&ty));
197 assert!(!layout.is_unsized(), "unsized statics aren't supported");
198 CPlace::Addr(global_ptr, None, layout)
201 fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
202 tcx: TyCtxt<'a, 'tcx, 'tcx>,
203 module: &mut Module<B>,
206 let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));
208 while let Some(todo_item) = pop_set(&mut cx.todo) {
209 let (data_id, alloc) = match todo_item {
210 TodoItem::Alloc(alloc_id) => {
211 //println!("alloc_id {}", alloc_id);
212 let data_id = data_id_for_alloc_id(module, alloc_id);
213 let alloc = memory.get(alloc_id).unwrap();
216 TodoItem::Static(def_id) => {
217 //println!("static {:?}", def_id);
218 let instance = ty::Instance::mono(tcx, def_id);
223 let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();
225 let alloc = match const_.val {
226 ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
227 _ => bug!("static const eval returned {:#?}", const_),
230 let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
235 //("data_id {}", data_id);
236 if cx.done.contains(&data_id) {
240 let mut data_ctx = DataContext::new();
242 data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());
244 for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
246 let endianness = tcx.data_layout.endian;
247 let offset = offset.bytes() as usize;
248 let ptr_size = tcx.data_layout.pointer_size;
249 let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
250 read_target_uint(endianness, bytes).unwrap()
253 let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
254 AllocKind::Function(instance) => {
255 assert_eq!(addend, 0);
256 let func_id = crate::abi::import_function(tcx, module, instance);
257 let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
258 data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
261 AllocKind::Memory(_) => {
262 cx.todo.insert(TodoItem::Alloc(reloc));
263 data_id_for_alloc_id(module, reloc)
265 AllocKind::Static(def_id) => {
266 cx.todo.insert(TodoItem::Static(def_id));
267 data_id_for_static(tcx, module, def_id, Linkage::Import)
271 let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
272 data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
275 module.define_data(data_id, &data_ctx).unwrap();
276 cx.done.insert(data_id);
279 assert!(cx.todo.is_empty(), "{:?}", cx.todo);
282 fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
283 if let Some(elem) = set.iter().next().map(|elem| *elem) {
291 struct TransPlaceInterpreter;
293 impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
294 type MemoryKinds = !;
295 type PointerTag = ();
296 type AllocExtra = ();
297 type MemoryExtra = ();
298 type FrameExtra = ();
299 type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
300 const STATIC_KIND: Option<!> = None;
302 fn enforce_validity(_: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
306 fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
311 _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
314 _: Option<PlaceTy<'tcx>>,
315 _: Option<BasicBlock>,
316 ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
321 _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
325 ) -> EvalResult<'tcx> {
329 fn find_foreign_static(
331 _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
333 ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
338 _: &EvalContext<'a, 'mir, 'tcx, Self>,
344 ) -> EvalResult<'tcx, (Scalar, bool)> {
348 fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
353 _: &EvalContext<'a, 'mir, 'tcx, Self>,
355 _: Option<::rustc::hir::Mutability>,
356 ) -> EvalResult<'tcx, Scalar> {
360 fn adjust_static_allocation<'alloc>(
361 alloc: &'alloc Allocation,
363 ) -> Cow<'alloc, Allocation> {
367 fn tag_new_allocation(
368 _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
375 fn stack_push(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>{
379 fn stack_pop(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {