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