]> git.lizzy.rs Git - rust.git/blob - src/common.rs
Fix some bugs
[rust.git] / src / common.rs
1 use std::fmt;
2
3 use rustc_target::spec::{HasTargetSpec, Target};
4
5 use cranelift_module::{DataId, Module};
6
7 use crate::prelude::*;
8
9 pub type CurrentBackend = ::cranelift_simplejit::SimpleJITBackend;
10
11 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
12 pub struct Variable(Local);
13
14 impl EntityRef for Variable {
15     fn new(u: usize) -> Self {
16         Variable(Local::new(u))
17     }
18
19     fn index(self) -> usize {
20         self.0.index()
21     }
22 }
23
24 pub fn cton_type_from_ty<'a, 'tcx: 'a>(
25     tcx: TyCtxt<'a, 'tcx, 'tcx>,
26     ty: Ty<'tcx>,
27 ) -> Option<types::Type> {
28     Some(match ty.sty {
29         TypeVariants::TyBool => types::I8,
30         TypeVariants::TyUint(size) => match size {
31             UintTy::U8 => types::I8,
32             UintTy::U16 => types::I16,
33             UintTy::U32 => types::I32,
34             UintTy::U64 => types::I64,
35             UintTy::U128 => unimplemented!("u128"),
36             UintTy::Usize => types::I64,
37         },
38         TypeVariants::TyInt(size) => match size {
39             IntTy::I8 => types::I8,
40             IntTy::I16 => types::I16,
41             IntTy::I32 => types::I32,
42             IntTy::I64 => types::I64,
43             IntTy::I128 => unimplemented!("i128"),
44             IntTy::Isize => types::I64,
45         },
46         TypeVariants::TyChar => types::I32,
47         TypeVariants::TyFloat(size) => match size {
48             FloatTy::F32 => types::F32,
49             FloatTy::F64 => types::F64,
50         },
51         TypeVariants::TyFnPtr(_) => types::I64,
52         TypeVariants::TyRawPtr(TypeAndMut { ty, mutbl: _ }) | TypeVariants::TyRef(_, ty, _) => {
53             if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
54                 types::I64
55             } else {
56                 return None;
57             }
58         }
59         TypeVariants::TyParam(_) => bug!("{:?}: {:?}", ty, ty.sty),
60         _ => return None,
61     })
62 }
63
64 fn codegen_field<'a, 'tcx: 'a>(
65     fx: &mut FunctionCx<'a, 'tcx>,
66     base: Value,
67     layout: TyLayout<'tcx>,
68     field: mir::Field,
69 ) -> (Value, TyLayout<'tcx>) {
70     let field_offset = layout.fields.offset(field.index());
71     let field_ty = layout.field(&*fx, field.index());
72     if field_offset.bytes() > 0 {
73         let field_offset = fx.bcx.ins().iconst(types::I64, field_offset.bytes() as i64);
74         (fx.bcx.ins().iadd(base, field_offset), field_ty)
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     Func(FuncRef, TyLayout<'tcx>),
86 }
87
88 impl<'tcx> CValue<'tcx> {
89     pub fn layout(&self) -> TyLayout<'tcx> {
90         match *self {
91             CValue::ByRef(_, layout) | CValue::ByVal(_, layout) | CValue::Func(_, layout) => layout,
92         }
93     }
94
95     pub fn force_stack<'a>(self, fx: &mut FunctionCx<'a, 'tcx>) -> Value
96     where
97         'tcx: 'a,
98     {
99         match self {
100             CValue::ByRef(value, _layout) => value,
101             CValue::ByVal(value, layout) => {
102                 let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
103                     kind: StackSlotKind::ExplicitSlot,
104                     size: layout.size.bytes() as u32,
105                     offset: None,
106                 });
107                 fx.bcx.ins().stack_store(value, stack_slot, 0);
108                 fx.bcx.ins().stack_addr(types::I64, stack_slot, 0)
109             }
110             CValue::Func(func, ty) => {
111                 let func = fx.bcx.ins().func_addr(types::I64, func);
112                 CValue::ByVal(func, ty).force_stack(fx)
113             }
114         }
115     }
116
117     pub fn load_value<'a>(self, fx: &mut FunctionCx<'a, 'tcx>) -> Value
118     where
119         'tcx: 'a,
120     {
121         match self {
122             CValue::ByRef(addr, layout) => {
123                 let cton_ty = fx
124                     .cton_type(layout.ty)
125                     .expect(&format!("load_value of type {:?}", layout.ty));
126                 fx.bcx.ins().load(cton_ty, MemFlags::new(), addr, 0)
127             }
128             CValue::ByVal(value, _layout) => value,
129             CValue::Func(func, _layout) => fx.bcx.ins().func_addr(types::I64, func),
130         }
131     }
132
133     pub fn expect_byref(self) -> (Value, TyLayout<'tcx>) {
134         match self {
135             CValue::ByRef(value, layout) => (value, layout),
136             CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal: {:?}", self),
137             CValue::Func(_, _) => bug!("Expected CValue::ByRef, found CValue::Func: {:?}", self),
138         }
139     }
140
141     pub fn value_field<'a>(self, fx: &mut FunctionCx<'a, 'tcx>, field: mir::Field) -> CValue<'tcx>
142     where
143         'tcx: 'a,
144     {
145         let (base, layout) = match self {
146             CValue::ByRef(addr, layout) => (addr, layout),
147             _ => bug!("place_field for {:?}", self),
148         };
149
150         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
151         CValue::ByRef(field_ptr, field_layout)
152     }
153
154     pub fn const_val<'a>(
155         fx: &mut FunctionCx<'a, 'tcx>,
156         ty: Ty<'tcx>,
157         const_val: i64,
158     ) -> CValue<'tcx>
159     where
160         'tcx: 'a,
161     {
162         let cton_ty = fx.cton_type(ty).unwrap();
163         let layout = fx.layout_of(ty);
164         CValue::ByVal(fx.bcx.ins().iconst(cton_ty, const_val), layout)
165     }
166
167     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
168         match self {
169             CValue::ByRef(addr, _) => CValue::ByRef(addr, layout),
170             CValue::ByVal(val, _) => CValue::ByVal(val, layout),
171             CValue::Func(fun, _) => CValue::Func(fun, layout),
172         }
173     }
174 }
175
176 /// A place where you can write a value to or read a value from
177 #[derive(Debug, Copy, Clone)]
178 pub enum CPlace<'tcx> {
179     Var(Variable, TyLayout<'tcx>),
180     Addr(Value, TyLayout<'tcx>),
181 }
182
183 impl<'a, 'tcx: 'a> CPlace<'tcx> {
184     pub fn layout(&self) -> TyLayout<'tcx> {
185         match *self {
186             CPlace::Var(_, layout) | CPlace::Addr(_, layout) => layout,
187         }
188     }
189
190     pub fn temp(fx: &mut FunctionCx<'a, 'tcx>, ty: Ty<'tcx>) -> CPlace<'tcx> {
191         let layout = fx.layout_of(ty);
192         let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
193             kind: StackSlotKind::ExplicitSlot,
194             size: layout.size.bytes() as u32,
195             offset: None,
196         });
197         CPlace::Addr(fx.bcx.ins().stack_addr(types::I64, stack_slot, 0), layout)
198     }
199
200     pub fn from_stack_slot(
201         fx: &mut FunctionCx<'a, 'tcx>,
202         stack_slot: StackSlot,
203         ty: Ty<'tcx>,
204     ) -> CPlace<'tcx> {
205         let layout = fx.layout_of(ty);
206         CPlace::Addr(fx.bcx.ins().stack_addr(types::I64, stack_slot, 0), layout)
207     }
208
209     pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx>) -> CValue<'tcx> {
210         match self {
211             CPlace::Var(var, layout) => CValue::ByVal(fx.bcx.use_var(var), layout),
212             CPlace::Addr(addr, layout) => CValue::ByRef(addr, layout),
213         }
214     }
215
216     pub fn expect_addr(self) -> Value {
217         match self {
218             CPlace::Addr(addr, _layout) => addr,
219             CPlace::Var(_, _) => bug!("Expected CPlace::Addr, found CPlace::Var"),
220         }
221     }
222
223     pub fn write_cvalue(self, fx: &mut FunctionCx<'a, 'tcx>, from: CValue<'tcx>) {
224         match (&self.layout().ty.sty, &from.layout().ty.sty) {
225             (TypeVariants::TyRef(_, t, dest_mut), TypeVariants::TyRef(_, u, src_mut))
226                 if (if *dest_mut != ::rustc::hir::Mutability::MutImmutable && src_mut != dest_mut {
227                     false
228                 } else if t != u {
229                     false
230                 } else {
231                     true
232                 }) =>
233             {
234                 // &mut T -> &T is allowed
235                 // &'a T -> &'b T is allowed
236             }
237             _ => {
238                 assert_eq!(
239                     self.layout().ty,
240                     from.layout().ty,
241                     "Can't write value of incompatible type to place {:?} {:?}\n\n{:#?}",
242                     self.layout().ty.sty,
243                     from.layout().ty.sty,
244                     fx,
245                 );
246             }
247         }
248
249         match self {
250             CPlace::Var(var, _) => {
251                 let data = from.load_value(fx);
252                 fx.bcx.def_var(var, data)
253             }
254             CPlace::Addr(addr, layout) => {
255                 let size = layout.size.bytes() as i32;
256
257                 if let Some(_) = fx.cton_type(layout.ty) {
258                     let data = from.load_value(fx);
259                     fx.bcx.ins().store(MemFlags::new(), data, addr, 0);
260                 } else {
261                     let from = from.expect_byref();
262                     let mut offset = 0;
263                     while size - offset >= 8 {
264                         let byte = fx
265                             .bcx
266                             .ins()
267                             .load(types::I64, MemFlags::new(), from.0, offset);
268                         fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
269                         offset += 8;
270                     }
271                     while size - offset >= 4 {
272                         let byte = fx
273                             .bcx
274                             .ins()
275                             .load(types::I32, MemFlags::new(), from.0, offset);
276                         fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
277                         offset += 4;
278                     }
279                     while offset < size {
280                         let byte = fx
281                             .bcx
282                             .ins()
283                             .load(types::I8, MemFlags::new(), from.0, offset);
284                         fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
285                         offset += 1;
286                     }
287                 }
288             }
289         }
290     }
291
292     pub fn place_field(self, fx: &mut FunctionCx<'a, 'tcx>, field: mir::Field) -> CPlace<'tcx> {
293         let base = self.expect_addr();
294         let layout = self.layout();
295
296         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
297         CPlace::Addr(field_ptr, field_layout)
298     }
299
300     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
301         match self {
302             CPlace::Var(var, _) => CPlace::Var(var, layout),
303             CPlace::Addr(addr, _) => CPlace::Addr(addr, layout),
304         }
305     }
306
307     pub fn downcast_variant(self, fx: &FunctionCx<'a, 'tcx>, variant: usize) -> Self {
308         let layout = self.layout().for_variant(fx, variant);
309         self.unchecked_cast_to(layout)
310     }
311 }
312
313 pub fn cton_intcast<'a, 'tcx: 'a>(
314     fx: &mut FunctionCx<'a, 'tcx>,
315     val: Value,
316     from: Ty<'tcx>,
317     to: Ty<'tcx>,
318     signed: bool,
319 ) -> Value {
320     let from = fx.cton_type(from).unwrap();
321     let to = fx.cton_type(to).unwrap();
322     if from == to {
323         return val;
324     }
325     if to.wider_or_equal(from) {
326         if signed {
327             fx.bcx.ins().sextend(to, val)
328         } else {
329             fx.bcx.ins().uextend(to, val)
330         }
331     } else {
332         fx.bcx.ins().ireduce(to, val)
333     }
334 }
335
336 pub struct FunctionCx<'a, 'tcx: 'a> {
337     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
338     pub module: &'a mut Module<CurrentBackend>,
339     pub instance: Instance<'tcx>,
340     pub mir: &'tcx Mir<'tcx>,
341     pub param_substs: &'tcx Substs<'tcx>,
342     pub bcx: FunctionBuilder<'a, Variable>,
343     pub ebb_map: HashMap<BasicBlock, Ebb>,
344     pub local_map: HashMap<Local, CPlace<'tcx>>,
345     pub comments: HashMap<Inst, String>,
346     pub constants: &'a mut HashMap<AllocId, DataId>,
347 }
348
349 impl<'a, 'tcx: 'a> fmt::Debug for FunctionCx<'a, 'tcx> {
350     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351         writeln!(f, "{:?}", self.param_substs)?;
352         writeln!(f, "{:?}", self.local_map)?;
353
354         let mut clif = String::new();
355         let mut writer = crate::pretty_clif::CommentWriter(self.comments.clone());
356         ::cranelift::codegen::write::decorate_function(
357             &mut writer,
358             &mut clif,
359             &self.bcx.func,
360             None,
361         ).unwrap();
362         writeln!(f, "\n{}", clif)
363     }
364 }
365
366 impl<'a, 'tcx: 'a> LayoutOf for &'a FunctionCx<'a, 'tcx> {
367     type Ty = Ty<'tcx>;
368     type TyLayout = TyLayout<'tcx>;
369
370     fn layout_of(self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
371         let ty = self.monomorphize(&ty);
372         self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
373     }
374 }
375
376 impl<'a, 'tcx> layout::HasTyCtxt<'tcx> for &'a FunctionCx<'a, 'tcx> {
377     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
378         self.tcx
379     }
380 }
381
382 impl<'a, 'tcx> layout::HasDataLayout for &'a FunctionCx<'a, 'tcx> {
383     fn data_layout(&self) -> &layout::TargetDataLayout {
384         &self.tcx.data_layout
385     }
386 }
387
388 impl<'a, 'tcx> HasTargetSpec for &'a FunctionCx<'a, 'tcx> {
389     fn target_spec(&self) -> &Target {
390         &self.tcx.sess.target.target
391     }
392 }
393
394 impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> {
395     pub fn monomorphize<T>(&self, value: &T) -> T
396     where
397         T: TypeFoldable<'tcx>,
398     {
399         self.tcx.subst_and_normalize_erasing_regions(
400             self.param_substs,
401             ty::ParamEnv::reveal_all(),
402             value,
403         )
404     }
405
406     pub fn cton_type(&self, ty: Ty<'tcx>) -> Option<Type> {
407         cton_type_from_ty(self.tcx, self.monomorphize(&ty))
408     }
409
410     pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
411         *self.ebb_map.get(&bb).unwrap()
412     }
413
414     pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
415         *self.local_map.get(&local).unwrap()
416     }
417 }