]>
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; |
54a0048b SL |
15 | use base::*; |
16 | use base; | |
17 | use build::*; | |
18 | use cleanup; | |
19 | use cleanup::CleanupMethods; | |
20 | use common::*; | |
21 | use consts; | |
22 | use datum::*; | |
23 | use debuginfo::DebugLoc; | |
24 | use expr::{Dest, Ignore, SaveIn}; | |
25 | use expr; | |
26 | use machine::llsize_of_alloc; | |
27 | use type_::Type; | |
28 | use type_of; | |
29 | use value::Value; | |
30 | use rustc::ty::{self, Ty}; | |
31 | ||
32 | use rustc::hir; | |
5bcae85e | 33 | use rustc_const_eval::eval_length; |
e9174d1e | 34 | |
b039eaaf | 35 | use syntax::ast; |
1a4d82fc JJ |
36 | use syntax::parse::token::InternedString; |
37 | ||
54a0048b | 38 | #[derive(Copy, Clone, Debug)] |
c34b1796 AL |
39 | struct VecTypes<'tcx> { |
40 | unit_ty: Ty<'tcx>, | |
41 | llunit_ty: Type | |
1a4d82fc JJ |
42 | } |
43 | ||
1a4d82fc | 44 | pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, |
e9174d1e | 45 | expr: &hir::Expr, |
1a4d82fc JJ |
46 | dest: expr::Dest) |
47 | -> Block<'blk, 'tcx> { | |
48 | //! | |
49 | // | |
50 | // [...] allocates a fixed-size array and moves it around "by value". | |
51 | // In this case, it means that the caller has already given us a location | |
52 | // to store the array of the suitable size, so all we have to do is | |
53 | // generate the content. | |
54 | ||
54a0048b | 55 | debug!("trans_fixed_vstore(expr={:?}, dest={:?})", expr, dest); |
1a4d82fc JJ |
56 | |
57 | let vt = vec_types_from_expr(bcx, expr); | |
58 | ||
59 | return match dest { | |
60 | Ignore => write_content(bcx, &vt, expr, expr, dest), | |
61 | SaveIn(lldest) => { | |
62 | // lldest will have type *[T x N], but we want the type *T, | |
63 | // so use GEP to convert: | |
e9174d1e | 64 | let lldest = StructGEP(bcx, lldest, 0); |
1a4d82fc JJ |
65 | write_content(bcx, &vt, expr, expr, SaveIn(lldest)) |
66 | } | |
67 | }; | |
68 | } | |
69 | ||
70 | /// &[...] allocates memory on the stack and writes the values into it, returning the vector (the | |
71 | /// caller must make the reference). "..." is similar except that the memory can be statically | |
72 | /// allocated and we return a reference (strings are always by-ref). | |
73 | pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
e9174d1e SL |
74 | slice_expr: &hir::Expr, |
75 | content_expr: &hir::Expr) | |
1a4d82fc JJ |
76 | -> DatumBlock<'blk, 'tcx, Expr> { |
77 | let fcx = bcx.fcx; | |
1a4d82fc JJ |
78 | let mut bcx = bcx; |
79 | ||
62682a34 SL |
80 | debug!("trans_slice_vec(slice_expr={:?})", |
81 | slice_expr); | |
1a4d82fc JJ |
82 | |
83 | let vec_ty = node_id_type(bcx, slice_expr.id); | |
84 | ||
85 | // Handle the "..." case (returns a slice since strings are always unsized): | |
e9174d1e | 86 | if let hir::ExprLit(ref lit) = content_expr.node { |
7453a54e | 87 | if let ast::LitKind::Str(ref s, _) = lit.node { |
1a4d82fc JJ |
88 | let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); |
89 | bcx = trans_lit_str(bcx, | |
90 | content_expr, | |
91 | s.clone(), | |
92 | SaveIn(scratch.val)); | |
93 | return DatumBlock::new(bcx, scratch.to_expr_datum()); | |
94 | } | |
95 | } | |
96 | ||
97 | // Handle the &[...] case: | |
98 | let vt = vec_types_from_expr(bcx, content_expr); | |
99 | let count = elements_required(bcx, content_expr); | |
54a0048b | 100 | debug!(" vt={:?}, count={}", vt, count); |
1a4d82fc | 101 | |
c1a9b12d | 102 | let fixed_ty = bcx.tcx().mk_array(vt.unit_ty, count); |
1a4d82fc | 103 | |
85aaf69f SL |
104 | // Always create an alloca even if zero-sized, to preserve |
105 | // the non-null invariant of the inner slice ptr | |
9cc50fc6 SL |
106 | let llfixed; |
107 | // Issue 30018: ensure state is initialized as dropped if necessary. | |
108 | if fcx.type_needs_drop(vt.unit_ty) { | |
109 | llfixed = base::alloc_ty_init(bcx, fixed_ty, InitAlloca::Dropped, ""); | |
110 | } else { | |
111 | let uninit = InitAlloca::Uninit("fcx says vt.unit_ty is non-drop"); | |
112 | llfixed = base::alloc_ty_init(bcx, fixed_ty, uninit, ""); | |
113 | call_lifetime_start(bcx, llfixed); | |
114 | }; | |
1a4d82fc | 115 | |
85aaf69f | 116 | if count > 0 { |
1a4d82fc | 117 | // Arrange for the backing array to be cleaned up. |
1a4d82fc | 118 | let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id); |
85aaf69f | 119 | fcx.schedule_lifetime_end(cleanup_scope, llfixed); |
c1a9b12d | 120 | fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty, None); |
1a4d82fc JJ |
121 | |
122 | // Generate the content into the backing array. | |
85aaf69f SL |
123 | // llfixed has type *[T x N], but we want the type *T, |
124 | // so use GEP to convert | |
125 | bcx = write_content(bcx, &vt, slice_expr, content_expr, | |
e9174d1e | 126 | SaveIn(StructGEP(bcx, llfixed, 0))); |
1a4d82fc JJ |
127 | }; |
128 | ||
129 | immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock() | |
130 | } | |
131 | ||
132 | /// Literal strings translate to slices into static memory. This is different from | |
133 | /// trans_slice_vstore() above because it doesn't need to copy the content anywhere. | |
134 | pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
e9174d1e | 135 | lit_expr: &hir::Expr, |
1a4d82fc JJ |
136 | str_lit: InternedString, |
137 | dest: Dest) | |
138 | -> Block<'blk, 'tcx> { | |
54a0048b | 139 | debug!("trans_lit_str(lit_expr={:?}, dest={:?})", lit_expr, dest); |
1a4d82fc JJ |
140 | |
141 | match dest { | |
142 | Ignore => bcx, | |
143 | SaveIn(lldest) => { | |
85aaf69f | 144 | let bytes = str_lit.len(); |
1a4d82fc JJ |
145 | let llbytes = C_uint(bcx.ccx(), bytes); |
146 | let llcstr = C_cstr(bcx.ccx(), str_lit, false); | |
147 | let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx())); | |
e9174d1e SL |
148 | Store(bcx, llcstr, expr::get_dataptr(bcx, lldest)); |
149 | Store(bcx, llbytes, expr::get_meta(bcx, lldest)); | |
1a4d82fc JJ |
150 | bcx |
151 | } | |
152 | } | |
153 | } | |
154 | ||
c34b1796 AL |
155 | fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, |
156 | vt: &VecTypes<'tcx>, | |
e9174d1e SL |
157 | vstore_expr: &hir::Expr, |
158 | content_expr: &hir::Expr, | |
c34b1796 AL |
159 | dest: Dest) |
160 | -> Block<'blk, 'tcx> { | |
1a4d82fc JJ |
161 | let _icx = push_ctxt("tvec::write_content"); |
162 | let fcx = bcx.fcx; | |
163 | let mut bcx = bcx; | |
164 | ||
54a0048b SL |
165 | debug!("write_content(vt={:?}, dest={:?}, vstore_expr={:?})", |
166 | vt, dest, vstore_expr); | |
1a4d82fc JJ |
167 | |
168 | match content_expr.node { | |
e9174d1e | 169 | hir::ExprLit(ref lit) => { |
1a4d82fc | 170 | match lit.node { |
7453a54e | 171 | ast::LitKind::Str(ref s, _) => { |
1a4d82fc JJ |
172 | match dest { |
173 | Ignore => return bcx, | |
174 | SaveIn(lldest) => { | |
85aaf69f | 175 | let bytes = s.len(); |
1a4d82fc JJ |
176 | let llbytes = C_uint(bcx.ccx(), bytes); |
177 | let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false); | |
54a0048b SL |
178 | if !bcx.unreachable.get() { |
179 | base::call_memcpy(&B(bcx), lldest, llcstr, llbytes, 1); | |
180 | } | |
1a4d82fc JJ |
181 | return bcx; |
182 | } | |
183 | } | |
184 | } | |
185 | _ => { | |
54a0048b | 186 | span_bug!(content_expr.span, "unexpected evec content"); |
1a4d82fc JJ |
187 | } |
188 | } | |
189 | } | |
e9174d1e | 190 | hir::ExprVec(ref elements) => { |
1a4d82fc JJ |
191 | match dest { |
192 | Ignore => { | |
85aaf69f | 193 | for element in elements { |
7453a54e | 194 | bcx = expr::trans_into(bcx, &element, Ignore); |
1a4d82fc JJ |
195 | } |
196 | } | |
197 | ||
198 | SaveIn(lldest) => { | |
199 | let temp_scope = fcx.push_custom_cleanup_scope(); | |
200 | for (i, element) in elements.iter().enumerate() { | |
201 | let lleltptr = GEPi(bcx, lldest, &[i]); | |
54a0048b SL |
202 | debug!("writing index {} with lleltptr={:?}", |
203 | i, Value(lleltptr)); | |
7453a54e | 204 | bcx = expr::trans_into(bcx, &element, |
1a4d82fc JJ |
205 | SaveIn(lleltptr)); |
206 | let scope = cleanup::CustomScope(temp_scope); | |
9cc50fc6 SL |
207 | // Issue #30822: mark memory as dropped after running destructor |
208 | fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None); | |
1a4d82fc JJ |
209 | } |
210 | fcx.pop_custom_cleanup_scope(temp_scope); | |
211 | } | |
212 | } | |
213 | return bcx; | |
214 | } | |
e9174d1e | 215 | hir::ExprRepeat(ref element, ref count_expr) => { |
1a4d82fc JJ |
216 | match dest { |
217 | Ignore => { | |
7453a54e | 218 | return expr::trans_into(bcx, &element, Ignore); |
1a4d82fc JJ |
219 | } |
220 | SaveIn(lldest) => { | |
5bcae85e | 221 | match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() { |
7453a54e SL |
222 | 0 => expr::trans_into(bcx, &element, Ignore), |
223 | 1 => expr::trans_into(bcx, &element, SaveIn(lldest)), | |
1a4d82fc | 224 | count => { |
7453a54e | 225 | let elem = unpack_datum!(bcx, expr::trans(bcx, &element)); |
1a4d82fc JJ |
226 | let bcx = iter_vec_loop(bcx, lldest, vt, |
227 | C_uint(bcx.ccx(), count), | |
228 | |set_bcx, lleltptr, _| { | |
229 | elem.shallow_copy(set_bcx, lleltptr) | |
230 | }); | |
1a4d82fc JJ |
231 | bcx |
232 | } | |
233 | } | |
234 | } | |
235 | } | |
236 | } | |
237 | _ => { | |
54a0048b | 238 | span_bug!(content_expr.span, "unexpected vec content"); |
1a4d82fc JJ |
239 | } |
240 | } | |
241 | } | |
242 | ||
e9174d1e | 243 | fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &hir::Expr) |
c34b1796 | 244 | -> VecTypes<'tcx> { |
1a4d82fc | 245 | let vec_ty = node_id_type(bcx, vec_expr.id); |
c1a9b12d | 246 | vec_types(bcx, vec_ty.sequence_element_type(bcx.tcx())) |
1a4d82fc JJ |
247 | } |
248 | ||
c34b1796 AL |
249 | fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>) |
250 | -> VecTypes<'tcx> { | |
1a4d82fc JJ |
251 | VecTypes { |
252 | unit_ty: unit_ty, | |
c34b1796 | 253 | llunit_ty: type_of::type_of(bcx.ccx(), unit_ty) |
1a4d82fc JJ |
254 | } |
255 | } | |
256 | ||
e9174d1e | 257 | fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { |
1a4d82fc JJ |
258 | //! Figure out the number of elements we need to store this content |
259 | ||
260 | match content_expr.node { | |
e9174d1e | 261 | hir::ExprLit(ref lit) => { |
1a4d82fc | 262 | match lit.node { |
7453a54e | 263 | ast::LitKind::Str(ref s, _) => s.len(), |
1a4d82fc | 264 | _ => { |
54a0048b | 265 | span_bug!(content_expr.span, "unexpected evec content") |
1a4d82fc JJ |
266 | } |
267 | } | |
268 | }, | |
e9174d1e SL |
269 | hir::ExprVec(ref es) => es.len(), |
270 | hir::ExprRepeat(_, ref count_expr) => { | |
5bcae85e | 271 | eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() |
1a4d82fc | 272 | } |
54a0048b | 273 | _ => span_bug!(content_expr.span, "unexpected vec content") |
1a4d82fc JJ |
274 | } |
275 | } | |
276 | ||
277 | /// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval` | |
278 | /// which should be by ref. | |
279 | pub fn get_fixed_base_and_len(bcx: Block, | |
280 | llval: ValueRef, | |
c34b1796 | 281 | vec_length: usize) |
1a4d82fc JJ |
282 | -> (ValueRef, ValueRef) { |
283 | let ccx = bcx.ccx(); | |
284 | ||
285 | let base = expr::get_dataptr(bcx, llval); | |
286 | let len = C_uint(ccx, vec_length); | |
287 | (base, len) | |
288 | } | |
289 | ||
1a4d82fc JJ |
290 | /// Converts a vector into the slice pair. The vector should be stored in `llval` which should be |
291 | /// by-reference. If you have a datum, you would probably prefer to call | |
292 | /// `Datum::get_base_and_len()` which will handle any conversions for you. | |
c34b1796 AL |
293 | pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, |
294 | llval: ValueRef, | |
295 | vec_ty: Ty<'tcx>) | |
296 | -> (ValueRef, ValueRef) { | |
1a4d82fc | 297 | match vec_ty.sty { |
62682a34 SL |
298 | ty::TyArray(_, n) => get_fixed_base_and_len(bcx, llval, n), |
299 | ty::TySlice(_) | ty::TyStr => { | |
c34b1796 | 300 | let base = Load(bcx, expr::get_dataptr(bcx, llval)); |
e9174d1e | 301 | let len = Load(bcx, expr::get_meta(bcx, llval)); |
c34b1796 AL |
302 | (base, len) |
303 | } | |
1a4d82fc JJ |
304 | |
305 | // Only used for pattern matching. | |
c1a9b12d | 306 | ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => { |
c34b1796 AL |
307 | let inner = if type_is_sized(bcx.tcx(), ty) { |
308 | Load(bcx, llval) | |
309 | } else { | |
310 | llval | |
311 | }; | |
312 | get_base_and_len(bcx, inner, ty) | |
1a4d82fc | 313 | }, |
54a0048b | 314 | _ => bug!("unexpected type in get_base_and_len"), |
1a4d82fc JJ |
315 | } |
316 | } | |
317 | ||
c34b1796 AL |
318 | fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, |
319 | data_ptr: ValueRef, | |
320 | vt: &VecTypes<'tcx>, | |
321 | count: ValueRef, | |
322 | f: F) | |
323 | -> Block<'blk, 'tcx> where | |
1a4d82fc JJ |
324 | F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, |
325 | { | |
326 | let _icx = push_ctxt("tvec::iter_vec_loop"); | |
1a4d82fc | 327 | |
c34b1796 AL |
328 | if bcx.unreachable.get() { |
329 | return bcx; | |
330 | } | |
331 | ||
332 | let fcx = bcx.fcx; | |
1a4d82fc | 333 | let loop_bcx = fcx.new_temp_block("expr_repeat"); |
85aaf69f | 334 | let next_bcx = fcx.new_temp_block("expr_repeat: next"); |
1a4d82fc | 335 | |
85aaf69f | 336 | Br(bcx, loop_bcx.llbb, DebugLoc::None); |
1a4d82fc | 337 | |
85aaf69f SL |
338 | let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(), |
339 | &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]); | |
1a4d82fc | 340 | |
85aaf69f | 341 | let bcx = loop_bcx; |
1a4d82fc | 342 | |
c34b1796 | 343 | let lleltptr = if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 { |
85aaf69f SL |
344 | data_ptr |
345 | } else { | |
346 | InBoundsGEP(bcx, data_ptr, &[loop_counter]) | |
347 | }; | |
348 | let bcx = f(bcx, lleltptr, vt.unit_ty); | |
9346a6ac | 349 | let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None); |
85aaf69f | 350 | AddIncomingToPhi(loop_counter, plusone, bcx.llbb); |
1a4d82fc | 351 | |
5bcae85e | 352 | let cond_val = ICmp(bcx, llvm::IntNE, plusone, count, DebugLoc::None); |
85aaf69f | 353 | CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None); |
1a4d82fc JJ |
354 | |
355 | next_bcx | |
356 | } | |
357 | ||
358 | pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, | |
359 | data_ptr: ValueRef, | |
360 | unit_ty: Ty<'tcx>, | |
361 | len: ValueRef, | |
362 | f: F) | |
363 | -> Block<'blk, 'tcx> where | |
364 | F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, | |
365 | { | |
366 | let _icx = push_ctxt("tvec::iter_vec_raw"); | |
367 | let fcx = bcx.fcx; | |
368 | ||
369 | let vt = vec_types(bcx, unit_ty); | |
1a4d82fc | 370 | |
c34b1796 | 371 | if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 { |
1a4d82fc | 372 | // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) |
85aaf69f | 373 | iter_vec_loop(bcx, data_ptr, &vt, len, f) |
1a4d82fc JJ |
374 | } else { |
375 | // Calculate the last pointer address we want to handle. | |
85aaf69f | 376 | let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]); |
1a4d82fc JJ |
377 | |
378 | // Now perform the iteration. | |
379 | let header_bcx = fcx.new_temp_block("iter_vec_loop_header"); | |
85aaf69f | 380 | Br(bcx, header_bcx.llbb, DebugLoc::None); |
1a4d82fc JJ |
381 | let data_ptr = |
382 | Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]); | |
383 | let not_yet_at_end = | |
5bcae85e | 384 | ICmp(header_bcx, llvm::IntNE, data_ptr, data_end_ptr, DebugLoc::None); |
1a4d82fc JJ |
385 | let body_bcx = fcx.new_temp_block("iter_vec_loop_body"); |
386 | let next_bcx = fcx.new_temp_block("iter_vec_next"); | |
85aaf69f | 387 | CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None); |
c34b1796 | 388 | let body_bcx = f(body_bcx, data_ptr, unit_ty); |
1a4d82fc | 389 | AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr, |
85aaf69f | 390 | &[C_int(bcx.ccx(), 1)]), |
1a4d82fc | 391 | body_bcx.llbb); |
85aaf69f | 392 | Br(body_bcx, header_bcx.llbb, DebugLoc::None); |
1a4d82fc JJ |
393 | next_bcx |
394 | } | |
395 | } |