]> git.lizzy.rs Git - rust.git/blob - src/value_and_place.rs
Split extract layout field of all CPlace variants into a sparate struct
[rust.git] / src / value_and_place.rs
1 use crate::prelude::*;
2
3 fn codegen_field<'tcx>(
4     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
5     base: Value,
6     layout: TyLayout<'tcx>,
7     field: mir::Field,
8 ) -> (Value, TyLayout<'tcx>) {
9     let field_offset = layout.fields.offset(field.index());
10     let field_ty = layout.field(&*fx, field.index());
11     if field_offset.bytes() > 0 {
12         (
13             fx.bcx.ins().iadd_imm(base, field_offset.bytes() as i64),
14             field_ty,
15         )
16     } else {
17         (base, field_ty)
18     }
19 }
20
21 fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: &Scalar, b_scalar: &Scalar) -> i32 {
22     let b_offset = a_scalar.value.size(&tcx).align_to(b_scalar.value.align(&tcx).abi);
23     b_offset.bytes().try_into().unwrap()
24 }
25
26 /// A read-only value
27 #[derive(Debug, Copy, Clone)]
28 pub struct CValue<'tcx>(CValueInner, TyLayout<'tcx>);
29
30 #[derive(Debug, Copy, Clone)]
31 enum CValueInner {
32     ByRef(Value),
33     ByVal(Value),
34     ByValPair(Value, Value),
35 }
36
37 impl<'tcx> CValue<'tcx> {
38     pub fn by_ref(value: Value, layout: TyLayout<'tcx>) -> CValue<'tcx> {
39         CValue(CValueInner::ByRef(value), layout)
40     }
41
42     pub fn by_val(value: Value, layout: TyLayout<'tcx>) -> CValue<'tcx> {
43         CValue(CValueInner::ByVal(value), layout)
44     }
45
46     pub fn by_val_pair(value: Value, extra: Value, layout: TyLayout<'tcx>) -> CValue<'tcx> {
47         CValue(CValueInner::ByValPair(value, extra), layout)
48     }
49
50     pub fn layout(&self) -> TyLayout<'tcx> {
51         self.1
52     }
53
54     pub fn force_stack<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> Value {
55         let layout = self.1;
56         match self.0 {
57             CValueInner::ByRef(value) => value,
58             CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => {
59                 let cplace = CPlace::new_stack_slot(fx, layout.ty);
60                 cplace.write_cvalue(fx, self);
61                 cplace.to_addr(fx)
62             }
63         }
64     }
65
66     /// Load a value with layout.abi of scalar
67     pub fn load_scalar<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> Value {
68         let layout = self.1;
69         match self.0 {
70             CValueInner::ByRef(addr) => {
71                 let scalar = match layout.abi {
72                     layout::Abi::Scalar(ref scalar) => scalar.clone(),
73                     _ => unreachable!(),
74                 };
75                 let clif_ty = scalar_to_clif_type(fx.tcx, scalar);
76                 fx.bcx.ins().load(clif_ty, MemFlags::new(), addr, 0)
77             }
78             CValueInner::ByVal(value) => value,
79             CValueInner::ByValPair(_, _) => bug!("Please use load_scalar_pair for ByValPair"),
80         }
81     }
82
83     /// Load a value pair with layout.abi of scalar pair
84     pub fn load_scalar_pair<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> (Value, Value) {
85         let layout = self.1;
86         match self.0 {
87             CValueInner::ByRef(addr) => {
88                 let (a_scalar, b_scalar) = match &layout.abi {
89                     layout::Abi::ScalarPair(a, b) => (a, b),
90                     _ => unreachable!(),
91                 };
92                 let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
93                 let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar.clone());
94                 let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar.clone());
95                 let val1 = fx.bcx.ins().load(clif_ty1, MemFlags::new(), addr, 0);
96                 let val2 = fx.bcx.ins().load(
97                     clif_ty2,
98                     MemFlags::new(),
99                     addr,
100                     b_offset,
101                 );
102                 (val1, val2)
103             }
104             CValueInner::ByVal(_) => bug!("Please use load_scalar for ByVal"),
105             CValueInner::ByValPair(val1, val2) => (val1, val2),
106         }
107     }
108
109     pub fn value_field<'a>(
110         self,
111         fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
112         field: mir::Field,
113     ) -> CValue<'tcx> {
114         let layout = self.1;
115         let base = match self.0 {
116             CValueInner::ByRef(addr) => addr,
117             _ => bug!("place_field for {:?}", self),
118         };
119
120         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
121         CValue::by_ref(field_ptr, field_layout)
122     }
123
124     pub fn unsize_value<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>, dest: CPlace<'tcx>) {
125         crate::unsize::coerce_unsized_into(fx, self, dest);
126     }
127
128     /// If `ty` is signed, `const_val` must already be sign extended.
129     pub fn const_val<'a>(
130         fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
131         ty: Ty<'tcx>,
132         const_val: u128,
133     ) -> CValue<'tcx> {
134         let clif_ty = fx.clif_type(ty).unwrap();
135         let layout = fx.layout_of(ty);
136
137         let val = match ty.sty {
138             ty::TyKind::Uint(UintTy::U128) | ty::TyKind::Int(IntTy::I128) => {
139                 let lsb = fx.bcx.ins().iconst(types::I64, const_val as u64 as i64);
140                 let msb = fx.bcx.ins().iconst(types::I64, (const_val >> 64) as u64 as i64);
141                 fx.bcx.ins().iconcat(lsb, msb)
142             }
143             ty::TyKind::Bool => {
144                 assert!(const_val == 0 || const_val == 1, "Invalid bool 0x{:032X}", const_val);
145                 fx.bcx.ins().iconst(types::I8, const_val as i64)
146             }
147             ty::TyKind::Uint(_) | ty::TyKind::Ref(..) | ty::TyKind::RawPtr(.. )=> {
148                 fx.bcx.ins().iconst(clif_ty, u64::try_from(const_val).expect("uint") as i64)
149             }
150             ty::TyKind::Int(_) => {
151                 fx.bcx.ins().iconst(clif_ty, const_val as i128 as i64)
152             }
153             _ => panic!("CValue::const_val for non bool/integer/pointer type {:?} is not allowed", ty),
154         };
155
156         CValue::by_val(val, layout)
157     }
158
159     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
160         CValue(self.0, layout)
161     }
162 }
163
164 /// A place where you can write a value to or read a value from
165 #[derive(Debug, Copy, Clone)]
166 pub struct CPlace<'tcx> {
167     inner: CPlaceInner,
168     layout: TyLayout<'tcx>,
169 }
170
171 #[derive(Debug, Copy, Clone)]
172 pub enum CPlaceInner {
173     Var(Local),
174     Addr(Value, Option<Value>),
175     Stack(StackSlot),
176     NoPlace,
177 }
178
179 impl<'tcx> CPlace<'tcx> {
180     pub fn layout(&self) -> TyLayout<'tcx> {
181         self.layout
182     }
183
184     pub fn inner(&self) -> &CPlaceInner {
185         &self.inner
186     }
187
188     pub fn no_place(layout: TyLayout<'tcx>) -> CPlace<'tcx> {
189         CPlace{
190             inner: CPlaceInner::NoPlace,
191             layout
192         }
193     }
194
195     pub fn new_stack_slot(
196         fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
197         ty: Ty<'tcx>,
198     ) -> CPlace<'tcx> {
199         let layout = fx.layout_of(ty);
200         assert!(!layout.is_unsized());
201         if layout.size.bytes() == 0 {
202             return CPlace {
203                 inner: CPlaceInner::NoPlace,
204                 layout,
205             };
206         }
207
208         let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
209             kind: StackSlotKind::ExplicitSlot,
210             size: layout.size.bytes() as u32,
211             offset: None,
212         });
213         CPlace {
214             inner: CPlaceInner::Stack(stack_slot),
215             layout,
216         }
217     }
218
219     pub fn new_var(
220         fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
221         local: Local,
222         layout: TyLayout<'tcx>,
223     ) -> CPlace<'tcx> {
224         fx.bcx
225             .declare_var(mir_var(local), fx.clif_type(layout.ty).unwrap());
226         CPlace {
227             inner: CPlaceInner::Var(local),
228             layout,
229         }
230     }
231
232     pub fn for_addr(addr: Value, layout: TyLayout<'tcx>) -> CPlace<'tcx> {
233         CPlace {
234             inner: CPlaceInner::Addr(addr, None),
235             layout,
236         }
237     }
238
239     pub fn for_addr_with_extra(addr: Value, extra: Value, layout: TyLayout<'tcx>) -> CPlace<'tcx> {
240         CPlace {
241             inner: CPlaceInner::Addr(addr, Some(extra)),
242             layout,
243         }
244     }
245
246     pub fn to_cvalue(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> CValue<'tcx> {
247         let layout = self.layout();
248         match self.inner {
249             CPlaceInner::Var(var) => CValue::by_val(fx.bcx.use_var(mir_var(var)), layout),
250             CPlaceInner::Addr(addr, extra) => {
251                 assert!(extra.is_none(), "unsized values are not yet supported");
252                 CValue::by_ref(addr, layout)
253             }
254             CPlaceInner::Stack(stack_slot) => CValue::by_ref(
255                 fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0),
256                 layout,
257             ),
258             CPlaceInner::NoPlace => CValue::by_ref(
259                 fx.bcx
260                     .ins()
261                     .iconst(fx.pointer_type, fx.pointer_type.bytes() as i64),
262                 layout,
263             ),
264         }
265     }
266
267     pub fn to_addr(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> Value {
268         match self.to_addr_maybe_unsized(fx) {
269             (addr, None) => addr,
270             (_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
271         }
272     }
273
274     pub fn to_addr_maybe_unsized(
275         self,
276         fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
277     ) -> (Value, Option<Value>) {
278         match self.inner {
279             CPlaceInner::Addr(addr, extra) => (addr, extra),
280             CPlaceInner::Stack(stack_slot) => (
281                 fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0),
282                 None,
283             ),
284             CPlaceInner::NoPlace => (fx.bcx.ins().iconst(fx.pointer_type, 45), None),
285             CPlaceInner::Var(_) => bug!("Expected CPlace::Addr, found CPlace::Var"),
286         }
287     }
288
289     pub fn write_cvalue(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>, from: CValue<'tcx>) {
290         use rustc::hir::Mutability::*;
291
292         let from_ty = from.layout().ty;
293         let to_ty = self.layout().ty;
294
295         fn assert_assignable<'tcx>(fx: &FunctionCx<'_, 'tcx, impl Backend>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) {
296             match (&from_ty.sty, &to_ty.sty) {
297                 (ty::Ref(_, t, MutImmutable), ty::Ref(_, u, MutImmutable))
298                 | (ty::Ref(_, t, MutMutable), ty::Ref(_, u, MutImmutable))
299                 | (ty::Ref(_, t, MutMutable), ty::Ref(_, u, MutMutable)) => {
300                     assert_assignable(fx, t, u);
301                     // &mut T -> &T is allowed
302                     // &'a T -> &'b T is allowed
303                 }
304                 (ty::Ref(_, _, MutImmutable), ty::Ref(_, _, MutMutable)) => {
305                     panic!("Cant assign value of type {} to place of type {}", from_ty, to_ty)
306                 }
307                 (ty::FnPtr(_), ty::FnPtr(_)) => {
308                     let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
309                         ParamEnv::reveal_all(),
310                         &from_ty.fn_sig(fx.tcx),
311                     );
312                     let to_sig = fx.tcx.normalize_erasing_late_bound_regions(
313                         ParamEnv::reveal_all(),
314                         &to_ty.fn_sig(fx.tcx),
315                     );
316                     assert_eq!(
317                         from_sig, to_sig,
318                         "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}",
319                         from_sig, to_sig, fx,
320                     );
321                     // fn(&T) -> for<'l> fn(&'l T) is allowed
322                 }
323                 (ty::Dynamic(from_traits, _), ty::Dynamic(to_traits, _)) => {
324                     let from_traits = fx.tcx.normalize_erasing_late_bound_regions(
325                         ParamEnv::reveal_all(),
326                         from_traits,
327                     );
328                     let to_traits = fx.tcx.normalize_erasing_late_bound_regions(
329                         ParamEnv::reveal_all(),
330                         to_traits,
331                     );
332                     assert_eq!(
333                         from_traits, to_traits,
334                         "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}",
335                         from_traits, to_traits, fx,
336                     );
337                     // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
338                 }
339                 _ => {
340                     assert_eq!(
341                         from_ty,
342                         to_ty,
343                         "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}",
344                         from_ty,
345                         to_ty,
346                         fx,
347                     );
348                 }
349             }
350         }
351
352         assert_assignable(fx, from_ty, to_ty);
353
354         let dst_layout = self.layout();
355         let addr = match self.inner {
356             CPlaceInner::Var(var) => {
357                 let data = from.load_scalar(fx);
358                 fx.bcx.def_var(mir_var(var), data);
359                 return;
360             }
361             CPlaceInner::Addr(addr, None) => addr,
362             CPlaceInner::Stack(stack_slot) => {
363                 fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0)
364             }
365             CPlaceInner::NoPlace => {
366                 if dst_layout.abi != Abi::Uninhabited {
367                     assert_eq!(dst_layout.size.bytes(), 0, "{:?}", dst_layout);
368                 }
369                 return;
370             }
371             CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self),
372         };
373
374         match from.0 {
375             CValueInner::ByVal(val) => {
376                 fx.bcx.ins().store(MemFlags::new(), val, addr, 0);
377             }
378             CValueInner::ByValPair(value, extra) => {
379                 match dst_layout.abi {
380                     Abi::ScalarPair(ref a_scalar, ref b_scalar) => {
381                         let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
382                         fx.bcx.ins().store(MemFlags::new(), value, addr, 0);
383                         fx.bcx.ins().store(
384                             MemFlags::new(),
385                             extra,
386                             addr,
387                             b_offset,
388                         );
389                     }
390                     _ => bug!(
391                         "Non ScalarPair abi {:?} for ByValPair CValue",
392                         dst_layout.abi
393                     ),
394                 }
395             }
396             CValueInner::ByRef(from_addr) => {
397                 let src_layout = from.1;
398                 let size = dst_layout.size.bytes();
399                 let src_align = src_layout.align.abi.bytes() as u8;
400                 let dst_align = dst_layout.align.abi.bytes() as u8;
401                 fx.bcx.emit_small_memcpy(
402                     fx.module.target_config(),
403                     addr,
404                     from_addr,
405                     size,
406                     dst_align,
407                     src_align,
408                 );
409             }
410         }
411     }
412
413     pub fn place_field(
414         self,
415         fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
416         field: mir::Field,
417     ) -> CPlace<'tcx> {
418         let layout = self.layout();
419         let (base, extra) = self.to_addr_maybe_unsized(fx);
420
421         let (field_ptr, field_layout) = codegen_field(fx, base, layout, field);
422         if field_layout.is_unsized() {
423             CPlace::for_addr_with_extra(field_ptr, extra.unwrap(), field_layout)
424         } else {
425             CPlace::for_addr(field_ptr, field_layout)
426         }
427     }
428
429     pub fn place_index(
430         self,
431         fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
432         index: Value,
433     ) -> CPlace<'tcx> {
434         let (elem_layout, addr) = match self.layout().ty.sty {
435             ty::Array(elem_ty, _) => (fx.layout_of(elem_ty), self.to_addr(fx)),
436             ty::Slice(elem_ty) => (fx.layout_of(elem_ty), self.to_addr_maybe_unsized(fx).0),
437             _ => bug!("place_index({:?})", self.layout().ty),
438         };
439
440         let offset = fx
441             .bcx
442             .ins()
443             .imul_imm(index, elem_layout.size.bytes() as i64);
444
445         CPlace::for_addr(fx.bcx.ins().iadd(addr, offset), elem_layout)
446     }
447
448     pub fn place_deref(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> CPlace<'tcx> {
449         let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap().ty);
450         if !inner_layout.is_unsized() {
451             CPlace::for_addr(self.to_cvalue(fx).load_scalar(fx), inner_layout)
452         } else {
453             let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx);
454             CPlace::for_addr_with_extra(addr, extra, inner_layout)
455         }
456     }
457
458     pub fn write_place_ref(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>, dest: CPlace<'tcx>) {
459         if !self.layout().is_unsized() {
460             let ptr = CValue::by_val(self.to_addr(fx), dest.layout());
461             dest.write_cvalue(fx, ptr);
462         } else {
463             let (value, extra) = self.to_addr_maybe_unsized(fx);
464             let ptr = CValue::by_val_pair(value, extra.expect("unsized type without metadata"), dest.layout());
465             dest.write_cvalue(fx, ptr);
466         }
467     }
468
469     pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
470         assert!(!self.layout().is_unsized());
471         match self.inner {
472             CPlaceInner::NoPlace => {
473                 assert!(layout.size.bytes() == 0);
474             }
475             _ => {}
476         }
477         CPlace {
478             inner: self.inner,
479             layout,
480         }
481     }
482
483     pub fn downcast_variant(
484         self,
485         fx: &FunctionCx<'_, 'tcx, impl Backend>,
486         variant: VariantIdx,
487     ) -> Self {
488         let layout = self.layout().for_variant(fx, variant);
489         self.unchecked_cast_to(layout)
490     }
491 }