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, ExternalLinkage, False};
121 use metadata::csearch;
122 use middle::trans::_match;
123 use middle::trans::adt;
124 use middle::trans::asm;
125 use middle::trans::base::*;
126 use middle::trans::base;
127 use middle::trans::build::*;
128 use middle::trans::callee::DoAutorefArg;
129 use middle::trans::callee;
130 use middle::trans::closure;
131 use middle::trans::common::*;
132 use middle::trans::consts;
133 use middle::trans::controlflow;
134 use middle::trans::datum::*;
135 use middle::trans::debuginfo;
136 use middle::trans::machine;
137 use middle::trans::meth;
138 use middle::trans::tvec;
139 use middle::trans::type_of;
140 use middle::ty::struct_fields;
141 use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoUnsafe};
142 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
144 use util::common::indenter;
145 use util::ppaux::Repr;
146 use middle::trans::machine::llsize_of;
148 use middle::trans::type_::Type;
150 use std::hashmap::HashMap;
152 use syntax::print::pprust::{expr_to_str};
154 use syntax::ast_map::path_mod;
159 // These are passed around by the code generating functions to track the
160 // destination of a computation's value.
169 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
171 SaveIn(v) => fmt!("SaveIn(%s)", ccx.tn.val_to_str(v)),
177 fn drop_and_cancel_clean(bcx: @mut Block, dat: Datum) -> @mut Block {
178 let bcx = dat.drop_val(bcx);
179 dat.cancel_clean(bcx);
183 pub fn trans_to_datum(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
184 debug!("trans_to_datum(expr=%s)", bcx.expr_to_str(expr));
187 let mut datum = unpack_datum!(bcx, trans_to_datum_unadjusted(bcx, expr));
188 let adjustment = match bcx.tcx().adjustments.find_copy(&expr.id) {
189 None => { return DatumBlock {bcx: bcx, datum: datum}; }
192 debug!("unadjusted datum: %s", datum.to_str(bcx.ccx()));
195 datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
197 AutoDerefRef(ref adj) => {
198 if adj.autoderefs > 0 {
202 datum.autoderef(bcx, expr.span,
203 expr.id, adj.autoderefs));
206 datum = match adj.autoref {
210 Some(AutoUnsafe(*)) | // region + unsafe ptrs have same repr
211 Some(AutoPtr(*)) => {
212 unpack_datum!(bcx, auto_ref(bcx, datum))
214 Some(AutoBorrowVec(*)) => {
215 unpack_datum!(bcx, auto_slice(bcx, adj.autoderefs,
218 Some(AutoBorrowVecRef(*)) => {
219 unpack_datum!(bcx, auto_slice_and_ref(bcx, adj.autoderefs,
222 Some(AutoBorrowFn(*)) => {
223 let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
224 datum.ty, Some(adjustment));
225 unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
227 Some(AutoBorrowObj(*)) => {
228 unpack_datum!(bcx, auto_borrow_obj(
229 bcx, adj.autoderefs, expr, datum))
234 debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx()));
235 return DatumBlock {bcx: bcx, datum: datum};
237 fn auto_ref(bcx: @mut Block, datum: Datum) -> DatumBlock {
238 DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
241 fn auto_borrow_fn(bcx: @mut Block,
243 datum: Datum) -> DatumBlock {
244 // Currently, all closure types are represented precisely the
245 // same, so no runtime adjustment is required, but we still
246 // must patchup the type.
247 DatumBlock {bcx: bcx,
248 datum: Datum {val: datum.val, ty: adjusted_ty,
252 fn auto_slice(bcx: @mut Block,
255 datum: Datum) -> DatumBlock {
256 // This is not the most efficient thing possible; since slices
257 // are two words it'd be better if this were compiled in
258 // 'dest' mode, but I can't find a nice way to structure the
259 // code and keep it DRY that accommodates that use case at the
263 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
265 let (bcx, base, len) =
266 datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1);
268 // this type may have a different region/mutability than the
269 // real one, but it will have the same runtime representation
270 let slice_ty = ty::mk_evec(tcx,
271 ty::mt { ty: unit_ty, mutbl: ast::MutImmutable },
272 ty::vstore_slice(ty::re_static));
274 let scratch = scratch_datum(bcx, slice_ty, "__adjust", false);
275 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
276 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
277 DatumBlock {bcx: bcx, datum: scratch}
280 fn add_env(bcx: @mut Block, expr: &ast::Expr, datum: Datum) -> DatumBlock {
281 // This is not the most efficient thing possible; since closures
282 // are two words it'd be better if this were compiled in
283 // 'dest' mode, but I can't find a nice way to structure the
284 // code and keep it DRY that accommodates that use case at the
288 let closure_ty = expr_ty_adjusted(bcx, expr);
289 debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx));
290 let scratch = scratch_datum(bcx, closure_ty, "__adjust", false);
291 let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
292 assert_eq!(datum.appropriate_mode(tcx), ByValue);
293 Store(bcx, datum.to_appropriate_llval(bcx), llfn);
294 let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
295 Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
296 DatumBlock {bcx: bcx, datum: scratch}
299 fn auto_slice_and_ref(bcx: @mut Block,
302 datum: Datum) -> DatumBlock {
303 let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
307 fn auto_borrow_obj(mut bcx: @mut Block,
310 source_datum: Datum) -> DatumBlock {
312 let target_obj_ty = expr_ty_adjusted(bcx, expr);
313 debug!("auto_borrow_obj(target=%s)",
314 target_obj_ty.repr(tcx));
315 let scratch = scratch_datum(bcx, target_obj_ty,
316 "__auto_borrow_obj", false);
318 // Convert a @Object, ~Object, or &Object pair into an &Object pair.
320 // Get a pointer to the source object, which is represented as
321 // a (vtable, data) pair.
322 let source_llval = source_datum.to_ref_llval(bcx);
324 // Set the vtable field of the new pair
325 let vtable_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_vtable]);
326 let vtable = Load(bcx, vtable_ptr);
327 Store(bcx, vtable, GEPi(bcx, scratch.val, [0u, abi::trt_field_vtable]));
329 // Load the data for the source, which is either an @T,
330 // ~T, or &T, depending on source_obj_ty.
331 let source_data_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_box]);
332 let source_data = Load(bcx, source_data_ptr); // always a ptr
333 let (source_store, source_mutbl) = match ty::get(source_datum.ty).sty {
334 ty::ty_trait(_, _, s, m, _) => (s, m),
338 fmt!("auto_borrow_trait_obj expected a trait, found %s",
339 source_datum.ty.repr(bcx.tcx())));
342 let target_data = match source_store {
343 ty::BoxTraitStore(*) => {
344 // For deref of @T or @mut T, create a dummy datum and
345 // use the datum's deref method. This is more work
346 // than just calling GEPi ourselves, but it ensures
347 // that any write guards will be appropriate
348 // processed. Note that we don't know the type T, so
349 // just substitute `i8`-- it doesn't really matter for
350 // our purposes right now.
355 mutbl: source_mutbl});
357 Datum {val: source_data,
362 source_datum.deref(bcx,
365 derefd_datum.to_rptr(bcx).to_value_llval(bcx)
367 ty::UniqTraitStore(*) => {
368 // For a ~T box, there may or may not be a header,
369 // depending on whether the type T references managed
370 // boxes. However, since we do not *know* the type T
371 // for objects, this presents a hurdle. Our solution is
372 // to load the "borrow offset" from the type descriptor;
373 // this value will either be 0 or sizeof(BoxHeader), depending
376 PointerCast(bcx, source_data, Type::opaque().ptr_to());
377 let lltydesc_ptr_ptr =
378 PointerCast(bcx, vtable,
379 bcx.ccx().tydesc_type.ptr_to().ptr_to());
381 Load(bcx, lltydesc_ptr_ptr);
382 let borrow_offset_ptr =
383 GEPi(bcx, lltydesc_ptr,
384 [0, abi::tydesc_field_borrow_offset]);
386 Load(bcx, borrow_offset_ptr);
387 InBoundsGEP(bcx, llopaque, [borrow_offset])
389 ty::RegionTraitStore(*) => {
393 Store(bcx, target_data,
394 GEPi(bcx, scratch.val, [0u, abi::trt_field_box]));
396 DatumBlock { bcx: bcx, datum: scratch }
400 pub fn trans_into(bcx: @mut Block, expr: @ast::Expr, dest: Dest) -> @mut Block {
401 if bcx.tcx().adjustments.contains_key(&expr.id) {
402 // use trans_to_datum, which is mildly less efficient but
403 // which will perform the adjustments:
404 let datumblock = trans_to_datum(bcx, expr);
406 Ignore => datumblock.bcx,
407 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
411 let ty = expr_ty(bcx, expr);
413 debug!("trans_into_unadjusted(expr=%s, dest=%s)",
414 bcx.expr_to_str(expr),
415 dest.to_str(bcx.ccx()));
416 let _indenter = indenter();
418 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
421 if ty::type_is_voidish(ty) {
428 let kind = bcx.expr_kind(expr);
429 debug!("expr kind = %?", kind);
432 let datumblock = trans_lvalue_unadjusted(bcx, expr);
434 Ignore => datumblock.bcx,
435 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
438 ty::RvalueDatumExpr => {
439 let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
441 Ignore => datumblock.drop_val(),
443 // When processing an rvalue, the value will be newly
444 // allocated, so we always `move_to` so as not to
445 // unnecessarily inc ref counts and so forth:
446 SaveIn(lldest) => datumblock.move_to(INIT, lldest)
449 ty::RvalueDpsExpr => {
450 trans_rvalue_dps_unadjusted(bcx, expr, dest)
452 ty::RvalueStmtExpr => {
453 trans_rvalue_stmt_unadjusted(bcx, expr)
458 fn trans_lvalue(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
461 * Translates an lvalue expression, always yielding a by-ref
462 * datum. Generally speaking you should call trans_to_datum()
463 * instead, but sometimes we call trans_lvalue() directly as a
464 * means of asserting that a particular expression is an lvalue. */
466 return match bcx.tcx().adjustments.find(&expr.id) {
467 None => trans_lvalue_unadjusted(bcx, expr),
471 fmt!("trans_lvalue() called on an expression \
477 fn trans_to_datum_unadjusted(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
479 * Translates an expression into a datum. If this expression
480 * is an rvalue, this will result in a temporary value being
481 * created. If you plan to store the value somewhere else,
482 * you should prefer `trans_into()` instead.
487 debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
488 let _indenter = indenter();
490 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
492 match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
494 return trans_lvalue_unadjusted(bcx, expr);
497 ty::RvalueDatumExpr => {
498 let datum = unpack_datum!(bcx, {
499 trans_rvalue_datum_unadjusted(bcx, expr)
501 datum.add_clean(bcx);
502 return DatumBlock {bcx: bcx, datum: datum};
505 ty::RvalueStmtExpr => {
506 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
507 return nil(bcx, expr_ty(bcx, expr));
510 ty::RvalueDpsExpr => {
511 let ty = expr_ty(bcx, expr);
512 if ty::type_is_voidish(ty) {
513 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
516 let scratch = scratch_datum(bcx, ty, "", false);
517 bcx = trans_rvalue_dps_unadjusted(
518 bcx, expr, SaveIn(scratch.val));
520 // Note: this is not obviously a good idea. It causes
521 // immediate values to be loaded immediately after a
522 // return from a call or other similar expression,
523 // which in turn leads to alloca's having shorter
524 // lifetimes and hence larger stack frames. However,
525 // in turn it can lead to more register pressure.
526 // Still, in practice it seems to increase
527 // performance, since we have fewer problems with
529 let scratch = scratch.to_appropriate_datum(bcx);
531 scratch.add_clean(bcx);
532 return DatumBlock {bcx: bcx, datum: scratch};
537 fn nil(bcx: @mut Block, ty: ty::t) -> DatumBlock {
538 let datum = immediate_rvalue(C_nil(), ty);
539 DatumBlock {bcx: bcx, datum: datum}
543 fn trans_rvalue_datum_unadjusted(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
544 let _icx = push_ctxt("trans_rvalue_datum_unadjusted");
546 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
549 ast::ExprPath(_) | ast::ExprSelf => {
550 return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id));
552 ast::ExprVstore(contents, ast::ExprVstoreBox) |
553 ast::ExprVstore(contents, ast::ExprVstoreMutBox) => {
554 return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed,
557 ast::ExprVstore(contents, ast::ExprVstoreUniq) => {
558 let heap = heap_for_unique(bcx, expr_ty(bcx, contents));
559 return tvec::trans_uniq_or_managed_vstore(bcx, heap,
562 ast::ExprLit(lit) => {
563 return trans_immediate_lit(bcx, expr, *lit);
565 ast::ExprBinary(_, op, lhs, rhs) => {
566 // if overloaded, would be RvalueDpsExpr
567 assert!(!bcx.ccx().maps.method_map.contains_key(&expr.id));
569 return trans_binary(bcx, expr, op, lhs, rhs);
571 ast::ExprUnary(_, op, x) => {
572 return trans_unary_datum(bcx, expr, op, x);
574 ast::ExprAddrOf(_, x) => {
575 return trans_addr_of(bcx, expr, x);
577 ast::ExprCast(val, _) => {
578 return trans_imm_cast(bcx, val, expr.id);
580 ast::ExprParen(e) => {
581 return trans_rvalue_datum_unadjusted(bcx, e);
583 ast::ExprLogLevel => {
584 return trans_log_level(bcx);
587 bcx.tcx().sess.span_bug(
589 fmt!("trans_rvalue_datum_unadjusted reached \
590 fall-through case: %?",
596 fn trans_rvalue_stmt_unadjusted(bcx: @mut Block, expr: @ast::Expr) -> @mut Block {
598 let _icx = push_ctxt("trans_rvalue_stmt");
604 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
607 ast::ExprBreak(label_opt) => {
608 return controlflow::trans_break(bcx, label_opt);
610 ast::ExprAgain(label_opt) => {
611 return controlflow::trans_cont(bcx, label_opt);
613 ast::ExprRet(ex) => {
614 return controlflow::trans_ret(bcx, ex);
616 ast::ExprWhile(cond, ref body) => {
617 return controlflow::trans_while(bcx, cond, body);
619 ast::ExprLoop(ref body, opt_label) => {
620 return controlflow::trans_loop(bcx, body, opt_label);
622 ast::ExprAssign(dst, src) => {
623 let src_datum = unpack_datum!(
624 bcx, trans_to_datum(bcx, src));
625 let dst_datum = unpack_datum!(
626 bcx, trans_lvalue(bcx, dst));
627 return src_datum.store_to_datum(
628 bcx, DROP_EXISTING, dst_datum);
630 ast::ExprAssignOp(callee_id, op, dst, src) => {
631 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
633 ast::ExprParen(a) => {
634 return trans_rvalue_stmt_unadjusted(bcx, a);
636 ast::ExprInlineAsm(ref a) => {
637 return asm::trans_inline_asm(bcx, a);
640 bcx.tcx().sess.span_bug(
642 fmt!("trans_rvalue_stmt_unadjusted reached \
643 fall-through case: %?",
649 fn trans_rvalue_dps_unadjusted(bcx: @mut Block, expr: @ast::Expr,
650 dest: Dest) -> @mut Block {
651 let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
654 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
657 ast::ExprParen(e) => {
658 return trans_rvalue_dps_unadjusted(bcx, e, dest);
660 ast::ExprPath(_) | ast::ExprSelf => {
661 return trans_def_dps_unadjusted(bcx, expr,
662 bcx.def(expr.id), dest);
664 ast::ExprIf(cond, ref thn, els) => {
665 return controlflow::trans_if(bcx, cond, thn, els, dest);
667 ast::ExprMatch(discr, ref arms) => {
668 return _match::trans_match(bcx, expr, discr, *arms, dest);
670 ast::ExprBlock(ref blk) => {
671 return do base::with_scope(bcx, blk.info(),
672 "block-expr body") |bcx| {
673 controlflow::trans_block(bcx, blk, dest)
676 ast::ExprStruct(_, ref fields, base) => {
677 return trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest);
679 ast::ExprTup(ref args) => {
680 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
681 let numbered_fields: ~[(uint, @ast::Expr)] =
682 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
683 return trans_adt(bcx, repr, 0, numbered_fields, None, dest);
685 ast::ExprLit(@codemap::Spanned {node: ast::lit_str(s), _}) => {
686 return tvec::trans_lit_str(bcx, expr, s, dest);
688 ast::ExprVstore(contents, ast::ExprVstoreSlice) |
689 ast::ExprVstore(contents, ast::ExprVstoreMutSlice) => {
690 return tvec::trans_slice_vstore(bcx, expr, contents, dest);
692 ast::ExprVec(*) | ast::ExprRepeat(*) => {
693 return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
695 ast::ExprFnBlock(ref decl, ref body) => {
696 let expr_ty = expr_ty(bcx, expr);
697 let sigil = ty::ty_closure_sigil(expr_ty);
698 debug!("translating fn_block %s with type %s",
699 expr_to_str(expr, tcx.sess.intr()),
701 return closure::trans_expr_fn(bcx, sigil, decl, body,
702 expr.id, expr.id, dest);
704 ast::ExprDoBody(blk) => {
705 return trans_into(bcx, blk, dest);
707 ast::ExprCall(f, ref args, _) => {
708 return callee::trans_call(
709 bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
711 ast::ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
712 return callee::trans_method_call(bcx,
716 callee::ArgExprs(*args),
719 ast::ExprBinary(callee_id, _, lhs, rhs) => {
720 // if not overloaded, would be RvalueDatumExpr
721 return trans_overloaded_op(bcx,
729 ast::ExprUnary(callee_id, _, subexpr) => {
730 // if not overloaded, would be RvalueDatumExpr
731 return trans_overloaded_op(bcx,
739 ast::ExprIndex(callee_id, base, idx) => {
740 // if not overloaded, would be RvalueDatumExpr
741 return trans_overloaded_op(bcx,
749 ast::ExprCast(val, _) => {
750 match ty::get(node_id_type(bcx, expr.id)).sty {
751 ty::ty_trait(_, _, store, _, _) => {
752 return meth::trans_trait_cast(bcx, val, expr.id, dest,
756 bcx.tcx().sess.span_bug(expr.span,
757 "expr_cast of non-trait");
761 ast::ExprAssignOp(callee_id, op, dst, src) => {
762 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
765 bcx.tcx().sess.span_bug(
767 fmt!("trans_rvalue_dps_unadjusted reached fall-through case: %?",
773 fn trans_def_dps_unadjusted(bcx: @mut Block, ref_expr: &ast::Expr,
774 def: ast::Def, dest: Dest) -> @mut Block {
775 let _icx = push_ctxt("trans_def_dps_unadjusted");
778 let lldest = match dest {
779 SaveIn(lldest) => lldest,
780 Ignore => { return bcx; }
784 ast::DefVariant(tid, vid) => {
785 let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
786 if variant_info.args.len() > 0u {
788 let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
789 Store(bcx, fn_data.llfn, lldest);
793 let ty = expr_ty(bcx, ref_expr);
794 let repr = adt::represent_type(ccx, ty);
795 adt::trans_start_init(bcx, repr, lldest,
796 variant_info.disr_val);
800 ast::DefStruct(def_id) => {
801 let ty = expr_ty(bcx, ref_expr);
802 match ty::get(ty).sty {
803 ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
804 let repr = adt::represent_type(ccx, ty);
805 adt::trans_start_init(bcx, repr, lldest, 0);
807 ty::ty_bare_fn(*) => {
808 let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
809 Store(bcx, fn_data.llfn, lldest);
816 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
817 "Non-DPS def %? referened by %s",
818 def, bcx.node_id_to_str(ref_expr.id)));
823 fn trans_def_datum_unadjusted(bcx: @mut Block,
824 ref_expr: &ast::Expr,
825 def: ast::Def) -> DatumBlock
827 let _icx = push_ctxt("trans_def_datum_unadjusted");
829 let fn_data = match def {
831 ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
832 callee::trans_fn_ref(bcx, did, ref_expr.id)
834 ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
835 meth::trans_static_method_callee(bcx,
841 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
842 "Non-DPS def %? referened by %s",
843 def, bcx.node_id_to_str(ref_expr.id)));
847 let fn_ty = expr_ty(bcx, ref_expr);
858 fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
861 * Translates an lvalue expression, always yielding a by-ref
862 * datum. Does not apply any adjustments. */
864 let _icx = push_ctxt("trans_lval");
867 debug!("trans_lvalue(expr=%s)", bcx.expr_to_str(expr));
868 let _indenter = indenter();
870 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
872 return match expr.node {
873 ast::ExprParen(e) => {
874 trans_lvalue_unadjusted(bcx, e)
876 ast::ExprPath(_) | ast::ExprSelf => {
877 trans_def_lvalue(bcx, expr, bcx.def(expr.id))
879 ast::ExprField(base, ident, _) => {
880 trans_rec_field(bcx, base, ident)
882 ast::ExprIndex(_, base, idx) => {
883 trans_index(bcx, expr, base, idx)
885 ast::ExprUnary(_, ast::UnDeref, base) => {
886 let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base));
887 basedatum.deref(bcx, expr, 0)
890 bcx.tcx().sess.span_bug(
892 fmt!("trans_lvalue reached fall-through case: %?",
897 fn trans_rec_field(bcx: @mut Block,
899 field: ast::Ident) -> DatumBlock {
900 //! Translates `base.field`.
903 let _icx = push_ctxt("trans_rec_field");
905 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
906 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
907 do with_field_tys(bcx.tcx(), base_datum.ty, None) |discr, field_tys| {
908 let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
910 datum: do base_datum.get_element(bcx,
913 adt::trans_field_ptr(bcx, repr, srcval, discr, ix)
920 fn trans_index(bcx: @mut Block,
921 index_expr: &ast::Expr,
923 idx: @ast::Expr) -> DatumBlock {
924 //! Translates `base[idx]`.
926 let _icx = push_ctxt("trans_index");
930 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
932 // Translate index expression and cast to a suitable LLVM integer.
933 // Rust is less strict than LLVM in this regard.
934 let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
935 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
936 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
938 if ix_size < int_size {
939 if ty::type_is_signed(expr_ty(bcx, idx)) {
940 SExt(bcx, ix_val, ccx.int_type)
941 } else { ZExt(bcx, ix_val, ccx.int_type) }
942 } else if ix_size > int_size {
943 Trunc(bcx, ix_val, ccx.int_type)
949 let vt = tvec::vec_types(bcx, base_datum.ty);
950 base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
951 let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
952 base::maybe_name_value(bcx.ccx(), scaled_ix, "scaled_ix");
954 let (bcx, base, len) =
955 base_datum.get_vec_base_and_len(bcx, index_expr.span,
958 debug!("trans_index: base %s", bcx.val_to_str(base));
959 debug!("trans_index: len %s", bcx.val_to_str(len));
961 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
962 let bcx = do with_cond(bcx, bounds_check) |bcx| {
963 let unscaled_len = UDiv(bcx, len, vt.llunit_size);
964 controlflow::trans_fail_bounds_check(bcx, index_expr.span,
965 ix_val, unscaled_len)
967 let elt = InBoundsGEP(bcx, base, [ix_val]);
968 let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
971 datum: Datum {val: elt,
973 mode: ByRef(ZeroMem)}
977 fn trans_def_lvalue(bcx: @mut Block,
978 ref_expr: &ast::Expr,
982 //! Translates a reference to a path.
984 let _icx = push_ctxt("trans_def_lvalue");
986 ast::DefStatic(did, _) => {
987 let const_ty = expr_ty(bcx, ref_expr);
989 fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
991 // For external constants, we don't inline.
992 if did.crate == ast::LOCAL_CRATE {
993 // The LLVM global has the type of its initializer,
994 // which may not be equal to the enum's type for
996 let val = base::get_item_val(bcx.ccx(), did.node);
997 let pty = type_of(bcx.ccx(), const_ty).ptr_to();
998 PointerCast(bcx, val, pty)
1001 let extern_const_values = &bcx.ccx().extern_const_values;
1002 match extern_const_values.find(&did) {
1003 None => {} // Continue.
1011 let llty = type_of(bcx.ccx(), const_ty);
1012 let symbol = csearch::get_symbol(
1013 bcx.ccx().sess.cstore,
1015 let llval = do symbol.with_c_str |buf| {
1016 llvm::LLVMAddGlobal(bcx.ccx().llmod,
1020 SetLinkage(llval, ExternalLinkage);
1021 let extern_const_values = &mut bcx.ccx().extern_const_values;
1022 extern_const_values.insert(did, llval);
1028 let val = get_val(bcx, did, const_ty);
1031 datum: Datum {val: val,
1033 mode: ByRef(ZeroMem)}
1039 datum: trans_local_var(bcx, def)
1046 pub fn trans_local_var(bcx: @mut Block, def: ast::Def) -> Datum {
1047 let _icx = push_ctxt("trans_local_var");
1050 ast::DefUpvar(nid, _, _, _) => {
1051 // Can't move upvars, so this is never a ZeroMemLastUse.
1052 let local_ty = node_id_type(bcx, nid);
1053 match bcx.fcx.llupvars.find(&nid) {
1058 mode: ByRef(ZeroMem)
1062 bcx.sess().bug(fmt!(
1063 "trans_local_var: no llval for upvar %? found", nid));
1067 ast::DefArg(nid, _) => {
1068 take_local(bcx, bcx.fcx.llargs, nid)
1070 ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
1071 take_local(bcx, bcx.fcx.lllocals, nid)
1073 ast::DefSelf(nid) => {
1074 let self_info: ValSelfData = match bcx.fcx.llself {
1075 Some(ref self_info) => *self_info,
1077 bcx.sess().bug(fmt!(
1078 "trans_local_var: reference to self \
1079 out of context with id %?", nid));
1083 debug!("def_self() reference, self_info.t=%s",
1084 self_info.t.repr(bcx.tcx()));
1089 mode: ByRef(ZeroMem)
1093 bcx.sess().unimpl(fmt!(
1094 "unsupported def type in trans_local_var: %?", def));
1098 fn take_local(bcx: @mut Block,
1099 table: &HashMap<ast::NodeId, ValueRef>,
1100 nid: ast::NodeId) -> Datum {
1101 let v = match table.find(&nid) {
1104 bcx.sess().bug(fmt!(
1105 "trans_local_var: no llval for local/arg %? found", nid));
1108 let ty = node_id_type(bcx, nid);
1109 debug!("take_local(nid=%?, v=%s, ty=%s)",
1110 nid, bcx.val_to_str(v), bcx.ty_to_str(ty));
1114 mode: ByRef(ZeroMem)
1119 // The optional node ID here is the node ID of the path identifying the enum
1120 // variant in use. If none, this cannot possibly an enum variant (so, if it
1121 // is and `node_id_opt` is none, this function fails).
1122 pub fn with_field_tys<R>(tcx: ty::ctxt,
1124 node_id_opt: Option<ast::NodeId>,
1125 op: &fn(ty::Disr, (&[ty::field])) -> R) -> R {
1126 match ty::get(ty).sty {
1127 ty::ty_struct(did, ref substs) => {
1128 op(0, struct_fields(tcx, did, substs))
1131 ty::ty_enum(_, ref substs) => {
1132 // We want the *variant* ID here, not the enum ID.
1136 "cannot get field types from the enum type %s \
1141 match tcx.def_map.get_copy(&node_id) {
1142 ast::DefVariant(enum_id, variant_id) => {
1143 let variant_info = ty::enum_variant_with_id(
1144 tcx, enum_id, variant_id);
1145 op(variant_info.disr_val,
1146 struct_fields(tcx, variant_id, substs))
1149 tcx.sess.bug("resolve didn't map this expr to a \
1159 "cannot get field types from the type %s",
1165 fn trans_rec_or_struct(bcx: @mut Block,
1166 fields: &[ast::Field],
1167 base: Option<@ast::Expr>,
1168 expr_span: codemap::Span,
1170 dest: Dest) -> @mut Block
1172 let _icx = push_ctxt("trans_rec");
1175 let ty = node_id_type(bcx, id);
1176 let tcx = bcx.tcx();
1177 do with_field_tys(tcx, ty, Some(id)) |discr, field_tys| {
1178 let mut need_base = vec::from_elem(field_tys.len(), true);
1180 let numbered_fields = do fields.map |field| {
1182 field_tys.iter().position(|field_ty|
1183 field_ty.ident.name == field.ident.name);
1186 need_base[i] = false;
1190 tcx.sess.span_bug(field.span,
1191 "Couldn't find field in struct type")
1195 let optbase = match base {
1196 Some(base_expr) => {
1197 let mut leftovers = ~[];
1198 for (i, b) in need_base.iter().enumerate() {
1200 leftovers.push((i, field_tys[i].mt.ty))
1203 Some(StructBaseInfo {expr: base_expr,
1204 fields: leftovers })
1207 if need_base.iter().any(|b| *b) {
1208 tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1214 let repr = adt::represent_type(bcx.ccx(), ty);
1215 trans_adt(bcx, repr, discr, numbered_fields, optbase, dest)
1220 * Information that `trans_adt` needs in order to fill in the fields
1221 * of a struct copied from a base struct (e.g., from an expression
1222 * like `Foo { a: b, ..base }`.
1224 * Note that `fields` may be empty; the base expression must always be
1225 * evaluated for side-effects.
1227 struct StructBaseInfo {
1228 /// The base expression; will be evaluated after all explicit fields.
1230 /// The indices of fields to copy paired with their types.
1231 fields: ~[(uint, ty::t)]
1235 * Constructs an ADT instance:
1237 * - `fields` should be a list of field indices paired with the
1238 * expression to store into that field. The initializers will be
1239 * evaluated in the order specified by `fields`.
1241 * - `optbase` contains information on the base struct (if any) from
1242 * which remaining fields are copied; see comments on `StructBaseInfo`.
1244 fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: ty::Disr,
1245 fields: &[(uint, @ast::Expr)],
1246 optbase: Option<StructBaseInfo>,
1247 dest: Dest) -> @mut Block {
1248 let _icx = push_ctxt("trans_adt");
1250 let addr = match dest {
1252 for &(_i, e) in fields.iter() {
1253 bcx = trans_into(bcx, e, Ignore);
1255 for sbi in optbase.iter() {
1256 // FIXME #7261: this moves entire base, not just certain fields
1257 bcx = trans_into(bcx, sbi.expr, Ignore);
1263 let mut temp_cleanups = ~[];
1264 adt::trans_start_init(bcx, repr, addr, discr);
1265 for &(i, e) in fields.iter() {
1266 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1267 let e_ty = expr_ty(bcx, e);
1268 bcx = trans_into(bcx, e, SaveIn(dest));
1269 add_clean_temp_mem(bcx, dest, e_ty);
1270 temp_cleanups.push(dest);
1272 for base in optbase.iter() {
1273 // FIXME #6573: is it sound to use the destination's repr on the base?
1274 // And, would it ever be reasonable to be here with discr != 0?
1275 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr));
1276 for &(i, t) in base.fields.iter() {
1277 let datum = do base_datum.get_element(bcx, t, ZeroMem) |srcval| {
1278 adt::trans_field_ptr(bcx, repr, srcval, discr, i)
1280 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1281 bcx = datum.store_to(bcx, INIT, dest);
1285 for cleanup in temp_cleanups.iter() {
1286 revoke_clean(bcx, *cleanup);
1292 fn trans_immediate_lit(bcx: @mut Block, expr: @ast::Expr,
1293 lit: ast::lit) -> DatumBlock {
1294 // must not be a string constant, that is a RvalueDpsExpr
1295 let _icx = push_ctxt("trans_immediate_lit");
1296 let ty = expr_ty(bcx, expr);
1297 immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty)
1300 fn trans_unary_datum(bcx: @mut Block,
1301 un_expr: &ast::Expr,
1303 sub_expr: @ast::Expr) -> DatumBlock {
1304 let _icx = push_ctxt("trans_unary_datum");
1306 // if deref, would be LvalueExpr
1307 assert!(op != ast::UnDeref);
1309 // if overloaded, would be RvalueDpsExpr
1310 assert!(!bcx.ccx().maps.method_map.contains_key(&un_expr.id));
1312 let un_ty = expr_ty(bcx, un_expr);
1313 let sub_ty = expr_ty(bcx, sub_expr);
1317 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1319 // If this is a boolean type, we must not use the LLVM Not
1320 // instruction, as that is a *bitwise* not and we want *logical*
1321 // not on our 8-bit boolean values.
1322 let llresult = match ty::get(un_ty).sty {
1324 let llcond = ICmp(bcx,
1328 Select(bcx, llcond, C_bool(true), C_bool(false))
1332 immediate_rvalue_bcx(bcx, llresult, un_ty)
1335 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1337 if ty::type_is_fp(un_ty) {
1343 immediate_rvalue_bcx(bcx, llneg, un_ty)
1346 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty,
1350 let heap = heap_for_unique(bcx, un_ty);
1351 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap)
1354 bcx.sess().bug("deref expressions should have been \
1355 translated using trans_lvalue(), not \
1356 trans_unary_datum()")
1360 fn trans_boxed_expr(bcx: @mut Block,
1362 contents: @ast::Expr,
1364 heap: heap) -> DatumBlock {
1365 let _icx = push_ctxt("trans_boxed_expr");
1366 if heap == heap_exchange {
1367 let llty = type_of(bcx.ccx(), contents_ty);
1368 let size = llsize_of(bcx.ccx(), llty);
1369 let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
1370 heap_exchange, size);
1371 add_clean_free(bcx, val, heap_exchange);
1372 let bcx = trans_into(bcx, contents, SaveIn(val));
1373 revoke_clean(bcx, val);
1374 return immediate_rvalue_bcx(bcx, val, box_ty);
1376 let base::MallocResult { bcx, box: bx, body } =
1377 base::malloc_general(bcx, contents_ty, heap);
1378 add_clean_free(bcx, bx, heap);
1379 let bcx = trans_into(bcx, contents, SaveIn(body));
1380 revoke_clean(bcx, bx);
1381 return immediate_rvalue_bcx(bcx, bx, box_ty);
1386 fn trans_addr_of(bcx: @mut Block, expr: &ast::Expr,
1387 subexpr: @ast::Expr) -> DatumBlock {
1388 let _icx = push_ctxt("trans_addr_of");
1390 let sub_datum = unpack_datum!(bcx, trans_to_datum(bcx, subexpr));
1391 let llval = sub_datum.to_ref_llval(bcx);
1392 return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
1395 // Important to get types for both lhs and rhs, because one might be _|_
1396 // and the other not.
1397 fn trans_eager_binop(bcx: @mut Block,
1398 binop_expr: &ast::Expr,
1404 let _icx = push_ctxt("trans_eager_binop");
1406 let lhs = lhs_datum.to_appropriate_llval(bcx);
1407 let lhs_t = lhs_datum.ty;
1409 let rhs = rhs_datum.to_appropriate_llval(bcx);
1410 let rhs_t = rhs_datum.ty;
1413 if ty::type_is_bot(lhs_t) { rhs_t }
1416 let tcx = bcx.tcx();
1417 if ty::type_is_simd(tcx, intype) {
1418 intype = ty::simd_type(tcx, intype);
1420 let is_float = ty::type_is_fp(intype);
1421 let signed = ty::type_is_signed(intype);
1423 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1426 let val = match op {
1428 if is_float { FAdd(bcx, lhs, rhs) }
1429 else { Add(bcx, lhs, rhs) }
1432 if is_float { FSub(bcx, lhs, rhs) }
1433 else { Sub(bcx, lhs, rhs) }
1436 if is_float { FMul(bcx, lhs, rhs) }
1437 else { Mul(bcx, lhs, rhs) }
1443 // Only zero-check integers; fp /0 is NaN
1444 bcx = base::fail_if_zero(bcx, binop_expr.span,
1457 // Only zero-check integers; fp %0 is NaN
1458 bcx = base::fail_if_zero(bcx, binop_expr.span,
1467 ast::BiBitOr => Or(bcx, lhs, rhs),
1468 ast::BiBitAnd => And(bcx, lhs, rhs),
1469 ast::BiBitXor => Xor(bcx, lhs, rhs),
1470 ast::BiShl => Shl(bcx, lhs, rhs),
1474 } else { LShr(bcx, lhs, rhs) }
1476 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
1477 if ty::type_is_bot(rhs_t) {
1480 if !ty::type_is_scalar(rhs_t) {
1481 bcx.tcx().sess.span_bug(binop_expr.span,
1482 "non-scalar comparison");
1484 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1486 ZExt(bcx, cmpr.val, Type::i8())
1490 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1494 return immediate_rvalue_bcx(bcx, val, binop_ty);
1497 // refinement types would obviate the need for this
1498 enum lazy_binop_ty { lazy_and, lazy_or }
1500 fn trans_lazy_binop(bcx: @mut Block,
1501 binop_expr: &ast::Expr,
1504 b: @ast::Expr) -> DatumBlock {
1505 let _icx = push_ctxt("trans_lazy_binop");
1506 let binop_ty = expr_ty(bcx, binop_expr);
1509 let Result {bcx: past_lhs, val: lhs} = {
1510 do base::with_scope_result(bcx, a.info(), "lhs") |bcx| {
1511 trans_to_datum(bcx, a).to_result()
1515 if past_lhs.unreachable {
1516 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty);
1519 let join = base::sub_block(bcx, "join");
1520 let before_rhs = base::sub_block(bcx, "rhs");
1522 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1524 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1525 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1528 let Result {bcx: past_rhs, val: rhs} = {
1529 do base::with_scope_result(before_rhs, b.info(), "rhs") |bcx| {
1530 trans_to_datum(bcx, b).to_result()
1534 if past_rhs.unreachable {
1535 return immediate_rvalue_bcx(join, lhs, binop_ty);
1538 Br(past_rhs, join.llbb);
1539 let phi = Phi(join, Type::bool(), [lhs, rhs], [past_lhs.llbb,
1542 return immediate_rvalue_bcx(join, phi, binop_ty);
1545 fn trans_binary(bcx: @mut Block,
1546 binop_expr: &ast::Expr,
1549 rhs: @ast::Expr) -> DatumBlock
1551 let _icx = push_ctxt("trans_binary");
1555 trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
1558 trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
1562 let lhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, lhs));
1563 let rhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, rhs));
1564 let binop_ty = expr_ty(bcx, binop_expr);
1565 trans_eager_binop(bcx, binop_expr, binop_ty, op,
1566 &lhs_datum, &rhs_datum)
1571 fn trans_overloaded_op(bcx: @mut Block,
1573 callee_id: ast::NodeId,
1575 args: ~[@ast::Expr],
1579 let origin = bcx.ccx().maps.method_map.get_copy(&expr.id);
1580 let fty = node_id_type(bcx, callee_id);
1581 callee::trans_call_inner(bcx,
1586 meth::trans_method_callee(bcx,
1591 callee::ArgExprs(args),
1596 fn int_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
1597 llsrc: ValueRef, signed: bool) -> ValueRef {
1598 let _icx = push_ctxt("int_cast");
1600 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1601 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1602 return if dstsz == srcsz {
1603 BitCast(bcx, llsrc, lldsttype)
1604 } else if srcsz > dstsz {
1605 TruncOrBitCast(bcx, llsrc, lldsttype)
1607 SExtOrBitCast(bcx, llsrc, lldsttype)
1609 ZExtOrBitCast(bcx, llsrc, lldsttype)
1614 fn float_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
1615 llsrc: ValueRef) -> ValueRef {
1616 let _icx = push_ctxt("float_cast");
1617 let srcsz = llsrctype.float_width();
1618 let dstsz = lldsttype.float_width();
1619 return if dstsz > srcsz {
1620 FPExt(bcx, llsrc, lldsttype)
1621 } else if srcsz > dstsz {
1622 FPTrunc(bcx, llsrc, lldsttype)
1627 pub enum cast_kind {
1635 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1636 match ty::get(t).sty {
1637 ty::ty_char => cast_integral,
1638 ty::ty_float(*) => cast_float,
1639 ty::ty_ptr(*) => cast_pointer,
1640 ty::ty_rptr(*) => cast_pointer,
1641 ty::ty_bare_fn(*) => cast_pointer,
1642 ty::ty_int(*) => cast_integral,
1643 ty::ty_uint(*) => cast_integral,
1644 ty::ty_bool => cast_integral,
1645 ty::ty_enum(*) => cast_enum,
1650 fn trans_imm_cast(bcx: @mut Block, expr: @ast::Expr,
1651 id: ast::NodeId) -> DatumBlock {
1652 let _icx = push_ctxt("trans_cast");
1653 let ccx = bcx.ccx();
1655 let t_out = node_id_type(bcx, id);
1658 let llexpr = unpack_result!(bcx, trans_to_datum(bcx, expr).to_result());
1659 let ll_t_in = val_ty(llexpr);
1660 let t_in = expr_ty(bcx, expr);
1661 let ll_t_out = type_of::type_of(ccx, t_out);
1663 let k_in = cast_type_kind(t_in);
1664 let k_out = cast_type_kind(t_out);
1665 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1668 match (k_in, k_out) {
1669 (cast_integral, cast_integral) => {
1670 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1672 (cast_float, cast_float) => {
1673 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1675 (cast_integral, cast_float) => {
1677 SIToFP(bcx, llexpr, ll_t_out)
1678 } else { UIToFP(bcx, llexpr, ll_t_out) }
1680 (cast_float, cast_integral) => {
1681 if ty::type_is_signed(t_out) {
1682 FPToSI(bcx, llexpr, ll_t_out)
1683 } else { FPToUI(bcx, llexpr, ll_t_out) }
1685 (cast_integral, cast_pointer) => {
1686 IntToPtr(bcx, llexpr, ll_t_out)
1688 (cast_pointer, cast_integral) => {
1689 PtrToInt(bcx, llexpr, ll_t_out)
1691 (cast_pointer, cast_pointer) => {
1692 PointerCast(bcx, llexpr, ll_t_out)
1694 (cast_enum, cast_integral) |
1695 (cast_enum, cast_float) => {
1697 let repr = adt::represent_type(ccx, t_in);
1698 let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr);
1700 cast_integral => int_cast(bcx, ll_t_out,
1701 val_ty(lldiscrim_a),
1703 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1704 _ => ccx.sess.bug(fmt!("translating unsupported cast: \
1705 %s (%?) -> %s (%?)",
1706 t_in.repr(ccx.tcx), k_in,
1707 t_out.repr(ccx.tcx), k_out))
1710 _ => ccx.sess.bug(fmt!("translating unsupported cast: \
1711 %s (%?) -> %s (%?)",
1712 t_in.repr(ccx.tcx), k_in,
1713 t_out.repr(ccx.tcx), k_out))
1715 return immediate_rvalue_bcx(bcx, newval, t_out);
1718 fn trans_assign_op(bcx: @mut Block,
1720 callee_id: ast::NodeId,
1723 src: @ast::Expr) -> @mut Block
1725 let _icx = push_ctxt("trans_assign_op");
1728 debug!("trans_assign_op(expr=%s)", bcx.expr_to_str(expr));
1730 // Evaluate LHS (destination), which should be an lvalue
1731 let dst_datum = unpack_datum!(bcx, trans_lvalue_unadjusted(bcx, dst));
1733 // A user-defined operator method
1734 if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
1735 // FIXME(#2528) evaluates the receiver twice!!
1736 let scratch = scratch_datum(bcx, dst_datum.ty, "__assign_op", false);
1737 let bcx = trans_overloaded_op(bcx,
1743 SaveIn(scratch.val));
1744 return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
1747 // Evaluate RHS (source)
1748 let src_datum = unpack_datum!(bcx, trans_to_datum(bcx, src));
1750 // Perform computation and store the result
1754 bcx, expr, dst_datum.ty, op,
1755 &dst_datum, &src_datum));
1756 return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
1759 fn shorten(x: &str) -> @str {
1760 (if x.char_len() > 60 {x.slice_chars(0, 60)} else {x}).to_managed()
1763 pub fn trans_log_level(bcx: @mut Block) -> DatumBlock {
1764 let _icx = push_ctxt("trans_log_level");
1765 let ccx = bcx.ccx();
1767 let (modpath, modname) = {
1768 let path = &mut bcx.fcx.path;
1769 let mut modpath = ~[path_mod(ccx.sess.ident_of(ccx.link_meta.name))];
1770 for e in path.iter() {
1772 path_mod(_) => { modpath.push(*e) }
1776 let modname = path_str(ccx.sess, modpath);
1780 let global = if ccx.module_data.contains_key(&modname) {
1781 ccx.module_data.get_copy(&modname)
1783 let s = link::mangle_internal_name_by_path_and_seq(
1784 ccx, modpath, "loglevel");
1787 global = do s.with_c_str |buf| {
1788 llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
1790 llvm::LLVMSetGlobalConstant(global, False);
1791 llvm::LLVMSetInitializer(global, C_null(Type::i32()));
1792 lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage);
1794 ccx.module_data.insert(modname, global);
1798 return immediate_rvalue_bcx(bcx, Load(bcx, global), ty::mk_u32());