]> git.lizzy.rs Git - rust.git/blob - src/common.rs
Rustup to rustc 1.30.0-nightly (63d66494a 2018-08-23)
[rust.git] / src / common.rs
1 use std::fmt;
2
3 use rustc_target::spec::{HasTargetSpec, Target};
4
5 use cranelift_module::Module;
6
7 use crate::prelude::*;
8
9 pub fn mir_var(loc: Local) -> Variable {
10     Variable::with_u32(loc.index() as u32)
11 }
12
13 pub fn pointer_ty(tcx: TyCtxt) -> types::Type {
14     match tcx.data_layout.pointer_size.bits() {
15         16 => types::I16,
16         32 => types::I32,
17         64 => types::I64,
18         bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
19     }
20 }
21
22 pub fn cton_type_from_ty<'a, 'tcx: 'a>(
23     tcx: TyCtxt<'a, 'tcx, 'tcx>,
24     ty: Ty<'tcx>,
25 ) -> Option<types::Type> {
26     Some(match ty.sty {
27         ty::Bool => types::I8,
28         ty::Uint(size) => match size {
29             UintTy::U8 => types::I8,
30             UintTy::U16 => types::I16,
31             UintTy::U32 => types::I32,
32             UintTy::U64 => types::I64,
33             UintTy::U128 => unimpl!("u128"),
34             UintTy::Usize => pointer_ty(tcx),
35         },
36         ty::Int(size) => match size {
37             IntTy::I8 => types::I8,
38             IntTy::I16 => types::I16,
39             IntTy::I32 => types::I32,
40             IntTy::I64 => types::I64,
41             IntTy::I128 => unimpl!("i128"),
42             IntTy::Isize => pointer_ty(tcx),
43         },
44         ty::Char => types::I32,
45         ty::Float(size) => match size {
46             FloatTy::F32 => types::F32,
47             FloatTy::F64 => types::F64,
48         },
49         ty::FnPtr(_) => pointer_ty(tcx),
50         ty::RawPtr(TypeAndMut { ty, mutbl: _ }) | ty::Ref(_, ty, _) => {
51             if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
52                 pointer_ty(tcx)
53             } else {
54                 return None;
55             }
56         }
57         ty::Param(_) => bug!("{:?}: {:?}", ty, ty.sty),
58         _ => return None,
59     })
60 }
61
62 fn codegen_field<'a, 'tcx: 'a>(
63     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
64     base: Value,
65     layout: TyLayout<'tcx>,
66     field: mir::Field,
67 ) -> (Value, TyLayout<'tcx>) {
68     let field_offset = layout.fields.offset(field.index());
69     let field_ty = layout.field(&*fx, field.index());
70     if field_offset.bytes() > 0 {
71         (
72             fx.bcx.ins().iadd_imm(base, field_offset.bytes() as i64),
73             field_ty,
74         )
75     } else {
76         (base, field_ty)
77     }
78 }
79
80 /// A read-only value
81 #[derive(Debug, Copy, Clone)]
82 pub enum CValue<'tcx> {
83     ByRef(Value, TyLayout<'tcx>),
84     ByVal(Value, TyLayout<'tcx>),
85     ByValPair(Value, Value, TyLayout<'tcx>),
86 }
87
88 impl<'tcx> CValue<'tcx> {
89     pub fn layout(&self) -> TyLayout<'tcx> {
90         match *self {
91             CValue::ByRef(_, layout)
92             | CValue::ByVal(_, layout)
93             | CValue::ByValPair(_, _, layout) => layout,
94         }
95     }
96
97     pub fn force_stack<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> Value
98     where
99         'tcx: 'a,
100     {
101         match self {
102             CValue::ByRef(value, _layout) => value,
103             CValue::ByVal(value, layout) => {
104                 let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
105                     kind: StackSlotKind::ExplicitSlot,
106                     size: layout.size.bytes() as u32,
107                     offset: None,
108                 });
109                 fx.bcx.ins().stack_store(value, stack_slot, 0);
110                 fx.bcx
111                     .ins()
112                     .stack_addr(fx.module.pointer_type(), stack_slot, 0)
113             }
114             CValue::ByValPair(value, extra, layout) => {
115                 let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
116                     kind: StackSlotKind::ExplicitSlot,
117                     size: layout.size.bytes() as u32,
118                     offset: None,
119                 });
120                 let base = fx.bcx.ins().stack_addr(types::I64, stack_slot, 0);
121                 let a_addr = codegen_field(fx, base, layout, mir::Field::new(0)).0;
122                 let b_addr = codegen_field(fx, base, layout, mir::Field::new(1)).0;
123                 fx.bcx.ins().store(MemFlags::new(), value, a_addr, 0);
124                 fx.bcx.ins().store(MemFlags::new(), extra, b_addr, 0);
125                 base
126             }
127         }
128     }
129
130     pub fn load_value<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> Value
131     where
132         'tcx: 'a,
133     {
134         match self {
135             CValue::ByRef(addr, layout) => {
136                 let cton_ty = fx
137                     .cton_type(layout.ty)
138                     .expect(&format!("load_value of type {:?}", layout.ty));
139                 fx.bcx.ins().load(cton_ty, MemFlags::new(), addr, 0)
140             }
141             CValue::ByVal(value, _layout) => value,
142             CValue::ByValPair(_, _, _layout) => bug!("Please use load_value_pair for ByValPair"),
143         }
144     }
145
146     pub fn load_value_pair<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> (Value, Value)
147     where
148         'tcx: 'a,
149     {
150         match self {
151             CValue::ByRef(addr, layout) => {
152                 assert_eq!(
153                     layout.size.bytes(),
154                     fx.tcx.data_layout.pointer_size.bytes() * 2
155                 );
156                 let val1_offset = layout.fields.offset(0).bytes() as i32;
157                 let val2_offset = layout.fields.offset(1).bytes() as i32;
158                 let val1 =
159                     fx.bcx
160                         .ins()
161                         .load(fx.module.pointer_type(), MemFlags::new(), addr, val1_offset);
162                 let val2 =
163                     fx.bcx
164                         .ins()
165                         .load(fx.module.pointer_type(), MemFlags::new(), addr, val2_offset);
166                 (val1, val2)
167             }
168             CValue::ByVal(_, _layout) => bug!("Please use load_value for ByVal"),
169             CValue::ByValPair(val1, val2, _layout) => (val1, val2),
170         }
171     }
172
173     pub fn expect_byref(self) -> (Value, TyLayout<'tcx>) {
174         match self {
175             CValue::ByRef(value, layout) => (value, layout),
176             CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal: {:?}", self),
177             CValue::ByValPair(_, _, _) => bug!(
178                 "Expected CValue::ByRef, found CValue::ByValPair: {:?}",
179                 self
180             ),
181         }
182     }
183
184     pub fn value_field<'a>(
185         self,
186         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
187         field: mir::Field,
188     ) -> CValue<'tcx>
189     where
190         'tcx: 'a,
191     {
192         let (base, layout) = match self {
193             CValue::ByRef(addr, layout) => (addr, layout),
194             _ => bug!("place_field for {:?}", self),
195         };
196
197         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
198         CValue::ByRef(field_ptr, field_layout)
199     }
200
201     pub fn const_val<'a>(
202         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
203         ty: Ty<'tcx>,
204         const_val: i64,
205     ) -> CValue<'tcx>
206     where
207         'tcx: 'a,
208     {
209         let cton_ty = fx.cton_type(ty).unwrap();
210         let layout = fx.layout_of(ty);
211         CValue::ByVal(fx.bcx.ins().iconst(cton_ty, const_val), layout)
212     }
213
214     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
215         match self {
216             CValue::ByRef(addr, _) => CValue::ByRef(addr, layout),
217             CValue::ByVal(val, _) => CValue::ByVal(val, layout),
218             CValue::ByValPair(val, extra, _) => CValue::ByValPair(val, extra, layout),
219         }
220     }
221 }
222
223 /// A place where you can write a value to or read a value from
224 #[derive(Debug, Copy, Clone)]
225 pub enum CPlace<'tcx> {
226     Var(Local, TyLayout<'tcx>),
227     Addr(Value, TyLayout<'tcx>),
228 }
229
230 impl<'a, 'tcx: 'a> CPlace<'tcx> {
231     pub fn layout(&self) -> TyLayout<'tcx> {
232         match *self {
233             CPlace::Var(_, layout) | CPlace::Addr(_, layout) => layout,
234         }
235     }
236
237     pub fn temp(fx: &mut FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>) -> CPlace<'tcx> {
238         let layout = fx.layout_of(ty);
239         let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
240             kind: StackSlotKind::ExplicitSlot,
241             size: layout.size.bytes() as u32,
242             offset: None,
243         });
244         CPlace::Addr(
245             fx.bcx
246                 .ins()
247                 .stack_addr(fx.module.pointer_type(), stack_slot, 0),
248             layout,
249         )
250     }
251
252     pub fn from_stack_slot(
253         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
254         stack_slot: StackSlot,
255         ty: Ty<'tcx>,
256     ) -> CPlace<'tcx> {
257         let layout = fx.layout_of(ty);
258         CPlace::Addr(
259             fx.bcx
260                 .ins()
261                 .stack_addr(fx.module.pointer_type(), stack_slot, 0),
262             layout,
263         )
264     }
265
266     pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CValue<'tcx> {
267         match self {
268             CPlace::Var(var, layout) => CValue::ByVal(fx.bcx.use_var(mir_var(var)), layout),
269             CPlace::Addr(addr, layout) => CValue::ByRef(addr, layout),
270         }
271     }
272
273     pub fn expect_addr(self) -> Value {
274         match self {
275             CPlace::Addr(addr, _layout) => addr,
276             CPlace::Var(_, _) => bug!("Expected CPlace::Addr, found CPlace::Var"),
277         }
278     }
279
280     pub fn write_cvalue(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>, from: CValue<'tcx>) {
281         match (&self.layout().ty.sty, &from.layout().ty.sty) {
282             (ty::Ref(_, t, dest_mut), ty::Ref(_, u, src_mut))
283                 if (if *dest_mut != ::rustc::hir::Mutability::MutImmutable && src_mut != dest_mut {
284                     false
285                 } else if t != u {
286                     false
287                 } else {
288                     true
289                 }) =>
290             {
291                 // &mut T -> &T is allowed
292                 // &'a T -> &'b T is allowed
293             }
294             _ => {
295                 assert_eq!(
296                     self.layout().ty,
297                     from.layout().ty,
298                     "Can't write value of incompatible type to place {:?} {:?}\n\n{:#?}",
299                     self.layout().ty.sty,
300                     from.layout().ty.sty,
301                     fx,
302                 );
303             }
304         }
305
306         match self {
307             CPlace::Var(var, _) => {
308                 let data = from.load_value(fx);
309                 fx.bcx.def_var(mir_var(var), data)
310             }
311             CPlace::Addr(addr, layout) => {
312                 let size = layout.size.bytes() as i32;
313
314                 match from {
315                     CValue::ByVal(val, _layout) => {
316                         fx.bcx.ins().store(MemFlags::new(), val, addr, 0);
317                     }
318                     CValue::ByValPair(val1, val2, _layout) => {
319                         let val1_offset = layout.fields.offset(0).bytes() as i32;
320                         let val2_offset = layout.fields.offset(1).bytes() as i32;
321                         fx.bcx.ins().store(MemFlags::new(), val1, addr, val1_offset);
322                         fx.bcx.ins().store(MemFlags::new(), val2, addr, val2_offset);
323                     }
324                     CValue::ByRef(from, _layout) => {
325                         let mut offset = 0;
326                         while size - offset >= 8 {
327                             let byte = fx.bcx.ins().load(
328                                 fx.module.pointer_type(),
329                                 MemFlags::new(),
330                                 from,
331                                 offset,
332                             );
333                             fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
334                             offset += 8;
335                         }
336                         while size - offset >= 4 {
337                             let byte = fx.bcx.ins().load(types::I32, MemFlags::new(), from, offset);
338                             fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
339                             offset += 4;
340                         }
341                         while offset < size {
342                             let byte = fx.bcx.ins().load(types::I8, MemFlags::new(), from, offset);
343                             fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
344                             offset += 1;
345                         }
346                     }
347                 }
348             }
349         }
350     }
351
352     pub fn place_field(
353         self,
354         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
355         field: mir::Field,
356     ) -> CPlace<'tcx> {
357         let base = self.expect_addr();
358         let layout = self.layout();
359
360         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
361         CPlace::Addr(field_ptr, field_layout)
362     }
363
364     pub fn place_index(
365         self,
366         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
367         index: Value,
368     ) -> CPlace<'tcx> {
369         let addr = self.expect_addr();
370         let layout = self.layout();
371         match layout.ty.sty {
372             ty::Array(elem_ty, _) => {
373                 let elem_layout = fx.layout_of(elem_ty);
374                 let offset = fx
375                     .bcx
376                     .ins()
377                     .imul_imm(index, elem_layout.size.bytes() as i64);
378                 CPlace::Addr(fx.bcx.ins().iadd(addr, offset), elem_layout)
379             }
380             ty::Slice(_elem_ty) => unimplemented!("place_index(TySlice)"),
381             _ => bug!("place_index({:?})", layout.ty),
382         }
383     }
384
385     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
386         match self {
387             CPlace::Var(var, _) => CPlace::Var(var, layout),
388             CPlace::Addr(addr, _) => CPlace::Addr(addr, layout),
389         }
390     }
391
392     pub fn downcast_variant(self, fx: &FunctionCx<'a, 'tcx, impl Backend>, variant: usize) -> Self {
393         let layout = self.layout().for_variant(fx, variant);
394         self.unchecked_cast_to(layout)
395     }
396 }
397
398 pub fn cton_intcast<'a, 'tcx: 'a>(
399     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
400     val: Value,
401     to: Type,
402     signed: bool,
403 ) -> Value {
404     let from = fx.bcx.func.dfg.value_type(val);
405     if from == to {
406         return val;
407     }
408     if to.wider_or_equal(from) {
409         if signed {
410             fx.bcx.ins().sextend(to, val)
411         } else {
412             fx.bcx.ins().uextend(to, val)
413         }
414     } else {
415         fx.bcx.ins().ireduce(to, val)
416     }
417 }
418
419 pub struct FunctionCx<'a, 'tcx: 'a, B: Backend + 'a> {
420     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
421     pub module: &'a mut Module<B>,
422     pub instance: Instance<'tcx>,
423     pub mir: &'tcx Mir<'tcx>,
424     pub param_substs: &'tcx Substs<'tcx>,
425     pub bcx: FunctionBuilder<'a>,
426     pub ebb_map: HashMap<BasicBlock, Ebb>,
427     pub local_map: HashMap<Local, CPlace<'tcx>>,
428     pub comments: HashMap<Inst, String>,
429     pub constants: &'a mut crate::constant::ConstantCx,
430
431     /// add_global_comment inserts a comment here
432     pub top_nop: Option<Inst>,
433 }
434
435 impl<'a, 'tcx: 'a, B: Backend + 'a> fmt::Debug for FunctionCx<'a, 'tcx, B> {
436     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
437         writeln!(f, "{:?}", self.param_substs)?;
438         writeln!(f, "{:?}", self.local_map)?;
439
440         let mut clif = String::new();
441         let mut writer = crate::pretty_clif::CommentWriter(self.comments.clone());
442         ::cranelift::codegen::write::decorate_function(
443             &mut writer,
444             &mut clif,
445             &self.bcx.func,
446             None,
447         ).unwrap();
448         writeln!(f, "\n{}", clif)
449     }
450 }
451
452 impl<'a, 'tcx: 'a, B: Backend> LayoutOf for &'a FunctionCx<'a, 'tcx, B> {
453     type Ty = Ty<'tcx>;
454     type TyLayout = TyLayout<'tcx>;
455
456     fn layout_of(self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
457         let ty = self.monomorphize(&ty);
458         self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
459     }
460 }
461
462 impl<'a, 'tcx, B: Backend + 'a> layout::HasTyCtxt<'tcx> for &'a FunctionCx<'a, 'tcx, B> {
463     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
464         self.tcx
465     }
466 }
467
468 impl<'a, 'tcx, B: Backend + 'a> layout::HasDataLayout for &'a FunctionCx<'a, 'tcx, B> {
469     fn data_layout(&self) -> &layout::TargetDataLayout {
470         &self.tcx.data_layout
471     }
472 }
473
474 impl<'a, 'tcx, B: Backend + 'a> HasTargetSpec for &'a FunctionCx<'a, 'tcx, B> {
475     fn target_spec(&self) -> &Target {
476         &self.tcx.sess.target.target
477     }
478 }
479
480 impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
481     pub fn monomorphize<T>(&self, value: &T) -> T
482     where
483         T: TypeFoldable<'tcx>,
484     {
485         self.tcx.subst_and_normalize_erasing_regions(
486             self.param_substs,
487             ty::ParamEnv::reveal_all(),
488             value,
489         )
490     }
491
492     pub fn cton_type(&self, ty: Ty<'tcx>) -> Option<Type> {
493         cton_type_from_ty(self.tcx, self.monomorphize(&ty))
494     }
495
496     pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
497         *self.ebb_map.get(&bb).unwrap()
498     }
499
500     pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
501         *self.local_map.get(&local).unwrap()
502     }
503 }