1 // Copyright 2012 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.
13 # Translation of expressions.
15 ## Recommended entry point
17 If you wish to translate an expression, the preferred way to do
20 expr::trans_into(block, expr, Dest) -> block
22 This will generate code that evaluates `expr`, storing the result into
23 `Dest`, which must either be the special flag ignore (throw the result
24 away) or be a pointer to memory of the same type/size as the
25 expression. It returns the resulting basic block. This form will
26 handle all automatic adjustments for you. The value will be moved if
27 its type is linear and copied otherwise.
29 ## Translation to a datum
31 In some cases, `trans_into()` is too narrow of an interface.
32 Generally this occurs either when you know that the result value is
33 going to be a scalar, or when you need to evaluate the expression into
34 some memory location so you can go and inspect it (e.g., assignments,
35 `match` expressions, the `&` operator).
37 In such cases, you want the following function:
39 trans_to_datum(block, expr) -> DatumBlock
41 This function generates code to evaluate the expression and return a
42 `Datum` describing where the result is to be found. This function
43 tries to return its result in the most efficient way possible, without
44 introducing extra copies or sacrificing information. Therefore, for
45 lvalue expressions, you always get a by-ref `Datum` in return that
46 points at the memory for this lvalue. For rvalue expressions, we will
47 return a by-value `Datum` whenever possible, but it is often necessary
48 to allocate a stack slot, store the result of the rvalue in there, and
49 then return a pointer to the slot (see the discussion later on about
50 the different kinds of rvalues).
52 NB: The `trans_to_datum()` function does perform adjustments, but
53 since it returns a pointer to the value "in place" it does not handle
54 moves. If you wish to copy/move the value returned into a new
55 location, you should use the Datum method `store_to()` (move or copy
56 depending on type). You can also use `move_to()` (force move) or
57 `copy_to()` (force copy) for special situations.
59 ## Translating local variables
61 `trans_local_var()` can be used to trans a ref to a local variable
62 that is not an expression. This is needed for captures.
64 ## Ownership and cleanups
66 The current system for cleanups associates required cleanups with
67 block contexts. Block contexts are structured into a tree that
68 resembles the code itself. Not every block context has cleanups
69 associated with it, only those blocks that have a kind of
70 `block_scope`. See `common::block_kind` for more details.
72 If you invoke `trans_into()`, no cleanup is scheduled for you. The
73 value is written into the given destination and is assumed to be owned
76 When you invoke `trans_to_datum()` on an rvalue, the resulting
77 datum/value will have an appropriate cleanup scheduled for the
78 innermost cleanup scope. If you later use `move_to()` or
79 `drop_val()`, this cleanup will be canceled.
81 During the evaluation of an expression, temporary cleanups are created
82 and later canceled. These represent intermediate or partial results
83 which must be cleaned up in the event of task failure.
85 ## Implementation details
87 We divide expressions into three categories, based on how they are most
88 naturally implemented:
95 Lvalues always refer to user-assignable memory locations.
96 Translating those always results in a by-ref datum; this introduces
97 no inefficiencies into the generated code, because all lvalues are
98 naturally addressable.
100 Datum rvalues are rvalues that always generate datums as a result.
101 These are generally scalar results, such as `a+b` where `a` and `b`
104 DPS rvalues are rvalues that, when translated, must be given a
105 memory location to write into (or the Ignore flag). These are
106 generally expressions that produce structural results that are
107 larger than one word (e.g., a struct literal), but also expressions
108 (like `if`) that involve control flow (otherwise we'd have to
111 Finally, statement rvalues are rvalues that always produce a nil
112 return type, such as `while` loops or assignments (`a = b`).
119 use lib::llvm::{ValueRef, llvm, SetLinkage, False};
121 use metadata::csearch;
122 use metadata::cstore;
123 use middle::trans::_match;
124 use middle::trans::adt;
125 use middle::trans::asm;
126 use middle::trans::base::*;
127 use middle::trans::base;
128 use middle::trans::build::*;
129 use middle::trans::callee::DoAutorefArg;
130 use middle::trans::callee;
131 use middle::trans::closure;
132 use middle::trans::common::*;
133 use middle::trans::consts;
134 use middle::trans::controlflow;
135 use middle::trans::datum::*;
136 use middle::trans::debuginfo;
137 use middle::trans::machine;
138 use middle::trans::meth;
139 use middle::trans::inline;
140 use middle::trans::tvec;
141 use middle::trans::type_of;
142 use middle::ty::struct_fields;
143 use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoUnsafe};
144 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
146 use util::common::indenter;
147 use util::ppaux::Repr;
148 use middle::trans::machine::llsize_of;
150 use middle::trans::type_::Type;
152 use std::hashmap::HashMap;
154 use syntax::print::pprust::{expr_to_str};
156 use syntax::ast_map::path_mod;
161 // These are passed around by the code generating functions to track the
162 // destination of a computation's value.
171 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
173 SaveIn(v) => format!("SaveIn({})", ccx.tn.val_to_str(v)),
179 fn drop_and_cancel_clean(bcx: @mut Block, dat: Datum) -> @mut Block {
180 let bcx = dat.drop_val(bcx);
181 dat.cancel_clean(bcx);
185 pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
186 debug!("trans_to_datum(expr={})", bcx.expr_to_str(expr));
189 let mut datum = unpack_datum!(bcx, trans_to_datum_unadjusted(bcx, expr));
190 let adjustment = match bcx.tcx().adjustments.find_copy(&expr.id) {
191 None => { return DatumBlock {bcx: bcx, datum: datum}; }
194 debug!("unadjusted datum: {}", datum.to_str(bcx.ccx()));
197 datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
199 AutoDerefRef(ref adj) => {
200 if adj.autoderefs > 0 {
204 datum.autoderef(bcx, expr.span,
205 expr.id, adj.autoderefs));
208 datum = match adj.autoref {
212 Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr
213 Some(AutoPtr(..)) => {
214 unpack_datum!(bcx, auto_ref(bcx, datum))
216 Some(AutoBorrowVec(..)) => {
217 unpack_datum!(bcx, auto_slice(bcx, adj.autoderefs,
220 Some(AutoBorrowVecRef(..)) => {
221 unpack_datum!(bcx, auto_slice_and_ref(bcx, adj.autoderefs,
224 Some(AutoBorrowFn(..)) => {
225 let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
226 datum.ty, Some(adjustment));
227 unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
229 Some(AutoBorrowObj(..)) => {
230 unpack_datum!(bcx, auto_borrow_obj(
231 bcx, adj.autoderefs, expr, datum))
236 debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
237 return DatumBlock {bcx: bcx, datum: datum};
239 fn auto_ref(bcx: @mut Block, datum: Datum) -> DatumBlock {
240 DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
243 fn auto_borrow_fn(bcx: @mut Block,
245 datum: Datum) -> DatumBlock {
246 // Currently, all closure types are represented precisely the
247 // same, so no runtime adjustment is required, but we still
248 // must patchup the type.
249 DatumBlock {bcx: bcx,
250 datum: Datum {val: datum.val, ty: adjusted_ty,
254 fn auto_slice(bcx: @mut Block,
257 datum: Datum) -> DatumBlock {
258 // This is not the most efficient thing possible; since slices
259 // are two words it'd be better if this were compiled in
260 // 'dest' mode, but I can't find a nice way to structure the
261 // code and keep it DRY that accommodates that use case at the
265 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
267 let (bcx, base, len) =
268 datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1);
270 // this type may have a different region/mutability than the
271 // real one, but it will have the same runtime representation
272 let slice_ty = ty::mk_evec(tcx,
273 ty::mt { ty: unit_ty, mutbl: ast::MutImmutable },
274 ty::vstore_slice(ty::ReStatic));
276 let scratch = scratch_datum(bcx, slice_ty, "__adjust", false);
278 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
279 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
280 DatumBlock {bcx: bcx, datum: scratch}
283 fn add_env(bcx: @mut Block, expr: &ast::Expr, datum: Datum) -> DatumBlock {
284 // This is not the most efficient thing possible; since closures
285 // are two words it'd be better if this were compiled in
286 // 'dest' mode, but I can't find a nice way to structure the
287 // code and keep it DRY that accommodates that use case at the
291 let closure_ty = expr_ty_adjusted(bcx, expr);
292 debug!("add_env(closure_ty={})", closure_ty.repr(tcx));
293 let scratch = scratch_datum(bcx, closure_ty, "__adjust", false);
294 let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
295 assert_eq!(datum.appropriate_mode(bcx.ccx()), ByValue);
296 Store(bcx, datum.to_appropriate_llval(bcx), llfn);
297 let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
298 Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
299 DatumBlock {bcx: bcx, datum: scratch}
302 fn auto_slice_and_ref(bcx: @mut Block,
305 datum: Datum) -> DatumBlock {
306 let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
310 fn auto_borrow_obj(mut bcx: @mut Block,
313 source_datum: Datum) -> DatumBlock {
315 let target_obj_ty = expr_ty_adjusted(bcx, expr);
316 debug!("auto_borrow_obj(target={})",
317 target_obj_ty.repr(tcx));
319 // Extract source store information
320 let (source_store, source_mutbl) = match ty::get(source_datum.ty).sty {
321 ty::ty_trait(_, _, s, m, _) => (s, m),
325 format!("auto_borrow_trait_obj expected a trait, found {}",
326 source_datum.ty.repr(bcx.tcx())));
330 // check if any borrowing is really needed or we could reuse the source_datum instead
331 match ty::get(target_obj_ty).sty {
332 ty::ty_trait(_, _, ty::RegionTraitStore(target_scope), target_mutbl, _) => {
333 if target_mutbl == ast::MutImmutable && target_mutbl == source_mutbl {
335 ty::RegionTraitStore(source_scope) => {
336 if tcx.region_maps.is_subregion_of(target_scope, source_scope) {
337 return DatumBlock { bcx: bcx, datum: source_datum };
348 let scratch = scratch_datum(bcx, target_obj_ty,
349 "__auto_borrow_obj", false);
351 // Convert a @Object, ~Object, or &Object pair into an &Object pair.
353 // Get a pointer to the source object, which is represented as
354 // a (vtable, data) pair.
355 let source_llval = source_datum.to_ref_llval(bcx);
357 // Set the vtable field of the new pair
358 let vtable_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_vtable]);
359 let vtable = Load(bcx, vtable_ptr);
360 Store(bcx, vtable, GEPi(bcx, scratch.val, [0u, abi::trt_field_vtable]));
362 // Load the data for the source, which is either an @T,
363 // ~T, or &T, depending on source_obj_ty.
364 let source_data_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_box]);
365 let source_data = Load(bcx, source_data_ptr); // always a ptr
366 let target_data = match source_store {
367 ty::BoxTraitStore(..) => {
368 // For deref of @T or @mut T, create a dummy datum and
369 // use the datum's deref method. This is more work
370 // than just calling GEPi ourselves, but it ensures
371 // that any write guards will be appropriate
372 // processed. Note that we don't know the type T, so
373 // just substitute `i8`-- it doesn't really matter for
374 // our purposes right now.
379 mutbl: source_mutbl});
381 Datum {val: source_data,
386 source_datum.deref(bcx,
389 derefd_datum.to_rptr(bcx).to_value_llval(bcx)
391 ty::UniqTraitStore(..) => {
392 // For a ~T box, there may or may not be a header,
393 // depending on whether the type T references managed
394 // boxes. However, since we do not *know* the type T
395 // for objects, this presents a hurdle. Our solution is
396 // to load the "borrow offset" from the type descriptor;
397 // this value will either be 0 or sizeof(BoxHeader), depending
400 PointerCast(bcx, source_data, Type::opaque().ptr_to());
401 let lltydesc_ptr_ptr =
402 PointerCast(bcx, vtable,
403 bcx.ccx().tydesc_type.ptr_to().ptr_to());
405 Load(bcx, lltydesc_ptr_ptr);
406 let borrow_offset_ptr =
407 GEPi(bcx, lltydesc_ptr,
408 [0, abi::tydesc_field_borrow_offset]);
410 Load(bcx, borrow_offset_ptr);
411 InBoundsGEP(bcx, llopaque, [borrow_offset])
413 ty::RegionTraitStore(..) => {
417 Store(bcx, target_data,
418 GEPi(bcx, scratch.val, [0u, abi::trt_field_box]));
420 DatumBlock { bcx: bcx, datum: scratch }
424 pub fn trans_into(bcx: @mut Block, expr: &ast::Expr, dest: Dest) -> @mut Block {
425 if bcx.tcx().adjustments.contains_key(&expr.id) {
426 // use trans_to_datum, which is mildly less efficient but
427 // which will perform the adjustments:
428 let datumblock = trans_to_datum(bcx, expr);
430 Ignore => datumblock.bcx,
431 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
435 let ty = expr_ty(bcx, expr);
437 debug!("trans_into_unadjusted(expr={}, dest={})",
438 bcx.expr_to_str(expr),
439 dest.to_str(bcx.ccx()));
440 let _indenter = indenter();
442 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
445 if ty::type_is_voidish(bcx.tcx(), ty) {
452 let kind = bcx.expr_kind(expr);
453 debug!("expr kind = {:?}", kind);
456 let datumblock = trans_lvalue_unadjusted(bcx, expr);
458 Ignore => datumblock.bcx,
459 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
462 ty::RvalueDatumExpr => {
463 let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
465 Ignore => datumblock.drop_val(),
467 // When processing an rvalue, the value will be newly
468 // allocated, so we always `move_to` so as not to
469 // unnecessarily inc ref counts and so forth:
470 SaveIn(lldest) => datumblock.move_to(INIT, lldest)
473 ty::RvalueDpsExpr => {
474 trans_rvalue_dps_unadjusted(bcx, expr, dest)
476 ty::RvalueStmtExpr => {
477 trans_rvalue_stmt_unadjusted(bcx, expr)
482 fn trans_lvalue(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
485 * Translates an lvalue expression, always yielding a by-ref
486 * datum. Generally speaking you should call trans_to_datum()
487 * instead, but sometimes we call trans_lvalue() directly as a
488 * means of asserting that a particular expression is an lvalue. */
490 return match bcx.tcx().adjustments.find(&expr.id) {
491 None => trans_lvalue_unadjusted(bcx, expr),
495 format!("trans_lvalue() called on an expression \
501 fn trans_to_datum_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
503 * Translates an expression into a datum. If this expression
504 * is an rvalue, this will result in a temporary value being
505 * created. If you plan to store the value somewhere else,
506 * you should prefer `trans_into()` instead.
511 debug!("trans_to_datum_unadjusted(expr={})", bcx.expr_to_str(expr));
512 let _indenter = indenter();
514 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
516 match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
518 return trans_lvalue_unadjusted(bcx, expr);
521 ty::RvalueDatumExpr => {
522 let datum = unpack_datum!(bcx, {
523 trans_rvalue_datum_unadjusted(bcx, expr)
525 datum.add_clean(bcx);
526 return DatumBlock {bcx: bcx, datum: datum};
529 ty::RvalueStmtExpr => {
530 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
531 return nil(bcx, expr_ty(bcx, expr));
534 ty::RvalueDpsExpr => {
535 let ty = expr_ty(bcx, expr);
536 if ty::type_is_voidish(bcx.tcx(), ty) {
537 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
540 let scratch = scratch_datum(bcx, ty, "", false);
541 bcx = trans_rvalue_dps_unadjusted(
542 bcx, expr, SaveIn(scratch.val));
544 // Note: this is not obviously a good idea. It causes
545 // immediate values to be loaded immediately after a
546 // return from a call or other similar expression,
547 // which in turn leads to alloca's having shorter
548 // lifetimes and hence larger stack frames. However,
549 // in turn it can lead to more register pressure.
550 // Still, in practice it seems to increase
551 // performance, since we have fewer problems with
553 let scratch = scratch.to_appropriate_datum(bcx);
555 scratch.add_clean(bcx);
556 return DatumBlock {bcx: bcx, datum: scratch};
561 fn nil(bcx: @mut Block, ty: ty::t) -> DatumBlock {
562 let datum = immediate_rvalue(C_nil(), ty);
563 DatumBlock {bcx: bcx, datum: datum}
567 fn trans_rvalue_datum_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
568 let _icx = push_ctxt("trans_rvalue_datum_unadjusted");
571 ast::ExprPath(_) | ast::ExprSelf => {
572 return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id));
574 ast::ExprVstore(contents, ast::ExprVstoreBox) |
575 ast::ExprVstore(contents, ast::ExprVstoreMutBox) => {
576 return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed,
579 ast::ExprVstore(contents, ast::ExprVstoreUniq) => {
580 let heap = heap_for_unique(bcx, expr_ty(bcx, contents));
581 return tvec::trans_uniq_or_managed_vstore(bcx, heap,
584 ast::ExprLit(lit) => {
585 return trans_immediate_lit(bcx, expr, *lit);
587 ast::ExprBinary(_, op, lhs, rhs) => {
588 // if overloaded, would be RvalueDpsExpr
589 assert!(!bcx.ccx().maps.method_map.contains_key(&expr.id));
591 return trans_binary(bcx, expr, op, lhs, rhs);
593 ast::ExprUnary(_, op, x) => {
594 return trans_unary_datum(bcx, expr, op, x);
596 ast::ExprAddrOf(_, x) => {
597 return trans_addr_of(bcx, expr, x);
599 ast::ExprCast(val, _) => {
600 return trans_imm_cast(bcx, val, expr.id);
602 ast::ExprParen(e) => {
603 return trans_rvalue_datum_unadjusted(bcx, e);
605 ast::ExprLogLevel => {
606 return trans_log_level(bcx);
609 bcx.tcx().sess.span_bug(
611 format!("trans_rvalue_datum_unadjusted reached \
612 fall-through case: {:?}",
618 fn trans_rvalue_stmt_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> @mut Block {
620 let _icx = push_ctxt("trans_rvalue_stmt");
627 ast::ExprBreak(label_opt) => {
628 return controlflow::trans_break(bcx, label_opt);
630 ast::ExprAgain(label_opt) => {
631 return controlflow::trans_cont(bcx, label_opt);
633 ast::ExprRet(ex) => {
634 return controlflow::trans_ret(bcx, ex);
636 ast::ExprWhile(cond, body) => {
637 return controlflow::trans_while(bcx, cond, body);
639 ast::ExprLoop(body, opt_label) => {
640 // FIXME #6993: map can go away when ast.rs is changed
641 return controlflow::trans_loop(bcx, body, opt_label.map(|x| x.name));
643 ast::ExprAssign(dst, src) => {
644 let src_datum = unpack_datum!(
645 bcx, trans_to_datum(bcx, src));
646 let dst_datum = unpack_datum!(
647 bcx, trans_lvalue(bcx, dst));
648 return src_datum.store_to_datum(
649 bcx, DROP_EXISTING, dst_datum);
651 ast::ExprAssignOp(callee_id, op, dst, src) => {
652 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
654 ast::ExprParen(a) => {
655 return trans_rvalue_stmt_unadjusted(bcx, a);
657 ast::ExprInlineAsm(ref a) => {
658 return asm::trans_inline_asm(bcx, a);
661 bcx.tcx().sess.span_bug(
663 format!("trans_rvalue_stmt_unadjusted reached \
664 fall-through case: {:?}",
670 fn trans_rvalue_dps_unadjusted(bcx: @mut Block, expr: &ast::Expr,
671 dest: Dest) -> @mut Block {
672 let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
676 ast::ExprParen(e) => {
677 return trans_rvalue_dps_unadjusted(bcx, e, dest);
679 ast::ExprPath(_) | ast::ExprSelf => {
680 return trans_def_dps_unadjusted(bcx, expr,
681 bcx.def(expr.id), dest);
683 ast::ExprIf(cond, thn, els) => {
684 return controlflow::trans_if(bcx, cond, thn, els, dest);
686 ast::ExprMatch(discr, ref arms) => {
687 return _match::trans_match(bcx, expr, discr, *arms, dest);
689 ast::ExprBlock(blk) => {
690 return base::with_scope(bcx,
694 controlflow::trans_block(bcx, blk, dest)
697 ast::ExprStruct(_, ref fields, base) => {
698 return trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest);
700 ast::ExprTup(ref args) => {
701 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
702 let numbered_fields: ~[(uint, @ast::Expr)] =
703 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
704 return trans_adt(bcx, repr, 0, numbered_fields, None, dest);
706 ast::ExprLit(@codemap::Spanned {node: ast::lit_str(s, _), ..}) => {
707 return tvec::trans_lit_str(bcx, expr, s, dest);
709 ast::ExprVstore(contents, ast::ExprVstoreSlice) |
710 ast::ExprVstore(contents, ast::ExprVstoreMutSlice) => {
711 return tvec::trans_slice_vstore(bcx, expr, contents, dest);
713 ast::ExprVec(..) | ast::ExprRepeat(..) => {
714 return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
716 ast::ExprFnBlock(decl, body) |
717 ast::ExprProc(decl, body) => {
718 let expr_ty = expr_ty(bcx, expr);
719 let sigil = ty::ty_closure_sigil(expr_ty);
720 debug!("translating block function {} with type {}",
721 expr_to_str(expr, tcx.sess.intr()),
723 return closure::trans_expr_fn(bcx, sigil, decl, body,
724 expr.id, expr.id, dest);
726 ast::ExprDoBody(blk) => {
727 return trans_into(bcx, blk, dest);
729 ast::ExprCall(f, ref args, _) => {
730 return callee::trans_call(
731 bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
733 ast::ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
734 return callee::trans_method_call(bcx,
738 callee::ArgExprs(*args),
741 ast::ExprBinary(callee_id, _, lhs, rhs) => {
742 // if not overloaded, would be RvalueDatumExpr
743 return trans_overloaded_op(bcx,
751 ast::ExprUnary(callee_id, _, subexpr) => {
752 // if not overloaded, would be RvalueDatumExpr
753 return trans_overloaded_op(bcx,
761 ast::ExprIndex(callee_id, base, idx) => {
762 // if not overloaded, would be RvalueDatumExpr
763 return trans_overloaded_op(bcx,
771 ast::ExprCast(val, _) => {
772 match ty::get(node_id_type(bcx, expr.id)).sty {
773 ty::ty_trait(_, _, store, _, _) => {
774 return meth::trans_trait_cast(bcx, val, expr.id, dest,
778 bcx.tcx().sess.span_bug(expr.span,
779 "expr_cast of non-trait");
783 ast::ExprAssignOp(callee_id, op, dst, src) => {
784 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
787 bcx.tcx().sess.span_bug(
789 format!("trans_rvalue_dps_unadjusted reached fall-through case: {:?}",
795 fn trans_def_dps_unadjusted(bcx: @mut Block, ref_expr: &ast::Expr,
796 def: ast::Def, dest: Dest) -> @mut Block {
797 let _icx = push_ctxt("trans_def_dps_unadjusted");
800 let lldest = match dest {
801 SaveIn(lldest) => lldest,
802 Ignore => { return bcx; }
806 ast::DefVariant(tid, vid, _) => {
807 let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
808 if variant_info.args.len() > 0u {
810 let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
811 Store(bcx, fn_data.llfn, lldest);
815 let ty = expr_ty(bcx, ref_expr);
816 let repr = adt::represent_type(ccx, ty);
817 adt::trans_start_init(bcx, repr, lldest,
818 variant_info.disr_val);
822 ast::DefStruct(def_id) => {
823 let ty = expr_ty(bcx, ref_expr);
824 match ty::get(ty).sty {
825 ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
826 let repr = adt::represent_type(ccx, ty);
827 adt::trans_start_init(bcx, repr, lldest, 0);
829 ty::ty_bare_fn(..) => {
830 let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
831 Store(bcx, fn_data.llfn, lldest);
838 bcx.tcx().sess.span_bug(ref_expr.span, format!(
839 "Non-DPS def {:?} referened by {}",
840 def, bcx.node_id_to_str(ref_expr.id)));
845 fn trans_def_datum_unadjusted(bcx: @mut Block,
846 ref_expr: &ast::Expr,
847 def: ast::Def) -> DatumBlock
849 let _icx = push_ctxt("trans_def_datum_unadjusted");
851 let fn_data = match def {
853 ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
854 callee::trans_fn_ref(bcx, did, ref_expr.id)
856 ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
857 meth::trans_static_method_callee(bcx,
863 bcx.tcx().sess.span_bug(ref_expr.span, format!(
864 "Non-DPS def {:?} referened by {}",
865 def, bcx.node_id_to_str(ref_expr.id)));
869 let fn_ty = expr_ty(bcx, ref_expr);
880 fn trans_lvalue_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
883 * Translates an lvalue expression, always yielding a by-ref
884 * datum. Does not apply any adjustments. */
886 let _icx = push_ctxt("trans_lval");
889 debug!("trans_lvalue(expr={})", bcx.expr_to_str(expr));
890 let _indenter = indenter();
892 return match expr.node {
893 ast::ExprParen(e) => {
894 trans_lvalue_unadjusted(bcx, e)
896 ast::ExprPath(_) | ast::ExprSelf => {
897 trans_def_lvalue(bcx, expr, bcx.def(expr.id))
899 ast::ExprField(base, ident, _) => {
900 trans_rec_field(bcx, base, ident)
902 ast::ExprIndex(_, base, idx) => {
903 trans_index(bcx, expr, base, idx)
905 ast::ExprUnary(_, ast::UnDeref, base) => {
906 let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base));
907 basedatum.deref(bcx, expr, 0)
910 bcx.tcx().sess.span_bug(
912 format!("trans_lvalue reached fall-through case: {:?}",
917 fn trans_rec_field(bcx: @mut Block,
919 field: ast::Ident) -> DatumBlock {
920 //! Translates `base.field`.
923 let _icx = push_ctxt("trans_rec_field");
925 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
926 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
927 with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
928 let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
930 datum: base_datum.get_element(bcx,
934 adt::trans_field_ptr(bcx, repr, srcval, discr, ix)
941 fn trans_index(bcx: @mut Block,
942 index_expr: &ast::Expr,
944 idx: &ast::Expr) -> DatumBlock {
945 //! Translates `base[idx]`.
947 let _icx = push_ctxt("trans_index");
951 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
953 // Translate index expression and cast to a suitable LLVM integer.
954 // Rust is less strict than LLVM in this regard.
955 let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
956 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
957 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
959 if ix_size < int_size {
960 if ty::type_is_signed(expr_ty(bcx, idx)) {
961 SExt(bcx, ix_val, ccx.int_type)
962 } else { ZExt(bcx, ix_val, ccx.int_type) }
963 } else if ix_size > int_size {
964 Trunc(bcx, ix_val, ccx.int_type)
970 let vt = tvec::vec_types(bcx, base_datum.ty);
971 base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
973 let (bcx, base, len) =
974 base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id, 0);
976 debug!("trans_index: base {}", bcx.val_to_str(base));
977 debug!("trans_index: len {}", bcx.val_to_str(len));
979 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
980 let expect = ccx.intrinsics.get_copy(&("llvm.expect.i1"));
981 let expected = Call(bcx, expect, [bounds_check, C_i1(false)], []);
982 let bcx = with_cond(bcx, expected, |bcx| {
983 controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
985 let elt = InBoundsGEP(bcx, base, [ix_val]);
986 let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
989 datum: Datum {val: elt,
991 mode: ByRef(ZeroMem)}
995 fn trans_def_lvalue(bcx: @mut Block,
996 ref_expr: &ast::Expr,
1000 //! Translates a reference to a path.
1002 let _icx = push_ctxt("trans_def_lvalue");
1004 ast::DefStatic(did, _) => {
1005 let const_ty = expr_ty(bcx, ref_expr);
1007 fn get_did(ccx: @mut CrateContext, did: ast::DefId)
1009 if did.crate != ast::LOCAL_CRATE {
1010 inline::maybe_instantiate_inline(ccx, did)
1016 fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
1018 // For external constants, we don't inline.
1019 if did.crate == ast::LOCAL_CRATE {
1020 // The LLVM global has the type of its initializer,
1021 // which may not be equal to the enum's type for
1022 // non-C-like enums.
1023 let val = base::get_item_val(bcx.ccx(), did.node);
1024 let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
1025 PointerCast(bcx, val, pty)
1028 let extern_const_values = &bcx.ccx().extern_const_values;
1029 match extern_const_values.find(&did) {
1030 None => {} // Continue.
1038 let llty = type_of::type_of(bcx.ccx(), const_ty);
1039 let symbol = csearch::get_symbol(
1040 bcx.ccx().sess.cstore,
1042 let llval = symbol.with_c_str(|buf| {
1043 llvm::LLVMAddGlobal(bcx.ccx().llmod,
1047 let extern_const_values = &mut bcx.ccx().extern_const_values;
1048 extern_const_values.insert(did, llval);
1054 let did = get_did(bcx.ccx(), did);
1055 let val = get_val(bcx, did, const_ty);
1058 datum: Datum {val: val,
1060 mode: ByRef(ZeroMem)}
1066 datum: trans_local_var(bcx, def)
1073 pub fn trans_local_var(bcx: @mut Block, def: ast::Def) -> Datum {
1074 let _icx = push_ctxt("trans_local_var");
1077 ast::DefUpvar(nid, _, _, _) => {
1078 // Can't move upvars, so this is never a ZeroMemLastUse.
1079 let local_ty = node_id_type(bcx, nid);
1080 match bcx.fcx.llupvars.find(&nid) {
1085 mode: ByRef(ZeroMem)
1089 bcx.sess().bug(format!(
1090 "trans_local_var: no llval for upvar {:?} found", nid));
1094 ast::DefArg(nid, _) => {
1095 take_local(bcx, bcx.fcx.llargs, nid)
1097 ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
1098 take_local(bcx, bcx.fcx.lllocals, nid)
1100 ast::DefSelf(nid, _) => {
1101 let self_info: ValSelfData = match bcx.fcx.llself {
1102 Some(ref self_info) => *self_info,
1104 bcx.sess().bug(format!(
1105 "trans_local_var: reference to self \
1106 out of context with id {:?}", nid));
1110 debug!("def_self() reference, self_info.t={}",
1111 self_info.t.repr(bcx.tcx()));
1116 mode: ByRef(ZeroMem)
1120 bcx.sess().unimpl(format!(
1121 "unsupported def type in trans_local_var: {:?}", def));
1125 fn take_local(bcx: @mut Block,
1126 table: &HashMap<ast::NodeId, ValueRef>,
1127 nid: ast::NodeId) -> Datum {
1128 let v = match table.find(&nid) {
1131 bcx.sess().bug(format!(
1132 "trans_local_var: no llval for local/arg {:?} found", nid));
1135 let ty = node_id_type(bcx, nid);
1136 debug!("take_local(nid={:?}, v={}, ty={})",
1137 nid, bcx.val_to_str(v), bcx.ty_to_str(ty));
1141 mode: ByRef(ZeroMem)
1146 // The optional node ID here is the node ID of the path identifying the enum
1147 // variant in use. If none, this cannot possibly an enum variant (so, if it
1148 // is and `node_id_opt` is none, this function fails).
1149 pub fn with_field_tys<R>(
1152 node_id_opt: Option<ast::NodeId>,
1153 op: |ty::Disr, (&[ty::field])| -> R)
1155 match ty::get(ty).sty {
1156 ty::ty_struct(did, ref substs) => {
1157 op(0, struct_fields(tcx, did, substs))
1160 ty::ty_enum(_, ref substs) => {
1161 // We want the *variant* ID here, not the enum ID.
1164 tcx.sess.bug(format!(
1165 "cannot get field types from the enum type {} \
1170 match tcx.def_map.get_copy(&node_id) {
1171 ast::DefVariant(enum_id, variant_id, _) => {
1172 let variant_info = ty::enum_variant_with_id(
1173 tcx, enum_id, variant_id);
1174 op(variant_info.disr_val,
1175 struct_fields(tcx, variant_id, substs))
1178 tcx.sess.bug("resolve didn't map this expr to a \
1187 tcx.sess.bug(format!(
1188 "cannot get field types from the type {}",
1194 fn trans_rec_or_struct(bcx: @mut Block,
1195 fields: &[ast::Field],
1196 base: Option<@ast::Expr>,
1197 expr_span: codemap::Span,
1199 dest: Dest) -> @mut Block
1201 let _icx = push_ctxt("trans_rec");
1204 let ty = node_id_type(bcx, id);
1205 let tcx = bcx.tcx();
1206 with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
1207 let mut need_base = vec::from_elem(field_tys.len(), true);
1209 let numbered_fields = fields.map(|field| {
1211 field_tys.iter().position(|field_ty|
1212 field_ty.ident.name == field.ident.node.name);
1215 need_base[i] = false;
1219 tcx.sess.span_bug(field.span,
1220 "Couldn't find field in struct type")
1224 let optbase = match base {
1225 Some(base_expr) => {
1226 let mut leftovers = ~[];
1227 for (i, b) in need_base.iter().enumerate() {
1229 leftovers.push((i, field_tys[i].mt.ty))
1232 Some(StructBaseInfo {expr: base_expr,
1233 fields: leftovers })
1236 if need_base.iter().any(|b| *b) {
1237 tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1243 let repr = adt::represent_type(bcx.ccx(), ty);
1244 trans_adt(bcx, repr, discr, numbered_fields, optbase, dest)
1249 * Information that `trans_adt` needs in order to fill in the fields
1250 * of a struct copied from a base struct (e.g., from an expression
1251 * like `Foo { a: b, ..base }`.
1253 * Note that `fields` may be empty; the base expression must always be
1254 * evaluated for side-effects.
1256 struct StructBaseInfo {
1257 /// The base expression; will be evaluated after all explicit fields.
1259 /// The indices of fields to copy paired with their types.
1260 fields: ~[(uint, ty::t)]
1264 * Constructs an ADT instance:
1266 * - `fields` should be a list of field indices paired with the
1267 * expression to store into that field. The initializers will be
1268 * evaluated in the order specified by `fields`.
1270 * - `optbase` contains information on the base struct (if any) from
1271 * which remaining fields are copied; see comments on `StructBaseInfo`.
1273 fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: ty::Disr,
1274 fields: &[(uint, @ast::Expr)],
1275 optbase: Option<StructBaseInfo>,
1276 dest: Dest) -> @mut Block {
1277 let _icx = push_ctxt("trans_adt");
1279 let addr = match dest {
1281 for &(_i, e) in fields.iter() {
1282 bcx = trans_into(bcx, e, Ignore);
1284 for sbi in optbase.iter() {
1285 // FIXME #7261: this moves entire base, not just certain fields
1286 bcx = trans_into(bcx, sbi.expr, Ignore);
1292 let mut temp_cleanups = ~[];
1293 adt::trans_start_init(bcx, repr, addr, discr);
1294 for &(i, e) in fields.iter() {
1295 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1296 let e_ty = expr_ty(bcx, e);
1297 bcx = trans_into(bcx, e, SaveIn(dest));
1298 add_clean_temp_mem(bcx, dest, e_ty);
1299 temp_cleanups.push(dest);
1301 for base in optbase.iter() {
1302 // FIXME #6573: is it sound to use the destination's repr on the base?
1303 // And, would it ever be reasonable to be here with discr != 0?
1304 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr));
1305 for &(i, t) in base.fields.iter() {
1306 let datum = base_datum.get_element(bcx, t, ZeroMem, |srcval| {
1307 adt::trans_field_ptr(bcx, repr, srcval, discr, i)
1309 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1310 bcx = datum.store_to(bcx, INIT, dest);
1314 for cleanup in temp_cleanups.iter() {
1315 revoke_clean(bcx, *cleanup);
1321 fn trans_immediate_lit(bcx: @mut Block, expr: &ast::Expr,
1322 lit: ast::lit) -> DatumBlock {
1323 // must not be a string constant, that is a RvalueDpsExpr
1324 let _icx = push_ctxt("trans_immediate_lit");
1325 let ty = expr_ty(bcx, expr);
1326 immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty)
1329 fn trans_unary_datum(bcx: @mut Block,
1330 un_expr: &ast::Expr,
1332 sub_expr: &ast::Expr) -> DatumBlock {
1333 let _icx = push_ctxt("trans_unary_datum");
1335 // if deref, would be LvalueExpr
1336 assert!(op != ast::UnDeref);
1338 // if overloaded, would be RvalueDpsExpr
1339 assert!(!bcx.ccx().maps.method_map.contains_key(&un_expr.id));
1341 let un_ty = expr_ty(bcx, un_expr);
1342 let sub_ty = expr_ty(bcx, sub_expr);
1346 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1348 // If this is a boolean type, we must not use the LLVM Not
1349 // instruction, as that is a *bitwise* not and we want *logical*
1350 // not on our 8-bit boolean values.
1351 let llresult = match ty::get(un_ty).sty {
1353 let llcond = ICmp(bcx,
1357 Select(bcx, llcond, C_bool(true), C_bool(false))
1361 immediate_rvalue_bcx(bcx, llresult, un_ty)
1364 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1366 if ty::type_is_fp(un_ty) {
1372 immediate_rvalue_bcx(bcx, llneg, un_ty)
1375 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty,
1379 let heap = heap_for_unique(bcx, un_ty);
1380 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap)
1383 bcx.sess().bug("deref expressions should have been \
1384 translated using trans_lvalue(), not \
1385 trans_unary_datum()")
1389 fn trans_boxed_expr(bcx: @mut Block,
1391 contents: &ast::Expr,
1393 heap: heap) -> DatumBlock {
1394 let _icx = push_ctxt("trans_boxed_expr");
1395 if heap == heap_exchange {
1396 let llty = type_of::type_of(bcx.ccx(), contents_ty);
1397 let size = llsize_of(bcx.ccx(), llty);
1398 let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
1399 heap_exchange, size);
1400 add_clean_free(bcx, val, heap_exchange);
1401 let bcx = trans_into(bcx, contents, SaveIn(val));
1402 revoke_clean(bcx, val);
1403 return immediate_rvalue_bcx(bcx, val, box_ty);
1405 let base::MallocResult { bcx, box: bx, body } =
1406 base::malloc_general(bcx, contents_ty, heap);
1407 add_clean_free(bcx, bx, heap);
1408 let bcx = trans_into(bcx, contents, SaveIn(body));
1409 revoke_clean(bcx, bx);
1410 return immediate_rvalue_bcx(bcx, bx, box_ty);
1415 fn trans_addr_of(bcx: @mut Block, expr: &ast::Expr,
1416 subexpr: &ast::Expr) -> DatumBlock {
1417 let _icx = push_ctxt("trans_addr_of");
1419 let sub_datum = unpack_datum!(bcx, trans_to_datum(bcx, subexpr));
1420 let llval = sub_datum.to_ref_llval(bcx);
1421 return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
1424 // Important to get types for both lhs and rhs, because one might be _|_
1425 // and the other not.
1426 fn trans_eager_binop(bcx: @mut Block,
1427 binop_expr: &ast::Expr,
1433 let _icx = push_ctxt("trans_eager_binop");
1435 let lhs = lhs_datum.to_appropriate_llval(bcx);
1436 let lhs_t = lhs_datum.ty;
1438 let rhs = rhs_datum.to_appropriate_llval(bcx);
1439 let rhs_t = rhs_datum.ty;
1442 if ty::type_is_bot(lhs_t) { rhs_t }
1445 let tcx = bcx.tcx();
1446 if ty::type_is_simd(tcx, intype) {
1447 intype = ty::simd_type(tcx, intype);
1449 let is_float = ty::type_is_fp(intype);
1450 let signed = ty::type_is_signed(intype);
1452 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1455 let val = match op {
1457 if is_float { FAdd(bcx, lhs, rhs) }
1458 else { Add(bcx, lhs, rhs) }
1461 if is_float { FSub(bcx, lhs, rhs) }
1462 else { Sub(bcx, lhs, rhs) }
1465 if is_float { FMul(bcx, lhs, rhs) }
1466 else { Mul(bcx, lhs, rhs) }
1472 // Only zero-check integers; fp /0 is NaN
1473 bcx = base::fail_if_zero(bcx, binop_expr.span,
1486 // Only zero-check integers; fp %0 is NaN
1487 bcx = base::fail_if_zero(bcx, binop_expr.span,
1496 ast::BiBitOr => Or(bcx, lhs, rhs),
1497 ast::BiBitAnd => And(bcx, lhs, rhs),
1498 ast::BiBitXor => Xor(bcx, lhs, rhs),
1499 ast::BiShl => Shl(bcx, lhs, rhs),
1503 } else { LShr(bcx, lhs, rhs) }
1505 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
1506 if ty::type_is_bot(rhs_t) {
1509 if !ty::type_is_scalar(rhs_t) {
1510 bcx.tcx().sess.span_bug(binop_expr.span,
1511 "non-scalar comparison");
1513 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1515 ZExt(bcx, cmpr.val, Type::i8())
1519 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1523 return immediate_rvalue_bcx(bcx, val, binop_ty);
1526 // refinement types would obviate the need for this
1527 enum lazy_binop_ty { lazy_and, lazy_or }
1529 fn trans_lazy_binop(bcx: @mut Block,
1530 binop_expr: &ast::Expr,
1533 b: &ast::Expr) -> DatumBlock {
1534 let _icx = push_ctxt("trans_lazy_binop");
1535 let binop_ty = expr_ty(bcx, binop_expr);
1538 let Result {bcx: past_lhs, val: lhs} = {
1539 base::with_scope_result(bcx, a.info(), "lhs", |bcx| {
1540 trans_to_datum(bcx, a).to_result()
1544 if past_lhs.unreachable {
1545 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty);
1548 let join = base::sub_block(bcx, "join");
1549 let before_rhs = base::sub_block(bcx, "rhs");
1551 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1553 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1554 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1557 let Result {bcx: past_rhs, val: rhs} = {
1558 base::with_scope_result(before_rhs, b.info(), "rhs", |bcx| {
1559 trans_to_datum(bcx, b).to_result()
1563 if past_rhs.unreachable {
1564 return immediate_rvalue_bcx(join, lhs, binop_ty);
1567 Br(past_rhs, join.llbb);
1568 let phi = Phi(join, Type::bool(), [lhs, rhs], [past_lhs.llbb,
1571 return immediate_rvalue_bcx(join, phi, binop_ty);
1574 fn trans_binary(bcx: @mut Block,
1575 binop_expr: &ast::Expr,
1578 rhs: &ast::Expr) -> DatumBlock
1580 let _icx = push_ctxt("trans_binary");
1584 trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
1587 trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
1591 let lhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, lhs));
1592 let rhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, rhs));
1593 let binop_ty = expr_ty(bcx, binop_expr);
1594 trans_eager_binop(bcx, binop_expr, binop_ty, op,
1595 &lhs_datum, &rhs_datum)
1600 fn trans_overloaded_op(bcx: @mut Block,
1602 callee_id: ast::NodeId,
1604 args: ~[@ast::Expr],
1608 let origin = bcx.ccx().maps.method_map.get_copy(&expr.id);
1609 let fty = node_id_type(bcx, callee_id);
1610 callee::trans_call_inner(bcx,
1615 meth::trans_method_callee(bcx,
1620 callee::ArgExprs(args),
1625 fn int_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
1626 llsrc: ValueRef, signed: bool) -> ValueRef {
1627 let _icx = push_ctxt("int_cast");
1629 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1630 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1631 return if dstsz == srcsz {
1632 BitCast(bcx, llsrc, lldsttype)
1633 } else if srcsz > dstsz {
1634 TruncOrBitCast(bcx, llsrc, lldsttype)
1636 SExtOrBitCast(bcx, llsrc, lldsttype)
1638 ZExtOrBitCast(bcx, llsrc, lldsttype)
1643 fn float_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
1644 llsrc: ValueRef) -> ValueRef {
1645 let _icx = push_ctxt("float_cast");
1646 let srcsz = llsrctype.float_width();
1647 let dstsz = lldsttype.float_width();
1648 return if dstsz > srcsz {
1649 FPExt(bcx, llsrc, lldsttype)
1650 } else if srcsz > dstsz {
1651 FPTrunc(bcx, llsrc, lldsttype)
1656 pub enum cast_kind {
1664 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1665 match ty::get(t).sty {
1666 ty::ty_char => cast_integral,
1667 ty::ty_float(..) => cast_float,
1668 ty::ty_ptr(..) => cast_pointer,
1669 ty::ty_rptr(..) => cast_pointer,
1670 ty::ty_bare_fn(..) => cast_pointer,
1671 ty::ty_int(..) => cast_integral,
1672 ty::ty_uint(..) => cast_integral,
1673 ty::ty_bool => cast_integral,
1674 ty::ty_enum(..) => cast_enum,
1679 fn trans_imm_cast(bcx: @mut Block, expr: &ast::Expr,
1680 id: ast::NodeId) -> DatumBlock {
1681 let _icx = push_ctxt("trans_cast");
1682 let ccx = bcx.ccx();
1684 let t_out = node_id_type(bcx, id);
1687 let llexpr = unpack_result!(bcx, trans_to_datum(bcx, expr).to_result());
1688 let ll_t_in = val_ty(llexpr);
1689 let t_in = expr_ty(bcx, expr);
1690 let ll_t_out = type_of::type_of(ccx, t_out);
1692 let k_in = cast_type_kind(t_in);
1693 let k_out = cast_type_kind(t_out);
1694 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1697 match (k_in, k_out) {
1698 (cast_integral, cast_integral) => {
1699 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1701 (cast_float, cast_float) => {
1702 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1704 (cast_integral, cast_float) => {
1706 SIToFP(bcx, llexpr, ll_t_out)
1707 } else { UIToFP(bcx, llexpr, ll_t_out) }
1709 (cast_float, cast_integral) => {
1710 if ty::type_is_signed(t_out) {
1711 FPToSI(bcx, llexpr, ll_t_out)
1712 } else { FPToUI(bcx, llexpr, ll_t_out) }
1714 (cast_integral, cast_pointer) => {
1715 IntToPtr(bcx, llexpr, ll_t_out)
1717 (cast_pointer, cast_integral) => {
1718 PtrToInt(bcx, llexpr, ll_t_out)
1720 (cast_pointer, cast_pointer) => {
1721 PointerCast(bcx, llexpr, ll_t_out)
1723 (cast_enum, cast_integral) |
1724 (cast_enum, cast_float) => {
1726 let repr = adt::represent_type(ccx, t_in);
1728 if type_is_immediate(ccx, t_in) {
1729 llexpr_ptr = Alloca(bcx, ll_t_in, "");
1730 Store(bcx, llexpr, llexpr_ptr);
1732 llexpr_ptr = llexpr;
1734 let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr_ptr, Some(Type::i64()));
1736 cast_integral => int_cast(bcx, ll_t_out,
1737 val_ty(lldiscrim_a),
1739 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1740 _ => ccx.sess.bug(format!("translating unsupported cast: \
1741 {} ({:?}) -> {} ({:?})",
1742 t_in.repr(ccx.tcx), k_in,
1743 t_out.repr(ccx.tcx), k_out))
1746 _ => ccx.sess.bug(format!("translating unsupported cast: \
1747 {} ({:?}) -> {} ({:?})",
1748 t_in.repr(ccx.tcx), k_in,
1749 t_out.repr(ccx.tcx), k_out))
1751 return immediate_rvalue_bcx(bcx, newval, t_out);
1754 fn trans_assign_op(bcx: @mut Block,
1756 callee_id: ast::NodeId,
1759 src: @ast::Expr) -> @mut Block
1761 let _icx = push_ctxt("trans_assign_op");
1764 debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
1766 // Evaluate LHS (destination), which should be an lvalue
1767 let dst_datum = unpack_datum!(bcx, trans_lvalue_unadjusted(bcx, dst));
1769 // A user-defined operator method
1770 if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
1771 // FIXME(#2528) evaluates the receiver twice!!
1772 let scratch = scratch_datum(bcx, dst_datum.ty, "__assign_op", false);
1773 let bcx = trans_overloaded_op(bcx,
1779 SaveIn(scratch.val));
1780 return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
1783 // Evaluate RHS (source)
1784 let src_datum = unpack_datum!(bcx, trans_to_datum(bcx, src));
1786 // Perform computation and store the result
1790 bcx, expr, dst_datum.ty, op,
1791 &dst_datum, &src_datum));
1792 return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
1795 fn shorten(x: &str) -> @str {
1796 (if x.char_len() > 60 {x.slice_chars(0, 60)} else {x}).to_managed()
1799 pub fn trans_log_level(bcx: @mut Block) -> DatumBlock {
1800 let _icx = push_ctxt("trans_log_level");
1801 let ccx = bcx.ccx();
1803 let (modpath, modname) = {
1804 let srccrate = match ccx.external_srcs.find(&bcx.fcx.id) {
1806 cstore::get_crate_data(ccx.sess.cstore, src.crate).name
1808 None => ccx.link_meta.name,
1810 let mut modpath = ~[path_mod(ccx.sess.ident_of(srccrate))];
1811 for e in bcx.fcx.path.iter() {
1813 path_mod(_) => { modpath.push(*e) }
1817 let modname = path_str(ccx.sess, modpath);
1821 let global = if ccx.module_data.contains_key(&modname) {
1822 ccx.module_data.get_copy(&modname)
1824 let s = link::mangle_internal_name_by_path_and_seq(
1825 ccx, modpath, "loglevel");
1828 global = s.with_c_str(|buf| {
1829 llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
1831 llvm::LLVMSetGlobalConstant(global, False);
1832 llvm::LLVMSetInitializer(global, C_null(Type::i32()));
1833 lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage);
1835 ccx.module_data.insert(modname, global);
1839 return immediate_rvalue_bcx(bcx, Load(bcx, global), ty::mk_u32());