]> git.lizzy.rs Git - rust.git/blob - src/common.rs
More debugging output
[rust.git] / src / common.rs
1 extern crate rustc_target;
2
3 use std::borrow::Cow;
4 use std::fmt;
5
6 use syntax::ast::{IntTy, UintTy};
7 use self::rustc_target::spec::{HasTargetSpec, Target};
8
9 use cranelift_module::{Module, Linkage, FuncId};
10
11 use prelude::*;
12
13 pub type CurrentBackend = ::cranelift_simplejit::SimpleJITBackend;
14
15 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
16 pub struct Variable(Local);
17
18 impl EntityRef for Variable {
19     fn new(u: usize) -> Self {
20         Variable(Local::new(u))
21     }
22
23     fn index(self) -> usize {
24         self.0.index()
25     }
26 }
27
28 fn cton_type_from_ty(ty: Ty) -> Option<types::Type> {
29     Some(match ty.sty {
30         TypeVariants::TyBool => types::I8,
31         TypeVariants::TyUint(size) => {
32             match size {
33                 UintTy::U8 => types::I8,
34                 UintTy::U16 => types::I16,
35                 UintTy::U32 => types::I32,
36                 UintTy::U64 => types::I64,
37                 UintTy::U128 => unimplemented!("u128"),
38                 UintTy::Usize => types::I64,
39             }
40         }
41         TypeVariants::TyInt(size) => {
42             match size {
43                 IntTy::I8 => types::I8,
44                 IntTy::I16 => types::I16,
45                 IntTy::I32 => types::I32,
46                 IntTy::I64 => types::I64,
47                 IntTy::I128 => unimplemented!("i128"),
48                 IntTy::Isize => types::I64,
49             }
50         }
51         TypeVariants::TyFnPtr(_) => types::I64,
52         TypeVariants::TyRef(..) | TypeVariants::TyRawPtr(..) => types::I64,
53         TypeVariants::TyParam(_)  => bug!("{:?}", ty),
54         _ => return None,
55     })
56 }
57
58 #[derive(Debug, Copy, Clone)]
59 pub enum CValue<'tcx> {
60     ByRef(Value, TyLayout<'tcx>),
61     ByVal(Value, TyLayout<'tcx>),
62     Func(FuncRef, TyLayout<'tcx>),
63 }
64
65 impl<'tcx> CValue<'tcx> {
66     pub fn layout(&self) -> TyLayout<'tcx> {
67         match *self {
68             CValue::ByRef(_, layout) |
69             CValue::ByVal(_, layout) |
70             CValue::Func(_, layout) => layout
71         }
72     }
73
74     pub fn force_stack<'a>(self, fx: &mut FunctionCx<'a, 'tcx>) -> Value where 'tcx: 'a {
75         match self {
76             CValue::ByRef(value, _layout) => value,
77             CValue::ByVal(value, layout) => {
78                 let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
79                     kind: StackSlotKind::ExplicitSlot,
80                     size: layout.size.bytes() as u32,
81                     offset: None,
82                 });
83                 fx.bcx.ins().stack_store(value, stack_slot, 0);
84                 fx.bcx.ins().stack_addr(types::I64, stack_slot, 0)
85             }
86             CValue::Func(func, ty) => {
87                 let func = fx.bcx.ins().func_addr(types::I64, func);
88                 CValue::ByVal(func, ty).force_stack(fx)
89             }
90         }
91     }
92
93     pub fn load_value<'a>(self, fx: &mut FunctionCx<'a, 'tcx>) -> Value where 'tcx: 'a{
94         match self {
95             CValue::ByRef(addr, layout) => {
96                 let cton_ty = fx.cton_type(layout.ty).expect(&format!("{:?}", layout.ty));
97                 fx.bcx.ins().load(cton_ty, MemFlags::new(), addr, 0)
98             }
99             CValue::ByVal(value, _layout) => value,
100             CValue::Func(func, _layout) => {
101                 fx.bcx.ins().func_addr(types::I64, func)
102             }
103         }
104     }
105
106     pub fn expect_byref(self) -> (Value, TyLayout<'tcx>) {
107         match self {
108             CValue::ByRef(value, layout) => (value, layout),
109             CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal"),
110             CValue::Func(_, _) => bug!("Expected CValue::ByRef, found CValue::Func"),
111         }
112     }
113
114     pub fn value_field<'a>(self, fx: &mut FunctionCx<'a, 'tcx>, field: mir::Field) -> CValue<'tcx> where 'tcx: 'a {
115         use rustc::ty::util::IntTypeExt;
116
117         let (base, layout) = match self {
118             CValue::ByRef(addr, layout) => (addr, layout),
119             _ => bug!("place_field for {:?}", self),
120         };
121         let field_offset = layout.fields.offset(field.index());
122         let field_layout = if field.index() == 0 {
123             fx.layout_of(if let ty::TyAdt(adt_def, _) = layout.ty.sty {
124                 adt_def.repr.discr_type().to_ty(fx.tcx)
125             } else {
126                 // This can only be `0`, for now, so `u8` will suffice.
127                 fx.tcx.types.u8
128             })
129         } else {
130             layout.field(&*fx, field.index())
131         };
132         if field_offset.bytes() > 0 {
133             let field_offset = fx.bcx.ins().iconst(types::I64, field_offset.bytes() as i64);
134             CValue::ByRef(fx.bcx.ins().iadd(base, field_offset), field_layout)
135         } else {
136             CValue::ByRef(base, field_layout)
137         }
138     }
139
140     pub fn const_val<'a>(fx: &mut FunctionCx<'a, 'tcx>, ty: Ty<'tcx>, const_val: i64) -> CValue<'tcx> where 'tcx: 'a {
141         let cton_ty = fx.cton_type(ty).unwrap();
142         let layout = fx.layout_of(ty);
143         CValue::ByVal(fx.bcx.ins().iconst(cton_ty, const_val), layout)
144     }
145
146     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
147         match self {
148             CValue::ByRef(addr, _) => CValue::ByRef(addr, layout),
149             CValue::ByVal(val, _) => CValue::ByVal(val, layout),
150             CValue::Func(fun, _) => CValue::Func(fun, layout),
151         }
152     }
153 }
154
155 #[derive(Debug, Copy, Clone)]
156 pub enum CPlace<'tcx> {
157     Var(Variable, TyLayout<'tcx>),
158     Addr(Value, TyLayout<'tcx>),
159 }
160
161 impl<'a, 'tcx: 'a> CPlace<'tcx> {
162     pub fn layout(&self) -> TyLayout<'tcx> {
163         match *self {
164             CPlace::Var(_, layout) |
165             CPlace::Addr(_, layout) => layout
166         }
167     }
168
169     pub fn from_stack_slot(fx: &mut FunctionCx<'a, 'tcx>, stack_slot: StackSlot, ty: Ty<'tcx>) -> CPlace<'tcx> {
170         let layout = fx.layout_of(ty);
171         CPlace::Addr(fx.bcx.ins().stack_addr(types::I64, stack_slot, 0), layout)
172     }
173
174     pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx>) -> CValue<'tcx> {
175         match self {
176             CPlace::Var(var, layout) => CValue::ByVal(fx.bcx.use_var(var), layout),
177             CPlace::Addr(addr, layout) => CValue::ByRef(addr, layout),
178         }
179     }
180
181     pub fn expect_addr(self) -> Value {
182         match self {
183             CPlace::Addr(addr, _layout) => addr,
184             CPlace::Var(_, _) => bug!("Expected CPlace::Addr, found CPlace::Var"),
185         }
186     }
187
188     pub fn write_cvalue(self, fx: &mut FunctionCx<'a, 'tcx>, from: CValue<'tcx>) {
189         assert_eq!(
190             self.layout().ty, from.layout().ty,
191             "Can't write value of incompatible type to place {:?} {:?}\n\n{:#?}",
192             self.layout().ty.sty, from.layout().ty.sty,
193             fx,
194         );
195
196         match self {
197             CPlace::Var(var, _) => {
198                 let data = from.load_value(fx);
199                 fx.bcx.def_var(var, data)
200             },
201             CPlace::Addr(addr, layout) => {
202                 let size = layout.size.bytes() as i32;
203
204                 if let Some(_) = fx.cton_type(layout.ty) {
205                     let data = from.load_value(fx);
206                     fx.bcx.ins().store(MemFlags::new(), data, addr, 0);
207                 } else {
208                     for i in 0..size {
209                         let from = from.expect_byref();
210                         let byte = fx.bcx.ins().load(types::I8, MemFlags::new(), from.0, i);
211                         fx.bcx.ins().store(MemFlags::new(), byte, addr, i);
212                     }
213                 }
214             }
215         }
216     }
217
218     pub fn place_field(self, fx: &mut FunctionCx<'a, 'tcx>, field: mir::Field) -> CPlace<'tcx> {
219         let base = self.expect_addr();
220         let layout = self.layout();
221         let field_offset = layout.fields.offset(field.index());
222         let field_ty = layout.field(&*fx, field.index());
223         if field_offset.bytes() > 0 {
224             let field_offset = fx.bcx.ins().iconst(types::I64, field_offset.bytes() as i64);
225             CPlace::Addr(fx.bcx.ins().iadd(base, field_offset), field_ty)
226         } else {
227             CPlace::Addr(base, field_ty)
228         }
229     }
230
231     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
232         match self {
233             CPlace::Var(var, _) => CPlace::Var(var, layout),
234             CPlace::Addr(addr, _) => CPlace::Addr(addr, layout),
235         }
236     }
237
238     pub fn downcast_variant(self, fx: &FunctionCx<'a, 'tcx>, variant: usize) -> Self {
239         let layout = self.layout().for_variant(fx, variant);
240         self.unchecked_cast_to(layout)
241     }
242 }
243
244 pub fn cton_sig_from_fn_sig<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sig: PolyFnSig<'tcx>, substs: &Substs<'tcx>) -> Signature {
245     let sig = tcx.subst_and_normalize_erasing_regions(substs, ParamEnv::reveal_all(), &sig);
246     cton_sig_from_mono_fn_sig(sig)
247 }
248
249 pub fn cton_sig_from_instance<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, inst: Instance<'tcx>) -> Signature {
250     let fn_ty = inst.ty(tcx);
251     let sig = fn_ty.fn_sig(tcx);
252     cton_sig_from_mono_fn_sig(sig)
253 }
254
255 pub fn cton_sig_from_mono_fn_sig<'a ,'tcx: 'a>(sig: PolyFnSig<'tcx>) -> Signature {
256     let sig = sig.skip_binder();
257     let inputs = sig.inputs();
258     let _output = sig.output();
259     assert!(!sig.variadic, "Variadic function are not yet supported");
260     let call_conv = match sig.abi {
261         _ => CallConv::SystemV,
262     };
263     Signature {
264         params: Some(types::I64).into_iter() // First param is place to put return val
265             .chain(inputs.into_iter().map(|ty| cton_type_from_ty(ty).unwrap_or(types::I64)))
266             .map(AbiParam::new).collect(),
267         returns: vec![],
268         call_conv,
269         argument_bytes: None,
270     }
271 }
272
273 pub fn cton_intcast<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, val: Value, from: Ty<'tcx>, to: Ty<'tcx>, signed: bool) -> Value {
274     let from = fx.cton_type(from).unwrap();
275     let to = fx.cton_type(to).unwrap();
276     if from == to {
277         return val;
278     }
279     if from.wider_or_equal(to) {
280         if signed {
281             fx.bcx.ins().sextend(to, val)
282         } else {
283             fx.bcx.ins().uextend(to, val)
284         }
285     } else {
286         fx.bcx.ins().ireduce(to, val)
287     }
288 }
289
290 pub struct FunctionCx<'a, 'tcx: 'a> {
291     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
292     pub module: &'a mut Module<CurrentBackend>,
293     pub def_id_fn_id_map: &'a mut HashMap<Instance<'tcx>, FuncId>,
294     pub instance: Instance<'tcx>,
295     pub mir: &'tcx Mir<'tcx>,
296     pub param_substs: &'tcx Substs<'tcx>,
297     pub bcx: FunctionBuilder<'a, Variable>,
298     pub ebb_map: HashMap<BasicBlock, Ebb>,
299     pub local_map: HashMap<Local, CPlace<'tcx>>,
300     pub comments: HashMap<Inst, String>,
301 }
302
303 impl<'a, 'tcx: 'a> fmt::Debug for FunctionCx<'a, 'tcx> {
304     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305         writeln!(f, "{:?}", self.def_id_fn_id_map)?;
306         writeln!(f, "{:?}", self.param_substs)?;
307         writeln!(f, "{:?}", self.local_map)?;
308
309         let mut clif = String::new();
310         let mut writer = ::pretty_clif::CommentWriter(self.comments.clone());
311         ::cranelift::codegen::write::decorate_function(
312             &mut writer,
313             &mut clif,
314             &self.bcx.func,
315             None,
316         ).unwrap();
317         writeln!(f, "\n{}", clif)
318     }
319 }
320
321 impl<'a, 'tcx: 'a> LayoutOf for &'a FunctionCx<'a, 'tcx> {
322     type Ty = Ty<'tcx>;
323     type TyLayout = TyLayout<'tcx>;
324
325     fn layout_of(self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
326         let ty = self.monomorphize(&ty);
327         self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
328     }
329 }
330
331 impl<'a, 'tcx> layout::HasTyCtxt<'tcx> for &'a FunctionCx<'a, 'tcx> {
332     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
333         self.tcx
334     }
335 }
336
337 impl<'a, 'tcx> layout::HasDataLayout for &'a FunctionCx<'a, 'tcx> {
338     fn data_layout(&self) -> &layout::TargetDataLayout {
339         &self.tcx.data_layout
340     }
341 }
342
343 impl<'a, 'tcx> HasTargetSpec for &'a FunctionCx<'a, 'tcx> {
344     fn target_spec(&self) -> &Target {
345         &self.tcx.sess.target.target
346     }
347 }
348
349 impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> {
350     pub fn monomorphize<T>(&self, value: &T) -> T
351         where T: TypeFoldable<'tcx>
352     {
353         self.tcx.subst_and_normalize_erasing_regions(
354             self.param_substs,
355             ty::ParamEnv::reveal_all(),
356             value,
357         )
358     }
359
360     pub fn cton_type(&self, ty: Ty<'tcx>) -> Option<Type> {
361         cton_type_from_ty(self.monomorphize(&ty))
362     }
363
364     pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
365         *self.ebb_map.get(&bb).unwrap()
366     }
367
368     pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
369         *self.local_map.get(&local).unwrap()
370     }
371
372     pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
373         let tcx = self.tcx;
374         let module = &mut self.module;
375         let func_id = *self.def_id_fn_id_map.entry(inst).or_insert_with(|| {
376             let sig = cton_sig_from_instance(tcx, inst);
377             module.declare_function(&tcx.absolute_item_path_str(inst.def_id()), Linkage::Local, &sig).unwrap()
378         });
379         module.declare_func_in_func(func_id, &mut self.bcx.func)
380     }
381
382     pub fn add_comment<'s, S: Into<Cow<'s, str>>>(&mut self, inst: Inst, comment: S) {
383         use std::collections::hash_map::Entry;
384         match self.comments.entry(inst) {
385             Entry::Occupied(mut occ) => {
386                 occ.get_mut().push('\n');
387                 occ.get_mut().push_str(comment.into().as_ref());
388             }
389             Entry::Vacant(vac) => {
390                 vac.insert(comment.into().into_owned());
391             }
392         }
393     }
394 }