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