]>
git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/tvec.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.
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)]
19 use trans
::cleanup
::CleanupMethods
;
23 use trans
::debuginfo
::DebugLoc
;
24 use trans
::expr
::{Dest, Ignore, SaveIn}
;
26 use trans
::machine
::llsize_of_alloc
;
27 use trans
::type_
::Type
;
29 use middle
::ty
::{self, Ty}
;
34 use syntax
::parse
::token
::InternedString
;
36 #[derive(Copy, Clone)]
37 struct VecTypes
<'tcx
> {
42 impl<'tcx
> VecTypes
<'tcx
> {
43 pub fn to_string
<'a
>(&self, ccx
: &CrateContext
<'a
, 'tcx
>) -> String
{
44 format
!("VecTypes {{unit_ty={}, llunit_ty={}}}",
46 ccx
.tn().type_to_string(self.llunit_ty
))
50 pub fn trans_fixed_vstore
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
53 -> Block
<'blk
, 'tcx
> {
56 // [...] allocates a fixed-size array and moves it around "by value".
57 // In this case, it means that the caller has already given us a location
58 // to store the array of the suitable size, so all we have to do is
59 // generate the content.
61 debug
!("trans_fixed_vstore(expr={:?}, dest={})",
62 expr
, dest
.to_string(bcx
.ccx()));
64 let vt
= vec_types_from_expr(bcx
, expr
);
67 Ignore
=> write_content(bcx
, &vt
, expr
, expr
, dest
),
69 // lldest will have type *[T x N], but we want the type *T,
70 // so use GEP to convert:
71 let lldest
= StructGEP(bcx
, lldest
, 0);
72 write_content(bcx
, &vt
, expr
, expr
, SaveIn(lldest
))
77 /// &[...] allocates memory on the stack and writes the values into it, returning the vector (the
78 /// caller must make the reference). "..." is similar except that the memory can be statically
79 /// allocated and we return a reference (strings are always by-ref).
80 pub fn trans_slice_vec
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
81 slice_expr
: &hir
::Expr
,
82 content_expr
: &hir
::Expr
)
83 -> DatumBlock
<'blk
, 'tcx
, Expr
> {
88 debug
!("trans_slice_vec(slice_expr={:?})",
91 let vec_ty
= node_id_type(bcx
, slice_expr
.id
);
93 // Handle the "..." case (returns a slice since strings are always unsized):
94 if let hir
::ExprLit(ref lit
) = content_expr
.node
{
95 if let ast
::LitStr(ref s
, _
) = lit
.node
{
96 let scratch
= rvalue_scratch_datum(bcx
, vec_ty
, "");
97 bcx
= trans_lit_str(bcx
,
100 SaveIn(scratch
.val
));
101 return DatumBlock
::new(bcx
, scratch
.to_expr_datum());
105 // Handle the &[...] case:
106 let vt
= vec_types_from_expr(bcx
, content_expr
);
107 let count
= elements_required(bcx
, content_expr
);
108 debug
!(" vt={}, count={}", vt
.to_string(ccx
), count
);
110 let fixed_ty
= bcx
.tcx().mk_array(vt
.unit_ty
, count
);
112 // Always create an alloca even if zero-sized, to preserve
113 // the non-null invariant of the inner slice ptr
115 // Issue 30018: ensure state is initialized as dropped if necessary.
116 if fcx
.type_needs_drop(vt
.unit_ty
) {
117 llfixed
= base
::alloc_ty_init(bcx
, fixed_ty
, InitAlloca
::Dropped
, "");
119 let uninit
= InitAlloca
::Uninit("fcx says vt.unit_ty is non-drop");
120 llfixed
= base
::alloc_ty_init(bcx
, fixed_ty
, uninit
, "");
121 call_lifetime_start(bcx
, llfixed
);
125 // Arrange for the backing array to be cleaned up.
126 let cleanup_scope
= cleanup
::temporary_scope(bcx
.tcx(), content_expr
.id
);
127 fcx
.schedule_lifetime_end(cleanup_scope
, llfixed
);
128 fcx
.schedule_drop_mem(cleanup_scope
, llfixed
, fixed_ty
, None
);
130 // Generate the content into the backing array.
131 // llfixed has type *[T x N], but we want the type *T,
132 // so use GEP to convert
133 bcx
= write_content(bcx
, &vt
, slice_expr
, content_expr
,
134 SaveIn(StructGEP(bcx
, llfixed
, 0)));
137 immediate_rvalue_bcx(bcx
, llfixed
, vec_ty
).to_expr_datumblock()
140 /// Literal strings translate to slices into static memory. This is different from
141 /// trans_slice_vstore() above because it doesn't need to copy the content anywhere.
142 pub fn trans_lit_str
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
143 lit_expr
: &hir
::Expr
,
144 str_lit
: InternedString
,
146 -> Block
<'blk
, 'tcx
> {
147 debug
!("trans_lit_str(lit_expr={:?}, dest={})",
149 dest
.to_string(bcx
.ccx()));
154 let bytes
= str_lit
.len();
155 let llbytes
= C_uint(bcx
.ccx(), bytes
);
156 let llcstr
= C_cstr(bcx
.ccx(), str_lit
, false);
157 let llcstr
= consts
::ptrcast(llcstr
, Type
::i8p(bcx
.ccx()));
158 Store(bcx
, llcstr
, expr
::get_dataptr(bcx
, lldest
));
159 Store(bcx
, llbytes
, expr
::get_meta(bcx
, lldest
));
165 fn write_content
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
167 vstore_expr
: &hir
::Expr
,
168 content_expr
: &hir
::Expr
,
170 -> Block
<'blk
, 'tcx
> {
171 let _icx
= push_ctxt("tvec::write_content");
175 debug
!("write_content(vt={}, dest={}, vstore_expr={:?})",
176 vt
.to_string(bcx
.ccx()),
177 dest
.to_string(bcx
.ccx()),
180 match content_expr
.node
{
181 hir
::ExprLit(ref lit
) => {
183 ast
::LitStr(ref s
, _
) => {
185 Ignore
=> return bcx
,
188 let llbytes
= C_uint(bcx
.ccx(), bytes
);
189 let llcstr
= C_cstr(bcx
.ccx(), (*s
).clone(), false);
190 base
::call_memcpy(bcx
,
200 bcx
.tcx().sess
.span_bug(content_expr
.span
,
201 "unexpected evec content");
205 hir
::ExprVec(ref elements
) => {
208 for element
in elements
{
209 bcx
= expr
::trans_into(bcx
, &**element
, Ignore
);
214 let temp_scope
= fcx
.push_custom_cleanup_scope();
215 for (i
, element
) in elements
.iter().enumerate() {
216 let lleltptr
= GEPi(bcx
, lldest
, &[i
]);
217 debug
!("writing index {} with lleltptr={}",
218 i
, bcx
.val_to_string(lleltptr
));
219 bcx
= expr
::trans_into(bcx
, &**element
,
221 let scope
= cleanup
::CustomScope(temp_scope
);
222 // Issue #30822: mark memory as dropped after running destructor
223 fcx
.schedule_drop_and_fill_mem(scope
, lleltptr
, vt
.unit_ty
, None
);
225 fcx
.pop_custom_cleanup_scope(temp_scope
);
230 hir
::ExprRepeat(ref element
, ref count_expr
) => {
233 return expr
::trans_into(bcx
, &**element
, Ignore
);
236 match bcx
.tcx().eval_repeat_count(&**count_expr
) {
237 0 => expr
::trans_into(bcx
, &**element
, Ignore
),
238 1 => expr
::trans_into(bcx
, &**element
, SaveIn(lldest
)),
240 let elem
= unpack_datum
!(bcx
, expr
::trans(bcx
, &**element
));
241 let bcx
= iter_vec_loop(bcx
, lldest
, vt
,
242 C_uint(bcx
.ccx(), count
),
243 |set_bcx
, lleltptr
, _
| {
244 elem
.shallow_copy(set_bcx
, lleltptr
)
253 bcx
.tcx().sess
.span_bug(content_expr
.span
,
254 "unexpected vec content");
259 fn vec_types_from_expr
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, vec_expr
: &hir
::Expr
)
261 let vec_ty
= node_id_type(bcx
, vec_expr
.id
);
262 vec_types(bcx
, vec_ty
.sequence_element_type(bcx
.tcx()))
265 fn vec_types
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, unit_ty
: Ty
<'tcx
>)
269 llunit_ty
: type_of
::type_of(bcx
.ccx(), unit_ty
)
273 fn elements_required(bcx
: Block
, content_expr
: &hir
::Expr
) -> usize {
274 //! Figure out the number of elements we need to store this content
276 match content_expr
.node
{
277 hir
::ExprLit(ref lit
) => {
279 ast
::LitStr(ref s
, _
) => s
.len(),
281 bcx
.tcx().sess
.span_bug(content_expr
.span
,
282 "unexpected evec content")
286 hir
::ExprVec(ref es
) => es
.len(),
287 hir
::ExprRepeat(_
, ref count_expr
) => {
288 bcx
.tcx().eval_repeat_count(&**count_expr
)
290 _
=> bcx
.tcx().sess
.span_bug(content_expr
.span
,
291 "unexpected vec content")
295 /// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval`
296 /// which should be by ref.
297 pub fn get_fixed_base_and_len(bcx
: Block
,
300 -> (ValueRef
, ValueRef
) {
303 let base
= expr
::get_dataptr(bcx
, llval
);
304 let len
= C_uint(ccx
, vec_length
);
308 /// Converts a vector into the slice pair. The vector should be stored in `llval` which should be
309 /// by-reference. If you have a datum, you would probably prefer to call
310 /// `Datum::get_base_and_len()` which will handle any conversions for you.
311 pub fn get_base_and_len
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
314 -> (ValueRef
, ValueRef
) {
318 ty
::TyArray(_
, n
) => get_fixed_base_and_len(bcx
, llval
, n
),
319 ty
::TySlice(_
) | ty
::TyStr
=> {
320 let base
= Load(bcx
, expr
::get_dataptr(bcx
, llval
));
321 let len
= Load(bcx
, expr
::get_meta(bcx
, llval
));
325 // Only used for pattern matching.
326 ty
::TyBox(ty
) | ty
::TyRef(_
, ty
::TypeAndMut{ty, ..}
) => {
327 let inner
= if type_is_sized(bcx
.tcx(), ty
) {
332 get_base_and_len(bcx
, inner
, ty
)
334 _
=> ccx
.sess().bug("unexpected type in get_base_and_len"),
338 fn iter_vec_loop
<'blk
, 'tcx
, F
>(bcx
: Block
<'blk
, 'tcx
>,
343 -> Block
<'blk
, 'tcx
> where
344 F
: FnOnce(Block
<'blk
, 'tcx
>, ValueRef
, Ty
<'tcx
>) -> Block
<'blk
, 'tcx
>,
346 let _icx
= push_ctxt("tvec::iter_vec_loop");
348 if bcx
.unreachable
.get() {
353 let loop_bcx
= fcx
.new_temp_block("expr_repeat");
354 let next_bcx
= fcx
.new_temp_block("expr_repeat: next");
356 Br(bcx
, loop_bcx
.llbb
, DebugLoc
::None
);
358 let loop_counter
= Phi(loop_bcx
, bcx
.ccx().int_type(),
359 &[C_uint(bcx
.ccx(), 0 as usize)], &[bcx
.llbb
]);
363 let lleltptr
= if llsize_of_alloc(bcx
.ccx(), vt
.llunit_ty
) == 0 {
366 InBoundsGEP(bcx
, data_ptr
, &[loop_counter
])
368 let bcx
= f(bcx
, lleltptr
, vt
.unit_ty
);
369 let plusone
= Add(bcx
, loop_counter
, C_uint(bcx
.ccx(), 1usize
), DebugLoc
::None
);
370 AddIncomingToPhi(loop_counter
, plusone
, bcx
.llbb
);
372 let cond_val
= ICmp(bcx
, llvm
::IntULT
, plusone
, count
, DebugLoc
::None
);
373 CondBr(bcx
, cond_val
, loop_bcx
.llbb
, next_bcx
.llbb
, DebugLoc
::None
);
378 pub fn iter_vec_raw
<'blk
, 'tcx
, F
>(bcx
: Block
<'blk
, 'tcx
>,
383 -> Block
<'blk
, 'tcx
> where
384 F
: FnOnce(Block
<'blk
, 'tcx
>, ValueRef
, Ty
<'tcx
>) -> Block
<'blk
, 'tcx
>,
386 let _icx
= push_ctxt("tvec::iter_vec_raw");
389 let vt
= vec_types(bcx
, unit_ty
);
391 if llsize_of_alloc(bcx
.ccx(), vt
.llunit_ty
) == 0 {
392 // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
393 iter_vec_loop(bcx
, data_ptr
, &vt
, len
, f
)
395 // Calculate the last pointer address we want to handle.
396 let data_end_ptr
= InBoundsGEP(bcx
, data_ptr
, &[len
]);
398 // Now perform the iteration.
399 let header_bcx
= fcx
.new_temp_block("iter_vec_loop_header");
400 Br(bcx
, header_bcx
.llbb
, DebugLoc
::None
);
402 Phi(header_bcx
, val_ty(data_ptr
), &[data_ptr
], &[bcx
.llbb
]);
404 ICmp(header_bcx
, llvm
::IntULT
, data_ptr
, data_end_ptr
, DebugLoc
::None
);
405 let body_bcx
= fcx
.new_temp_block("iter_vec_loop_body");
406 let next_bcx
= fcx
.new_temp_block("iter_vec_next");
407 CondBr(header_bcx
, not_yet_at_end
, body_bcx
.llbb
, next_bcx
.llbb
, DebugLoc
::None
);
408 let body_bcx
= f(body_bcx
, data_ptr
, unit_ty
);
409 AddIncomingToPhi(data_ptr
, InBoundsGEP(body_bcx
, data_ptr
,
410 &[C_int(bcx
.ccx(), 1)]),
412 Br(body_bcx
, header_bcx
.llbb
, DebugLoc
::None
);