]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/mir/operand.rs
c2725acbf1234c020aed407e26cfe3665bb79fb7
[rust.git] / src / librustc_codegen_llvm / mir / operand.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use rustc::mir::interpret::{ConstValue, ErrorHandled};
12 use rustc::mir;
13 use rustc::ty;
14 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
15
16 use base;
17 use common::CodegenCx;
18 use builder::{Builder, MemFlags};
19 use value::Value;
20 use type_of::LayoutLlvmExt;
21 use glue;
22
23 use interfaces::{BuilderMethods, CommonMethods, TypeMethods};
24
25 use std::fmt;
26
27 use super::{FunctionCx, LocalRef};
28 use super::constant::scalar_to_llvm;
29 use super::place::PlaceRef;
30
31 /// The representation of a Rust value. The enum variant is in fact
32 /// uniquely determined by the value's type, but is kept as a
33 /// safety check.
34 #[derive(Copy, Clone, Debug)]
35 pub enum OperandValue<V> {
36     /// A reference to the actual operand. The data is guaranteed
37     /// to be valid for the operand's lifetime.
38     /// The second value, if any, is the extra data (vtable or length)
39     /// which indicates that it refers to an unsized rvalue.
40     Ref(V, Option<V>, Align),
41     /// A single LLVM value.
42     Immediate(V),
43     /// A pair of immediate LLVM values. Used by fat pointers too.
44     Pair(V, V)
45 }
46
47 /// An `OperandRef` is an "SSA" reference to a Rust value, along with
48 /// its type.
49 ///
50 /// NOTE: unless you know a value's type exactly, you should not
51 /// generate LLVM opcodes acting on it and instead act via methods,
52 /// to avoid nasty edge cases. In particular, using `Builder::store`
53 /// directly is sure to cause problems -- use `OperandRef::store`
54 /// instead.
55 #[derive(Copy, Clone)]
56 pub struct OperandRef<'tcx, V> {
57     // The value.
58     pub val: OperandValue<V>,
59
60     // The layout of value, based on its Rust type.
61     pub layout: TyLayout<'tcx>,
62 }
63
64 impl fmt::Debug for OperandRef<'tcx, &'ll Value> {
65     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66         write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout)
67     }
68 }
69
70 impl OperandRef<'tcx, &'ll Value> {
71     pub fn new_zst(cx: &CodegenCx<'ll, 'tcx>,
72                    layout: TyLayout<'tcx>) -> OperandRef<'tcx, &'ll Value> {
73         assert!(layout.is_zst());
74         OperandRef {
75             val: OperandValue::Immediate(cx.const_undef(layout.immediate_llvm_type(cx))),
76             layout
77         }
78     }
79
80     pub fn from_const(bx: &Builder<'a, 'll, 'tcx>,
81                       val: &'tcx ty::Const<'tcx>)
82                       -> Result<OperandRef<'tcx, &'ll Value>, ErrorHandled> {
83         let layout = bx.cx().layout_of(val.ty);
84
85         if layout.is_zst() {
86             return Ok(OperandRef::new_zst(bx.cx(), layout));
87         }
88
89         let val = match val.val {
90             ConstValue::Unevaluated(..) => bug!(),
91             ConstValue::Scalar(x) => {
92                 let scalar = match layout.abi {
93                     layout::Abi::Scalar(ref x) => x,
94                     _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
95                 };
96                 let llval = scalar_to_llvm(
97                     bx.cx(),
98                     x,
99                     scalar,
100                     layout.immediate_llvm_type(bx.cx()),
101                 );
102                 OperandValue::Immediate(llval)
103             },
104             ConstValue::ScalarPair(a, b) => {
105                 let (a_scalar, b_scalar) = match layout.abi {
106                     layout::Abi::ScalarPair(ref a, ref b) => (a, b),
107                     _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
108                 };
109                 let a_llval = scalar_to_llvm(
110                     bx.cx(),
111                     a,
112                     a_scalar,
113                     layout.scalar_pair_element_llvm_type(bx.cx(), 0, true),
114                 );
115                 let b_layout = layout.scalar_pair_element_llvm_type(bx.cx(), 1, true);
116                 let b_llval = scalar_to_llvm(
117                     bx.cx(),
118                     b,
119                     b_scalar,
120                     b_layout,
121                 );
122                 OperandValue::Pair(a_llval, b_llval)
123             },
124             ConstValue::ByRef(_, alloc, offset) => {
125                 return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
126             },
127         };
128
129         Ok(OperandRef {
130             val,
131             layout
132         })
133     }
134
135     /// Asserts that this operand refers to a scalar and returns
136     /// a reference to its value.
137     pub fn immediate(self) -> &'ll Value {
138         match self.val {
139             OperandValue::Immediate(s) => s,
140             _ => bug!("not immediate: {:?}", self)
141         }
142     }
143
144     pub fn deref(self, cx: &CodegenCx<'ll, 'tcx>) -> PlaceRef<'tcx, &'ll Value> {
145         let projected_ty = self.layout.ty.builtin_deref(true)
146             .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty;
147         let (llptr, llextra) = match self.val {
148             OperandValue::Immediate(llptr) => (llptr, None),
149             OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
150             OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self)
151         };
152         let layout = cx.layout_of(projected_ty);
153         PlaceRef {
154             llval: llptr,
155             llextra,
156             layout,
157             align: layout.align,
158         }
159     }
160
161     /// If this operand is a `Pair`, we return an aggregate with the two values.
162     /// For other cases, see `immediate`.
163     pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'll, 'tcx>) -> &'ll Value {
164         if let OperandValue::Pair(a, b) = self.val {
165             let llty = self.layout.llvm_type(bx.cx());
166             debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}",
167                    self, llty);
168             // Reconstruct the immediate aggregate.
169             let mut llpair = bx.cx().const_undef(llty);
170             llpair = bx.insert_value(llpair, base::from_immediate(bx, a), 0);
171             llpair = bx.insert_value(llpair, base::from_immediate(bx, b), 1);
172             llpair
173         } else {
174             self.immediate()
175         }
176     }
177
178     /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`.
179     pub fn from_immediate_or_packed_pair(bx: &Builder<'a, 'll, 'tcx>,
180                                          llval: &'ll Value,
181                                          layout: TyLayout<'tcx>)
182                                          -> OperandRef<'tcx, &'ll Value> {
183         let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi {
184             debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
185                     llval, layout);
186
187             // Deconstruct the immediate aggregate.
188             let a_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 0), a);
189             let b_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 1), b);
190             OperandValue::Pair(a_llval, b_llval)
191         } else {
192             OperandValue::Immediate(llval)
193         };
194         OperandRef { val, layout }
195     }
196
197     pub fn extract_field(
198         &self,
199         bx: &Builder<'a, 'll, 'tcx>,
200         i: usize,
201     ) -> OperandRef<'tcx, &'ll Value> {
202         let field = self.layout.field(bx.cx(), i);
203         let offset = self.layout.fields.offset(i);
204
205         let mut val = match (self.val, &self.layout.abi) {
206             // If the field is ZST, it has no data.
207             _ if field.is_zst() => {
208                 return OperandRef::new_zst(bx.cx(), field);
209             }
210
211             // Newtype of a scalar, scalar pair or vector.
212             (OperandValue::Immediate(_), _) |
213             (OperandValue::Pair(..), _) if field.size == self.layout.size => {
214                 assert_eq!(offset.bytes(), 0);
215                 self.val
216             }
217
218             // Extract a scalar component from a pair.
219             (OperandValue::Pair(a_llval, b_llval), &layout::Abi::ScalarPair(ref a, ref b)) => {
220                 if offset.bytes() == 0 {
221                     assert_eq!(field.size, a.value.size(bx.cx()));
222                     OperandValue::Immediate(a_llval)
223                 } else {
224                     assert_eq!(offset, a.value.size(bx.cx())
225                         .abi_align(b.value.align(bx.cx())));
226                     assert_eq!(field.size, b.value.size(bx.cx()));
227                     OperandValue::Immediate(b_llval)
228                 }
229             }
230
231             // `#[repr(simd)]` types are also immediate.
232             (OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => {
233                 OperandValue::Immediate(
234                     bx.extract_element(llval, bx.cx().const_usize(i as u64)))
235             }
236
237             _ => bug!("OperandRef::extract_field({:?}): not applicable", self)
238         };
239
240         // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
241         match val {
242             OperandValue::Immediate(ref mut llval) => {
243                 *llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx()));
244             }
245             OperandValue::Pair(ref mut a, ref mut b) => {
246                 *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx(), 0, true));
247                 *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx(), 1, true));
248             }
249             OperandValue::Ref(..) => bug!()
250         }
251
252         OperandRef {
253             val,
254             layout: field
255         }
256     }
257 }
258
259 impl OperandValue<&'ll Value> {
260     pub fn store(self, bx: &Builder<'a, 'll, 'tcx>, dest: PlaceRef<'tcx, &'ll Value>) {
261         self.store_with_flags(bx, dest, MemFlags::empty());
262     }
263
264     pub fn volatile_store(
265         self,
266         bx: &Builder<'a, 'll, 'tcx>,
267         dest: PlaceRef<'tcx, &'ll Value>
268     ) {
269         self.store_with_flags(bx, dest, MemFlags::VOLATILE);
270     }
271
272     pub fn unaligned_volatile_store(
273         self,
274         bx: &Builder<'a, 'll, 'tcx>,
275         dest: PlaceRef<'tcx, &'ll Value>,
276     ) {
277         self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED);
278     }
279 }
280
281 impl<'a, 'll: 'a, 'tcx: 'll> OperandValue<&'ll Value> {
282     pub fn nontemporal_store(
283         self,
284         bx: &Builder<'a, 'll, 'tcx>,
285         dest: PlaceRef<'tcx, &'ll Value>
286     ) {
287         self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
288     }
289
290     fn store_with_flags(
291         self,
292         bx: &Builder<'a, 'll, 'tcx, &'ll Value>,
293         dest: PlaceRef<'tcx, &'ll Value>,
294         flags: MemFlags,
295     ) {
296         debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
297         // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
298         // value is through `undef`, and store itself is useless.
299         if dest.layout.is_zst() {
300             return;
301         }
302         match self {
303             OperandValue::Ref(r, None, source_align) => {
304                 base::memcpy_ty(bx, dest.llval, dest.align, r, source_align,
305                                 dest.layout, flags)
306             }
307             OperandValue::Ref(_, Some(_), _) => {
308                 bug!("cannot directly store unsized values");
309             }
310             OperandValue::Immediate(s) => {
311                 let val = base::from_immediate(bx, s);
312                 bx.store_with_flags(val, dest.llval, dest.align, flags);
313             }
314             OperandValue::Pair(a, b) => {
315                 for (i, &x) in [a, b].iter().enumerate() {
316                     let llptr = bx.struct_gep(dest.llval, i as u64);
317                     let val = base::from_immediate(bx, x);
318                     bx.store_with_flags(val, llptr, dest.align, flags);
319                 }
320             }
321         }
322     }
323 }
324
325 impl OperandValue<&'ll Value> {
326     pub fn store_unsized(
327         self,
328         bx: &Builder<'a, 'll, 'tcx>,
329         indirect_dest: PlaceRef<'tcx, &'ll Value>
330     ) {
331         debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
332         let flags = MemFlags::empty();
333
334         // `indirect_dest` must have `*mut T` type. We extract `T` out of it.
335         let unsized_ty = indirect_dest.layout.ty.builtin_deref(true)
336             .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)).ty;
337
338         let (llptr, llextra) =
339             if let OperandValue::Ref(llptr, Some(llextra), _) = self {
340                 (llptr, llextra)
341             } else {
342                 bug!("store_unsized called with a sized value")
343             };
344
345         // FIXME: choose an appropriate alignment, or use dynamic align somehow
346         let max_align = Align::from_bits(128, 128).unwrap();
347         let min_align = Align::from_bits(8, 8).unwrap();
348
349         // Allocate an appropriate region on the stack, and copy the value into it
350         let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
351         let lldst = bx.array_alloca(bx.cx().i8(), llsize, "unsized_tmp", max_align);
352         base::call_memcpy(bx, lldst, max_align, llptr, min_align, llsize, flags);
353
354         // Store the allocated region and the extra to the indirect place.
355         let indirect_operand = OperandValue::Pair(lldst, llextra);
356         indirect_operand.store(bx, indirect_dest);
357     }
358 }
359
360 impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
361     fn maybe_codegen_consume_direct(&mut self,
362                                   bx: &Builder<'a, 'll, 'tcx>,
363                                   place: &mir::Place<'tcx>)
364                                    -> Option<OperandRef<'tcx, &'ll Value>>
365     {
366         debug!("maybe_codegen_consume_direct(place={:?})", place);
367
368         // watch out for locals that do not have an
369         // alloca; they are handled somewhat differently
370         if let mir::Place::Local(index) = *place {
371             match self.locals[index] {
372                 LocalRef::Operand(Some(o)) => {
373                     return Some(o);
374                 }
375                 LocalRef::Operand(None) => {
376                     bug!("use of {:?} before def", place);
377                 }
378                 LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
379                     // use path below
380                 }
381             }
382         }
383
384         // Moves out of scalar and scalar pair fields are trivial.
385         if let &mir::Place::Projection(ref proj) = place {
386             if let Some(o) = self.maybe_codegen_consume_direct(bx, &proj.base) {
387                 match proj.elem {
388                     mir::ProjectionElem::Field(ref f, _) => {
389                         return Some(o.extract_field(bx, f.index()));
390                     }
391                     mir::ProjectionElem::Index(_) |
392                     mir::ProjectionElem::ConstantIndex { .. } => {
393                         // ZSTs don't require any actual memory access.
394                         // FIXME(eddyb) deduplicate this with the identical
395                         // checks in `codegen_consume` and `extract_field`.
396                         let elem = o.layout.field(bx.cx(), 0);
397                         if elem.is_zst() {
398                             return Some(OperandRef::new_zst(bx.cx(), elem));
399                         }
400                     }
401                     _ => {}
402                 }
403             }
404         }
405
406         None
407     }
408
409     pub fn codegen_consume(&mut self,
410                          bx: &Builder<'a, 'll, 'tcx>,
411                          place: &mir::Place<'tcx>)
412                          -> OperandRef<'tcx, &'ll Value>
413     {
414         debug!("codegen_consume(place={:?})", place);
415
416         let ty = self.monomorphized_place_ty(place);
417         let layout = bx.cx().layout_of(ty);
418
419         // ZSTs don't require any actual memory access.
420         if layout.is_zst() {
421             return OperandRef::new_zst(bx.cx(), layout);
422         }
423
424         if let Some(o) = self.maybe_codegen_consume_direct(bx, place) {
425             return o;
426         }
427
428         // for most places, to consume them we just load them
429         // out from their home
430         self.codegen_place(bx, place).load(bx)
431     }
432
433     pub fn codegen_operand(&mut self,
434                          bx: &Builder<'a, 'll, 'tcx>,
435                          operand: &mir::Operand<'tcx>)
436                          -> OperandRef<'tcx, &'ll Value>
437     {
438         debug!("codegen_operand(operand={:?})", operand);
439
440         match *operand {
441             mir::Operand::Copy(ref place) |
442             mir::Operand::Move(ref place) => {
443                 self.codegen_consume(bx, place)
444             }
445
446             mir::Operand::Constant(ref constant) => {
447                 let ty = self.monomorphize(&constant.ty);
448                 self.eval_mir_constant(bx, constant)
449                     .and_then(|c| OperandRef::from_const(bx, c))
450                     .unwrap_or_else(|err| {
451                         match err {
452                             // errored or at least linted
453                             ErrorHandled::Reported => {},
454                             ErrorHandled::TooGeneric => {
455                                 bug!("codgen encountered polymorphic constant")
456                             },
457                         }
458                         // Allow RalfJ to sleep soundly knowing that even refactorings that remove
459                         // the above error (or silence it under some conditions) will not cause UB
460                         let fnname = bx.cx().get_intrinsic(&("llvm.trap"));
461                         bx.call(fnname, &[], None);
462                         // We've errored, so we don't have to produce working code.
463                         let layout = bx.cx().layout_of(ty);
464                         PlaceRef::new_sized(
465                             bx.cx().const_undef(bx.cx().ptr_to(layout.llvm_type(bx.cx()))),
466                             layout,
467                             layout.align,
468                         ).load(bx)
469                     })
470             }
471         }
472     }
473 }