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