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