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
::mir
::repr
as mir
;
15 use common
::{self, Block, BlockAndBuilder}
;
22 use super::lvalue
::load_fat_ptr
;
23 use super::{MirContext, TempRef, drop}
;
25 /// The representation of a Rust value. The enum variant is in fact
26 /// uniquely determined by the value's type, but is kept as a
28 #[derive(Copy, Clone)]
29 pub enum OperandValue
{
30 /// A reference to the actual operand. The data is guaranteed
31 /// to be valid for the operand's lifetime.
33 /// A single LLVM value.
35 /// A fat pointer. The first ValueRef is the data and the second
37 FatPtr(ValueRef
, ValueRef
)
40 /// An `OperandRef` is an "SSA" reference to a Rust value, along with
43 /// NOTE: unless you know a value's type exactly, you should not
44 /// generate LLVM opcodes acting on it and instead act via methods,
45 /// to avoid nasty edge cases. In particular, using `Builder.store`
46 /// directly is sure to cause problems -- use `MirContext.store_operand`
48 #[derive(Copy, Clone)]
49 pub struct OperandRef
<'tcx
> {
51 pub val
: OperandValue
,
53 // The type of value being returned.
57 impl<'tcx
> fmt
::Debug
for OperandRef
<'tcx
> {
58 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
60 OperandValue
::Ref(r
) => {
61 write
!(f
, "OperandRef(Ref({:?}) @ {:?})",
64 OperandValue
::Immediate(i
) => {
65 write
!(f
, "OperandRef(Immediate({:?}) @ {:?})",
68 OperandValue
::FatPtr(a
, d
) => {
69 write
!(f
, "OperandRef(FatPtr({:?}, {:?}) @ {:?})",
70 Value(a
), Value(d
), self.ty
)
76 impl<'tcx
> OperandRef
<'tcx
> {
77 /// Asserts that this operand refers to a scalar and returns
78 /// a reference to its value.
79 pub fn immediate(self) -> ValueRef
{
81 OperandValue
::Immediate(s
) => s
,
87 impl<'bcx
, 'tcx
> MirContext
<'bcx
, 'tcx
> {
88 pub fn trans_load(&mut self,
89 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
94 debug
!("trans_load: {:?} @ {:?}", Value(llval
), ty
);
96 let val
= match datum
::appropriate_rvalue_mode(bcx
.ccx(), ty
) {
98 OperandValue
::Immediate(base
::load_ty_builder(bcx
, llval
, ty
))
100 datum
::ByRef
if common
::type_is_fat_ptr(bcx
.tcx(), ty
) => {
101 let (lldata
, llextra
) = load_fat_ptr(bcx
, llval
);
102 OperandValue
::FatPtr(lldata
, llextra
)
104 datum
::ByRef
=> OperandValue
::Ref(llval
)
107 OperandRef { val: val, ty: ty }
110 pub fn trans_operand(&mut self,
111 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
112 operand
: &mir
::Operand
<'tcx
>)
115 debug
!("trans_operand(operand={:?})", operand
);
118 mir
::Operand
::Consume(ref lvalue
) => {
119 // watch out for temporaries that do not have an
120 // alloca; they are handled somewhat differently
121 if let &mir
::Lvalue
::Temp(index
) = lvalue
{
122 match self.temps
[index
as usize] {
123 TempRef
::Operand(Some(o
)) => {
126 TempRef
::Operand(None
) => {
127 bug
!("use of {:?} before def", lvalue
);
129 TempRef
::Lvalue(..) => {
135 // for most lvalues, to consume them we just load them
136 // out from their home
137 let tr_lvalue
= self.trans_lvalue(bcx
, lvalue
);
138 let ty
= tr_lvalue
.ty
.to_ty(bcx
.tcx());
139 self.trans_load(bcx
, tr_lvalue
.llval
, ty
)
142 mir
::Operand
::Constant(ref constant
) => {
143 self.trans_constant(bcx
, constant
)
148 pub fn store_operand(&mut self,
149 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
151 operand
: OperandRef
<'tcx
>)
153 debug
!("store_operand: operand={:?}", operand
);
154 bcx
.with_block(|bcx
| self.store_operand_direct(bcx
, lldest
, operand
))
157 pub fn store_operand_direct(&mut self,
158 bcx
: Block
<'bcx
, 'tcx
>,
160 operand
: OperandRef
<'tcx
>)
162 // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
163 // value is through `undef`, and store itself is useless.
164 if common
::type_is_zero_size(bcx
.ccx(), operand
.ty
) {
168 OperandValue
::Ref(r
) => base
::memcpy_ty(bcx
, lldest
, r
, operand
.ty
),
169 OperandValue
::Immediate(s
) => base
::store_ty(bcx
, s
, lldest
, operand
.ty
),
170 OperandValue
::FatPtr(data
, extra
) => {
171 base
::store_fat_ptr(bcx
, data
, extra
, lldest
, operand
.ty
);
176 pub fn set_operand_dropped(&mut self,
177 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
178 operand
: &mir
::Operand
<'tcx
>) {
180 mir
::Operand
::Constant(_
) => return,
181 mir
::Operand
::Consume(ref lvalue
) => {
182 if let mir
::Lvalue
::Temp(idx
) = *lvalue
{
183 if let TempRef
::Operand(..) = self.temps
[idx
as usize] {
184 // All lvalues which have an associated drop are promoted to an alloca
185 // beforehand. If this is an operand, it is safe to say this is never
186 // dropped and there’s no reason for us to zero this out at all.
190 let lvalue
= self.trans_lvalue(bcx
, lvalue
);
191 let ty
= lvalue
.ty
.to_ty(bcx
.tcx());
192 if !glue
::type_needs_drop(bcx
.tcx(), ty
) {
195 drop
::drop_fill(bcx
, lvalue
.llval
, ty
);