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.
12 use rustc
::middle
::ty
::{self, Ty}
;
13 use rustc
::mir
::repr
as mir
;
16 use trans
::common
::{self, Block, BlockAndBuilder}
;
20 use super::{MirContext, TempRef}
;
21 use super::lvalue
::LvalueRef
;
23 /// The representation of a Rust value. The enum variant is in fact
24 /// uniquely determined by the value's type, but is kept as a
26 #[derive(Copy, Clone)]
27 pub enum OperandValue
{
28 /// A reference to the actual operand. The data is guaranteed
29 /// to be valid for the operand's lifetime.
31 /// A single LLVM value.
33 /// A fat pointer. The first ValueRef is the data and the second
35 FatPtr(ValueRef
, ValueRef
)
38 /// An `OperandRef` is an "SSA" reference to a Rust value, along with
41 /// NOTE: unless you know a value's type exactly, you should not
42 /// generate LLVM opcodes acting on it and instead act via methods,
43 /// to avoid nasty edge cases. In particular, using `Builder.store`
44 /// directly is sure to cause problems -- use `MirContext.store_operand`
46 #[derive(Copy, Clone)]
47 pub struct OperandRef
<'tcx
> {
49 pub val
: OperandValue
,
51 // The type of value being returned.
55 impl<'tcx
> OperandRef
<'tcx
> {
56 /// Asserts that this operand refers to a scalar and returns
57 /// a reference to its value.
58 pub fn immediate(self) -> ValueRef
{
60 OperandValue
::Immediate(s
) => s
,
65 pub fn repr
<'bcx
>(self, bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>) -> String
{
67 OperandValue
::Ref(r
) => {
68 format
!("OperandRef(Ref({}) @ {:?})",
69 bcx
.val_to_string(r
), self.ty
)
71 OperandValue
::Immediate(i
) => {
72 format
!("OperandRef(Immediate({}) @ {:?})",
73 bcx
.val_to_string(i
), self.ty
)
75 OperandValue
::FatPtr(a
, d
) => {
76 format
!("OperandRef(FatPtr({}, {}) @ {:?})",
84 pub fn from_rvalue_datum(datum
: datum
::Datum
<'tcx
, datum
::Rvalue
>) -> OperandRef
{
87 val
: match datum
.kind
.mode
{
88 datum
::RvalueMode
::ByRef
=> OperandValue
::Ref(datum
.val
),
89 datum
::RvalueMode
::ByValue
=> OperandValue
::Immediate(datum
.val
),
95 impl<'bcx
, 'tcx
> MirContext
<'bcx
, 'tcx
> {
96 pub fn trans_load(&mut self,
97 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
102 debug
!("trans_load: {} @ {:?}", bcx
.val_to_string(llval
), ty
);
104 let val
= match datum
::appropriate_rvalue_mode(bcx
.ccx(), ty
) {
106 bcx
.with_block(|bcx
| {
107 OperandValue
::Immediate(base
::load_ty(bcx
, llval
, ty
))
110 datum
::ByRef
if common
::type_is_fat_ptr(bcx
.tcx(), ty
) => {
111 let (lldata
, llextra
) = bcx
.with_block(|bcx
| {
112 base
::load_fat_ptr(bcx
, llval
, ty
)
114 OperandValue
::FatPtr(lldata
, llextra
)
116 datum
::ByRef
=> OperandValue
::Ref(llval
)
119 OperandRef { val: val, ty: ty }
122 pub fn trans_operand(&mut self,
123 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
124 operand
: &mir
::Operand
<'tcx
>)
127 debug
!("trans_operand(operand={:?})", operand
);
130 mir
::Operand
::Consume(ref lvalue
) => {
131 // watch out for temporaries that do not have an
132 // alloca; they are handled somewhat differently
133 if let &mir
::Lvalue
::Temp(index
) = lvalue
{
134 match self.temps
[index
as usize] {
135 TempRef
::Operand(Some(o
)) => {
138 TempRef
::Operand(None
) => {
140 &format
!("use of {:?} before def", lvalue
));
142 TempRef
::Lvalue(..) => {
148 // for most lvalues, to consume them we just load them
149 // out from their home
150 let tr_lvalue
= self.trans_lvalue(bcx
, lvalue
);
151 let ty
= tr_lvalue
.ty
.to_ty(bcx
.tcx());
152 self.trans_load(bcx
, tr_lvalue
.llval
, ty
)
155 mir
::Operand
::Constant(ref constant
) => {
156 self.trans_constant(bcx
, constant
)
161 pub fn trans_operand_into(&mut self,
162 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
164 operand
: &mir
::Operand
<'tcx
>)
166 debug
!("trans_operand_into(lldest={}, operand={:?})",
167 bcx
.val_to_string(lldest
),
170 // FIXME: consider not copying constants through the
173 let o
= self.trans_operand(bcx
, operand
);
174 self.store_operand(bcx
, lldest
, o
);
177 pub fn store_operand(&mut self,
178 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
180 operand
: OperandRef
<'tcx
>)
182 debug
!("store_operand: operand={}", operand
.repr(bcx
));
183 bcx
.with_block(|bcx
| {
184 self.store_operand_direct(bcx
, lldest
, operand
)
188 pub fn store_operand_direct(&mut self,
189 bcx
: Block
<'bcx
, 'tcx
>,
191 operand
: OperandRef
<'tcx
>)
193 // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
194 // value is through `undef`, and store itself is useless.
195 if common
::type_is_zero_size(bcx
.ccx(), operand
.ty
) {
199 OperandValue
::Ref(r
) => base
::memcpy_ty(bcx
, lldest
, r
, operand
.ty
),
200 OperandValue
::Immediate(s
) => base
::store_ty(bcx
, s
, lldest
, operand
.ty
),
201 OperandValue
::FatPtr(data
, extra
) => {
202 base
::store_fat_ptr(bcx
, data
, extra
, lldest
, operand
.ty
);
207 pub fn trans_operand_untupled(&mut self,
208 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
209 operand
: &mir
::Operand
<'tcx
>)
210 -> Vec
<OperandRef
<'tcx
>>
212 // FIXME: consider having some optimization to avoid tupling/untupling
213 // (and storing/loading in the case of immediates)
215 // avoid trans_operand for pointless copying
216 let lv
= match *operand
{
217 mir
::Operand
::Consume(ref lvalue
) => self.trans_lvalue(bcx
, lvalue
),
218 mir
::Operand
::Constant(ref constant
) => {
219 // FIXME: consider being less pessimized
220 if constant
.ty
.is_nil() {
224 let ty
= bcx
.monomorphize(&constant
.ty
);
225 let lv
= LvalueRef
::alloca(bcx
, ty
, "__untuple_alloca");
226 let constant
= self.trans_constant(bcx
, constant
);
227 self.store_operand(bcx
, lv
.llval
, constant
);
232 let lv_ty
= lv
.ty
.to_ty(bcx
.tcx());
233 let result_types
= match lv_ty
.sty
{
234 ty
::TyTuple(ref tys
) => tys
,
235 _
=> bcx
.tcx().sess
.span_bug(
237 &format
!("bad final argument to \"rust-call\" fn {:?}", lv_ty
))
240 let base_repr
= adt
::represent_type(bcx
.ccx(), lv_ty
);
241 let base
= adt
::MaybeSizedValue
::sized(lv
.llval
);
242 result_types
.iter().enumerate().map(|(n
, &ty
)| {
243 self.trans_load(bcx
, bcx
.with_block(|bcx
| {
244 adt
::trans_field_ptr(bcx
, &base_repr
, base
, Disr(0), n
)