]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
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 | ||
3157f602 | 11 | use rustc::middle::lang_items; |
83c7162d | 12 | use rustc::ty::{self, Ty, TypeFoldable}; |
a1dfa0c6 | 13 | use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; |
c30ab7b3 | 14 | use rustc::mir; |
83c7162d | 15 | use rustc::mir::interpret::EvalErrorKind; |
a1dfa0c6 XL |
16 | use rustc_target::abi::call::{ArgType, FnType, PassMode}; |
17 | use rustc_target::spec::abi::Abi; | |
ff7c6d11 | 18 | use base; |
a1dfa0c6 XL |
19 | use MemFlags; |
20 | use common::{self, IntPredicate}; | |
54a0048b | 21 | use meth; |
a1dfa0c6 XL |
22 | use rustc_mir::monomorphize; |
23 | ||
24 | use traits::*; | |
3157f602 | 25 | |
476ff2be | 26 | use syntax::symbol::Symbol; |
041b39d2 | 27 | use syntax_pos::Pos; |
54a0048b | 28 | |
2c00a5a8 | 29 | use super::{FunctionCx, LocalRef}; |
ff7c6d11 | 30 | use super::place::PlaceRef; |
54a0048b | 31 | use super::operand::OperandRef; |
c30ab7b3 SL |
32 | use super::operand::OperandValue::{Pair, Ref, Immediate}; |
33 | ||
a1dfa0c6 XL |
34 | impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
35 | pub fn codegen_block( | |
36 | &mut self, | |
37 | bb: mir::BasicBlock, | |
38 | ) { | |
2c00a5a8 | 39 | let mut bx = self.build_block(bb); |
32a655c1 | 40 | let data = &self.mir[bb]; |
3157f602 | 41 | |
94b46f34 | 42 | debug!("codegen_block({:?}={:?})", bb, data); |
3157f602 | 43 | |
7cac9316 | 44 | for statement in &data.statements { |
94b46f34 | 45 | bx = self.codegen_statement(bx, statement); |
7cac9316 XL |
46 | } |
47 | ||
94b46f34 | 48 | self.codegen_terminator(bx, bb, data.terminator()); |
7cac9316 XL |
49 | } |
50 | ||
a1dfa0c6 XL |
51 | fn codegen_terminator( |
52 | &mut self, | |
53 | mut bx: Bx, | |
54 | bb: mir::BasicBlock, | |
55 | terminator: &mir::Terminator<'tcx> | |
56 | ) { | |
94b46f34 | 57 | debug!("codegen_terminator: {:?}", terminator); |
32a655c1 | 58 | |
3157f602 | 59 | // Create the cleanup bundle, if needed. |
a1dfa0c6 | 60 | let tcx = self.cx.tcx(); |
7cac9316 XL |
61 | let span = terminator.source_info.span; |
62 | let funclet_bb = self.cleanup_kinds[bb].funclet_bb(bb); | |
7cac9316 | 63 | |
a1dfa0c6 XL |
64 | // HACK(eddyb) force the right lifetimes, NLL can't figure them out. |
65 | fn funclet_closure_factory<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( | |
66 | funclet_bb: Option<mir::BasicBlock> | |
67 | ) -> impl for<'b> Fn( | |
68 | &'b FunctionCx<'a, 'tcx, Bx>, | |
69 | ) -> Option<&'b Bx::Funclet> { | |
70 | move |this| { | |
71 | match funclet_bb { | |
72 | Some(funclet_bb) => this.funclets[funclet_bb].as_ref(), | |
73 | None => None, | |
74 | } | |
75 | } | |
76 | } | |
77 | let funclet = funclet_closure_factory(funclet_bb); | |
3157f602 | 78 | |
7cac9316 XL |
79 | let lltarget = |this: &mut Self, target: mir::BasicBlock| { |
80 | let lltarget = this.blocks[target]; | |
81 | let target_funclet = this.cleanup_kinds[target].funclet_bb(target); | |
82 | match (funclet_bb, target_funclet) { | |
83 | (None, None) => (lltarget, false), | |
84 | (Some(f), Some(t_f)) | |
85 | if f == t_f || !base::wants_msvc_seh(tcx.sess) | |
86 | => (lltarget, false), | |
87 | (None, Some(_)) => { | |
88 | // jump *into* cleanup - need a landing pad if GNU | |
89 | (this.landing_pad_to(target), false) | |
90 | } | |
91 | (Some(_), None) => span_bug!(span, "{:?} - jump out of cleanup?", terminator), | |
92 | (Some(_), Some(_)) => { | |
93 | (this.landing_pad_to(target), true) | |
3157f602 | 94 | } |
3157f602 | 95 | } |
54a0048b | 96 | }; |
3157f602 XL |
97 | |
98 | let llblock = |this: &mut Self, target: mir::BasicBlock| { | |
7cac9316 XL |
99 | let (lltarget, is_cleanupret) = lltarget(this, target); |
100 | if is_cleanupret { | |
101 | // MSVC cross-funclet jump - need a trampoline | |
102 | ||
103 | debug!("llblock: creating cleanup trampoline for {:?}", target); | |
104 | let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target); | |
a1dfa0c6 XL |
105 | let mut trampoline = this.new_block(name); |
106 | trampoline.cleanup_ret(funclet(this).unwrap(), Some(lltarget)); | |
7cac9316 XL |
107 | trampoline.llbb() |
108 | } else { | |
109 | lltarget | |
110 | } | |
111 | }; | |
3157f602 | 112 | |
a1dfa0c6 XL |
113 | let funclet_br = |
114 | |this: &mut Self, bx: &mut Bx, target: mir::BasicBlock| { | |
115 | let (lltarget, is_cleanupret) = lltarget(this, target); | |
116 | if is_cleanupret { | |
117 | // micro-optimization: generate a `ret` rather than a jump | |
118 | // to a trampoline. | |
119 | bx.cleanup_ret(funclet(this).unwrap(), Some(lltarget)); | |
120 | } else { | |
121 | bx.br(lltarget); | |
122 | } | |
123 | }; | |
3157f602 | 124 | |
7cac9316 XL |
125 | let do_call = | |
126 | this: &mut Self, | |
a1dfa0c6 | 127 | bx: &mut Bx, |
83c7162d | 128 | fn_ty: FnType<'tcx, Ty<'tcx>>, |
a1dfa0c6 XL |
129 | fn_ptr: Bx::Value, |
130 | llargs: &[Bx::Value], | |
131 | destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, | |
7cac9316 XL |
132 | cleanup: Option<mir::BasicBlock> |
133 | | { | |
134 | if let Some(cleanup) = cleanup { | |
2c00a5a8 | 135 | let ret_bx = if let Some((_, target)) = destination { |
7cac9316 XL |
136 | this.blocks[target] |
137 | } else { | |
138 | this.unreachable_block() | |
139 | }; | |
2c00a5a8 | 140 | let invokeret = bx.invoke(fn_ptr, |
0bf4aa26 XL |
141 | &llargs, |
142 | ret_bx, | |
143 | llblock(this, cleanup), | |
a1dfa0c6 XL |
144 | funclet(this)); |
145 | bx.apply_attrs_callsite(&fn_ty, invokeret); | |
7cac9316 | 146 | |
ff7c6d11 | 147 | if let Some((ret_dest, target)) = destination { |
a1dfa0c6 XL |
148 | let mut ret_bx = this.build_block(target); |
149 | this.set_debug_loc(&mut ret_bx, terminator.source_info); | |
150 | this.store_return(&mut ret_bx, ret_dest, &fn_ty.ret, invokeret); | |
3157f602 XL |
151 | } |
152 | } else { | |
a1dfa0c6 XL |
153 | let llret = bx.call(fn_ptr, &llargs, funclet(this)); |
154 | bx.apply_attrs_callsite(&fn_ty, llret); | |
041b39d2 XL |
155 | if this.mir[bb].is_cleanup { |
156 | // Cleanup is always the cold path. Don't inline | |
157 | // drop glue. Also, when there is a deeply-nested | |
158 | // struct, there are "symmetry" issues that cause | |
159 | // exponential inlining - see issue #41696. | |
a1dfa0c6 | 160 | bx.do_not_inline(llret); |
041b39d2 | 161 | } |
7cac9316 | 162 | |
ff7c6d11 | 163 | if let Some((ret_dest, target)) = destination { |
a1dfa0c6 | 164 | this.store_return(bx, ret_dest, &fn_ty.ret, llret); |
2c00a5a8 | 165 | funclet_br(this, bx, target); |
3157f602 | 166 | } else { |
2c00a5a8 | 167 | bx.unreachable(); |
3157f602 XL |
168 | } |
169 | } | |
54a0048b SL |
170 | }; |
171 | ||
a1dfa0c6 | 172 | self.set_debug_loc(&mut bx, terminator.source_info); |
a7813a04 | 173 | match terminator.kind { |
54a0048b | 174 | mir::TerminatorKind::Resume => { |
a1dfa0c6 XL |
175 | if let Some(funclet) = funclet(self) { |
176 | bx.cleanup_ret(funclet, None); | |
54a0048b | 177 | } else { |
a1dfa0c6 XL |
178 | let slot = self.get_personality_slot(&mut bx); |
179 | let lp0 = slot.project_field(&mut bx, 0); | |
180 | let lp0 = bx.load_operand(lp0).immediate(); | |
181 | let lp1 = slot.project_field(&mut bx, 1); | |
182 | let lp1 = bx.load_operand(lp1).immediate(); | |
183 | slot.storage_dead(&mut bx); | |
ff7c6d11 | 184 | |
2c00a5a8 | 185 | if !bx.sess().target.target.options.custom_unwind_resume { |
a1dfa0c6 | 186 | let mut lp = bx.const_undef(self.landing_pad_type()); |
2c00a5a8 XL |
187 | lp = bx.insert_value(lp, lp0, 0); |
188 | lp = bx.insert_value(lp, lp1, 1); | |
189 | bx.resume(lp); | |
32a655c1 | 190 | } else { |
a1dfa0c6 | 191 | bx.call(bx.eh_unwind_resume(), &[lp0], funclet(self)); |
2c00a5a8 | 192 | bx.unreachable(); |
32a655c1 | 193 | } |
54a0048b SL |
194 | } |
195 | } | |
196 | ||
ff7c6d11 | 197 | mir::TerminatorKind::Abort => { |
a1dfa0c6 | 198 | bx.abort(); |
2c00a5a8 | 199 | bx.unreachable(); |
ff7c6d11 XL |
200 | } |
201 | ||
54a0048b | 202 | mir::TerminatorKind::Goto { target } => { |
a1dfa0c6 | 203 | funclet_br(self, &mut bx, target); |
54a0048b SL |
204 | } |
205 | ||
8bb4bdeb | 206 | mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { |
a1dfa0c6 | 207 | let discr = self.codegen_operand(&mut bx, discr); |
94b46f34 XL |
208 | if targets.len() == 2 { |
209 | // If there are two targets, emit br instead of switch | |
8bb4bdeb XL |
210 | let lltrue = llblock(self, targets[0]); |
211 | let llfalse = llblock(self, targets[1]); | |
94b46f34 XL |
212 | if switch_ty == bx.tcx().types.bool { |
213 | // Don't generate trivial icmps when switching on bool | |
214 | if let [0] = values[..] { | |
215 | bx.cond_br(discr.immediate(), llfalse, lltrue); | |
216 | } else { | |
217 | assert_eq!(&values[..], &[1]); | |
218 | bx.cond_br(discr.immediate(), lltrue, llfalse); | |
219 | } | |
8bb4bdeb | 220 | } else { |
a1dfa0c6 XL |
221 | let switch_llty = bx.immediate_backend_type( |
222 | bx.layout_of(switch_ty) | |
223 | ); | |
224 | let llval = bx.const_uint_big(switch_llty, values[0]); | |
225 | let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); | |
94b46f34 | 226 | bx.cond_br(cmp, lltrue, llfalse); |
a7813a04 | 227 | } |
8bb4bdeb XL |
228 | } else { |
229 | let (otherwise, targets) = targets.split_last().unwrap(); | |
2c00a5a8 | 230 | let switch = bx.switch(discr.immediate(), |
0bf4aa26 XL |
231 | llblock(self, *otherwise), |
232 | values.len()); | |
a1dfa0c6 XL |
233 | let switch_llty = bx.immediate_backend_type( |
234 | bx.layout_of(switch_ty) | |
235 | ); | |
0531ce1d | 236 | for (&value, target) in values.iter().zip(targets) { |
a1dfa0c6 | 237 | let llval = bx.const_uint_big(switch_llty, value); |
8bb4bdeb | 238 | let llbb = llblock(self, *target); |
0531ce1d | 239 | bx.add_case(switch, llval, llbb) |
a7813a04 | 240 | } |
54a0048b SL |
241 | } |
242 | } | |
243 | ||
54a0048b | 244 | mir::TerminatorKind::Return => { |
ff7c6d11 | 245 | let llval = match self.fn_ty.ret.mode { |
b7449926 | 246 | PassMode::Ignore | PassMode::Indirect(..) => { |
2c00a5a8 | 247 | bx.ret_void(); |
ff7c6d11 XL |
248 | return; |
249 | } | |
3157f602 | 250 | |
ff7c6d11 | 251 | PassMode::Direct(_) | PassMode::Pair(..) => { |
a1dfa0c6 XL |
252 | let op = |
253 | self.codegen_consume(&mut bx, &mir::Place::Local(mir::RETURN_PLACE)); | |
b7449926 | 254 | if let Ref(llval, _, align) = op.val { |
2c00a5a8 | 255 | bx.load(llval, align) |
ff7c6d11 | 256 | } else { |
a1dfa0c6 | 257 | op.immediate_or_packed_pair(&mut bx) |
32a655c1 | 258 | } |
ff7c6d11 XL |
259 | } |
260 | ||
261 | PassMode::Cast(cast_ty) => { | |
262 | let op = match self.locals[mir::RETURN_PLACE] { | |
263 | LocalRef::Operand(Some(op)) => op, | |
264 | LocalRef::Operand(None) => bug!("use of return before def"), | |
94b46f34 | 265 | LocalRef::Place(cg_place) => { |
ff7c6d11 | 266 | OperandRef { |
b7449926 | 267 | val: Ref(cg_place.llval, None, cg_place.align), |
94b46f34 | 268 | layout: cg_place.layout |
ff7c6d11 XL |
269 | } |
270 | } | |
b7449926 | 271 | LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), |
ff7c6d11 XL |
272 | }; |
273 | let llslot = match op.val { | |
274 | Immediate(_) | Pair(..) => { | |
a1dfa0c6 XL |
275 | let scratch = |
276 | PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout, "ret"); | |
277 | op.val.store(&mut bx, scratch); | |
ff7c6d11 XL |
278 | scratch.llval |
279 | } | |
b7449926 | 280 | Ref(llval, _, align) => { |
a1dfa0c6 | 281 | assert_eq!(align, op.layout.align.abi, |
ff7c6d11 XL |
282 | "return place is unaligned!"); |
283 | llval | |
284 | } | |
285 | }; | |
a1dfa0c6 XL |
286 | let addr = bx.pointercast(llslot, bx.type_ptr_to( |
287 | bx.cast_backend_type(&cast_ty) | |
288 | )); | |
289 | bx.load(addr, self.fn_ty.ret.layout.align.abi) | |
476ff2be | 290 | } |
3157f602 | 291 | }; |
2c00a5a8 | 292 | bx.ret(llval); |
3157f602 XL |
293 | } |
294 | ||
295 | mir::TerminatorKind::Unreachable => { | |
2c00a5a8 | 296 | bx.unreachable(); |
54a0048b SL |
297 | } |
298 | ||
3157f602 | 299 | mir::TerminatorKind::Drop { ref location, target, unwind } => { |
2c00a5a8 | 300 | let ty = location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); |
32a655c1 | 301 | let ty = self.monomorphize(&ty); |
a1dfa0c6 | 302 | let drop_fn = monomorphize::resolve_drop_in_place(bx.tcx(), ty); |
3157f602 | 303 | |
cc61c64b XL |
304 | if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { |
305 | // we don't actually need to drop anything. | |
a1dfa0c6 | 306 | funclet_br(self, &mut bx, target); |
cc61c64b | 307 | return |
54a0048b | 308 | } |
3157f602 | 309 | |
a1dfa0c6 | 310 | let place = self.codegen_place(&mut bx, location); |
b7449926 XL |
311 | let (args1, args2); |
312 | let mut args = if let Some(llextra) = place.llextra { | |
313 | args2 = [place.llval, llextra]; | |
314 | &args2[..] | |
315 | } else { | |
316 | args1 = [place.llval]; | |
317 | &args1[..] | |
318 | }; | |
ff7c6d11 | 319 | let (drop_fn, fn_ty) = match ty.sty { |
b7449926 | 320 | ty::Dynamic(..) => { |
a1dfa0c6 XL |
321 | let sig = drop_fn.fn_sig(tcx); |
322 | let sig = tcx.normalize_erasing_late_bound_regions( | |
0531ce1d XL |
323 | ty::ParamEnv::reveal_all(), |
324 | &sig, | |
325 | ); | |
a1dfa0c6 | 326 | let fn_ty = bx.new_vtable(sig, &[]); |
b7449926 | 327 | let vtable = args[1]; |
ff7c6d11 | 328 | args = &args[..1]; |
a1dfa0c6 | 329 | (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty) |
ff7c6d11 XL |
330 | } |
331 | _ => { | |
a1dfa0c6 XL |
332 | (bx.get_fn(drop_fn), |
333 | bx.fn_type_of_instance(&drop_fn)) | |
ff7c6d11 | 334 | } |
cc61c64b | 335 | }; |
a1dfa0c6 | 336 | do_call(self, &mut bx, fn_ty, drop_fn, args, |
ff7c6d11 | 337 | Some((ReturnDest::Nothing, target)), |
7cac9316 | 338 | unwind); |
3157f602 XL |
339 | } |
340 | ||
341 | mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { | |
a1dfa0c6 XL |
342 | let cond = self.codegen_operand(&mut bx, cond).immediate(); |
343 | let mut const_cond = bx.const_to_opt_u128(cond, false).map(|c| c == 1); | |
5bcae85e SL |
344 | |
345 | // This case can currently arise only from functions marked | |
346 | // with #[rustc_inherit_overflow_checks] and inlined from | |
347 | // another crate (mostly core::num generic/#[inline] fns), | |
348 | // while the current crate doesn't use overflow checks. | |
349 | // NOTE: Unlike binops, negation doesn't have its own | |
350 | // checked operation, just a comparison with the minimum | |
351 | // value, so we have to check for the assert message. | |
a1dfa0c6 | 352 | if !bx.check_overflow() { |
83c7162d | 353 | if let mir::interpret::EvalErrorKind::OverflowNeg = *msg { |
5bcae85e SL |
354 | const_cond = Some(expected); |
355 | } | |
356 | } | |
3157f602 | 357 | |
94b46f34 | 358 | // Don't codegen the panic block if success if known. |
3157f602 | 359 | if const_cond == Some(expected) { |
a1dfa0c6 | 360 | funclet_br(self, &mut bx, target); |
3157f602 XL |
361 | return; |
362 | } | |
363 | ||
364 | // Pass the condition through llvm.expect for branch hinting. | |
a1dfa0c6 | 365 | let cond = bx.expect(cond, expected); |
3157f602 XL |
366 | |
367 | // Create the failure block and the conditional branch to it. | |
368 | let lltarget = llblock(self, target); | |
32a655c1 | 369 | let panic_block = self.new_block("panic"); |
3157f602 | 370 | if expected { |
2c00a5a8 | 371 | bx.cond_br(cond, lltarget, panic_block.llbb()); |
3157f602 | 372 | } else { |
2c00a5a8 | 373 | bx.cond_br(cond, panic_block.llbb(), lltarget); |
3157f602 XL |
374 | } |
375 | ||
2c00a5a8 XL |
376 | // After this point, bx is the block for the call to panic. |
377 | bx = panic_block; | |
a1dfa0c6 | 378 | self.set_debug_loc(&mut bx, terminator.source_info); |
3157f602 XL |
379 | |
380 | // Get the location information. | |
b7449926 | 381 | let loc = bx.sess().source_map().lookup_char_pos(span.lo()); |
ff7c6d11 | 382 | let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); |
a1dfa0c6 XL |
383 | let filename = bx.const_str_slice(filename); |
384 | let line = bx.const_u32(loc.line as u32); | |
385 | let col = bx.const_u32(loc.col.to_usize() as u32 + 1); | |
386 | let align = tcx.data_layout.aggregate_align.abi | |
387 | .max(tcx.data_layout.i32_align.abi) | |
388 | .max(tcx.data_layout.pointer_align.abi); | |
3157f602 XL |
389 | |
390 | // Put together the arguments to the panic entry point. | |
0531ce1d | 391 | let (lang_item, args) = match *msg { |
83c7162d | 392 | EvalErrorKind::BoundsCheck { ref len, ref index } => { |
94b46f34 XL |
393 | let len = self.codegen_operand(&mut bx, len).immediate(); |
394 | let index = self.codegen_operand(&mut bx, index).immediate(); | |
3157f602 | 395 | |
a1dfa0c6 XL |
396 | let file_line_col = bx.const_struct(&[filename, line, col], false); |
397 | let file_line_col = bx.static_addr_of( | |
398 | file_line_col, | |
399 | align, | |
400 | Some("panic_bounds_check_loc") | |
401 | ); | |
3157f602 | 402 | (lang_items::PanicBoundsCheckFnLangItem, |
0531ce1d | 403 | vec![file_line_col, index, len]) |
3157f602 | 404 | } |
83c7162d XL |
405 | _ => { |
406 | let str = msg.description(); | |
ea8adc8c | 407 | let msg_str = Symbol::intern(str).as_str(); |
a1dfa0c6 XL |
408 | let msg_str = bx.const_str_slice(msg_str); |
409 | let msg_file_line_col = bx.const_struct( | |
410 | &[msg_str, filename, line, col], | |
411 | false | |
412 | ); | |
413 | let msg_file_line_col = bx.static_addr_of( | |
414 | msg_file_line_col, | |
415 | align, | |
416 | Some("panic_loc") | |
417 | ); | |
ea8adc8c | 418 | (lang_items::PanicFnLangItem, |
0531ce1d | 419 | vec![msg_file_line_col]) |
ea8adc8c | 420 | } |
3157f602 XL |
421 | }; |
422 | ||
3157f602 | 423 | // Obtain the panic entry point. |
2c00a5a8 XL |
424 | let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); |
425 | let instance = ty::Instance::mono(bx.tcx(), def_id); | |
a1dfa0c6 XL |
426 | let fn_ty = bx.fn_type_of_instance(&instance); |
427 | let llfn = bx.get_fn(instance); | |
3157f602 | 428 | |
94b46f34 | 429 | // Codegen the actual panic invoke/call. |
a1dfa0c6 | 430 | do_call(self, &mut bx, fn_ty, llfn, &args, None, cleanup); |
54a0048b SL |
431 | } |
432 | ||
3157f602 | 433 | mir::TerminatorKind::DropAndReplace { .. } => { |
94b46f34 | 434 | bug!("undesugared DropAndReplace in codegen: {:?}", terminator); |
3157f602 XL |
435 | } |
436 | ||
0bf4aa26 XL |
437 | mir::TerminatorKind::Call { |
438 | ref func, | |
439 | ref args, | |
440 | ref destination, | |
441 | cleanup, | |
442 | from_hir_call: _ | |
443 | } => { | |
54a0048b | 444 | // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. |
a1dfa0c6 | 445 | let callee = self.codegen_operand(&mut bx, func); |
54a0048b | 446 | |
ff7c6d11 | 447 | let (instance, mut llfn) = match callee.layout.ty.sty { |
b7449926 | 448 | ty::FnDef(def_id, substs) => { |
a1dfa0c6 | 449 | (Some(ty::Instance::resolve(bx.tcx(), |
0531ce1d | 450 | ty::ParamEnv::reveal_all(), |
ea8adc8c XL |
451 | def_id, |
452 | substs).unwrap()), | |
041b39d2 | 453 | None) |
54a0048b | 454 | } |
b7449926 | 455 | ty::FnPtr(_) => { |
041b39d2 | 456 | (None, Some(callee.immediate())) |
54a0048b | 457 | } |
ff7c6d11 | 458 | _ => bug!("{} is not callable", callee.layout.ty) |
54a0048b | 459 | }; |
cc61c64b | 460 | let def = instance.map(|i| i.def); |
2c00a5a8 | 461 | let sig = callee.layout.ty.fn_sig(bx.tcx()); |
0531ce1d XL |
462 | let sig = bx.tcx().normalize_erasing_late_bound_regions( |
463 | ty::ParamEnv::reveal_all(), | |
464 | &sig, | |
465 | ); | |
8bb4bdeb | 466 | let abi = sig.abi; |
54a0048b | 467 | |
94b46f34 | 468 | // Handle intrinsics old codegen wants Expr's for, ourselves. |
cc61c64b XL |
469 | let intrinsic = match def { |
470 | Some(ty::InstanceDef::Intrinsic(def_id)) | |
83c7162d | 471 | => Some(bx.tcx().item_name(def_id).as_str()), |
54a0048b SL |
472 | _ => None |
473 | }; | |
cc61c64b | 474 | let intrinsic = intrinsic.as_ref().map(|s| &s[..]); |
54a0048b SL |
475 | |
476 | if intrinsic == Some("transmute") { | |
94b46f34 XL |
477 | if let Some(destination_ref) = destination.as_ref() { |
478 | let &(ref dest, target) = destination_ref; | |
a1dfa0c6 XL |
479 | self.codegen_transmute(&mut bx, &args[0], dest); |
480 | funclet_br(self, &mut bx, target); | |
94b46f34 XL |
481 | } else { |
482 | // If we are trying to transmute to an uninhabited type, | |
483 | // it is likely there is no allotted destination. In fact, | |
484 | // transmuting to an uninhabited type is UB, which means | |
485 | // we can do what we like. Here, we declare that transmuting | |
486 | // into an uninhabited type is impossible, so anything following | |
487 | // it must be unreachable. | |
a1dfa0c6 | 488 | assert_eq!(bx.layout_of(sig.output()).abi, layout::Abi::Uninhabited); |
94b46f34 XL |
489 | bx.unreachable(); |
490 | } | |
54a0048b SL |
491 | return; |
492 | } | |
493 | ||
476ff2be | 494 | let extra_args = &args[sig.inputs().len()..]; |
54a0048b | 495 | let extra_args = extra_args.iter().map(|op_arg| { |
2c00a5a8 | 496 | let op_ty = op_arg.ty(self.mir, bx.tcx()); |
32a655c1 | 497 | self.monomorphize(&op_ty) |
54a0048b | 498 | }).collect::<Vec<_>>(); |
32a655c1 | 499 | |
cc61c64b XL |
500 | let fn_ty = match def { |
501 | Some(ty::InstanceDef::Virtual(..)) => { | |
a1dfa0c6 | 502 | bx.new_vtable(sig, &extra_args) |
cc61c64b XL |
503 | } |
504 | Some(ty::InstanceDef::DropGlue(_, None)) => { | |
505 | // empty drop glue - a nop. | |
506 | let &(_, target) = destination.as_ref().unwrap(); | |
a1dfa0c6 | 507 | funclet_br(self, &mut bx, target); |
32a655c1 SL |
508 | return; |
509 | } | |
a1dfa0c6 | 510 | _ => bx.new_fn_type(sig, &extra_args) |
cc61c64b | 511 | }; |
54a0048b | 512 | |
0bf4aa26 XL |
513 | // emit a panic instead of instantiating an uninhabited type |
514 | if (intrinsic == Some("init") || intrinsic == Some("uninit")) && | |
515 | fn_ty.ret.layout.abi.is_uninhabited() | |
516 | { | |
517 | let loc = bx.sess().source_map().lookup_char_pos(span.lo()); | |
518 | let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); | |
a1dfa0c6 XL |
519 | let filename = bx.const_str_slice(filename); |
520 | let line = bx.const_u32(loc.line as u32); | |
521 | let col = bx.const_u32(loc.col.to_usize() as u32 + 1); | |
522 | let align = tcx.data_layout.aggregate_align.abi | |
523 | .max(tcx.data_layout.i32_align.abi) | |
524 | .max(tcx.data_layout.pointer_align.abi); | |
0bf4aa26 XL |
525 | |
526 | let str = format!( | |
527 | "Attempted to instantiate uninhabited type {} using mem::{}", | |
528 | sig.output(), | |
529 | if intrinsic == Some("init") { "zeroed" } else { "uninitialized" } | |
530 | ); | |
531 | let msg_str = Symbol::intern(&str).as_str(); | |
a1dfa0c6 XL |
532 | let msg_str = bx.const_str_slice(msg_str); |
533 | let msg_file_line_col = bx.const_struct( | |
534 | &[msg_str, filename, line, col], | |
535 | false, | |
536 | ); | |
537 | let msg_file_line_col = bx.static_addr_of( | |
538 | msg_file_line_col, | |
539 | align, | |
540 | Some("panic_loc"), | |
541 | ); | |
0bf4aa26 XL |
542 | |
543 | // Obtain the panic entry point. | |
544 | let def_id = | |
545 | common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); | |
546 | let instance = ty::Instance::mono(bx.tcx(), def_id); | |
a1dfa0c6 XL |
547 | let fn_ty = bx.fn_type_of_instance(&instance); |
548 | let llfn = bx.get_fn(instance); | |
0bf4aa26 XL |
549 | |
550 | // Codegen the actual panic invoke/call. | |
551 | do_call( | |
552 | self, | |
a1dfa0c6 | 553 | &mut bx, |
0bf4aa26 XL |
554 | fn_ty, |
555 | llfn, | |
556 | &[msg_file_line_col], | |
557 | destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), | |
558 | cleanup, | |
559 | ); | |
560 | return; | |
561 | } | |
562 | ||
54a0048b SL |
563 | // The arguments we'll be passing. Plus one to account for outptr, if used. |
564 | let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize; | |
565 | let mut llargs = Vec::with_capacity(arg_count); | |
566 | ||
567 | // Prepare the return value destination | |
568 | let ret_dest = if let Some((ref dest, _)) = *destination { | |
cc61c64b | 569 | let is_intrinsic = intrinsic.is_some(); |
a1dfa0c6 | 570 | self.make_return_dest(&mut bx, dest, &fn_ty.ret, &mut llargs, |
cc61c64b | 571 | is_intrinsic) |
54a0048b SL |
572 | } else { |
573 | ReturnDest::Nothing | |
574 | }; | |
575 | ||
cc61c64b | 576 | if intrinsic.is_some() && intrinsic != Some("drop_in_place") { |
ff7c6d11 XL |
577 | let dest = match ret_dest { |
578 | _ if fn_ty.ret.is_indirect() => llargs[0], | |
cc61c64b | 579 | ReturnDest::Nothing => { |
a1dfa0c6 | 580 | bx.const_undef(bx.type_ptr_to(bx.memory_ty(&fn_ty.ret))) |
54a0048b | 581 | } |
cc61c64b | 582 | ReturnDest::IndirectOperand(dst, _) | |
ff7c6d11 | 583 | ReturnDest::Store(dst) => dst.llval, |
cc61c64b XL |
584 | ReturnDest::DirectOperand(_) => |
585 | bug!("Cannot use direct operand with an intrinsic call") | |
586 | }; | |
54a0048b | 587 | |
ff7c6d11 XL |
588 | let args: Vec<_> = args.iter().enumerate().map(|(i, arg)| { |
589 | // The indices passed to simd_shuffle* in the | |
590 | // third argument must be constant. This is | |
591 | // checked by const-qualification, which also | |
592 | // promotes any complex rvalues to constants. | |
593 | if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { | |
594 | match *arg { | |
8faf50e0 XL |
595 | // The shuffle array argument is usually not an explicit constant, |
596 | // but specified directly in the code. This means it gets promoted | |
597 | // and we can then extract the value by evaluating the promoted. | |
598 | mir::Operand::Copy(mir::Place::Promoted(box(index, ty))) | | |
599 | mir::Operand::Move(mir::Place::Promoted(box(index, ty))) => { | |
600 | let param_env = ty::ParamEnv::reveal_all(); | |
601 | let cid = mir::interpret::GlobalId { | |
602 | instance: self.instance, | |
603 | promoted: Some(index), | |
604 | }; | |
605 | let c = bx.tcx().const_eval(param_env.and(cid)); | |
606 | let (llval, ty) = self.simd_shuffle_indices( | |
607 | &bx, | |
608 | terminator.source_info.span, | |
609 | ty, | |
610 | c, | |
611 | ); | |
612 | return OperandRef { | |
613 | val: Immediate(llval), | |
a1dfa0c6 | 614 | layout: bx.layout_of(ty), |
8faf50e0 XL |
615 | }; |
616 | ||
617 | }, | |
ff7c6d11 XL |
618 | mir::Operand::Copy(_) | |
619 | mir::Operand::Move(_) => { | |
620 | span_bug!(span, "shuffle indices must be constant"); | |
621 | } | |
622 | mir::Operand::Constant(ref constant) => { | |
8faf50e0 | 623 | let c = self.eval_mir_constant(&bx, constant); |
0531ce1d XL |
624 | let (llval, ty) = self.simd_shuffle_indices( |
625 | &bx, | |
8faf50e0 XL |
626 | constant.span, |
627 | constant.ty, | |
628 | c, | |
0531ce1d | 629 | ); |
ff7c6d11 | 630 | return OperandRef { |
0531ce1d | 631 | val: Immediate(llval), |
a1dfa0c6 | 632 | layout: bx.layout_of(ty) |
ff7c6d11 XL |
633 | }; |
634 | } | |
635 | } | |
636 | } | |
637 | ||
a1dfa0c6 | 638 | self.codegen_operand(&mut bx, arg) |
ff7c6d11 XL |
639 | }).collect(); |
640 | ||
641 | ||
a1dfa0c6 XL |
642 | let callee_ty = instance.as_ref().unwrap().ty(bx.tcx()); |
643 | bx.codegen_intrinsic_call(callee_ty, &fn_ty, &args, dest, | |
644 | terminator.source_info.span); | |
cc61c64b XL |
645 | |
646 | if let ReturnDest::IndirectOperand(dst, _) = ret_dest { | |
a1dfa0c6 | 647 | self.store_return(&mut bx, ret_dest, &fn_ty.ret, dst.llval); |
cc61c64b XL |
648 | } |
649 | ||
650 | if let Some((_, target)) = *destination { | |
a1dfa0c6 | 651 | funclet_br(self, &mut bx, target); |
cc61c64b | 652 | } else { |
2c00a5a8 | 653 | bx.unreachable(); |
54a0048b | 654 | } |
cc61c64b XL |
655 | |
656 | return; | |
657 | } | |
658 | ||
ff7c6d11 XL |
659 | // Split the rust-call tupled arguments off. |
660 | let (first_args, untuple) = if abi == Abi::RustCall && !args.is_empty() { | |
661 | let (tup, args) = args.split_last().unwrap(); | |
662 | (args, Some(tup)) | |
663 | } else { | |
664 | (&args[..], None) | |
665 | }; | |
666 | ||
a1dfa0c6 XL |
667 | 'make_args: for (i, arg) in first_args.iter().enumerate() { |
668 | let mut op = self.codegen_operand(&mut bx, arg); | |
669 | ||
ff7c6d11 | 670 | if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { |
a1dfa0c6 XL |
671 | if let Pair(..) = op.val { |
672 | // In the case of Rc<Self>, we need to explicitly pass a | |
673 | // *mut RcBox<Self> with a Scalar (not ScalarPair) ABI. This is a hack | |
674 | // that is understood elsewhere in the compiler as a method on | |
675 | // `dyn Trait`. | |
676 | // To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until | |
677 | // we get a value of a built-in pointer type | |
678 | 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() | |
679 | && !op.layout.ty.is_region_ptr() | |
680 | { | |
681 | 'iter_fields: for i in 0..op.layout.fields.count() { | |
682 | let field = op.extract_field(&mut bx, i); | |
683 | if !field.layout.is_zst() { | |
684 | // we found the one non-zero-sized field that is allowed | |
685 | // now find *its* non-zero-sized field, or stop if it's a | |
686 | // pointer | |
687 | op = field; | |
688 | continue 'descend_newtypes | |
689 | } | |
690 | } | |
691 | ||
692 | span_bug!(span, "receiver has no non-zero-sized fields {:?}", op); | |
693 | } | |
694 | ||
695 | // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its | |
696 | // data pointer and vtable. Look up the method in the vtable, and pass | |
697 | // the data pointer as the first argument | |
698 | match op.val { | |
699 | Pair(data_ptr, meta) => { | |
700 | llfn = Some(meth::VirtualIndex::from_index(idx) | |
701 | .get_fn(&mut bx, meta, &fn_ty)); | |
702 | llargs.push(data_ptr); | |
703 | continue 'make_args | |
704 | } | |
705 | other => bug!("expected a Pair, got {:?}", other) | |
706 | } | |
707 | } else if let Ref(data_ptr, Some(meta), _) = op.val { | |
708 | // by-value dynamic dispatch | |
ff7c6d11 | 709 | llfn = Some(meth::VirtualIndex::from_index(idx) |
a1dfa0c6 | 710 | .get_fn(&mut bx, meta, &fn_ty)); |
ff7c6d11 XL |
711 | llargs.push(data_ptr); |
712 | continue; | |
a1dfa0c6 XL |
713 | } else { |
714 | span_bug!(span, "can't codegen a virtual call on {:?}", op); | |
ff7c6d11 XL |
715 | } |
716 | } | |
717 | ||
718 | // The callee needs to own the argument memory if we pass it | |
719 | // by-ref, so make a local copy of non-immediate constants. | |
720 | match (arg, op.val) { | |
b7449926 XL |
721 | (&mir::Operand::Copy(_), Ref(_, None, _)) | |
722 | (&mir::Operand::Constant(_), Ref(_, None, _)) => { | |
a1dfa0c6 XL |
723 | let tmp = PlaceRef::alloca(&mut bx, op.layout, "const"); |
724 | op.val.store(&mut bx, tmp); | |
b7449926 | 725 | op.val = Ref(tmp.llval, None, tmp.align); |
ff7c6d11 XL |
726 | } |
727 | _ => {} | |
728 | } | |
729 | ||
a1dfa0c6 | 730 | self.codegen_argument(&mut bx, op, &mut llargs, &fn_ty.args[i]); |
ff7c6d11 XL |
731 | } |
732 | if let Some(tup) = untuple { | |
a1dfa0c6 | 733 | self.codegen_arguments_untupled(&mut bx, tup, &mut llargs, |
ff7c6d11 XL |
734 | &fn_ty.args[first_args.len()..]) |
735 | } | |
736 | ||
cc61c64b XL |
737 | let fn_ptr = match (llfn, instance) { |
738 | (Some(llfn), _) => llfn, | |
a1dfa0c6 | 739 | (None, Some(instance)) => bx.get_fn(instance), |
cc61c64b | 740 | _ => span_bug!(span, "no llfn for call"), |
54a0048b SL |
741 | }; |
742 | ||
a1dfa0c6 | 743 | do_call(self, &mut bx, fn_ty, fn_ptr, &llargs, |
ff7c6d11 | 744 | destination.as_ref().map(|&(_, target)| (ret_dest, target)), |
7cac9316 | 745 | cleanup); |
54a0048b | 746 | } |
ea8adc8c | 747 | mir::TerminatorKind::GeneratorDrop | |
94b46f34 | 748 | mir::TerminatorKind::Yield { .. } => bug!("generator ops in codegen"), |
2c00a5a8 | 749 | mir::TerminatorKind::FalseEdges { .. } | |
94b46f34 | 750 | mir::TerminatorKind::FalseUnwind { .. } => bug!("borrowck false edges in codegen"), |
54a0048b SL |
751 | } |
752 | } | |
753 | ||
a1dfa0c6 XL |
754 | fn codegen_argument( |
755 | &mut self, | |
756 | bx: &mut Bx, | |
757 | op: OperandRef<'tcx, Bx::Value>, | |
758 | llargs: &mut Vec<Bx::Value>, | |
759 | arg: &ArgType<'tcx, Ty<'tcx>> | |
760 | ) { | |
54a0048b SL |
761 | // Fill padding with undef value, where applicable. |
762 | if let Some(ty) = arg.pad { | |
a1dfa0c6 | 763 | llargs.push(bx.const_undef(bx.reg_backend_type(&ty))) |
54a0048b SL |
764 | } |
765 | ||
766 | if arg.is_ignore() { | |
767 | return; | |
768 | } | |
769 | ||
ff7c6d11 XL |
770 | if let PassMode::Pair(..) = arg.mode { |
771 | match op.val { | |
772 | Pair(a, b) => { | |
773 | llargs.push(a); | |
774 | llargs.push(b); | |
775 | return; | |
776 | } | |
b7449926 XL |
777 | _ => bug!("codegen_argument: {:?} invalid for pair argument", op) |
778 | } | |
779 | } else if arg.is_unsized_indirect() { | |
780 | match op.val { | |
781 | Ref(a, Some(b), _) => { | |
782 | llargs.push(a); | |
783 | llargs.push(b); | |
784 | return; | |
785 | } | |
786 | _ => bug!("codegen_argument: {:?} invalid for unsized indirect argument", op) | |
ff7c6d11 XL |
787 | } |
788 | } | |
789 | ||
54a0048b | 790 | // Force by-ref if we have to load through a cast pointer. |
32a655c1 | 791 | let (mut llval, align, by_ref) = match op.val { |
3157f602 | 792 | Immediate(_) | Pair(..) => { |
ff7c6d11 | 793 | match arg.mode { |
b7449926 | 794 | PassMode::Indirect(..) | PassMode::Cast(_) => { |
2c00a5a8 XL |
795 | let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); |
796 | op.val.store(bx, scratch); | |
ff7c6d11 XL |
797 | (scratch.llval, scratch.align, true) |
798 | } | |
799 | _ => { | |
a1dfa0c6 | 800 | (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false) |
ff7c6d11 | 801 | } |
3157f602 | 802 | } |
54a0048b | 803 | } |
b7449926 | 804 | Ref(llval, _, align) => { |
a1dfa0c6 | 805 | if arg.is_indirect() && align < arg.layout.align.abi { |
ff7c6d11 XL |
806 | // `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I |
807 | // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't | |
808 | // have scary latent bugs around. | |
809 | ||
2c00a5a8 | 810 | let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); |
a1dfa0c6 XL |
811 | base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align, |
812 | op.layout, MemFlags::empty()); | |
ff7c6d11 XL |
813 | (scratch.llval, scratch.align, true) |
814 | } else { | |
815 | (llval, align, true) | |
816 | } | |
32a655c1 | 817 | } |
54a0048b SL |
818 | }; |
819 | ||
820 | if by_ref && !arg.is_indirect() { | |
821 | // Have to load the argument, maybe while casting it. | |
ff7c6d11 | 822 | if let PassMode::Cast(ty) = arg.mode { |
a1dfa0c6 XL |
823 | let addr = bx.pointercast(llval, bx.type_ptr_to( |
824 | bx.cast_backend_type(&ty)) | |
825 | ); | |
826 | llval = bx.load(addr, align.min(arg.layout.align.abi)); | |
54a0048b | 827 | } else { |
ff7c6d11 XL |
828 | // We can't use `PlaceRef::load` here because the argument |
829 | // may have a type we don't treat as immediate, but the ABI | |
830 | // used for this call is passing it by-value. In that case, | |
831 | // the load would just produce `OperandValue::Ref` instead | |
832 | // of the `OperandValue::Immediate` we need for the call. | |
2c00a5a8 | 833 | llval = bx.load(llval, align); |
ff7c6d11 XL |
834 | if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { |
835 | if scalar.is_bool() { | |
2c00a5a8 | 836 | bx.range_metadata(llval, 0..2); |
ff7c6d11 XL |
837 | } |
838 | } | |
839 | // We store bools as i8 so we need to truncate to i1. | |
2c00a5a8 | 840 | llval = base::to_immediate(bx, llval, arg.layout); |
54a0048b SL |
841 | } |
842 | } | |
843 | ||
844 | llargs.push(llval); | |
845 | } | |
846 | ||
a1dfa0c6 XL |
847 | fn codegen_arguments_untupled( |
848 | &mut self, | |
849 | bx: &mut Bx, | |
850 | operand: &mir::Operand<'tcx>, | |
851 | llargs: &mut Vec<Bx::Value>, | |
852 | args: &[ArgType<'tcx, Ty<'tcx>>] | |
853 | ) { | |
94b46f34 | 854 | let tuple = self.codegen_operand(bx, operand); |
54a0048b | 855 | |
a7813a04 | 856 | // Handle both by-ref and immediate tuples. |
b7449926 | 857 | if let Ref(llval, None, align) = tuple.val { |
ff7c6d11 XL |
858 | let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align); |
859 | for i in 0..tuple.layout.fields.count() { | |
2c00a5a8 | 860 | let field_ptr = tuple_ptr.project_field(bx, i); |
a1dfa0c6 XL |
861 | let field = bx.load_operand(field_ptr); |
862 | self.codegen_argument(bx, field, llargs, &args[i]); | |
3157f602 | 863 | } |
b7449926 XL |
864 | } else if let Ref(_, Some(_), _) = tuple.val { |
865 | bug!("closure arguments must be sized") | |
ff7c6d11 XL |
866 | } else { |
867 | // If the tuple is immediate, the elements are as well. | |
868 | for i in 0..tuple.layout.fields.count() { | |
2c00a5a8 | 869 | let op = tuple.extract_field(bx, i); |
94b46f34 | 870 | self.codegen_argument(bx, op, llargs, &args[i]); |
a7813a04 | 871 | } |
54a0048b SL |
872 | } |
873 | } | |
874 | ||
a1dfa0c6 XL |
875 | fn get_personality_slot( |
876 | &mut self, | |
877 | bx: &mut Bx | |
878 | ) -> PlaceRef<'tcx, Bx::Value> { | |
879 | let cx = bx.cx(); | |
ff7c6d11 | 880 | if let Some(slot) = self.personality_slot { |
54a0048b SL |
881 | slot |
882 | } else { | |
a1dfa0c6 XL |
883 | let layout = cx.layout_of(cx.tcx().intern_tup(&[ |
884 | cx.tcx().mk_mut_ptr(cx.tcx().types.u8), | |
885 | cx.tcx().types.i32 | |
0531ce1d | 886 | ])); |
2c00a5a8 | 887 | let slot = PlaceRef::alloca(bx, layout, "personalityslot"); |
ff7c6d11 | 888 | self.personality_slot = Some(slot); |
32a655c1 | 889 | slot |
54a0048b SL |
890 | } |
891 | } | |
892 | ||
3157f602 | 893 | /// Return the landingpad wrapper around the given basic block |
54a0048b SL |
894 | /// |
895 | /// No-op in MSVC SEH scheme. | |
a1dfa0c6 XL |
896 | fn landing_pad_to( |
897 | &mut self, | |
898 | target_bb: mir::BasicBlock | |
899 | ) -> Bx::BasicBlock { | |
3157f602 XL |
900 | if let Some(block) = self.landing_pads[target_bb] { |
901 | return block; | |
902 | } | |
903 | ||
cc61c64b XL |
904 | let block = self.blocks[target_bb]; |
905 | let landing_pad = self.landing_pad_uncached(block); | |
906 | self.landing_pads[target_bb] = Some(landing_pad); | |
907 | landing_pad | |
908 | } | |
909 | ||
a1dfa0c6 XL |
910 | fn landing_pad_uncached( |
911 | &mut self, | |
912 | target_bb: Bx::BasicBlock | |
913 | ) -> Bx::BasicBlock { | |
2c00a5a8 | 914 | if base::wants_msvc_seh(self.cx.sess()) { |
7cac9316 | 915 | span_bug!(self.mir.span, "landing pad was not inserted?") |
54a0048b | 916 | } |
3157f602 | 917 | |
a1dfa0c6 | 918 | let mut bx = self.new_block("cleanup"); |
3157f602 | 919 | |
2c00a5a8 | 920 | let llpersonality = self.cx.eh_personality(); |
ff7c6d11 | 921 | let llretty = self.landing_pad_type(); |
2c00a5a8 XL |
922 | let lp = bx.landing_pad(llretty, llpersonality, 1); |
923 | bx.set_cleanup(lp); | |
ff7c6d11 | 924 | |
a1dfa0c6 XL |
925 | let slot = self.get_personality_slot(&mut bx); |
926 | slot.storage_live(&mut bx); | |
927 | Pair(bx.extract_value(lp, 0), bx.extract_value(lp, 1)).store(&mut bx, slot); | |
ff7c6d11 | 928 | |
2c00a5a8 XL |
929 | bx.br(target_bb); |
930 | bx.llbb() | |
54a0048b SL |
931 | } |
932 | ||
a1dfa0c6 | 933 | fn landing_pad_type(&self) -> Bx::Type { |
2c00a5a8 | 934 | let cx = self.cx; |
a1dfa0c6 | 935 | cx.type_struct(&[cx.type_i8p(), cx.type_i32()], false) |
ff7c6d11 XL |
936 | } |
937 | ||
a1dfa0c6 XL |
938 | fn unreachable_block( |
939 | &mut self | |
940 | ) -> Bx::BasicBlock { | |
54a0048b | 941 | self.unreachable_block.unwrap_or_else(|| { |
a1dfa0c6 XL |
942 | let mut bx = self.new_block("unreachable"); |
943 | bx.unreachable(); | |
944 | self.unreachable_block = Some(bx.llbb()); | |
945 | bx.llbb() | |
54a0048b SL |
946 | }) |
947 | } | |
948 | ||
a1dfa0c6 XL |
949 | pub fn new_block(&self, name: &str) -> Bx { |
950 | Bx::new_block(self.cx, self.llfn, name) | |
32a655c1 SL |
951 | } |
952 | ||
a1dfa0c6 XL |
953 | pub fn build_block( |
954 | &self, | |
955 | bb: mir::BasicBlock | |
956 | ) -> Bx { | |
957 | let mut bx = Bx::with_cx(self.cx); | |
2c00a5a8 XL |
958 | bx.position_at_end(self.blocks[bb]); |
959 | bx | |
54a0048b SL |
960 | } |
961 | ||
a1dfa0c6 XL |
962 | fn make_return_dest( |
963 | &mut self, | |
964 | bx: &mut Bx, | |
965 | dest: &mir::Place<'tcx>, | |
966 | fn_ret: &ArgType<'tcx, Ty<'tcx>>, | |
967 | llargs: &mut Vec<Bx::Value>, is_intrinsic: bool | |
968 | ) -> ReturnDest<'tcx, Bx::Value> { | |
54a0048b | 969 | // If the return is ignored, we can just return a do-nothing ReturnDest |
ff7c6d11 | 970 | if fn_ret.is_ignore() { |
54a0048b SL |
971 | return ReturnDest::Nothing; |
972 | } | |
ff7c6d11 | 973 | let dest = if let mir::Place::Local(index) = *dest { |
3157f602 | 974 | match self.locals[index] { |
ff7c6d11 | 975 | LocalRef::Place(dest) => dest, |
b7449926 | 976 | LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), |
3157f602 | 977 | LocalRef::Operand(None) => { |
ff7c6d11 | 978 | // Handle temporary places, specifically Operand ones, as |
3157f602 | 979 | // they don't have allocas |
ff7c6d11 | 980 | return if fn_ret.is_indirect() { |
3157f602 XL |
981 | // Odd, but possible, case, we have an operand temporary, |
982 | // but the calling convention has an indirect return. | |
2c00a5a8 XL |
983 | let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); |
984 | tmp.storage_live(bx); | |
32a655c1 | 985 | llargs.push(tmp.llval); |
ff7c6d11 | 986 | ReturnDest::IndirectOperand(tmp, index) |
3157f602 XL |
987 | } else if is_intrinsic { |
988 | // Currently, intrinsics always need a location to store | |
989 | // the result. so we create a temporary alloca for the | |
990 | // result | |
2c00a5a8 XL |
991 | let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); |
992 | tmp.storage_live(bx); | |
ff7c6d11 | 993 | ReturnDest::IndirectOperand(tmp, index) |
3157f602 XL |
994 | } else { |
995 | ReturnDest::DirectOperand(index) | |
996 | }; | |
997 | } | |
998 | LocalRef::Operand(Some(_)) => { | |
ff7c6d11 | 999 | bug!("place local already assigned to"); |
54a0048b SL |
1000 | } |
1001 | } | |
3157f602 | 1002 | } else { |
94b46f34 | 1003 | self.codegen_place(bx, dest) |
54a0048b | 1004 | }; |
ff7c6d11 | 1005 | if fn_ret.is_indirect() { |
a1dfa0c6 | 1006 | if dest.align < dest.layout.align.abi { |
ff7c6d11 XL |
1007 | // Currently, MIR code generation does not create calls |
1008 | // that store directly to fields of packed structs (in | |
1009 | // fact, the calls it creates write only to temps), | |
1010 | // | |
1011 | // If someone changes that, please update this code path | |
1012 | // to create a temporary. | |
1013 | span_bug!(self.mir.span, "can't directly store to unaligned value"); | |
8bb4bdeb | 1014 | } |
ff7c6d11 XL |
1015 | llargs.push(dest.llval); |
1016 | ReturnDest::Nothing | |
54a0048b | 1017 | } else { |
ff7c6d11 | 1018 | ReturnDest::Store(dest) |
54a0048b SL |
1019 | } |
1020 | } | |
1021 | ||
a1dfa0c6 XL |
1022 | fn codegen_transmute( |
1023 | &mut self, | |
1024 | bx: &mut Bx, | |
1025 | src: &mir::Operand<'tcx>, | |
1026 | dst: &mir::Place<'tcx> | |
1027 | ) { | |
ff7c6d11 | 1028 | if let mir::Place::Local(index) = *dst { |
32a655c1 | 1029 | match self.locals[index] { |
94b46f34 | 1030 | LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), |
b7449926 | 1031 | LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), |
32a655c1 | 1032 | LocalRef::Operand(None) => { |
a1dfa0c6 | 1033 | let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst)); |
ff7c6d11 | 1034 | assert!(!dst_layout.ty.has_erasable_regions()); |
2c00a5a8 XL |
1035 | let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp"); |
1036 | place.storage_live(bx); | |
94b46f34 | 1037 | self.codegen_transmute_into(bx, src, place); |
a1dfa0c6 | 1038 | let op = bx.load_operand(place); |
2c00a5a8 | 1039 | place.storage_dead(bx); |
32a655c1 SL |
1040 | self.locals[index] = LocalRef::Operand(Some(op)); |
1041 | } | |
ff7c6d11 XL |
1042 | LocalRef::Operand(Some(op)) => { |
1043 | assert!(op.layout.is_zst(), | |
32a655c1 SL |
1044 | "assigning to initialized SSAtemp"); |
1045 | } | |
1046 | } | |
1047 | } else { | |
94b46f34 XL |
1048 | let dst = self.codegen_place(bx, dst); |
1049 | self.codegen_transmute_into(bx, src, dst); | |
32a655c1 SL |
1050 | } |
1051 | } | |
1052 | ||
a1dfa0c6 XL |
1053 | fn codegen_transmute_into( |
1054 | &mut self, | |
1055 | bx: &mut Bx, | |
1056 | src: &mir::Operand<'tcx>, | |
1057 | dst: PlaceRef<'tcx, Bx::Value> | |
1058 | ) { | |
94b46f34 | 1059 | let src = self.codegen_operand(bx, src); |
a1dfa0c6 XL |
1060 | let llty = bx.backend_type(src.layout); |
1061 | let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); | |
1062 | let align = src.layout.align.abi.min(dst.align); | |
2c00a5a8 | 1063 | src.val.store(bx, PlaceRef::new_sized(cast_ptr, src.layout, align)); |
54a0048b SL |
1064 | } |
1065 | ||
3157f602 | 1066 | |
54a0048b | 1067 | // Stores the return value of a function call into it's final location. |
a1dfa0c6 XL |
1068 | fn store_return( |
1069 | &mut self, | |
1070 | bx: &mut Bx, | |
1071 | dest: ReturnDest<'tcx, Bx::Value>, | |
1072 | ret_ty: &ArgType<'tcx, Ty<'tcx>>, | |
1073 | llval: Bx::Value | |
1074 | ) { | |
54a0048b SL |
1075 | use self::ReturnDest::*; |
1076 | ||
1077 | match dest { | |
1078 | Nothing => (), | |
a1dfa0c6 | 1079 | Store(dst) => bx.store_arg_ty(&ret_ty, llval, dst), |
3157f602 | 1080 | IndirectOperand(tmp, index) => { |
a1dfa0c6 | 1081 | let op = bx.load_operand(tmp); |
2c00a5a8 | 1082 | tmp.storage_dead(bx); |
3157f602 | 1083 | self.locals[index] = LocalRef::Operand(Some(op)); |
54a0048b | 1084 | } |
3157f602 XL |
1085 | DirectOperand(index) => { |
1086 | // If there is a cast, we have to store and reload. | |
ff7c6d11 | 1087 | let op = if let PassMode::Cast(_) = ret_ty.mode { |
2c00a5a8 XL |
1088 | let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret"); |
1089 | tmp.storage_live(bx); | |
a1dfa0c6 XL |
1090 | bx.store_arg_ty(&ret_ty, llval, tmp); |
1091 | let op = bx.load_operand(tmp); | |
2c00a5a8 | 1092 | tmp.storage_dead(bx); |
ff7c6d11 | 1093 | op |
54a0048b | 1094 | } else { |
2c00a5a8 | 1095 | OperandRef::from_immediate_or_packed_pair(bx, llval, ret_ty.layout) |
54a0048b | 1096 | }; |
3157f602 | 1097 | self.locals[index] = LocalRef::Operand(Some(op)); |
54a0048b SL |
1098 | } |
1099 | } | |
1100 | } | |
1101 | } | |
1102 | ||
a1dfa0c6 | 1103 | enum ReturnDest<'tcx, V> { |
54a0048b SL |
1104 | // Do nothing, the return value is indirect or ignored |
1105 | Nothing, | |
1106 | // Store the return value to the pointer | |
a1dfa0c6 | 1107 | Store(PlaceRef<'tcx, V>), |
ff7c6d11 | 1108 | // Stores an indirect return value to an operand local place |
a1dfa0c6 | 1109 | IndirectOperand(PlaceRef<'tcx, V>, mir::Local), |
ff7c6d11 | 1110 | // Stores a direct return value to an operand local place |
3157f602 | 1111 | DirectOperand(mir::Local) |
54a0048b | 1112 | } |