]>
git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/tvec.rs
bba0f6d26083a6d04e4fd1e7c72a7dd4c0540835
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.
11 #![allow(non_camel_case_types)]
20 use trans
::cleanup
::CleanupMethods
;
24 use trans
::debuginfo
::DebugLoc
;
25 use trans
::expr
::{Dest, Ignore, SaveIn}
;
27 use trans
::machine
::llsize_of_alloc
;
28 use trans
::type_
::Type
;
30 use middle
::ty
::{self, Ty}
;
33 use syntax
::parse
::token
::InternedString
;
35 #[derive(Copy, Clone)]
36 struct VecTypes
<'tcx
> {
41 impl<'tcx
> VecTypes
<'tcx
> {
42 pub fn to_string
<'a
>(&self, ccx
: &CrateContext
<'a
, 'tcx
>) -> String
{
43 format
!("VecTypes {{unit_ty={}, llunit_ty={}}}",
45 ccx
.tn().type_to_string(self.llunit_ty
))
49 pub fn trans_fixed_vstore
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
52 -> Block
<'blk
, 'tcx
> {
55 // [...] allocates a fixed-size array and moves it around "by value".
56 // In this case, it means that the caller has already given us a location
57 // to store the array of the suitable size, so all we have to do is
58 // generate the content.
60 debug
!("trans_fixed_vstore(expr={:?}, dest={})",
61 expr
, dest
.to_string(bcx
.ccx()));
63 let vt
= vec_types_from_expr(bcx
, expr
);
66 Ignore
=> write_content(bcx
, &vt
, expr
, expr
, dest
),
68 // lldest will have type *[T x N], but we want the type *T,
69 // so use GEP to convert:
70 let lldest
= GEPi(bcx
, lldest
, &[0, 0]);
71 write_content(bcx
, &vt
, expr
, expr
, SaveIn(lldest
))
76 /// &[...] allocates memory on the stack and writes the values into it, returning the vector (the
77 /// caller must make the reference). "..." is similar except that the memory can be statically
78 /// allocated and we return a reference (strings are always by-ref).
79 pub fn trans_slice_vec
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
80 slice_expr
: &ast
::Expr
,
81 content_expr
: &ast
::Expr
)
82 -> DatumBlock
<'blk
, 'tcx
, Expr
> {
87 debug
!("trans_slice_vec(slice_expr={:?})",
90 let vec_ty
= node_id_type(bcx
, slice_expr
.id
);
92 // Handle the "..." case (returns a slice since strings are always unsized):
93 if let ast
::ExprLit(ref lit
) = content_expr
.node
{
94 if let ast
::LitStr(ref s
, _
) = lit
.node
{
95 let scratch
= rvalue_scratch_datum(bcx
, vec_ty
, "");
96 bcx
= trans_lit_str(bcx
,
100 return DatumBlock
::new(bcx
, scratch
.to_expr_datum());
104 // Handle the &[...] case:
105 let vt
= vec_types_from_expr(bcx
, content_expr
);
106 let count
= elements_required(bcx
, content_expr
);
107 debug
!(" vt={}, count={}", vt
.to_string(ccx
), count
);
109 let fixed_ty
= ty
::mk_vec(bcx
.tcx(),
112 let llfixed_ty
= type_of
::type_of(bcx
.ccx(), fixed_ty
);
114 // Always create an alloca even if zero-sized, to preserve
115 // the non-null invariant of the inner slice ptr
116 let llfixed
= base
::alloca(bcx
, llfixed_ty
, "");
119 // Arrange for the backing array to be cleaned up.
120 let cleanup_scope
= cleanup
::temporary_scope(bcx
.tcx(), content_expr
.id
);
121 fcx
.schedule_lifetime_end(cleanup_scope
, llfixed
);
122 fcx
.schedule_drop_mem(cleanup_scope
, llfixed
, fixed_ty
);
124 // Generate the content into the backing array.
125 // llfixed has type *[T x N], but we want the type *T,
126 // so use GEP to convert
127 bcx
= write_content(bcx
, &vt
, slice_expr
, content_expr
,
128 SaveIn(GEPi(bcx
, llfixed
, &[0, 0])));
131 immediate_rvalue_bcx(bcx
, llfixed
, vec_ty
).to_expr_datumblock()
134 /// Literal strings translate to slices into static memory. This is different from
135 /// trans_slice_vstore() above because it doesn't need to copy the content anywhere.
136 pub fn trans_lit_str
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
137 lit_expr
: &ast
::Expr
,
138 str_lit
: InternedString
,
140 -> Block
<'blk
, 'tcx
> {
141 debug
!("trans_lit_str(lit_expr={:?}, dest={})",
143 dest
.to_string(bcx
.ccx()));
148 let bytes
= str_lit
.len();
149 let llbytes
= C_uint(bcx
.ccx(), bytes
);
150 let llcstr
= C_cstr(bcx
.ccx(), str_lit
, false);
151 let llcstr
= consts
::ptrcast(llcstr
, Type
::i8p(bcx
.ccx()));
152 Store(bcx
, llcstr
, GEPi(bcx
, lldest
, &[0, abi
::FAT_PTR_ADDR
]));
153 Store(bcx
, llbytes
, GEPi(bcx
, lldest
, &[0, abi
::FAT_PTR_EXTRA
]));
159 fn write_content
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
161 vstore_expr
: &ast
::Expr
,
162 content_expr
: &ast
::Expr
,
164 -> Block
<'blk
, 'tcx
> {
165 let _icx
= push_ctxt("tvec::write_content");
169 debug
!("write_content(vt={}, dest={}, vstore_expr={:?})",
170 vt
.to_string(bcx
.ccx()),
171 dest
.to_string(bcx
.ccx()),
174 match content_expr
.node
{
175 ast
::ExprLit(ref lit
) => {
177 ast
::LitStr(ref s
, _
) => {
179 Ignore
=> return bcx
,
182 let llbytes
= C_uint(bcx
.ccx(), bytes
);
183 let llcstr
= C_cstr(bcx
.ccx(), (*s
).clone(), false);
184 base
::call_memcpy(bcx
,
194 bcx
.tcx().sess
.span_bug(content_expr
.span
,
195 "unexpected evec content");
199 ast
::ExprVec(ref elements
) => {
202 for element
in elements
{
203 bcx
= expr
::trans_into(bcx
, &**element
, Ignore
);
208 let temp_scope
= fcx
.push_custom_cleanup_scope();
209 for (i
, element
) in elements
.iter().enumerate() {
210 let lleltptr
= GEPi(bcx
, lldest
, &[i
]);
211 debug
!("writing index {} with lleltptr={}",
212 i
, bcx
.val_to_string(lleltptr
));
213 bcx
= expr
::trans_into(bcx
, &**element
,
215 let scope
= cleanup
::CustomScope(temp_scope
);
216 fcx
.schedule_lifetime_end(scope
, lleltptr
);
217 fcx
.schedule_drop_mem(scope
, lleltptr
, vt
.unit_ty
);
219 fcx
.pop_custom_cleanup_scope(temp_scope
);
224 ast
::ExprRepeat(ref element
, ref count_expr
) => {
227 return expr
::trans_into(bcx
, &**element
, Ignore
);
230 match ty
::eval_repeat_count(bcx
.tcx(), &**count_expr
) {
231 0 => expr
::trans_into(bcx
, &**element
, Ignore
),
232 1 => expr
::trans_into(bcx
, &**element
, SaveIn(lldest
)),
234 let elem
= unpack_datum
!(bcx
, expr
::trans(bcx
, &**element
));
235 let bcx
= iter_vec_loop(bcx
, lldest
, vt
,
236 C_uint(bcx
.ccx(), count
),
237 |set_bcx
, lleltptr
, _
| {
238 elem
.shallow_copy(set_bcx
, lleltptr
)
247 bcx
.tcx().sess
.span_bug(content_expr
.span
,
248 "unexpected vec content");
253 fn vec_types_from_expr
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, vec_expr
: &ast
::Expr
)
255 let vec_ty
= node_id_type(bcx
, vec_expr
.id
);
256 vec_types(bcx
, ty
::sequence_element_type(bcx
.tcx(), vec_ty
))
259 fn vec_types
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, unit_ty
: Ty
<'tcx
>)
263 llunit_ty
: type_of
::type_of(bcx
.ccx(), unit_ty
)
267 fn elements_required(bcx
: Block
, content_expr
: &ast
::Expr
) -> usize {
268 //! Figure out the number of elements we need to store this content
270 match content_expr
.node
{
271 ast
::ExprLit(ref lit
) => {
273 ast
::LitStr(ref s
, _
) => s
.len(),
275 bcx
.tcx().sess
.span_bug(content_expr
.span
,
276 "unexpected evec content")
280 ast
::ExprVec(ref es
) => es
.len(),
281 ast
::ExprRepeat(_
, ref count_expr
) => {
282 ty
::eval_repeat_count(bcx
.tcx(), &**count_expr
)
284 _
=> bcx
.tcx().sess
.span_bug(content_expr
.span
,
285 "unexpected vec content")
289 /// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval`
290 /// which should be by ref.
291 pub fn get_fixed_base_and_len(bcx
: Block
,
294 -> (ValueRef
, ValueRef
) {
297 let base
= expr
::get_dataptr(bcx
, llval
);
298 let len
= C_uint(ccx
, vec_length
);
302 /// Converts a vector into the slice pair. The vector should be stored in `llval` which should be
303 /// by-reference. If you have a datum, you would probably prefer to call
304 /// `Datum::get_base_and_len()` which will handle any conversions for you.
305 pub fn get_base_and_len
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
308 -> (ValueRef
, ValueRef
) {
312 ty
::TyArray(_
, n
) => get_fixed_base_and_len(bcx
, llval
, n
),
313 ty
::TySlice(_
) | ty
::TyStr
=> {
314 let base
= Load(bcx
, expr
::get_dataptr(bcx
, llval
));
315 let len
= Load(bcx
, expr
::get_len(bcx
, llval
));
319 // Only used for pattern matching.
320 ty
::TyBox(ty
) | ty
::TyRef(_
, ty
::mt{ty, ..}
) => {
321 let inner
= if type_is_sized(bcx
.tcx(), ty
) {
326 get_base_and_len(bcx
, inner
, ty
)
328 _
=> ccx
.sess().bug("unexpected type in get_base_and_len"),
332 fn iter_vec_loop
<'blk
, 'tcx
, F
>(bcx
: Block
<'blk
, 'tcx
>,
337 -> Block
<'blk
, 'tcx
> where
338 F
: FnOnce(Block
<'blk
, 'tcx
>, ValueRef
, Ty
<'tcx
>) -> Block
<'blk
, 'tcx
>,
340 let _icx
= push_ctxt("tvec::iter_vec_loop");
342 if bcx
.unreachable
.get() {
347 let loop_bcx
= fcx
.new_temp_block("expr_repeat");
348 let next_bcx
= fcx
.new_temp_block("expr_repeat: next");
350 Br(bcx
, loop_bcx
.llbb
, DebugLoc
::None
);
352 let loop_counter
= Phi(loop_bcx
, bcx
.ccx().int_type(),
353 &[C_uint(bcx
.ccx(), 0 as usize)], &[bcx
.llbb
]);
357 let lleltptr
= if llsize_of_alloc(bcx
.ccx(), vt
.llunit_ty
) == 0 {
360 InBoundsGEP(bcx
, data_ptr
, &[loop_counter
])
362 let bcx
= f(bcx
, lleltptr
, vt
.unit_ty
);
363 let plusone
= Add(bcx
, loop_counter
, C_uint(bcx
.ccx(), 1usize
), DebugLoc
::None
);
364 AddIncomingToPhi(loop_counter
, plusone
, bcx
.llbb
);
366 let cond_val
= ICmp(bcx
, llvm
::IntULT
, plusone
, count
, DebugLoc
::None
);
367 CondBr(bcx
, cond_val
, loop_bcx
.llbb
, next_bcx
.llbb
, DebugLoc
::None
);
372 pub fn iter_vec_raw
<'blk
, 'tcx
, F
>(bcx
: Block
<'blk
, 'tcx
>,
377 -> Block
<'blk
, 'tcx
> where
378 F
: FnOnce(Block
<'blk
, 'tcx
>, ValueRef
, Ty
<'tcx
>) -> Block
<'blk
, 'tcx
>,
380 let _icx
= push_ctxt("tvec::iter_vec_raw");
383 let vt
= vec_types(bcx
, unit_ty
);
385 if llsize_of_alloc(bcx
.ccx(), vt
.llunit_ty
) == 0 {
386 // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
387 iter_vec_loop(bcx
, data_ptr
, &vt
, len
, f
)
389 // Calculate the last pointer address we want to handle.
390 let data_end_ptr
= InBoundsGEP(bcx
, data_ptr
, &[len
]);
392 // Now perform the iteration.
393 let header_bcx
= fcx
.new_temp_block("iter_vec_loop_header");
394 Br(bcx
, header_bcx
.llbb
, DebugLoc
::None
);
396 Phi(header_bcx
, val_ty(data_ptr
), &[data_ptr
], &[bcx
.llbb
]);
398 ICmp(header_bcx
, llvm
::IntULT
, data_ptr
, data_end_ptr
, DebugLoc
::None
);
399 let body_bcx
= fcx
.new_temp_block("iter_vec_loop_body");
400 let next_bcx
= fcx
.new_temp_block("iter_vec_next");
401 CondBr(header_bcx
, not_yet_at_end
, body_bcx
.llbb
, next_bcx
.llbb
, DebugLoc
::None
);
402 let body_bcx
= f(body_bcx
, data_ptr
, unit_ty
);
403 AddIncomingToPhi(data_ptr
, InBoundsGEP(body_bcx
, data_ptr
,
404 &[C_int(bcx
.ccx(), 1)]),
406 Br(body_bcx
, header_bcx
.llbb
, DebugLoc
::None
);