]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/trans/tvec.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_trans / trans / tvec.rs
CommitLineData
1a4d82fc
JJ
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.
4//
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.
10
11#![allow(non_camel_case_types)]
12
1a4d82fc 13use llvm;
c34b1796 14use llvm::ValueRef;
1a4d82fc
JJ
15use trans::base::*;
16use trans::base;
17use trans::build::*;
18use trans::cleanup;
19use trans::cleanup::CleanupMethods;
20use trans::common::*;
21use trans::consts;
22use trans::datum::*;
85aaf69f 23use trans::debuginfo::DebugLoc;
1a4d82fc
JJ
24use trans::expr::{Dest, Ignore, SaveIn};
25use trans::expr;
85aaf69f 26use trans::machine::llsize_of_alloc;
1a4d82fc
JJ
27use trans::type_::Type;
28use trans::type_of;
29use middle::ty::{self, Ty};
1a4d82fc 30
e9174d1e
SL
31use rustc_front::hir;
32
b039eaaf 33use syntax::ast;
1a4d82fc
JJ
34use syntax::parse::token::InternedString;
35
c34b1796
AL
36#[derive(Copy, Clone)]
37struct VecTypes<'tcx> {
38 unit_ty: Ty<'tcx>,
39 llunit_ty: Type
1a4d82fc
JJ
40}
41
42impl<'tcx> VecTypes<'tcx> {
43 pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
c34b1796 44 format!("VecTypes {{unit_ty={}, llunit_ty={}}}",
62682a34 45 self.unit_ty,
c34b1796 46 ccx.tn().type_to_string(self.llunit_ty))
1a4d82fc
JJ
47 }
48}
49
50pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
e9174d1e 51 expr: &hir::Expr,
1a4d82fc
JJ
52 dest: expr::Dest)
53 -> Block<'blk, 'tcx> {
54 //!
55 //
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.
60
62682a34
SL
61 debug!("trans_fixed_vstore(expr={:?}, dest={})",
62 expr, dest.to_string(bcx.ccx()));
1a4d82fc
JJ
63
64 let vt = vec_types_from_expr(bcx, expr);
65
66 return match dest {
67 Ignore => write_content(bcx, &vt, expr, expr, dest),
68 SaveIn(lldest) => {
69 // lldest will have type *[T x N], but we want the type *T,
70 // so use GEP to convert:
e9174d1e 71 let lldest = StructGEP(bcx, lldest, 0);
1a4d82fc
JJ
72 write_content(bcx, &vt, expr, expr, SaveIn(lldest))
73 }
74 };
75}
76
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).
80pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
e9174d1e
SL
81 slice_expr: &hir::Expr,
82 content_expr: &hir::Expr)
1a4d82fc
JJ
83 -> DatumBlock<'blk, 'tcx, Expr> {
84 let fcx = bcx.fcx;
85 let ccx = fcx.ccx;
86 let mut bcx = bcx;
87
62682a34
SL
88 debug!("trans_slice_vec(slice_expr={:?})",
89 slice_expr);
1a4d82fc
JJ
90
91 let vec_ty = node_id_type(bcx, slice_expr.id);
92
93 // Handle the "..." case (returns a slice since strings are always unsized):
e9174d1e 94 if let hir::ExprLit(ref lit) = content_expr.node {
7453a54e 95 if let ast::LitKind::Str(ref s, _) = lit.node {
1a4d82fc
JJ
96 let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
97 bcx = trans_lit_str(bcx,
98 content_expr,
99 s.clone(),
100 SaveIn(scratch.val));
101 return DatumBlock::new(bcx, scratch.to_expr_datum());
102 }
103 }
104
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);
1a4d82fc 109
c1a9b12d 110 let fixed_ty = bcx.tcx().mk_array(vt.unit_ty, count);
1a4d82fc 111
85aaf69f
SL
112 // Always create an alloca even if zero-sized, to preserve
113 // the non-null invariant of the inner slice ptr
9cc50fc6
SL
114 let llfixed;
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, "");
118 } else {
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);
122 };
1a4d82fc 123
85aaf69f 124 if count > 0 {
1a4d82fc 125 // Arrange for the backing array to be cleaned up.
1a4d82fc 126 let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
85aaf69f 127 fcx.schedule_lifetime_end(cleanup_scope, llfixed);
c1a9b12d 128 fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty, None);
1a4d82fc
JJ
129
130 // Generate the content into the backing array.
85aaf69f
SL
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,
e9174d1e 134 SaveIn(StructGEP(bcx, llfixed, 0)));
1a4d82fc
JJ
135 };
136
137 immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock()
138}
139
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.
142pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
e9174d1e 143 lit_expr: &hir::Expr,
1a4d82fc
JJ
144 str_lit: InternedString,
145 dest: Dest)
146 -> Block<'blk, 'tcx> {
62682a34
SL
147 debug!("trans_lit_str(lit_expr={:?}, dest={})",
148 lit_expr,
1a4d82fc
JJ
149 dest.to_string(bcx.ccx()));
150
151 match dest {
152 Ignore => bcx,
153 SaveIn(lldest) => {
85aaf69f 154 let bytes = str_lit.len();
1a4d82fc
JJ
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()));
e9174d1e
SL
158 Store(bcx, llcstr, expr::get_dataptr(bcx, lldest));
159 Store(bcx, llbytes, expr::get_meta(bcx, lldest));
1a4d82fc
JJ
160 bcx
161 }
162 }
163}
164
c34b1796
AL
165fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
166 vt: &VecTypes<'tcx>,
e9174d1e
SL
167 vstore_expr: &hir::Expr,
168 content_expr: &hir::Expr,
c34b1796
AL
169 dest: Dest)
170 -> Block<'blk, 'tcx> {
1a4d82fc
JJ
171 let _icx = push_ctxt("tvec::write_content");
172 let fcx = bcx.fcx;
173 let mut bcx = bcx;
174
62682a34 175 debug!("write_content(vt={}, dest={}, vstore_expr={:?})",
1a4d82fc
JJ
176 vt.to_string(bcx.ccx()),
177 dest.to_string(bcx.ccx()),
62682a34 178 vstore_expr);
1a4d82fc
JJ
179
180 match content_expr.node {
e9174d1e 181 hir::ExprLit(ref lit) => {
1a4d82fc 182 match lit.node {
7453a54e 183 ast::LitKind::Str(ref s, _) => {
1a4d82fc
JJ
184 match dest {
185 Ignore => return bcx,
186 SaveIn(lldest) => {
85aaf69f 187 let bytes = s.len();
1a4d82fc
JJ
188 let llbytes = C_uint(bcx.ccx(), bytes);
189 let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
190 base::call_memcpy(bcx,
191 lldest,
192 llcstr,
193 llbytes,
194 1);
195 return bcx;
196 }
197 }
198 }
199 _ => {
200 bcx.tcx().sess.span_bug(content_expr.span,
201 "unexpected evec content");
202 }
203 }
204 }
e9174d1e 205 hir::ExprVec(ref elements) => {
1a4d82fc
JJ
206 match dest {
207 Ignore => {
85aaf69f 208 for element in elements {
7453a54e 209 bcx = expr::trans_into(bcx, &element, Ignore);
1a4d82fc
JJ
210 }
211 }
212
213 SaveIn(lldest) => {
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));
7453a54e 219 bcx = expr::trans_into(bcx, &element,
1a4d82fc
JJ
220 SaveIn(lleltptr));
221 let scope = cleanup::CustomScope(temp_scope);
9cc50fc6
SL
222 // Issue #30822: mark memory as dropped after running destructor
223 fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None);
1a4d82fc
JJ
224 }
225 fcx.pop_custom_cleanup_scope(temp_scope);
226 }
227 }
228 return bcx;
229 }
e9174d1e 230 hir::ExprRepeat(ref element, ref count_expr) => {
1a4d82fc
JJ
231 match dest {
232 Ignore => {
7453a54e 233 return expr::trans_into(bcx, &element, Ignore);
1a4d82fc
JJ
234 }
235 SaveIn(lldest) => {
7453a54e
SL
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)),
1a4d82fc 239 count => {
7453a54e 240 let elem = unpack_datum!(bcx, expr::trans(bcx, &element));
1a4d82fc
JJ
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)
245 });
1a4d82fc
JJ
246 bcx
247 }
248 }
249 }
250 }
251 }
252 _ => {
253 bcx.tcx().sess.span_bug(content_expr.span,
254 "unexpected vec content");
255 }
256 }
257}
258
e9174d1e 259fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &hir::Expr)
c34b1796 260 -> VecTypes<'tcx> {
1a4d82fc 261 let vec_ty = node_id_type(bcx, vec_expr.id);
c1a9b12d 262 vec_types(bcx, vec_ty.sequence_element_type(bcx.tcx()))
1a4d82fc
JJ
263}
264
c34b1796
AL
265fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>)
266 -> VecTypes<'tcx> {
1a4d82fc
JJ
267 VecTypes {
268 unit_ty: unit_ty,
c34b1796 269 llunit_ty: type_of::type_of(bcx.ccx(), unit_ty)
1a4d82fc
JJ
270 }
271}
272
e9174d1e 273fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize {
1a4d82fc
JJ
274 //! Figure out the number of elements we need to store this content
275
276 match content_expr.node {
e9174d1e 277 hir::ExprLit(ref lit) => {
1a4d82fc 278 match lit.node {
7453a54e 279 ast::LitKind::Str(ref s, _) => s.len(),
1a4d82fc
JJ
280 _ => {
281 bcx.tcx().sess.span_bug(content_expr.span,
282 "unexpected evec content")
283 }
284 }
285 },
e9174d1e
SL
286 hir::ExprVec(ref es) => es.len(),
287 hir::ExprRepeat(_, ref count_expr) => {
7453a54e 288 bcx.tcx().eval_repeat_count(&count_expr)
1a4d82fc
JJ
289 }
290 _ => bcx.tcx().sess.span_bug(content_expr.span,
291 "unexpected vec content")
292 }
293}
294
295/// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval`
296/// which should be by ref.
297pub fn get_fixed_base_and_len(bcx: Block,
298 llval: ValueRef,
c34b1796 299 vec_length: usize)
1a4d82fc
JJ
300 -> (ValueRef, ValueRef) {
301 let ccx = bcx.ccx();
302
303 let base = expr::get_dataptr(bcx, llval);
304 let len = C_uint(ccx, vec_length);
305 (base, len)
306}
307
1a4d82fc
JJ
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.
c34b1796
AL
311pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
312 llval: ValueRef,
313 vec_ty: Ty<'tcx>)
314 -> (ValueRef, ValueRef) {
1a4d82fc
JJ
315 let ccx = bcx.ccx();
316
317 match vec_ty.sty {
62682a34
SL
318 ty::TyArray(_, n) => get_fixed_base_and_len(bcx, llval, n),
319 ty::TySlice(_) | ty::TyStr => {
c34b1796 320 let base = Load(bcx, expr::get_dataptr(bcx, llval));
e9174d1e 321 let len = Load(bcx, expr::get_meta(bcx, llval));
c34b1796
AL
322 (base, len)
323 }
1a4d82fc
JJ
324
325 // Only used for pattern matching.
c1a9b12d 326 ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => {
c34b1796
AL
327 let inner = if type_is_sized(bcx.tcx(), ty) {
328 Load(bcx, llval)
329 } else {
330 llval
331 };
332 get_base_and_len(bcx, inner, ty)
1a4d82fc
JJ
333 },
334 _ => ccx.sess().bug("unexpected type in get_base_and_len"),
335 }
336}
337
c34b1796
AL
338fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
339 data_ptr: ValueRef,
340 vt: &VecTypes<'tcx>,
341 count: ValueRef,
342 f: F)
343 -> Block<'blk, 'tcx> where
1a4d82fc
JJ
344 F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
345{
346 let _icx = push_ctxt("tvec::iter_vec_loop");
1a4d82fc 347
c34b1796
AL
348 if bcx.unreachable.get() {
349 return bcx;
350 }
351
352 let fcx = bcx.fcx;
1a4d82fc 353 let loop_bcx = fcx.new_temp_block("expr_repeat");
85aaf69f 354 let next_bcx = fcx.new_temp_block("expr_repeat: next");
1a4d82fc 355
85aaf69f 356 Br(bcx, loop_bcx.llbb, DebugLoc::None);
1a4d82fc 357
85aaf69f
SL
358 let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(),
359 &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]);
1a4d82fc 360
85aaf69f 361 let bcx = loop_bcx;
1a4d82fc 362
c34b1796 363 let lleltptr = if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
85aaf69f
SL
364 data_ptr
365 } else {
366 InBoundsGEP(bcx, data_ptr, &[loop_counter])
367 };
368 let bcx = f(bcx, lleltptr, vt.unit_ty);
9346a6ac 369 let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None);
85aaf69f 370 AddIncomingToPhi(loop_counter, plusone, bcx.llbb);
1a4d82fc 371
85aaf69f
SL
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);
1a4d82fc
JJ
374
375 next_bcx
376}
377
378pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
379 data_ptr: ValueRef,
380 unit_ty: Ty<'tcx>,
381 len: ValueRef,
382 f: F)
383 -> Block<'blk, 'tcx> where
384 F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
385{
386 let _icx = push_ctxt("tvec::iter_vec_raw");
387 let fcx = bcx.fcx;
388
389 let vt = vec_types(bcx, unit_ty);
1a4d82fc 390
c34b1796 391 if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
1a4d82fc 392 // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
85aaf69f 393 iter_vec_loop(bcx, data_ptr, &vt, len, f)
1a4d82fc
JJ
394 } else {
395 // Calculate the last pointer address we want to handle.
85aaf69f 396 let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
1a4d82fc
JJ
397
398 // Now perform the iteration.
399 let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
85aaf69f 400 Br(bcx, header_bcx.llbb, DebugLoc::None);
1a4d82fc
JJ
401 let data_ptr =
402 Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]);
403 let not_yet_at_end =
85aaf69f 404 ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None);
1a4d82fc
JJ
405 let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
406 let next_bcx = fcx.new_temp_block("iter_vec_next");
85aaf69f 407 CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
c34b1796 408 let body_bcx = f(body_bcx, data_ptr, unit_ty);
1a4d82fc 409 AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
85aaf69f 410 &[C_int(bcx.ccx(), 1)]),
1a4d82fc 411 body_bcx.llbb);
85aaf69f 412 Br(body_bcx, header_bcx.llbb, DebugLoc::None);
1a4d82fc
JJ
413 next_bcx
414 }
415}