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