]>
Commit | Line | Data |
---|---|---|
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 | 13 | use llvm; |
c34b1796 | 14 | use llvm::ValueRef; |
1a4d82fc JJ |
15 | use trans::base::*; |
16 | use trans::base; | |
17 | use trans::build::*; | |
18 | use trans::cleanup; | |
19 | use trans::cleanup::CleanupMethods; | |
20 | use trans::common::*; | |
21 | use trans::consts; | |
22 | use trans::datum::*; | |
85aaf69f | 23 | use trans::debuginfo::DebugLoc; |
1a4d82fc JJ |
24 | use trans::expr::{Dest, Ignore, SaveIn}; |
25 | use trans::expr; | |
85aaf69f | 26 | use trans::machine::llsize_of_alloc; |
1a4d82fc JJ |
27 | use trans::type_::Type; |
28 | use trans::type_of; | |
29 | use middle::ty::{self, Ty}; | |
1a4d82fc | 30 | |
e9174d1e SL |
31 | use rustc_front::hir; |
32 | ||
b039eaaf | 33 | use syntax::ast; |
1a4d82fc JJ |
34 | use syntax::parse::token::InternedString; |
35 | ||
c34b1796 AL |
36 | #[derive(Copy, Clone)] |
37 | struct VecTypes<'tcx> { | |
38 | unit_ty: Ty<'tcx>, | |
39 | llunit_ty: Type | |
1a4d82fc JJ |
40 | } |
41 | ||
42 | impl<'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 | ||
50 | pub 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). | |
80 | pub 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. | |
142 | pub 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 |
165 | fn 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 | 259 | fn 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 |
265 | fn 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 | 273 | fn 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. | |
297 | pub 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 |
311 | pub 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 |
338 | fn 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 | ||
378 | pub 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 | } |