]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/mir/operand.rs
Optimized error reporting for recursive requirements #47720
[rust.git] / src / librustc_trans / 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 llvm::ValueRef;
12 use rustc::ty;
13 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
14 use rustc::mir;
15 use rustc_data_structures::indexed_vec::Idx;
16
17 use base;
18 use common::{self, CodegenCx, C_undef, C_usize};
19 use builder::Builder;
20 use value::Value;
21 use type_of::LayoutLlvmExt;
22 use type_::Type;
23
24 use std::fmt;
25 use std::ptr;
26
27 use super::{FunctionCx, LocalRef};
28 use super::place::PlaceRef;
29
30 /// The representation of a Rust value. The enum variant is in fact
31 /// uniquely determined by the value's type, but is kept as a
32 /// safety check.
33 #[derive(Copy, Clone)]
34 pub enum OperandValue {
35     /// A reference to the actual operand. The data is guaranteed
36     /// to be valid for the operand's lifetime.
37     Ref(ValueRef, Align),
38     /// A single LLVM value.
39     Immediate(ValueRef),
40     /// A pair of immediate LLVM values. Used by fat pointers too.
41     Pair(ValueRef, ValueRef)
42 }
43
44 impl fmt::Debug for OperandValue {
45     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46         match *self {
47             OperandValue::Ref(r, align) => {
48                 write!(f, "Ref({:?}, {:?})", Value(r), align)
49             }
50             OperandValue::Immediate(i) => {
51                 write!(f, "Immediate({:?})", Value(i))
52             }
53             OperandValue::Pair(a, b) => {
54                 write!(f, "Pair({:?}, {:?})", Value(a), Value(b))
55             }
56         }
57     }
58 }
59
60 /// An `OperandRef` is an "SSA" reference to a Rust value, along with
61 /// its type.
62 ///
63 /// NOTE: unless you know a value's type exactly, you should not
64 /// generate LLVM opcodes acting on it and instead act via methods,
65 /// to avoid nasty edge cases. In particular, using `Builder::store`
66 /// directly is sure to cause problems -- use `OperandRef::store`
67 /// instead.
68 #[derive(Copy, Clone)]
69 pub struct OperandRef<'tcx> {
70     // The value.
71     pub val: OperandValue,
72
73     // The layout of value, based on its Rust type.
74     pub layout: TyLayout<'tcx>,
75 }
76
77 impl<'tcx> fmt::Debug for OperandRef<'tcx> {
78     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79         write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout)
80     }
81 }
82
83 impl<'a, 'tcx> OperandRef<'tcx> {
84     pub fn new_zst(cx: &CodegenCx<'a, 'tcx>,
85                    layout: TyLayout<'tcx>) -> OperandRef<'tcx> {
86         assert!(layout.is_zst());
87         OperandRef {
88             val: OperandValue::Immediate(C_undef(layout.immediate_llvm_type(cx))),
89             layout
90         }
91     }
92
93     /// Asserts that this operand refers to a scalar and returns
94     /// a reference to its value.
95     pub fn immediate(self) -> ValueRef {
96         match self.val {
97             OperandValue::Immediate(s) => s,
98             _ => bug!("not immediate: {:?}", self)
99         }
100     }
101
102     pub fn deref(self, cx: &CodegenCx<'a, 'tcx>) -> PlaceRef<'tcx> {
103         let projected_ty = self.layout.ty.builtin_deref(true, ty::NoPreference)
104             .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty;
105         let (llptr, llextra) = match self.val {
106             OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
107             OperandValue::Pair(llptr, llextra) => (llptr, llextra),
108             OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self)
109         };
110         let layout = cx.layout_of(projected_ty);
111         PlaceRef {
112             llval: llptr,
113             llextra,
114             layout,
115             align: layout.align,
116         }
117     }
118
119     /// If this operand is a `Pair`, we return an aggregate with the two values.
120     /// For other cases, see `immediate`.
121     pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'tcx>) -> ValueRef {
122         if let OperandValue::Pair(a, b) = self.val {
123             let llty = self.layout.llvm_type(bx.cx);
124             debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}",
125                    self, llty);
126             // Reconstruct the immediate aggregate.
127             let mut llpair = C_undef(llty);
128             llpair = bx.insert_value(llpair, a, 0);
129             llpair = bx.insert_value(llpair, b, 1);
130             llpair
131         } else {
132             self.immediate()
133         }
134     }
135
136     /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`.
137     pub fn from_immediate_or_packed_pair(bx: &Builder<'a, 'tcx>,
138                                          llval: ValueRef,
139                                          layout: TyLayout<'tcx>)
140                                          -> OperandRef<'tcx> {
141         let val = if layout.is_llvm_scalar_pair() {
142             debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
143                     llval, layout);
144
145             // Deconstruct the immediate aggregate.
146             OperandValue::Pair(bx.extract_value(llval, 0),
147                                bx.extract_value(llval, 1))
148         } else {
149             OperandValue::Immediate(llval)
150         };
151         OperandRef { val, layout }
152     }
153
154     pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx> {
155         let field = self.layout.field(bx.cx, i);
156         let offset = self.layout.fields.offset(i);
157
158         let mut val = match (self.val, &self.layout.abi) {
159             // If we're uninhabited, or the field is ZST, it has no data.
160             _ if self.layout.abi == layout::Abi::Uninhabited || field.is_zst() => {
161                 return OperandRef {
162                     val: OperandValue::Immediate(C_undef(field.immediate_llvm_type(bx.cx))),
163                     layout: field
164                 };
165             }
166
167             // Newtype of a scalar, scalar pair or vector.
168             (OperandValue::Immediate(_), _) |
169             (OperandValue::Pair(..), _) if field.size == self.layout.size => {
170                 assert_eq!(offset.bytes(), 0);
171                 self.val
172             }
173
174             // Extract a scalar component from a pair.
175             (OperandValue::Pair(a_llval, b_llval), &layout::Abi::ScalarPair(ref a, ref b)) => {
176                 if offset.bytes() == 0 {
177                     assert_eq!(field.size, a.value.size(bx.cx));
178                     OperandValue::Immediate(a_llval)
179                 } else {
180                     assert_eq!(offset, a.value.size(bx.cx)
181                         .abi_align(b.value.align(bx.cx)));
182                     assert_eq!(field.size, b.value.size(bx.cx));
183                     OperandValue::Immediate(b_llval)
184                 }
185             }
186
187             // `#[repr(simd)]` types are also immediate.
188             (OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => {
189                 OperandValue::Immediate(
190                     bx.extract_element(llval, C_usize(bx.cx, i as u64)))
191             }
192
193             _ => bug!("OperandRef::extract_field({:?}): not applicable", self)
194         };
195
196         // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
197         match val {
198             OperandValue::Immediate(ref mut llval) => {
199                 *llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx));
200             }
201             OperandValue::Pair(ref mut a, ref mut b) => {
202                 *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0));
203                 *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1));
204             }
205             OperandValue::Ref(..) => bug!()
206         }
207
208         OperandRef {
209             val,
210             layout: field
211         }
212     }
213 }
214
215 impl<'a, 'tcx> OperandValue {
216     pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
217         debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
218         // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
219         // value is through `undef`, and store itself is useless.
220         if dest.layout.is_zst() {
221             return;
222         }
223         match self {
224             OperandValue::Ref(r, source_align) =>
225                 base::memcpy_ty(bx, dest.llval, r, dest.layout,
226                                 source_align.min(dest.align)),
227             OperandValue::Immediate(s) => {
228                 bx.store(base::from_immediate(bx, s), dest.llval, dest.align);
229             }
230             OperandValue::Pair(a, b) => {
231                 for (i, &x) in [a, b].iter().enumerate() {
232                     let mut llptr = bx.struct_gep(dest.llval, i as u64);
233                     // Make sure to always store i1 as i8.
234                     if common::val_ty(x) == Type::i1(bx.cx) {
235                         llptr = bx.pointercast(llptr, Type::i8p(bx.cx));
236                     }
237                     bx.store(base::from_immediate(bx, x), llptr, dest.align);
238                 }
239             }
240         }
241     }
242 }
243
244 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
245     fn maybe_trans_consume_direct(&mut self,
246                                   bx: &Builder<'a, 'tcx>,
247                                   place: &mir::Place<'tcx>)
248                                    -> Option<OperandRef<'tcx>>
249     {
250         debug!("maybe_trans_consume_direct(place={:?})", place);
251
252         // watch out for locals that do not have an
253         // alloca; they are handled somewhat differently
254         if let mir::Place::Local(index) = *place {
255             match self.locals[index] {
256                 LocalRef::Operand(Some(o)) => {
257                     return Some(o);
258                 }
259                 LocalRef::Operand(None) => {
260                     bug!("use of {:?} before def", place);
261                 }
262                 LocalRef::Place(..) => {
263                     // use path below
264                 }
265             }
266         }
267
268         // Moves out of scalar and scalar pair fields are trivial.
269         if let &mir::Place::Projection(ref proj) = place {
270             if let Some(o) = self.maybe_trans_consume_direct(bx, &proj.base) {
271                 match proj.elem {
272                     mir::ProjectionElem::Field(ref f, _) => {
273                         return Some(o.extract_field(bx, f.index()));
274                     }
275                     mir::ProjectionElem::Index(_) |
276                     mir::ProjectionElem::ConstantIndex { .. } => {
277                         // ZSTs don't require any actual memory access.
278                         // FIXME(eddyb) deduplicate this with the identical
279                         // checks in `trans_consume` and `extract_field`.
280                         let elem = o.layout.field(bx.cx, 0);
281                         if elem.is_zst() {
282                             return Some(OperandRef::new_zst(bx.cx, elem));
283                         }
284                     }
285                     _ => {}
286                 }
287             }
288         }
289
290         None
291     }
292
293     pub fn trans_consume(&mut self,
294                          bx: &Builder<'a, 'tcx>,
295                          place: &mir::Place<'tcx>)
296                          -> OperandRef<'tcx>
297     {
298         debug!("trans_consume(place={:?})", place);
299
300         let ty = self.monomorphized_place_ty(place);
301         let layout = bx.cx.layout_of(ty);
302
303         // ZSTs don't require any actual memory access.
304         if layout.is_zst() {
305             return OperandRef::new_zst(bx.cx, layout);
306         }
307
308         if let Some(o) = self.maybe_trans_consume_direct(bx, place) {
309             return o;
310         }
311
312         // for most places, to consume them we just load them
313         // out from their home
314         self.trans_place(bx, place).load(bx)
315     }
316
317     pub fn trans_operand(&mut self,
318                          bx: &Builder<'a, 'tcx>,
319                          operand: &mir::Operand<'tcx>)
320                          -> OperandRef<'tcx>
321     {
322         debug!("trans_operand(operand={:?})", operand);
323
324         match *operand {
325             mir::Operand::Copy(ref place) |
326             mir::Operand::Move(ref place) => {
327                 self.trans_consume(bx, place)
328             }
329
330             mir::Operand::Constant(ref constant) => {
331                 let val = self.trans_constant(&bx, constant);
332                 let operand = val.to_operand(bx.cx);
333                 if let OperandValue::Ref(ptr, align) = operand.val {
334                     // If this is a OperandValue::Ref to an immediate constant, load it.
335                     PlaceRef::new_sized(ptr, operand.layout, align).load(bx)
336                 } else {
337                     operand
338                 }
339             }
340         }
341     }
342 }