]> git.lizzy.rs Git - rust.git/blob - src/common.rs
Support unsized types
[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 pointer_ty(tcx: TyCtxt) -> types::Type {
14     match tcx.data_layout.pointer_size.bits() {
15         16 => types::I16,
16         32 => types::I32,
17         64 => types::I64,
18         bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
19     }
20 }
21
22 fn scalar_to_cton_type(tcx: TyCtxt, scalar: &Scalar) -> Type {
23     match scalar.value.size(tcx).bits() {
24         8 => types::I8,
25         16 => types::I16,
26         32 => types::I32,
27         64 => types::I64,
28         size => bug!("Unsupported scalar size {}", size),
29     }
30 }
31
32 fn ptr_referee<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
33     match ty.sty {
34         ty::Ref(_, ty, _) => ty,
35         ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty,
36         _ => bug!("{:?}", ty),
37     }
38 }
39
40 pub fn cton_type_from_ty<'a, 'tcx: 'a>(
41     tcx: TyCtxt<'a, 'tcx, 'tcx>,
42     ty: Ty<'tcx>,
43 ) -> Option<types::Type> {
44     Some(match ty.sty {
45         ty::Bool => types::I8,
46         ty::Uint(size) => match size {
47             UintTy::U8 => types::I8,
48             UintTy::U16 => types::I16,
49             UintTy::U32 => types::I32,
50             UintTy::U64 => types::I64,
51             UintTy::U128 => unimpl!("u128"),
52             UintTy::Usize => pointer_ty(tcx),
53         },
54         ty::Int(size) => match size {
55             IntTy::I8 => types::I8,
56             IntTy::I16 => types::I16,
57             IntTy::I32 => types::I32,
58             IntTy::I64 => types::I64,
59             IntTy::I128 => unimpl!("i128"),
60             IntTy::Isize => pointer_ty(tcx),
61         },
62         ty::Char => types::I32,
63         ty::Float(size) => match size {
64             FloatTy::F32 => types::F32,
65             FloatTy::F64 => types::F64,
66         },
67         ty::FnPtr(_) => pointer_ty(tcx),
68         ty::RawPtr(TypeAndMut { ty, mutbl: _ }) | ty::Ref(_, ty, _) => {
69             if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
70                 pointer_ty(tcx)
71             } else {
72                 return None;
73             }
74         }
75         ty::Param(_) => bug!("{:?}: {:?}", ty, ty.sty),
76         _ => return None,
77     })
78 }
79
80 fn codegen_field<'a, 'tcx: 'a>(
81     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
82     base: Value,
83     layout: TyLayout<'tcx>,
84     field: mir::Field,
85 ) -> (Value, TyLayout<'tcx>) {
86     let field_offset = layout.fields.offset(field.index());
87     let field_ty = layout.field(&*fx, field.index());
88     if field_offset.bytes() > 0 {
89         (
90             fx.bcx.ins().iadd_imm(base, field_offset.bytes() as i64),
91             field_ty,
92         )
93     } else {
94         (base, field_ty)
95     }
96 }
97
98 /// A read-only value
99 #[derive(Debug, Copy, Clone)]
100 pub enum CValue<'tcx> {
101     ByRef(Value, TyLayout<'tcx>),
102     ByVal(Value, TyLayout<'tcx>),
103     ByValPair(Value, Value, TyLayout<'tcx>),
104 }
105
106 impl<'tcx> CValue<'tcx> {
107     pub fn layout(&self) -> TyLayout<'tcx> {
108         match *self {
109             CValue::ByRef(_, layout)
110             | CValue::ByVal(_, layout)
111             | CValue::ByValPair(_, _, layout) => layout,
112         }
113     }
114
115     pub fn force_stack<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> Value
116     where
117         'tcx: 'a,
118     {
119         match self {
120             CValue::ByRef(value, _layout) => value,
121             CValue::ByVal(value, layout) => {
122                 let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
123                     kind: StackSlotKind::ExplicitSlot,
124                     size: layout.size.bytes() as u32,
125                     offset: None,
126                 });
127                 fx.bcx.ins().stack_store(value, stack_slot, 0);
128                 fx.bcx
129                     .ins()
130                     .stack_addr(fx.module.pointer_type(), stack_slot, 0)
131             }
132             CValue::ByValPair(value, extra, layout) => {
133                 let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
134                     kind: StackSlotKind::ExplicitSlot,
135                     size: layout.size.bytes() as u32,
136                     offset: None,
137                 });
138                 let base = fx.bcx.ins().stack_addr(types::I64, stack_slot, 0);
139                 let a_addr = codegen_field(fx, base, layout, mir::Field::new(0)).0;
140                 let b_addr = codegen_field(fx, base, layout, mir::Field::new(1)).0;
141                 fx.bcx.ins().store(MemFlags::new(), value, a_addr, 0);
142                 fx.bcx.ins().store(MemFlags::new(), extra, b_addr, 0);
143                 base
144             }
145         }
146     }
147
148     pub fn load_value<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> Value
149     where
150         'tcx: 'a,
151     {
152         match self {
153             CValue::ByRef(addr, layout) => {
154                 let cton_ty = fx
155                     .cton_type(layout.ty)
156                     .expect(&format!("load_value of type {:?}", layout.ty));
157                 fx.bcx.ins().load(cton_ty, MemFlags::new(), addr, 0)
158             }
159             CValue::ByVal(value, _layout) => value,
160             CValue::ByValPair(_, _, _layout) => bug!("Please use load_value_pair for ByValPair"),
161         }
162     }
163
164     pub fn load_value_pair<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> (Value, Value)
165     where
166         'tcx: 'a,
167     {
168         match self {
169             CValue::ByRef(addr, layout) => {
170                 assert_eq!(
171                     layout.size.bytes(),
172                     fx.tcx.data_layout.pointer_size.bytes() * 2
173                 );
174                 let val1_offset = layout.fields.offset(0).bytes() as i32;
175                 let val2_offset = layout.fields.offset(1).bytes() as i32;
176                 let val1 =
177                     fx.bcx
178                         .ins()
179                         .load(fx.module.pointer_type(), MemFlags::new(), addr, val1_offset);
180                 let val2 =
181                     fx.bcx
182                         .ins()
183                         .load(fx.module.pointer_type(), MemFlags::new(), addr, val2_offset);
184                 (val1, val2)
185             }
186             CValue::ByVal(_, _layout) => bug!("Please use load_value for ByVal"),
187             CValue::ByValPair(val1, val2, _layout) => (val1, val2),
188         }
189     }
190
191     pub fn expect_byref(self) -> (Value, TyLayout<'tcx>) {
192         match self {
193             CValue::ByRef(value, layout) => (value, layout),
194             CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal: {:?}", self),
195             CValue::ByValPair(_, _, _) => bug!(
196                 "Expected CValue::ByRef, found CValue::ByValPair: {:?}",
197                 self
198             ),
199         }
200     }
201
202     pub fn value_field<'a>(
203         self,
204         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
205         field: mir::Field,
206     ) -> CValue<'tcx>
207     where
208         'tcx: 'a,
209     {
210         let (base, layout) = match self {
211             CValue::ByRef(addr, layout) => (addr, layout),
212             _ => bug!("place_field for {:?}", self),
213         };
214
215         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
216         CValue::ByRef(field_ptr, field_layout)
217     }
218
219     pub fn const_val<'a>(
220         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
221         ty: Ty<'tcx>,
222         const_val: i64,
223     ) -> CValue<'tcx>
224     where
225         'tcx: 'a,
226     {
227         let cton_ty = fx.cton_type(ty).unwrap();
228         let layout = fx.layout_of(ty);
229         CValue::ByVal(fx.bcx.ins().iconst(cton_ty, const_val), layout)
230     }
231
232     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
233         match self {
234             CValue::ByRef(addr, _) => CValue::ByRef(addr, layout),
235             CValue::ByVal(val, _) => CValue::ByVal(val, layout),
236             CValue::ByValPair(val, extra, _) => CValue::ByValPair(val, extra, layout),
237         }
238     }
239 }
240
241 /// A place where you can write a value to or read a value from
242 #[derive(Debug, Copy, Clone)]
243 pub enum CPlace<'tcx> {
244     Var(Local, TyLayout<'tcx>),
245     Addr(Value, Option<Value>, TyLayout<'tcx>),
246 }
247
248 impl<'a, 'tcx: 'a> CPlace<'tcx> {
249     pub fn layout(&self) -> TyLayout<'tcx> {
250         match *self {
251             CPlace::Var(_, layout) | CPlace::Addr(_, _, layout) => layout,
252         }
253     }
254
255     pub fn temp(fx: &mut FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>) -> CPlace<'tcx> {
256         let layout = fx.layout_of(ty);
257         assert!(!layout.is_unsized());
258         let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
259             kind: StackSlotKind::ExplicitSlot,
260             size: layout.size.bytes() as u32,
261             offset: None,
262         });
263         CPlace::Addr(
264             fx.bcx
265                 .ins()
266                 .stack_addr(fx.module.pointer_type(), stack_slot, 0),
267             None,
268             layout,
269         )
270     }
271
272     pub fn from_stack_slot(
273         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
274         stack_slot: StackSlot,
275         ty: Ty<'tcx>,
276     ) -> CPlace<'tcx> {
277         let layout = fx.layout_of(ty);
278         assert!(!layout.is_unsized());
279         CPlace::Addr(
280             fx.bcx
281                 .ins()
282                 .stack_addr(fx.module.pointer_type(), stack_slot, 0),
283             None,
284             layout,
285         )
286     }
287
288     pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CValue<'tcx> {
289         match self {
290             CPlace::Var(var, layout) => CValue::ByVal(fx.bcx.use_var(mir_var(var)), layout),
291             CPlace::Addr(addr, extra, layout) => {
292                 assert!(extra.is_none(), "unsized values are not yet supported");
293                 CValue::ByRef(addr, layout)
294             }
295         }
296     }
297
298     pub fn expect_addr(self) -> Value {
299         match self {
300             CPlace::Addr(addr, None, _layout) => addr,
301             CPlace::Addr(_, _, _) => bug!("Expected sized CPlace::Addr, found {:?}", self),
302             CPlace::Var(_, _) => bug!("Expected CPlace::Addr, found CPlace::Var"),
303         }
304     }
305
306     pub fn write_cvalue(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>, from: CValue<'tcx>) {
307         match (&self.layout().ty.sty, &from.layout().ty.sty) {
308             (ty::Ref(_, t, dest_mut), ty::Ref(_, u, src_mut))
309                 if (if *dest_mut != ::rustc::hir::Mutability::MutImmutable && src_mut != dest_mut {
310                     false
311                 } else if t != u {
312                     false
313                 } else {
314                     true
315                 }) =>
316             {
317                 // &mut T -> &T is allowed
318                 // &'a T -> &'b T is allowed
319             }
320             _ => {
321                 assert_eq!(
322                     self.layout().ty,
323                     from.layout().ty,
324                     "Can't write value of incompatible type to place {:?} {:?}\n\n{:#?}",
325                     self.layout().ty.sty,
326                     from.layout().ty.sty,
327                     fx,
328                 );
329             }
330         }
331
332         match self {
333             CPlace::Var(var, _) => {
334                 let data = from.load_value(fx);
335                 fx.bcx.def_var(mir_var(var), data)
336             }
337             CPlace::Addr(addr, None, layout) => {
338                 let size = layout.size.bytes() as i32;
339
340                 match from {
341                     CValue::ByVal(val, _layout) => {
342                         fx.bcx.ins().store(MemFlags::new(), val, addr, 0);
343                     }
344                     CValue::ByValPair(val1, val2, _layout) => {
345                         let val1_offset = layout.fields.offset(0).bytes() as i32;
346                         let val2_offset = layout.fields.offset(1).bytes() as i32;
347                         fx.bcx.ins().store(MemFlags::new(), val1, addr, val1_offset);
348                         fx.bcx.ins().store(MemFlags::new(), val2, addr, val2_offset);
349                     }
350                     CValue::ByRef(from, _layout) => {
351                         let mut offset = 0;
352                         while size - offset >= 8 {
353                             let byte = fx.bcx.ins().load(
354                                 fx.module.pointer_type(),
355                                 MemFlags::new(),
356                                 from,
357                                 offset,
358                             );
359                             fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
360                             offset += 8;
361                         }
362                         while size - offset >= 4 {
363                             let byte = fx.bcx.ins().load(types::I32, MemFlags::new(), from, offset);
364                             fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
365                             offset += 4;
366                         }
367                         while offset < size {
368                             let byte = fx.bcx.ins().load(types::I8, MemFlags::new(), from, offset);
369                             fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
370                             offset += 1;
371                         }
372                     }
373                 }
374             }
375             CPlace::Addr(_, _, _) => bug!("Can't write value to unsized place {:?}", self),
376         }
377     }
378
379     pub fn place_field(
380         self,
381         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
382         field: mir::Field,
383     ) -> CPlace<'tcx> {
384         let layout = self.layout();
385         if layout.is_unsized() {
386             unimpl!("unsized place_field");
387         }
388
389         let base = self.expect_addr();
390         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
391         CPlace::Addr(field_ptr, None, field_layout)
392     }
393
394     pub fn place_index(
395         self,
396         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
397         index: Value,
398     ) -> CPlace<'tcx> {
399         let addr = self.expect_addr();
400         let layout = self.layout();
401         if layout.is_unsized() {
402             unimpl!("unsized place_field");
403         }
404
405         match layout.ty.sty {
406             ty::Array(elem_ty, _) => {
407                 let elem_layout = fx.layout_of(elem_ty);
408                 let offset = fx
409                     .bcx
410                     .ins()
411                     .imul_imm(index, elem_layout.size.bytes() as i64);
412                 CPlace::Addr(fx.bcx.ins().iadd(addr, offset), None, elem_layout)
413             }
414             ty::Slice(_elem_ty) => unimplemented!("place_index(TySlice)"),
415             _ => bug!("place_index({:?})", layout.ty),
416         }
417     }
418
419     pub fn place_deref(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CPlace<'tcx> {
420         let inner_layout = fx.layout_of(ptr_referee(self.layout().ty));
421         if !inner_layout.is_unsized() {
422             CPlace::Addr(self.to_cvalue(fx).load_value(fx), None, inner_layout)
423         } else {
424             match self.layout().abi {
425                 Abi::ScalarPair(ref a, ref b) => {
426                     let addr = self.expect_addr();
427                     let ptr =
428                         fx.bcx
429                             .ins()
430                             .load(scalar_to_cton_type(fx.tcx, a), MemFlags::new(), addr, 0);
431                     let extra = fx.bcx.ins().load(
432                         scalar_to_cton_type(fx.tcx, b),
433                         MemFlags::new(),
434                         addr,
435                         a.value.size(fx.tcx).bytes() as u32 as i32,
436                     );
437                     println!(
438                         "unsized deref: ptr: {:?} extra: {:?} self: {:?}",
439                         ptr, extra, self
440                     );
441                     CPlace::Addr(ptr, Some(extra), inner_layout)
442                 }
443                 _ => bug!(
444                     "Fat ptr doesn't have abi ScalarPair, but it has {:?}",
445                     self.layout().abi
446                 ),
447             }
448         }
449     }
450
451     pub fn write_place_ref(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>, dest: CPlace<'tcx>) {
452         if !self.layout().is_unsized() {
453             let ptr = CValue::ByVal(self.expect_addr(), dest.layout());
454             dest.write_cvalue(fx, ptr);
455         } else {
456             match self {
457                 CPlace::Var(_, _) => bug!("expected CPlace::Addr found CPlace::Var"),
458                 CPlace::Addr(value, extra, _) => match dest.layout().abi {
459                     Abi::ScalarPair(ref a, _) => {
460                         fx.bcx
461                             .ins()
462                             .store(MemFlags::new(), value, dest.expect_addr(), 0);
463                         fx.bcx.ins().store(
464                             MemFlags::new(),
465                             extra.expect("unsized type without metadata"),
466                             dest.expect_addr(),
467                             a.value.size(fx.tcx).bytes() as u32 as i32,
468                         );
469                     }
470                     _ => bug!(
471                         "Non ScalarPair abi {:?} in write_place_ref dest",
472                         dest.layout().abi
473                     ),
474                 },
475             }
476         }
477     }
478
479     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
480         match self {
481             CPlace::Var(var, _) => CPlace::Var(var, layout),
482             CPlace::Addr(addr, extra, _) => {
483                 assert!(!layout.is_unsized());
484                 CPlace::Addr(addr, extra, layout)
485             }
486         }
487     }
488
489     pub fn downcast_variant(self, fx: &FunctionCx<'a, 'tcx, impl Backend>, variant: usize) -> Self {
490         let layout = self.layout().for_variant(fx, variant);
491         self.unchecked_cast_to(layout)
492     }
493 }
494
495 pub fn cton_intcast<'a, 'tcx: 'a>(
496     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
497     val: Value,
498     to: Type,
499     signed: bool,
500 ) -> Value {
501     let from = fx.bcx.func.dfg.value_type(val);
502     if from == to {
503         return val;
504     }
505     if to.wider_or_equal(from) {
506         if signed {
507             fx.bcx.ins().sextend(to, val)
508         } else {
509             fx.bcx.ins().uextend(to, val)
510         }
511     } else {
512         fx.bcx.ins().ireduce(to, val)
513     }
514 }
515
516 pub struct FunctionCx<'a, 'tcx: 'a, B: Backend + 'a> {
517     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
518     pub module: &'a mut Module<B>,
519     pub instance: Instance<'tcx>,
520     pub mir: &'tcx Mir<'tcx>,
521     pub param_substs: &'tcx Substs<'tcx>,
522     pub bcx: FunctionBuilder<'a>,
523     pub ebb_map: HashMap<BasicBlock, Ebb>,
524     pub local_map: HashMap<Local, CPlace<'tcx>>,
525     pub comments: HashMap<Inst, String>,
526     pub constants: &'a mut crate::constant::ConstantCx,
527     pub caches: &'a mut Caches,
528
529     /// add_global_comment inserts a comment here
530     pub top_nop: Option<Inst>,
531 }
532
533 impl<'a, 'tcx: 'a, B: Backend + 'a> fmt::Debug for FunctionCx<'a, 'tcx, B> {
534     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
535         writeln!(f, "{:?}", self.param_substs)?;
536         writeln!(f, "{:?}", self.local_map)?;
537
538         let mut clif = String::new();
539         let mut writer = crate::pretty_clif::CommentWriter(self.comments.clone());
540         ::cranelift::codegen::write::decorate_function(
541             &mut writer,
542             &mut clif,
543             &self.bcx.func,
544             None,
545         ).unwrap();
546         writeln!(f, "\n{}", clif)
547     }
548 }
549
550 impl<'a, 'tcx: 'a, B: Backend> LayoutOf for &'a FunctionCx<'a, 'tcx, B> {
551     type Ty = Ty<'tcx>;
552     type TyLayout = TyLayout<'tcx>;
553
554     fn layout_of(self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
555         let ty = self.monomorphize(&ty);
556         self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
557     }
558 }
559
560 impl<'a, 'tcx, B: Backend + 'a> layout::HasTyCtxt<'tcx> for &'a FunctionCx<'a, 'tcx, B> {
561     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
562         self.tcx
563     }
564 }
565
566 impl<'a, 'tcx, B: Backend + 'a> layout::HasDataLayout for &'a FunctionCx<'a, 'tcx, B> {
567     fn data_layout(&self) -> &layout::TargetDataLayout {
568         &self.tcx.data_layout
569     }
570 }
571
572 impl<'a, 'tcx, B: Backend + 'a> HasTargetSpec for &'a FunctionCx<'a, 'tcx, B> {
573     fn target_spec(&self) -> &Target {
574         &self.tcx.sess.target.target
575     }
576 }
577
578 impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
579     pub fn monomorphize<T>(&self, value: &T) -> T
580     where
581         T: TypeFoldable<'tcx>,
582     {
583         self.tcx.subst_and_normalize_erasing_regions(
584             self.param_substs,
585             ty::ParamEnv::reveal_all(),
586             value,
587         )
588     }
589
590     pub fn cton_type(&self, ty: Ty<'tcx>) -> Option<Type> {
591         cton_type_from_ty(self.tcx, self.monomorphize(&ty))
592     }
593
594     pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
595         *self.ebb_map.get(&bb).unwrap()
596     }
597
598     pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
599         *self.local_map.get(&local).unwrap()
600     }
601 }