]> git.lizzy.rs Git - rust.git/blob - src/common.rs
Implement enums
[rust.git] / src / common.rs
1 use syntax::ast::{IntTy, UintTy};
2
3 use cretonne_module::{Module, Linkage, FuncId};
4
5 use prelude::*;
6
7 pub type CurrentBackend = ::cretonne_simplejit::SimpleJITBackend;
8
9 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
10 pub struct Variable(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(ty: Ty) -> Option<types::Type> {
23     Some(match ty.sty {
24         TypeVariants::TyBool => types::I8,
25         TypeVariants::TyUint(size) => {
26             match size {
27                 UintTy::U8 => types::I8,
28                 UintTy::U16 => types::I16,
29                 UintTy::U32 => types::I32,
30                 UintTy::U64 => types::I64,
31                 UintTy::U128 => unimplemented!(),
32                 UintTy::Usize => types::I64,
33             }
34         }
35         TypeVariants::TyInt(size) => {
36             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 => unimplemented!(),
42                 IntTy::Isize => types::I64,
43             }
44         }
45         TypeVariants::TyFnPtr(_) => types::I64,
46         _ => return None,
47     })
48 }
49
50 pub fn extend_val<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, val: Value, ty: Ty) -> Value {
51     let cton_ty = cton_type_from_ty(ty).unwrap();
52     let to_ty = match cton_ty {
53         types::I64 => return val,
54         types::I32 => return val,
55         _ => types::I32,
56     };
57     match ty.sty {
58         TypeVariants::TyBool => fx.bcx.ins().uextend(to_ty, val),
59         TypeVariants::TyUint(_) => fx.bcx.ins().uextend(to_ty, val),
60         TypeVariants::TyInt(_) => fx.bcx.ins().sextend(to_ty, val),
61         TypeVariants::TyFnPtr(_) => val,
62         _ => unimplemented!(),
63     }
64 }
65
66 // FIXME(cretonne) fix load.i8
67 fn load_workaround(fx: &mut FunctionCx, ty: Type, addr: Value, offset: i32) -> Value {
68     use cretonne::codegen::ir::types::*;
69     match ty {
70         I8 => fx.bcx.ins().uload8(I32, MemFlags::new(), addr, offset),
71         I16 => fx.bcx.ins().uload16(I32, MemFlags::new(), addr, offset),
72         // I32 and I64 work
73         _ => fx.bcx.ins().load(ty, MemFlags::new(), addr, offset),
74     }
75 }
76
77 // FIXME(cretonne) fix store.i8
78 fn store_workaround(fx: &mut FunctionCx, ty: Type, addr: Value, val: Value, offset: i32) {
79     use cretonne::codegen::ir::types::*;
80     match ty {
81         I8 => fx.bcx.ins().istore8(MemFlags::new(), val, addr, offset),
82         I16 => fx.bcx.ins().istore16(MemFlags::new(), val, addr, offset),
83         // I32 and I64 work
84         _ => fx.bcx.ins().store(MemFlags::new(), val, addr, offset),
85     };
86 }
87
88 #[derive(Debug, Copy, Clone)]
89 pub enum CValue {
90     ByRef(Value),
91     ByVal(Value),
92     Func(FuncRef),
93 }
94
95 impl CValue {
96     pub fn force_stack<'a, 'tcx: 'a>(self, fx: &mut FunctionCx<'a, 'tcx>, ty: Ty<'tcx>) -> Value {
97         match self {
98             CValue::ByRef(value) => value,
99             CValue::ByVal(value) => {
100                 let layout = fx.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
101                 let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
102                     kind: StackSlotKind::ExplicitSlot,
103                     size: layout.size.bytes() as u32,
104                     offset: None,
105                 });
106                 fx.bcx.ins().stack_store(value, stack_slot, 0);
107                 fx.bcx.ins().stack_addr(types::I64, stack_slot, 0)
108             }
109             CValue::Func(func) => {
110                 let func = fx.bcx.ins().func_addr(types::I64, func);
111                 CValue::ByVal(func).force_stack(fx, ty)
112             }
113         }
114     }
115
116     pub fn load_value<'a, 'tcx: 'a>(self, fx: &mut FunctionCx<'a, 'tcx>, ty: Ty<'tcx>) -> Value {
117         match self {
118             CValue::ByRef(value) => {
119                 let cton_ty = cton_type_from_ty(ty).unwrap();
120                 load_workaround(fx, cton_ty, value, 0)
121             }
122             CValue::ByVal(value) => value,
123             CValue::Func(func) => {
124                 fx.bcx.ins().func_addr(types::I64, func)
125             }
126         }
127     }
128
129     pub fn expect_byref(self) -> Value {
130         match self {
131             CValue::ByRef(value) => value,
132             CValue::ByVal(_) => bug!("Expected CValue::ByRef, found CValue::ByVal"),
133             CValue::Func(_) => bug!("Expected CValue::ByRef, found CValue::Func"),
134         }
135     }
136
137     pub fn value_field<'a, 'tcx: 'a>(self, fx: &mut FunctionCx<'a, 'tcx>, field: mir::Field, ty: Ty<'tcx>) -> CValue {
138         let base = match self {
139             CValue::ByRef(addr) => addr,
140             _ => bug!("place_field for {:?}", self),
141         };
142         let layout = fx.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
143         let field_offset = layout.fields.offset(field.index());
144         if field_offset.bytes() > 0 {
145             let field_offset = fx.bcx.ins().iconst(types::I64, field_offset.bytes() as i64);
146             CValue::ByRef(fx.bcx.ins().iadd(base, field_offset))
147         } else {
148             CValue::ByRef(base)
149         }
150     }
151
152     pub fn const_val<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, ty: Ty<'tcx>, const_val: i64) -> CValue {
153         CValue::ByVal(fx.bcx.ins().iconst(cton_type_from_ty(ty).unwrap(), const_val))
154     }
155 }
156
157 #[derive(Debug, Copy, Clone)]
158 pub enum CPlace {
159     Var(Variable),
160     Addr(Value),
161 }
162
163 impl<'a, 'tcx: 'a> CPlace {
164     pub fn from_stack_slot(fx: &mut FunctionCx<'a, 'tcx>, stack_slot: StackSlot) -> CPlace {
165         CPlace::Addr(fx.bcx.ins().stack_addr(types::I64, stack_slot, 0))
166     }
167
168     pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx>) -> CValue {
169         match self {
170             CPlace::Var(var) => CValue::ByVal(fx.bcx.use_var(var)),
171             CPlace::Addr(addr) => CValue::ByRef(addr),
172         }
173     }
174
175     pub fn expect_addr(self) -> Value {
176         match self {
177             CPlace::Addr(addr) => addr,
178             CPlace::Var(_) => bug!("Expected CPlace::Addr, found CPlace::Var"),
179         }
180     }
181
182     pub fn write_cvalue(self, fx: &mut FunctionCx<'a, 'tcx>, from: CValue, ty: Ty<'tcx>) {
183         let layout = fx.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();
184         let size = layout.size.bytes() as i32;
185         match self {
186             CPlace::Var(var) => {
187                 let data = from.load_value(fx, ty);
188                 fx.bcx.def_var(var, data)
189             },
190             CPlace::Addr(addr) => {
191                 if let Some(cton_ty) = cton_type_from_ty(ty) {
192                     let data = from.load_value(fx, ty);
193                     store_workaround(fx, cton_ty, addr, data, 0);
194                 } else {
195                     for i in 0..size {
196                         let from = from.expect_byref();
197                         let byte = load_workaround(fx, types::I8, from, i);
198                         store_workaround(fx, types::I8, addr, byte, i);
199                     }
200                 }
201             }
202         }
203     }
204
205     pub fn place_field(self, fx: &mut FunctionCx<'a, 'tcx>, field: mir::Field, ty: Ty<'tcx>) -> (CPlace, layout::TyLayout<'tcx>) {
206         let base = self.expect_addr();
207         let layout = fx.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
208         let field_offset = layout.fields.offset(field.index());
209         if field_offset.bytes() > 0 {
210             let field_offset = fx.bcx.ins().iconst(types::I64, field_offset.bytes() as i64);
211             (CPlace::Addr(fx.bcx.ins().iadd(base, field_offset)), layout)
212         } else {
213             (CPlace::Addr(base), layout)
214         }
215     }
216 }
217
218 pub fn cton_sig_from_fn_sig<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sig: PolyFnSig<'tcx>, substs: &Substs<'tcx>) -> Signature {
219     let sig = tcx.subst_and_normalize_erasing_regions(substs, ParamEnv::reveal_all(), &sig);
220     cton_sig_from_mono_fn_sig(sig)
221 }
222
223 pub fn cton_sig_from_instance<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, inst: Instance<'tcx>) -> Signature {
224     let fn_ty = inst.ty(tcx);
225     let sig = fn_ty.fn_sig(tcx);
226     cton_sig_from_mono_fn_sig(sig)
227 }
228
229 pub fn cton_sig_from_mono_fn_sig<'a ,'tcx: 'a>(sig: PolyFnSig<'tcx>) -> Signature {
230     let sig = sig.skip_binder();
231     let inputs = sig.inputs();
232     let _output = sig.output();
233     assert!(!sig.variadic, "Variadic function are not yet supported");
234     let call_conv = match sig.abi {
235         _ => CallConv::SystemV,
236     };
237     Signature {
238         params: Some(types::I64).into_iter() // First param is place to put return val
239             .chain(inputs.into_iter().map(|ty| cton_type_from_ty(ty).unwrap_or(types::I64)))
240             .map(AbiParam::new).collect(),
241         returns: vec![],
242         call_conv,
243         argument_bytes: None,
244     }
245 }
246
247 pub fn cton_intcast<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, val: Value, from: Ty<'tcx>, to: Ty<'tcx>, signed: bool) -> Value {
248     let from = cton_type_from_ty(from).unwrap();
249     let to = cton_type_from_ty(to).unwrap();
250     if from == to {
251         return val;
252     }
253     if from.wider_or_equal(to) {
254         if signed {
255             fx.bcx.ins().sextend(to, val)
256         } else {
257             fx.bcx.ins().uextend(to, val)
258         }
259     } else {
260         fx.bcx.ins().ireduce(to, val)
261     }
262 }
263
264 pub struct FunctionCx<'a, 'tcx: 'a> {
265     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
266     pub module: &'a mut Module<CurrentBackend>,
267     pub def_id_fn_id_map: &'a mut HashMap<Instance<'tcx>, FuncId>,
268     pub bcx: FunctionBuilder<'a, Variable>,
269     pub mir: &'tcx Mir<'tcx>,
270     pub ebb_map: HashMap<BasicBlock, Ebb>,
271     pub local_map: HashMap<Local, CPlace>,
272 }
273
274 impl<'f, 'tcx> FunctionCx<'f, 'tcx> {
275     pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
276         *self.ebb_map.get(&bb).unwrap()
277     }
278
279     pub fn get_local_place(&mut self, local: Local) -> CPlace {
280         *self.local_map.get(&local).unwrap()
281     }
282
283     pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
284         let tcx = self.tcx;
285         let module = &mut self.module;
286         let func_id = *self.def_id_fn_id_map.entry(inst).or_insert_with(|| {
287             let sig = cton_sig_from_instance(tcx, inst);
288             module.declare_function(&tcx.absolute_item_path_str(inst.def_id()), Linkage::Local, &sig).unwrap()
289         });
290         module.declare_func_in_func(func_id, &mut self.bcx.func)
291     }
292 }