1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use llvm
::{self, ValueRef, BasicBlockRef}
;
12 use rustc
::middle
::lang_items
;
13 use rustc
::middle
::const_val
::{ConstEvalErr, ConstInt, ErrKind}
;
14 use rustc
::ty
::{self, TypeFoldable}
;
15 use rustc
::ty
::layout
::{self, LayoutTyper}
;
17 use abi
::{Abi, FnType, ArgType}
;
19 use base
::{self, Lifetime}
;
22 use common
::{self, C_bool, C_str_slice, C_struct, C_u32, C_undef}
;
24 use machine
::llalign_of_min
;
30 use syntax
::symbol
::Symbol
;
34 use super::{MirContext, LocalRef}
;
35 use super::constant
::Const
;
36 use super::lvalue
::{Alignment, LvalueRef}
;
37 use super::operand
::OperandRef
;
38 use super::operand
::OperandValue
::{Pair, Ref, Immediate}
;
40 impl<'a
, 'tcx
> MirContext
<'a
, 'tcx
> {
41 pub fn trans_block(&mut self, bb
: mir
::BasicBlock
) {
42 let mut bcx
= self.get_builder(bb
);
43 let data
= &self.mir
[bb
];
45 debug
!("trans_block({:?}={:?})", bb
, data
);
47 for statement
in &data
.statements
{
48 bcx
= self.trans_statement(bcx
, statement
);
51 self.trans_terminator(bcx
, bb
, data
.terminator());
54 fn trans_terminator(&mut self,
55 mut bcx
: Builder
<'a
, 'tcx
>,
57 terminator
: &mir
::Terminator
<'tcx
>)
59 debug
!("trans_terminator: {:?}", terminator
);
61 // Create the cleanup bundle, if needed.
63 let span
= terminator
.source_info
.span
;
64 let funclet_bb
= self.cleanup_kinds
[bb
].funclet_bb(bb
);
65 let funclet
= funclet_bb
.and_then(|funclet_bb
| self.funclets
[funclet_bb
].as_ref());
67 let cleanup_pad
= funclet
.map(|lp
| lp
.cleanuppad());
68 let cleanup_bundle
= funclet
.map(|l
| l
.bundle());
70 let lltarget
= |this
: &mut Self, target
: mir
::BasicBlock
| {
71 let lltarget
= this
.blocks
[target
];
72 let target_funclet
= this
.cleanup_kinds
[target
].funclet_bb(target
);
73 match (funclet_bb
, target_funclet
) {
74 (None
, None
) => (lltarget
, false),
76 if f
== t_f
|| !base
::wants_msvc_seh(tcx
.sess
)
79 // jump *into* cleanup - need a landing pad if GNU
80 (this
.landing_pad_to(target
), false)
82 (Some(_
), None
) => span_bug
!(span
, "{:?} - jump out of cleanup?", terminator
),
83 (Some(_
), Some(_
)) => {
84 (this
.landing_pad_to(target
), true)
89 let llblock
= |this
: &mut Self, target
: mir
::BasicBlock
| {
90 let (lltarget
, is_cleanupret
) = lltarget(this
, target
);
92 // MSVC cross-funclet jump - need a trampoline
94 debug
!("llblock: creating cleanup trampoline for {:?}", target
);
95 let name
= &format
!("{:?}_cleanup_trampoline_{:?}", bb
, target
);
96 let trampoline
= this
.new_block(name
);
97 trampoline
.cleanup_ret(cleanup_pad
.unwrap(), Some(lltarget
));
104 let funclet_br
= |this
: &mut Self, bcx
: Builder
, target
: mir
::BasicBlock
| {
105 let (lltarget
, is_cleanupret
) = lltarget(this
, target
);
107 // micro-optimization: generate a `ret` rather than a jump
109 bcx
.cleanup_ret(cleanup_pad
.unwrap(), Some(lltarget
));
117 bcx
: Builder
<'a
, 'tcx
>,
121 destination
: Option
<(ReturnDest
, ty
::Ty
<'tcx
>, mir
::BasicBlock
)>,
122 cleanup
: Option
<mir
::BasicBlock
>
124 if let Some(cleanup
) = cleanup
{
125 let ret_bcx
= if let Some((_
, _
, target
)) = destination
{
128 this
.unreachable_block()
130 let invokeret
= bcx
.invoke(fn_ptr
,
133 llblock(this
, cleanup
),
135 fn_ty
.apply_attrs_callsite(invokeret
);
137 if let Some((ret_dest
, ret_ty
, target
)) = destination
{
138 let ret_bcx
= this
.get_builder(target
);
139 this
.set_debug_loc(&ret_bcx
, terminator
.source_info
);
140 let op
= OperandRef
{
141 val
: Immediate(invokeret
),
144 this
.store_return(&ret_bcx
, ret_dest
, &fn_ty
.ret
, op
);
147 let llret
= bcx
.call(fn_ptr
, &llargs
, cleanup_bundle
);
148 fn_ty
.apply_attrs_callsite(llret
);
150 if let Some((ret_dest
, ret_ty
, target
)) = destination
{
151 let op
= OperandRef
{
152 val
: Immediate(llret
),
155 this
.store_return(&bcx
, ret_dest
, &fn_ty
.ret
, op
);
156 funclet_br(this
, bcx
, target
);
163 self.set_debug_loc(&bcx
, terminator
.source_info
);
164 match terminator
.kind
{
165 mir
::TerminatorKind
::Resume
=> {
166 if let Some(cleanup_pad
) = cleanup_pad
{
167 bcx
.cleanup_ret(cleanup_pad
, None
);
169 let ps
= self.get_personality_slot(&bcx
);
170 let lp
= bcx
.load(ps
, None
);
171 Lifetime
::End
.call(&bcx
, ps
);
172 if !bcx
.sess().target
.target
.options
.custom_unwind_resume
{
175 let exc_ptr
= bcx
.extract_value(lp
, 0);
176 bcx
.call(bcx
.ccx
.eh_unwind_resume(), &[exc_ptr
], cleanup_bundle
);
182 mir
::TerminatorKind
::Goto { target }
=> {
183 funclet_br(self, bcx
, target
);
186 mir
::TerminatorKind
::SwitchInt { ref discr, switch_ty, ref values, ref targets }
=> {
187 let discr
= self.trans_operand(&bcx
, discr
);
188 if switch_ty
== bcx
.tcx().types
.bool
{
189 let lltrue
= llblock(self, targets
[0]);
190 let llfalse
= llblock(self, targets
[1]);
191 if let [ConstInt
::U8(0)] = values
[..] {
192 bcx
.cond_br(discr
.immediate(), llfalse
, lltrue
);
194 bcx
.cond_br(discr
.immediate(), lltrue
, llfalse
);
197 let (otherwise
, targets
) = targets
.split_last().unwrap();
198 let switch
= bcx
.switch(discr
.immediate(),
199 llblock(self, *otherwise
), values
.len());
200 for (value
, target
) in values
.iter().zip(targets
) {
201 let val
= Const
::from_constint(bcx
.ccx
, value
);
202 let llbb
= llblock(self, *target
);
203 bcx
.add_case(switch
, val
.llval
, llbb
)
208 mir
::TerminatorKind
::Return
=> {
209 let ret
= self.fn_ty
.ret
;
210 if ret
.is_ignore() || ret
.is_indirect() {
215 let llval
= if let Some(cast_ty
) = ret
.cast
{
216 let op
= match self.locals
[mir
::RETURN_POINTER
] {
217 LocalRef
::Operand(Some(op
)) => op
,
218 LocalRef
::Operand(None
) => bug
!("use of return before def"),
219 LocalRef
::Lvalue(tr_lvalue
) => {
221 val
: Ref(tr_lvalue
.llval
, tr_lvalue
.alignment
),
222 ty
: tr_lvalue
.ty
.to_ty(bcx
.tcx())
226 let llslot
= match op
.val
{
227 Immediate(_
) | Pair(..) => {
228 let llscratch
= bcx
.alloca(ret
.memory_ty(bcx
.ccx
), "ret", None
);
229 self.store_operand(&bcx
, llscratch
, None
, op
);
232 Ref(llval
, align
) => {
233 assert_eq
!(align
, Alignment
::AbiAligned
,
234 "return pointer is unaligned!");
239 bcx
.pointercast(llslot
, cast_ty
.ptr_to()),
240 Some(ret
.layout
.align(bcx
.ccx
).abi() as u32));
243 let op
= self.trans_consume(&bcx
, &mir
::Lvalue
::Local(mir
::RETURN_POINTER
));
244 if let Ref(llval
, align
) = op
.val
{
245 base
::load_ty(&bcx
, llval
, align
, op
.ty
)
247 op
.pack_if_pair(&bcx
).immediate()
253 mir
::TerminatorKind
::Unreachable
=> {
257 mir
::TerminatorKind
::Drop { ref location, target, unwind }
=> {
258 let ty
= location
.ty(&self.mir
, bcx
.tcx()).to_ty(bcx
.tcx());
259 let ty
= self.monomorphize(&ty
);
260 let drop_fn
= monomorphize
::resolve_drop_in_place(bcx
.ccx
.shared(), ty
);
262 if let ty
::InstanceDef
::DropGlue(_
, None
) = drop_fn
.def
{
263 // we don't actually need to drop anything.
264 funclet_br(self, bcx
, target
);
268 let lvalue
= self.trans_lvalue(&bcx
, location
);
269 let fn_ty
= FnType
::of_instance(bcx
.ccx
, &drop_fn
);
270 let (drop_fn
, need_extra
) = match ty
.sty
{
271 ty
::TyDynamic(..) => (meth
::DESTRUCTOR
.get_fn(&bcx
, lvalue
.llextra
),
273 _
=> (callee
::get_fn(bcx
.ccx
, drop_fn
), lvalue
.has_extra())
275 let args
= &[lvalue
.llval
, lvalue
.llextra
][..1 + need_extra
as usize];
276 do_call(self, bcx
, fn_ty
, drop_fn
, args
,
277 Some((ReturnDest
::Nothing
, tcx
.mk_nil(), target
)),
281 mir
::TerminatorKind
::Assert { ref cond, expected, ref msg, target, cleanup }
=> {
282 let cond
= self.trans_operand(&bcx
, cond
).immediate();
283 let mut const_cond
= common
::const_to_opt_u128(cond
, false).map(|c
| c
== 1);
285 // This case can currently arise only from functions marked
286 // with #[rustc_inherit_overflow_checks] and inlined from
287 // another crate (mostly core::num generic/#[inline] fns),
288 // while the current crate doesn't use overflow checks.
289 // NOTE: Unlike binops, negation doesn't have its own
290 // checked operation, just a comparison with the minimum
291 // value, so we have to check for the assert message.
292 if !bcx
.ccx
.check_overflow() {
293 use rustc_const_math
::ConstMathErr
::Overflow
;
294 use rustc_const_math
::Op
::Neg
;
296 if let mir
::AssertMessage
::Math(Overflow(Neg
)) = *msg
{
297 const_cond
= Some(expected
);
301 // Don't translate the panic block if success if known.
302 if const_cond
== Some(expected
) {
303 funclet_br(self, bcx
, target
);
307 // Pass the condition through llvm.expect for branch hinting.
308 let expect
= bcx
.ccx
.get_intrinsic(&"llvm.expect.i1");
309 let cond
= bcx
.call(expect
, &[cond
, C_bool(bcx
.ccx
, expected
)], None
);
311 // Create the failure block and the conditional branch to it.
312 let lltarget
= llblock(self, target
);
313 let panic_block
= self.new_block("panic");
315 bcx
.cond_br(cond
, lltarget
, panic_block
.llbb());
317 bcx
.cond_br(cond
, panic_block
.llbb(), lltarget
);
320 // After this point, bcx is the block for the call to panic.
322 self.set_debug_loc(&bcx
, terminator
.source_info
);
324 // Get the location information.
325 let loc
= bcx
.sess().codemap().lookup_char_pos(span
.lo
);
326 let filename
= Symbol
::intern(&loc
.file
.name
).as_str();
327 let filename
= C_str_slice(bcx
.ccx
, filename
);
328 let line
= C_u32(bcx
.ccx
, loc
.line
as u32);
330 // Put together the arguments to the panic entry point.
331 let (lang_item
, args
, const_err
) = match *msg
{
332 mir
::AssertMessage
::BoundsCheck { ref len, ref index }
=> {
333 let len
= self.trans_operand(&mut bcx
, len
).immediate();
334 let index
= self.trans_operand(&mut bcx
, index
).immediate();
336 let const_err
= common
::const_to_opt_u128(len
, false)
337 .and_then(|len
| common
::const_to_opt_u128(index
, false)
338 .map(|index
| ErrKind
::IndexOutOfBounds
{
343 let file_line
= C_struct(bcx
.ccx
, &[filename
, line
], false);
344 let align
= llalign_of_min(bcx
.ccx
, common
::val_ty(file_line
));
345 let file_line
= consts
::addr_of(bcx
.ccx
,
348 "panic_bounds_check_loc");
349 (lang_items
::PanicBoundsCheckFnLangItem
,
350 vec
![file_line
, index
, len
],
353 mir
::AssertMessage
::Math(ref err
) => {
354 let msg_str
= Symbol
::intern(err
.description()).as_str();
355 let msg_str
= C_str_slice(bcx
.ccx
, msg_str
);
356 let msg_file_line
= C_struct(bcx
.ccx
,
357 &[msg_str
, filename
, line
],
359 let align
= llalign_of_min(bcx
.ccx
, common
::val_ty(msg_file_line
));
360 let msg_file_line
= consts
::addr_of(bcx
.ccx
,
364 (lang_items
::PanicFnLangItem
,
366 Some(ErrKind
::Math(err
.clone())))
370 // If we know we always panic, and the error message
371 // is also constant, then we can produce a warning.
372 if const_cond
== Some(!expected
) {
373 if let Some(err
) = const_err
{
374 let err
= ConstEvalErr{ span: span, kind: err }
;
375 let mut diag
= bcx
.tcx().sess
.struct_span_warn(
376 span
, "this expression will panic at run-time");
377 err
.note(bcx
.tcx(), span
, "expression", &mut diag
);
382 // Obtain the panic entry point.
383 let def_id
= common
::langcall(bcx
.tcx(), Some(span
), "", lang_item
);
384 let instance
= ty
::Instance
::mono(bcx
.tcx(), def_id
);
385 let fn_ty
= FnType
::of_instance(bcx
.ccx
, &instance
);
386 let llfn
= callee
::get_fn(bcx
.ccx
, instance
);
388 // Translate the actual panic invoke/call.
389 do_call(self, bcx
, fn_ty
, llfn
, &args
, None
, cleanup
);
392 mir
::TerminatorKind
::DropAndReplace { .. }
=> {
393 bug
!("undesugared DropAndReplace in trans: {:?}", terminator
);
396 mir
::TerminatorKind
::Call { ref func, ref args, ref destination, cleanup }
=> {
397 // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
398 let callee
= self.trans_operand(&bcx
, func
);
400 let (instance
, mut llfn
, sig
) = match callee
.ty
.sty
{
401 ty
::TyFnDef(def_id
, substs
, sig
) => {
402 (Some(monomorphize
::resolve(bcx
.ccx
.shared(), def_id
, substs
)),
406 ty
::TyFnPtr(sig
) => {
408 Some(callee
.immediate()),
411 _
=> bug
!("{} is not callable", callee
.ty
)
413 let def
= instance
.map(|i
| i
.def
);
414 let sig
= bcx
.tcx().erase_late_bound_regions_and_normalize(&sig
);
417 // Handle intrinsics old trans wants Expr's for, ourselves.
418 let intrinsic
= match def
{
419 Some(ty
::InstanceDef
::Intrinsic(def_id
))
420 => Some(bcx
.tcx().item_name(def_id
).as_str()),
423 let intrinsic
= intrinsic
.as_ref().map(|s
| &s
[..]);
425 if intrinsic
== Some("transmute") {
426 let &(ref dest
, target
) = destination
.as_ref().unwrap();
427 self.trans_transmute(&bcx
, &args
[0], dest
);
428 funclet_br(self, bcx
, target
);
432 let extra_args
= &args
[sig
.inputs().len()..];
433 let extra_args
= extra_args
.iter().map(|op_arg
| {
434 let op_ty
= op_arg
.ty(&self.mir
, bcx
.tcx());
435 self.monomorphize(&op_ty
)
436 }).collect
::<Vec
<_
>>();
438 let fn_ty
= match def
{
439 Some(ty
::InstanceDef
::Virtual(..)) => {
440 FnType
::new_vtable(bcx
.ccx
, sig
, &extra_args
)
442 Some(ty
::InstanceDef
::DropGlue(_
, None
)) => {
443 // empty drop glue - a nop.
444 let &(_
, target
) = destination
.as_ref().unwrap();
445 funclet_br(self, bcx
, target
);
448 _
=> FnType
::new(bcx
.ccx
, sig
, &extra_args
)
451 // The arguments we'll be passing. Plus one to account for outptr, if used.
452 let arg_count
= fn_ty
.args
.len() + fn_ty
.ret
.is_indirect() as usize;
453 let mut llargs
= Vec
::with_capacity(arg_count
);
455 // Prepare the return value destination
456 let ret_dest
= if let Some((ref dest
, _
)) = *destination
{
457 let is_intrinsic
= intrinsic
.is_some();
458 self.make_return_dest(&bcx
, dest
, &fn_ty
.ret
, &mut llargs
,
464 // Split the rust-call tupled arguments off.
465 let (first_args
, untuple
) = if abi
== Abi
::RustCall
&& !args
.is_empty() {
466 let (tup
, args
) = args
.split_last().unwrap();
472 let is_shuffle
= intrinsic
.map_or(false, |name
| {
473 name
.starts_with("simd_shuffle")
476 for arg
in first_args
{
477 // The indices passed to simd_shuffle* in the
478 // third argument must be constant. This is
479 // checked by const-qualification, which also
480 // promotes any complex rvalues to constants.
481 if is_shuffle
&& idx
== 2 {
483 mir
::Operand
::Consume(_
) => {
484 span_bug
!(span
, "shuffle indices must be constant");
486 mir
::Operand
::Constant(ref constant
) => {
487 let val
= self.trans_constant(&bcx
, constant
);
488 llargs
.push(val
.llval
);
495 let op
= self.trans_operand(&bcx
, arg
);
496 self.trans_argument(&bcx
, op
, &mut llargs
, &fn_ty
,
497 &mut idx
, &mut llfn
, &def
);
499 if let Some(tup
) = untuple
{
500 self.trans_arguments_untupled(&bcx
, tup
, &mut llargs
, &fn_ty
,
501 &mut idx
, &mut llfn
, &def
)
504 if intrinsic
.is_some() && intrinsic
!= Some("drop_in_place") {
505 use intrinsic
::trans_intrinsic_call
;
507 let (dest
, llargs
) = match ret_dest
{
508 _
if fn_ty
.ret
.is_indirect() => {
509 (llargs
[0], &llargs
[1..])
511 ReturnDest
::Nothing
=> {
512 (C_undef(fn_ty
.ret
.memory_ty(bcx
.ccx
).ptr_to()), &llargs
[..])
514 ReturnDest
::IndirectOperand(dst
, _
) |
515 ReturnDest
::Store(dst
) => (dst
, &llargs
[..]),
516 ReturnDest
::DirectOperand(_
) =>
517 bug
!("Cannot use direct operand with an intrinsic call")
520 let callee_ty
= common
::instance_ty(
521 bcx
.ccx
.shared(), instance
.as_ref().unwrap());
522 trans_intrinsic_call(&bcx
, callee_ty
, &fn_ty
, &llargs
, dest
,
523 terminator
.source_info
.span
);
525 if let ReturnDest
::IndirectOperand(dst
, _
) = ret_dest
{
526 // Make a fake operand for store_return
527 let op
= OperandRef
{
528 val
: Ref(dst
, Alignment
::AbiAligned
),
531 self.store_return(&bcx
, ret_dest
, &fn_ty
.ret
, op
);
534 if let Some((_
, target
)) = *destination
{
535 funclet_br(self, bcx
, target
);
543 let fn_ptr
= match (llfn
, instance
) {
544 (Some(llfn
), _
) => llfn
,
545 (None
, Some(instance
)) => callee
::get_fn(bcx
.ccx
, instance
),
546 _
=> span_bug
!(span
, "no llfn for call"),
549 do_call(self, bcx
, fn_ty
, fn_ptr
, &llargs
,
550 destination
.as_ref().map(|&(_
, target
)| (ret_dest
, sig
.output(), target
)),
556 fn trans_argument(&mut self,
557 bcx
: &Builder
<'a
, 'tcx
>,
558 op
: OperandRef
<'tcx
>,
559 llargs
: &mut Vec
<ValueRef
>,
560 fn_ty
: &FnType
<'tcx
>,
561 next_idx
: &mut usize,
562 llfn
: &mut Option
<ValueRef
>,
563 def
: &Option
<ty
::InstanceDef
<'tcx
>>) {
564 if let Pair(a
, b
) = op
.val
{
565 // Treat the values in a fat pointer separately.
566 if common
::type_is_fat_ptr(bcx
.ccx
, op
.ty
) {
567 let (ptr
, meta
) = (a
, b
);
569 if let Some(ty
::InstanceDef
::Virtual(_
, idx
)) = *def
{
570 let llmeth
= meth
::VirtualIndex
::from_index(idx
).get_fn(bcx
, meta
);
571 let llty
= fn_ty
.llvm_type(bcx
.ccx
).ptr_to();
572 *llfn
= Some(bcx
.pointercast(llmeth
, llty
));
576 let imm_op
= |x
| OperandRef
{
578 // We won't be checking the type again.
579 ty
: bcx
.tcx().types
.err
581 self.trans_argument(bcx
, imm_op(ptr
), llargs
, fn_ty
, next_idx
, llfn
, def
);
582 self.trans_argument(bcx
, imm_op(meta
), llargs
, fn_ty
, next_idx
, llfn
, def
);
587 let arg
= &fn_ty
.args
[*next_idx
];
590 // Fill padding with undef value, where applicable.
591 if let Some(ty
) = arg
.pad
{
592 llargs
.push(C_undef(ty
));
599 // Force by-ref if we have to load through a cast pointer.
600 let (mut llval
, align
, by_ref
) = match op
.val
{
601 Immediate(_
) | Pair(..) => {
602 if arg
.is_indirect() || arg
.cast
.is_some() {
603 let llscratch
= bcx
.alloca(arg
.memory_ty(bcx
.ccx
), "arg", None
);
604 self.store_operand(bcx
, llscratch
, None
, op
);
605 (llscratch
, Alignment
::AbiAligned
, true)
607 (op
.pack_if_pair(bcx
).immediate(), Alignment
::AbiAligned
, false)
610 Ref(llval
, Alignment
::Packed
) if arg
.is_indirect() => {
611 // `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I
612 // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
613 // have scary latent bugs around.
615 let llscratch
= bcx
.alloca(arg
.memory_ty(bcx
.ccx
), "arg", None
);
616 base
::memcpy_ty(bcx
, llscratch
, llval
, op
.ty
, Some(1));
617 (llscratch
, Alignment
::AbiAligned
, true)
619 Ref(llval
, align
) => (llval
, align
, true)
622 if by_ref
&& !arg
.is_indirect() {
623 // Have to load the argument, maybe while casting it.
624 if arg
.layout
.ty
== bcx
.tcx().types
.bool
{
625 // We store bools as i8 so we need to truncate to i1.
626 llval
= bcx
.load_range_assert(llval
, 0, 2, llvm
::False
, None
);
627 llval
= bcx
.trunc(llval
, Type
::i1(bcx
.ccx
));
628 } else if let Some(ty
) = arg
.cast
{
629 llval
= bcx
.load(bcx
.pointercast(llval
, ty
.ptr_to()),
630 align
.min_with(arg
.layout
.align(bcx
.ccx
).abi() as u32));
632 llval
= bcx
.load(llval
, align
.to_align());
639 fn trans_arguments_untupled(&mut self,
640 bcx
: &Builder
<'a
, 'tcx
>,
641 operand
: &mir
::Operand
<'tcx
>,
642 llargs
: &mut Vec
<ValueRef
>,
643 fn_ty
: &FnType
<'tcx
>,
644 next_idx
: &mut usize,
645 llfn
: &mut Option
<ValueRef
>,
646 def
: &Option
<ty
::InstanceDef
<'tcx
>>) {
647 let tuple
= self.trans_operand(bcx
, operand
);
649 let arg_types
= match tuple
.ty
.sty
{
650 ty
::TyTuple(ref tys
, _
) => tys
,
651 _
=> span_bug
!(self.mir
.span
,
652 "bad final argument to \"rust-call\" fn {:?}", tuple
.ty
)
655 // Handle both by-ref and immediate tuples.
657 Ref(llval
, align
) => {
658 for (n
, &ty
) in arg_types
.iter().enumerate() {
659 let ptr
= LvalueRef
::new_sized_ty(llval
, tuple
.ty
, align
);
660 let (ptr
, align
) = ptr
.trans_field_ptr(bcx
, n
);
661 let val
= if common
::type_is_fat_ptr(bcx
.ccx
, ty
) {
662 let (lldata
, llextra
) = base
::load_fat_ptr(bcx
, ptr
, align
, ty
);
663 Pair(lldata
, llextra
)
665 // trans_argument will load this if it needs to
668 let op
= OperandRef
{
672 self.trans_argument(bcx
, op
, llargs
, fn_ty
, next_idx
, llfn
, def
);
676 Immediate(llval
) => {
677 let l
= bcx
.ccx
.layout_of(tuple
.ty
);
678 let v
= if let layout
::Univariant { ref variant, .. }
= *l
{
681 bug
!("Not a tuple.");
683 for (n
, &ty
) in arg_types
.iter().enumerate() {
684 let mut elem
= bcx
.extract_value(
685 llval
, adt
::struct_llfields_index(v
, n
));
686 // Truncate bools to i1, if needed
687 if ty
.is_bool() && common
::val_ty(elem
) != Type
::i1(bcx
.ccx
) {
688 elem
= bcx
.trunc(elem
, Type
::i1(bcx
.ccx
));
690 // If the tuple is immediate, the elements are as well
691 let op
= OperandRef
{
692 val
: Immediate(elem
),
695 self.trans_argument(bcx
, op
, llargs
, fn_ty
, next_idx
, llfn
, def
);
700 for (n
, &ty
) in arg_types
.iter().enumerate() {
701 let mut elem
= elems
[n
];
702 // Truncate bools to i1, if needed
703 if ty
.is_bool() && common
::val_ty(elem
) != Type
::i1(bcx
.ccx
) {
704 elem
= bcx
.trunc(elem
, Type
::i1(bcx
.ccx
));
706 // Pair is always made up of immediates
707 let op
= OperandRef
{
708 val
: Immediate(elem
),
711 self.trans_argument(bcx
, op
, llargs
, fn_ty
, next_idx
, llfn
, def
);
718 fn get_personality_slot(&mut self, bcx
: &Builder
<'a
, 'tcx
>) -> ValueRef
{
720 if let Some(slot
) = self.llpersonalityslot
{
723 let llretty
= Type
::struct_(ccx
, &[Type
::i8p(ccx
), Type
::i32(ccx
)], false);
724 let slot
= bcx
.alloca(llretty
, "personalityslot", None
);
725 self.llpersonalityslot
= Some(slot
);
730 /// Return the landingpad wrapper around the given basic block
732 /// No-op in MSVC SEH scheme.
733 fn landing_pad_to(&mut self, target_bb
: mir
::BasicBlock
) -> BasicBlockRef
{
734 if let Some(block
) = self.landing_pads
[target_bb
] {
738 let block
= self.blocks
[target_bb
];
739 let landing_pad
= self.landing_pad_uncached(block
);
740 self.landing_pads
[target_bb
] = Some(landing_pad
);
744 fn landing_pad_uncached(&mut self, target_bb
: BasicBlockRef
) -> BasicBlockRef
{
745 if base
::wants_msvc_seh(self.ccx
.sess()) {
746 span_bug
!(self.mir
.span
, "landing pad was not inserted?")
749 let bcx
= self.new_block("cleanup");
752 let llpersonality
= self.ccx
.eh_personality();
753 let llretty
= Type
::struct_(ccx
, &[Type
::i8p(ccx
), Type
::i32(ccx
)], false);
754 let llretval
= bcx
.landing_pad(llretty
, llpersonality
, 1, self.llfn
);
755 bcx
.set_cleanup(llretval
);
756 let slot
= self.get_personality_slot(&bcx
);
757 Lifetime
::Start
.call(&bcx
, slot
);
758 bcx
.store(llretval
, slot
, None
);
763 fn unreachable_block(&mut self) -> BasicBlockRef
{
764 self.unreachable_block
.unwrap_or_else(|| {
765 let bl
= self.new_block("unreachable");
767 self.unreachable_block
= Some(bl
.llbb());
772 pub fn new_block(&self, name
: &str) -> Builder
<'a
, 'tcx
> {
773 Builder
::new_block(self.ccx
, self.llfn
, name
)
776 pub fn get_builder(&self, bb
: mir
::BasicBlock
) -> Builder
<'a
, 'tcx
> {
777 let builder
= Builder
::with_ccx(self.ccx
);
778 builder
.position_at_end(self.blocks
[bb
]);
782 fn make_return_dest(&mut self, bcx
: &Builder
<'a
, 'tcx
>,
783 dest
: &mir
::Lvalue
<'tcx
>, fn_ret_ty
: &ArgType
,
784 llargs
: &mut Vec
<ValueRef
>, is_intrinsic
: bool
) -> ReturnDest
{
785 // If the return is ignored, we can just return a do-nothing ReturnDest
786 if fn_ret_ty
.is_ignore() {
787 return ReturnDest
::Nothing
;
789 let dest
= if let mir
::Lvalue
::Local(index
) = *dest
{
790 let ret_ty
= self.monomorphized_lvalue_ty(dest
);
791 match self.locals
[index
] {
792 LocalRef
::Lvalue(dest
) => dest
,
793 LocalRef
::Operand(None
) => {
794 // Handle temporary lvalues, specifically Operand ones, as
795 // they don't have allocas
796 return if fn_ret_ty
.is_indirect() {
797 // Odd, but possible, case, we have an operand temporary,
798 // but the calling convention has an indirect return.
799 let tmp
= LvalueRef
::alloca(bcx
, ret_ty
, "tmp_ret");
800 llargs
.push(tmp
.llval
);
801 ReturnDest
::IndirectOperand(tmp
.llval
, index
)
802 } else if is_intrinsic
{
803 // Currently, intrinsics always need a location to store
804 // the result. so we create a temporary alloca for the
806 let tmp
= LvalueRef
::alloca(bcx
, ret_ty
, "tmp_ret");
807 ReturnDest
::IndirectOperand(tmp
.llval
, index
)
809 ReturnDest
::DirectOperand(index
)
812 LocalRef
::Operand(Some(_
)) => {
813 bug
!("lvalue local already assigned to");
817 self.trans_lvalue(bcx
, dest
)
819 if fn_ret_ty
.is_indirect() {
820 match dest
.alignment
{
821 Alignment
::AbiAligned
=> {
822 llargs
.push(dest
.llval
);
825 Alignment
::Packed
=> {
826 // Currently, MIR code generation does not create calls
827 // that store directly to fields of packed structs (in
828 // fact, the calls it creates write only to temps),
830 // If someone changes that, please update this code path
831 // to create a temporary.
832 span_bug
!(self.mir
.span
, "can't directly store to unaligned value");
836 ReturnDest
::Store(dest
.llval
)
840 fn trans_transmute(&mut self, bcx
: &Builder
<'a
, 'tcx
>,
841 src
: &mir
::Operand
<'tcx
>,
842 dst
: &mir
::Lvalue
<'tcx
>) {
843 if let mir
::Lvalue
::Local(index
) = *dst
{
844 match self.locals
[index
] {
845 LocalRef
::Lvalue(lvalue
) => self.trans_transmute_into(bcx
, src
, &lvalue
),
846 LocalRef
::Operand(None
) => {
847 let lvalue_ty
= self.monomorphized_lvalue_ty(dst
);
848 assert
!(!lvalue_ty
.has_erasable_regions());
849 let lvalue
= LvalueRef
::alloca(bcx
, lvalue_ty
, "transmute_temp");
850 self.trans_transmute_into(bcx
, src
, &lvalue
);
851 let op
= self.trans_load(bcx
, lvalue
.llval
, lvalue
.alignment
, lvalue_ty
);
852 self.locals
[index
] = LocalRef
::Operand(Some(op
));
854 LocalRef
::Operand(Some(_
)) => {
855 let ty
= self.monomorphized_lvalue_ty(dst
);
856 assert
!(common
::type_is_zero_size(bcx
.ccx
, ty
),
857 "assigning to initialized SSAtemp");
861 let dst
= self.trans_lvalue(bcx
, dst
);
862 self.trans_transmute_into(bcx
, src
, &dst
);
866 fn trans_transmute_into(&mut self, bcx
: &Builder
<'a
, 'tcx
>,
867 src
: &mir
::Operand
<'tcx
>,
868 dst
: &LvalueRef
<'tcx
>) {
869 let val
= self.trans_operand(bcx
, src
);
870 let llty
= type_of
::type_of(bcx
.ccx
, val
.ty
);
871 let cast_ptr
= bcx
.pointercast(dst
.llval
, llty
.ptr_to());
872 let in_type
= val
.ty
;
873 let out_type
= dst
.ty
.to_ty(bcx
.tcx());
874 let llalign
= cmp
::min(bcx
.ccx
.align_of(in_type
), bcx
.ccx
.align_of(out_type
));
875 self.store_operand(bcx
, cast_ptr
, Some(llalign
), val
);
879 // Stores the return value of a function call into it's final location.
880 fn store_return(&mut self,
881 bcx
: &Builder
<'a
, 'tcx
>,
883 ret_ty
: &ArgType
<'tcx
>,
884 op
: OperandRef
<'tcx
>) {
885 use self::ReturnDest
::*;
889 Store(dst
) => ret_ty
.store(bcx
, op
.immediate(), dst
),
890 IndirectOperand(tmp
, index
) => {
891 let op
= self.trans_load(bcx
, tmp
, Alignment
::AbiAligned
, op
.ty
);
892 self.locals
[index
] = LocalRef
::Operand(Some(op
));
894 DirectOperand(index
) => {
895 // If there is a cast, we have to store and reload.
896 let op
= if ret_ty
.cast
.is_some() {
897 let tmp
= LvalueRef
::alloca(bcx
, op
.ty
, "tmp_ret");
898 ret_ty
.store(bcx
, op
.immediate(), tmp
.llval
);
899 self.trans_load(bcx
, tmp
.llval
, tmp
.alignment
, op
.ty
)
901 op
.unpack_if_pair(bcx
)
903 self.locals
[index
] = LocalRef
::Operand(Some(op
));
910 // Do nothing, the return value is indirect or ignored
912 // Store the return value to the pointer
914 // Stores an indirect return value to an operand local lvalue
915 IndirectOperand(ValueRef
, mir
::Local
),
916 // Stores a direct return value to an operand local lvalue
917 DirectOperand(mir
::Local
)