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.
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.
13 use rustc
::ty
::layout
::Layout
;
15 use rustc_data_structures
::indexed_vec
::Idx
;
26 use super::{MirContext, LocalRef}
;
27 use super::lvalue
::Alignment
;
29 /// The representation of a Rust value. The enum variant is in fact
30 /// uniquely determined by the value's type, but is kept as a
32 #[derive(Copy, Clone)]
33 pub enum OperandValue
{
34 /// A reference to the actual operand. The data is guaranteed
35 /// to be valid for the operand's lifetime.
36 Ref(ValueRef
, Alignment
),
37 /// A single LLVM value.
39 /// A pair of immediate LLVM values. Used by fat pointers too.
40 Pair(ValueRef
, ValueRef
)
43 /// An `OperandRef` is an "SSA" reference to a Rust value, along with
46 /// NOTE: unless you know a value's type exactly, you should not
47 /// generate LLVM opcodes acting on it and instead act via methods,
48 /// to avoid nasty edge cases. In particular, using `Builder.store`
49 /// directly is sure to cause problems -- use `MirContext.store_operand`
51 #[derive(Copy, Clone)]
52 pub struct OperandRef
<'tcx
> {
54 pub val
: OperandValue
,
56 // The type of value being returned.
60 impl<'tcx
> fmt
::Debug
for OperandRef
<'tcx
> {
61 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
63 OperandValue
::Ref(r
, align
) => {
64 write
!(f
, "OperandRef(Ref({:?}, {:?}) @ {:?})",
65 Value(r
), align
, self.ty
)
67 OperandValue
::Immediate(i
) => {
68 write
!(f
, "OperandRef(Immediate({:?}) @ {:?})",
71 OperandValue
::Pair(a
, b
) => {
72 write
!(f
, "OperandRef(Pair({:?}, {:?}) @ {:?})",
73 Value(a
), Value(b
), self.ty
)
79 impl<'a
, 'tcx
> OperandRef
<'tcx
> {
80 /// Asserts that this operand refers to a scalar and returns
81 /// a reference to its value.
82 pub fn immediate(self) -> ValueRef
{
84 OperandValue
::Immediate(s
) => s
,
85 _
=> bug
!("not immediate: {:?}", self)
89 /// If this operand is a Pair, we return an
90 /// Immediate aggregate with the two values.
91 pub fn pack_if_pair(mut self, bcx
: &Builder
<'a
, 'tcx
>) -> OperandRef
<'tcx
> {
92 if let OperandValue
::Pair(a
, b
) = self.val
{
93 // Reconstruct the immediate aggregate.
94 let llty
= type_of
::type_of(bcx
.ccx
, self.ty
);
95 let mut llpair
= common
::C_undef(llty
);
98 let mut elem
= elems
[i
];
99 // Extend boolean i1's to i8.
100 if common
::val_ty(elem
) == Type
::i1(bcx
.ccx
) {
101 elem
= bcx
.zext(elem
, Type
::i8(bcx
.ccx
));
103 llpair
= bcx
.insert_value(llpair
, elem
, i
);
105 self.val
= OperandValue
::Immediate(llpair
);
110 /// If this operand is a pair in an Immediate,
111 /// we return a Pair with the two halves.
112 pub fn unpack_if_pair(mut self, bcx
: &Builder
<'a
, 'tcx
>) -> OperandRef
<'tcx
> {
113 if let OperandValue
::Immediate(llval
) = self.val
{
114 // Deconstruct the immediate aggregate.
115 if common
::type_is_imm_pair(bcx
.ccx
, self.ty
) {
116 debug
!("Operand::unpack_if_pair: unpacking {:?}", self);
118 let mut a
= bcx
.extract_value(llval
, 0);
119 let mut b
= bcx
.extract_value(llval
, 1);
121 let pair_fields
= common
::type_pair_fields(bcx
.ccx
, self.ty
);
122 if let Some([a_ty
, b_ty
]) = pair_fields
{
124 a
= bcx
.trunc(a
, Type
::i1(bcx
.ccx
));
127 b
= bcx
.trunc(b
, Type
::i1(bcx
.ccx
));
131 self.val
= OperandValue
::Pair(a
, b
);
138 impl<'a
, 'tcx
> MirContext
<'a
, 'tcx
> {
139 pub fn trans_load(&mut self,
140 bcx
: &Builder
<'a
, 'tcx
>,
146 debug
!("trans_load: {:?} @ {:?}", Value(llval
), ty
);
148 let val
= if common
::type_is_fat_ptr(bcx
.ccx
, ty
) {
149 let (lldata
, llextra
) = base
::load_fat_ptr(bcx
, llval
, align
, ty
);
150 OperandValue
::Pair(lldata
, llextra
)
151 } else if common
::type_is_imm_pair(bcx
.ccx
, ty
) {
152 let f_align
= match *bcx
.ccx
.layout_of(ty
) {
153 Layout
::Univariant { ref variant, .. }
=>
154 Alignment
::from_packed(variant
.packed
) | align
,
157 let [a_ty
, b_ty
] = common
::type_pair_fields(bcx
.ccx
, ty
).unwrap();
158 let a_ptr
= bcx
.struct_gep(llval
, 0);
159 let b_ptr
= bcx
.struct_gep(llval
, 1);
162 base
::load_ty(bcx
, a_ptr
, f_align
, a_ty
),
163 base
::load_ty(bcx
, b_ptr
, f_align
, b_ty
)
165 } else if common
::type_is_immediate(bcx
.ccx
, ty
) {
166 OperandValue
::Immediate(base
::load_ty(bcx
, llval
, align
, ty
))
168 OperandValue
::Ref(llval
, align
)
171 OperandRef { val: val, ty: ty }
174 pub fn trans_consume(&mut self,
175 bcx
: &Builder
<'a
, 'tcx
>,
176 lvalue
: &mir
::Lvalue
<'tcx
>)
179 debug
!("trans_consume(lvalue={:?})", lvalue
);
181 // watch out for locals that do not have an
182 // alloca; they are handled somewhat differently
183 if let mir
::Lvalue
::Local(index
) = *lvalue
{
184 match self.locals
[index
] {
185 LocalRef
::Operand(Some(o
)) => {
188 LocalRef
::Operand(None
) => {
189 bug
!("use of {:?} before def", lvalue
);
191 LocalRef
::Lvalue(..) => {
197 // Moves out of pair fields are trivial.
198 if let &mir
::Lvalue
::Projection(ref proj
) = lvalue
{
199 if let mir
::Lvalue
::Local(index
) = proj
.base
{
200 if let LocalRef
::Operand(Some(o
)) = self.locals
[index
] {
201 match (o
.val
, &proj
.elem
) {
202 (OperandValue
::Pair(a
, b
),
203 &mir
::ProjectionElem
::Field(ref f
, ty
)) => {
204 let llval
= [a
, b
][f
.index()];
205 let op
= OperandRef
{
206 val
: OperandValue
::Immediate(llval
),
207 ty
: self.monomorphize(&ty
)
210 // Handle nested pairs.
211 return op
.unpack_if_pair(bcx
);
219 // for most lvalues, to consume them we just load them
220 // out from their home
221 let tr_lvalue
= self.trans_lvalue(bcx
, lvalue
);
222 let ty
= tr_lvalue
.ty
.to_ty(bcx
.tcx());
223 self.trans_load(bcx
, tr_lvalue
.llval
, tr_lvalue
.alignment
, ty
)
226 pub fn trans_operand(&mut self,
227 bcx
: &Builder
<'a
, 'tcx
>,
228 operand
: &mir
::Operand
<'tcx
>)
231 debug
!("trans_operand(operand={:?})", operand
);
234 mir
::Operand
::Consume(ref lvalue
) => {
235 self.trans_consume(bcx
, lvalue
)
238 mir
::Operand
::Constant(ref constant
) => {
239 let val
= self.trans_constant(bcx
, constant
);
240 let operand
= val
.to_operand(bcx
.ccx
);
241 if let OperandValue
::Ref(ptr
, align
) = operand
.val
{
242 // If this is a OperandValue::Ref to an immediate constant, load it.
243 self.trans_load(bcx
, ptr
, align
, operand
.ty
)
251 pub fn store_operand(&mut self,
252 bcx
: &Builder
<'a
, 'tcx
>,
255 operand
: OperandRef
<'tcx
>) {
256 debug
!("store_operand: operand={:?}, align={:?}", operand
, align
);
257 // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
258 // value is through `undef`, and store itself is useless.
259 if common
::type_is_zero_size(bcx
.ccx
, operand
.ty
) {
263 OperandValue
::Ref(r
, Alignment
::Packed
) =>
264 base
::memcpy_ty(bcx
, lldest
, r
, operand
.ty
, Some(1)),
265 OperandValue
::Ref(r
, Alignment
::AbiAligned
) =>
266 base
::memcpy_ty(bcx
, lldest
, r
, operand
.ty
, align
),
267 OperandValue
::Immediate(s
) => {
268 bcx
.store(base
::from_immediate(bcx
, s
), lldest
, align
);
270 OperandValue
::Pair(a
, b
) => {
271 let f_align
= match *bcx
.ccx
.layout_of(operand
.ty
) {
272 Layout
::Univariant { ref variant, .. }
if variant
.packed
=> {
278 let a
= base
::from_immediate(bcx
, a
);
279 let b
= base
::from_immediate(bcx
, b
);
280 bcx
.store(a
, bcx
.struct_gep(lldest
, 0), f_align
);
281 bcx
.store(b
, bcx
.struct_gep(lldest
, 1), f_align
);