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