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 and moves for you.
28 ## Translation to a datum
30 In some cases, `trans_into()` is too narrow of an interface.
31 Generally this occurs either when you know that the result value is
32 going to be a scalar, or when you need to evaluate the expression into
33 some memory location so you can go and inspect it (e.g., assignments,
34 `match` expressions, the `&` operator).
36 In such cases, you want the following function:
38 trans_to_datum(block, expr) -> DatumBlock
40 This function generates code to evaluate the expression and return a
41 `Datum` describing where the result is to be found. This function
42 tries to return its result in the most efficient way possible, without
43 introducing extra copies or sacrificing information. Therefore, for
44 lvalue expressions, you always get a by-ref `Datum` in return that
45 points at the memory for this lvalue (almost, see [1]). For rvalue
46 expressions, we will return a by-value `Datum` whenever possible, but
47 it is often necessary to allocate a stack slot, store the result of
48 the rvalue in there, and then return a pointer to the slot (see the
49 discussion later on about the different kinds of rvalues).
51 NB: The `trans_to_datum()` function does perform adjustments, but
52 since it returns a pointer to the value "in place" it does not handle
53 any moves that may be relevant. If you are transing an expression
54 whose result should be moved, you should either use the Datum methods
55 `move_to()` (for unconditional moves) or `store_to()` (for moves
56 conditioned on the type of the expression) at some point.
58 ## Translating local variables
60 `trans_local_var()` can be used to trans a ref to a local variable
61 that is not an expression. This is needed for captures.
63 ## Ownership and cleanups
65 The current system for cleanups associates required cleanups with
66 block contexts. Block contexts are structured into a tree that
67 resembles the code itself. Not every block context has cleanups
68 associated with it, only those blocks that have a kind of
69 `block_scope`. See `common::block_kind` for more details.
71 If you invoke `trans_into()`, no cleanup is scheduled for you. The
72 value is written into the given destination and is assumed to be owned
75 When you invoke `trans_to_datum()` on an rvalue, the resulting
76 datum/value will have an appropriate cleanup scheduled for the
77 innermost cleanup scope. If you later use `move_to()` or
78 `drop_val()`, this cleanup will be canceled.
80 During the evaluation of an expression, temporary cleanups are created
81 and later canceled. These represent intermediate or partial results
82 which must be cleaned up in the event of task failure.
84 ## Implementation details
86 We divide expressions into three categories, based on how they are most
87 naturally implemented:
94 Lvalues always refer to user-assignable memory locations.
95 Translating those always results in a by-ref datum; this introduces
96 no inefficiencies into the generated code, because all lvalues are
97 naturally addressable.
99 Datum rvalues are rvalues that always generate datums as a result.
100 These are generally scalar results, such as `a+b` where `a` and `b`
103 DPS rvalues are rvalues that, when translated, must be given a
104 memory location to write into (or the Ignore flag). These are
105 generally expressions that produce structural results that are
106 larger than one word (e.g., a struct literal), but also expressions
107 (like `if`) that involve control flow (otherwise we'd have to
110 Finally, statement rvalues are rvalues that always produce a nil
111 return type, such as `while` loops or assignments (`a = b`).
115 [1] Actually, some lvalues are only stored by value and not by
116 reference. An example (as of this writing) would be immutable
117 arguments or pattern bindings of immediate type. However, mutable
118 lvalues are *never* stored by value.
122 use core::prelude::*;
126 use lib::llvm::{ValueRef, TypeRef, llvm, True};
127 use middle::borrowck::root_map_key;
128 use middle::trans::_match;
129 use middle::trans::adt;
130 use middle::trans::base;
131 use middle::trans::base::*;
132 use middle::trans::build::*;
133 use middle::trans::callee::{AutorefArg, DoAutorefArg, DontAutorefArg};
134 use middle::trans::callee;
135 use middle::trans::closure;
136 use middle::trans::common::*;
137 use middle::trans::consts;
138 use middle::trans::controlflow;
139 use middle::trans::datum::*;
140 use middle::trans::debuginfo;
141 use middle::trans::inline;
142 use middle::trans::machine;
143 use middle::trans::meth;
144 use middle::trans::tvec;
145 use middle::trans::type_of;
147 use middle::ty::struct_mutable_fields;
148 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
149 AutoDerefRef, AutoAddEnv};
150 use util::common::indenter;
151 use util::ppaux::ty_to_str;
153 use core::hashmap::linear::LinearMap;
154 use syntax::print::pprust::{expr_to_str};
160 // These are passed around by the code generating functions to track the
161 // destination of a computation's value.
169 fn to_str(&self, ccx: @CrateContext) -> ~str {
171 SaveIn(v) => fmt!("SaveIn(%s)", val_str(ccx.tn, v)),
177 impl cmp::Eq for Dest {
178 fn eq(&self, other: &Dest) -> bool {
179 match ((*self), (*other)) {
180 (SaveIn(e0a), SaveIn(e0b)) => e0a == e0b,
181 (Ignore, Ignore) => true,
182 (SaveIn(*), _) => false,
183 (Ignore, _) => false,
186 fn ne(&self, other: &Dest) -> bool { !(*self).eq(other) }
189 fn drop_and_cancel_clean(bcx: block, dat: Datum) -> block {
190 let bcx = dat.drop_val(bcx);
191 dat.cancel_clean(bcx);
195 pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
196 debug!("trans_to_datum(expr=%s)", bcx.expr_to_str(expr));
197 return match bcx.tcx().adjustments.find(&expr.id) {
199 trans_to_datum_unadjusted(bcx, expr)
201 Some(&@AutoAddEnv(*)) => {
203 let mut datum = unpack_datum!(bcx, {
204 trans_to_datum_unadjusted(bcx, expr)
206 add_env(bcx, expr, datum)
208 Some(&@AutoDerefRef(ref adj)) => {
210 let mut datum = unpack_datum!(bcx, {
211 trans_to_datum_unadjusted(bcx, expr)
214 if adj.autoderefs > 0 {
215 let DatumBlock { bcx: new_bcx, datum: new_datum } =
216 datum.autoderef(bcx, expr.id, adj.autoderefs);
221 datum = match adj.autoref {
223 Some(ref autoref) => {
226 unpack_datum!(bcx, auto_ref(bcx, datum))
229 unpack_datum!(bcx, auto_slice(bcx, datum))
231 AutoBorrowVecRef => {
232 unpack_datum!(bcx, auto_slice_and_ref(bcx, datum))
235 // currently, all closure types are
236 // represented precisely the same, so no
237 // runtime adjustment is required:
244 debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx()));
246 return DatumBlock {bcx: bcx, datum: datum};
250 fn auto_ref(bcx: block, datum: Datum) -> DatumBlock {
251 DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
254 fn auto_slice(bcx: block, datum: Datum) -> DatumBlock {
255 // This is not the most efficient thing possible; since slices
256 // are two words it'd be better if this were compiled in
257 // 'dest' mode, but I can't find a nice way to structure the
258 // code and keep it DRY that accommodates that use case at the
262 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
263 let (base, len) = datum.get_base_and_len(bcx);
265 // this type may have a different region/mutability than the
266 // real one, but it will have the same runtime representation
267 let slice_ty = ty::mk_evec(tcx,
268 ty::mt { ty: unit_ty, mutbl: ast::m_imm },
269 ty::vstore_slice(ty::re_static));
271 let scratch = scratch_datum(bcx, slice_ty, false);
272 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
273 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
274 DatumBlock {bcx: bcx, datum: scratch}
277 fn add_env(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock {
278 // This is not the most efficient thing possible; since closures
279 // are two words it'd be better if this were compiled in
280 // 'dest' mode, but I can't find a nice way to structure the
281 // code and keep it DRY that accommodates that use case at the
285 let closure_ty = expr_ty_adjusted(bcx, expr);
286 debug!("add_env(closure_ty=%s)", ty_to_str(tcx, closure_ty));
287 let scratch = scratch_datum(bcx, closure_ty, false);
288 let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
289 fail_unless!(datum.appropriate_mode() == ByValue);
290 Store(bcx, datum.to_appropriate_llval(bcx), llfn);
291 let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
292 Store(bcx, base::null_env_ptr(bcx), llenv);
293 DatumBlock {bcx: bcx, datum: scratch}
296 fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock {
297 let DatumBlock { bcx, datum } = auto_slice(bcx, datum);
302 pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
303 if bcx.tcx().adjustments.contains_key(&expr.id) {
304 // use trans_to_datum, which is mildly less efficient but
305 // which will perform the adjustments:
306 let datumblock = trans_to_datum(bcx, expr);
308 Ignore => datumblock.bcx,
309 SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
313 let ty = expr_ty(bcx, expr);
315 debug!("trans_into_unadjusted(expr=%s, dest=%s)",
316 bcx.expr_to_str(expr),
317 dest.to_str(bcx.ccx()));
318 let _indenter = indenter();
320 debuginfo::update_source_pos(bcx, expr.span);
323 if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
330 let kind = bcx.expr_kind(expr);
331 debug!("expr kind = %?", kind);
334 let datumblock = trans_lvalue_unadjusted(bcx, expr);
336 Ignore => datumblock.bcx,
337 SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
340 ty::RvalueDatumExpr => {
341 let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
343 Ignore => datumblock.drop_val(),
345 // NB: We always do `move_to()` regardless of the
346 // moves_map because we're processing an rvalue
347 SaveIn(lldest) => datumblock.move_to(INIT, lldest)
350 ty::RvalueDpsExpr => {
351 trans_rvalue_dps_unadjusted(bcx, expr, dest)
353 ty::RvalueStmtExpr => {
354 trans_rvalue_stmt_unadjusted(bcx, expr)
359 fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
362 * Translates an lvalue expression, always yielding a by-ref
363 * datum. Generally speaking you should call trans_to_datum()
364 * instead, but sometimes we call trans_lvalue() directly as a
365 * means of asserting that a particular expression is an lvalue. */
367 return match bcx.tcx().adjustments.find(&expr.id) {
368 None => trans_lvalue_unadjusted(bcx, expr),
372 fmt!("trans_lvalue() called on an expression \
378 fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
381 * Translates an expression into a datum. If this expression
382 * is an rvalue, this will result in a temporary value being
383 * created. If you already know where the result should be stored,
384 * you should use `trans_into()` instead. */
388 debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
389 let _indenter = indenter();
391 debuginfo::update_source_pos(bcx, expr.span);
393 match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
395 return trans_lvalue_unadjusted(bcx, expr);
398 ty::RvalueDatumExpr => {
399 let datum = unpack_datum!(bcx, {
400 trans_rvalue_datum_unadjusted(bcx, expr)
402 datum.add_clean(bcx);
403 return DatumBlock {bcx: bcx, datum: datum};
406 ty::RvalueStmtExpr => {
407 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
408 return nil(bcx, expr_ty(bcx, expr));
411 ty::RvalueDpsExpr => {
412 let ty = expr_ty(bcx, expr);
413 if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
414 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
417 let scratch = scratch_datum(bcx, ty, false);
418 bcx = trans_rvalue_dps_unadjusted(
419 bcx, expr, SaveIn(scratch.val));
421 // Note: this is not obviously a good idea. It causes
422 // immediate values to be loaded immediately after a
423 // return from a call or other similar expression,
424 // which in turn leads to alloca's having shorter
425 // lifetimes and hence larger stack frames. However,
426 // in turn it can lead to more register pressure.
427 // Still, in practice it seems to increase
428 // performance, since we have fewer problems with
430 let scratch = scratch.to_appropriate_datum(bcx);
432 scratch.add_clean(bcx);
433 return DatumBlock {bcx: bcx, datum: scratch};
438 fn nil(bcx: block, ty: ty::t) -> DatumBlock {
439 let datum = immediate_rvalue(C_nil(), ty);
440 DatumBlock {bcx: bcx, datum: datum}
444 fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
445 let _icx = bcx.insn_ctxt("trans_rvalue_datum_unadjusted");
447 trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
450 ast::expr_path(_) => {
451 return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id));
453 ast::expr_vstore(contents, ast::expr_vstore_box) |
454 ast::expr_vstore(contents, ast::expr_vstore_mut_box) => {
455 return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed,
458 ast::expr_vstore(contents, ast::expr_vstore_uniq) => {
459 let heap = heap_for_unique(bcx, expr_ty(bcx, contents));
460 return tvec::trans_uniq_or_managed_vstore(bcx, heap,
463 ast::expr_lit(lit) => {
464 return trans_immediate_lit(bcx, expr, *lit);
466 ast::expr_binary(op, lhs, rhs) => {
467 // if overloaded, would be RvalueDpsExpr
468 fail_unless!(!bcx.ccx().maps.method_map.contains_key(&expr.id));
470 return trans_binary(bcx, expr, op, lhs, rhs);
472 ast::expr_unary(op, x) => {
473 return trans_unary_datum(bcx, expr, op, x);
475 ast::expr_addr_of(_, x) => {
476 return trans_addr_of(bcx, expr, x);
478 ast::expr_cast(val, _) => {
479 return trans_imm_cast(bcx, val, expr.id);
481 ast::expr_paren(e) => {
482 return trans_rvalue_datum_unadjusted(bcx, e);
485 bcx.tcx().sess.span_bug(
487 fmt!("trans_rvalue_datum_unadjusted reached \
488 fall-through case: %?",
494 fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
496 let _icx = bcx.insn_ctxt("trans_rvalue_stmt");
498 trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
501 ast::expr_break(label_opt) => {
502 return controlflow::trans_break(bcx, label_opt);
504 ast::expr_again(label_opt) => {
505 return controlflow::trans_cont(bcx, label_opt);
507 ast::expr_ret(ex) => {
508 return controlflow::trans_ret(bcx, ex);
510 ast::expr_log(_, lvl, a) => {
511 return controlflow::trans_log(expr, lvl, bcx, a);
513 ast::expr_while(cond, ref body) => {
514 return controlflow::trans_while(bcx, cond, body);
516 ast::expr_loop(ref body, opt_label) => {
517 return controlflow::trans_loop(bcx, body, opt_label);
519 ast::expr_assign(dst, src) => {
520 let src_datum = unpack_datum!(
521 bcx, trans_to_datum(bcx, src));
522 let dst_datum = unpack_datum!(
523 bcx, trans_lvalue(bcx, dst));
524 return src_datum.store_to_datum(
525 bcx, src.id, DROP_EXISTING, dst_datum);
527 ast::expr_swap(dst, src) => {
528 let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst));
529 let src_datum = unpack_datum!(bcx, trans_lvalue(bcx, src));
531 // If the source and destination are the same, then don't swap.
532 // Avoids performing an overlapping memcpy
533 let dst_datum_ref = dst_datum.to_ref_llval(bcx);
534 let src_datum_ref = src_datum.to_ref_llval(bcx);
535 let cmp = ICmp(bcx, lib::llvm::IntEQ,
539 let swap_cx = base::sub_block(bcx, ~"swap");
540 let next_cx = base::sub_block(bcx, ~"next");
542 CondBr(bcx, cmp, next_cx.llbb, swap_cx.llbb);
544 let scratch = scratch_datum(swap_cx, dst_datum.ty, false);
546 let swap_cx = dst_datum.move_to_datum(swap_cx, INIT, scratch);
547 let swap_cx = src_datum.move_to_datum(swap_cx, INIT, dst_datum);
548 let swap_cx = scratch.move_to_datum(swap_cx, INIT, src_datum);
550 Br(swap_cx, next_cx.llbb);
554 ast::expr_assign_op(op, dst, src) => {
555 return trans_assign_op(bcx, expr, op, dst, src);
557 ast::expr_paren(a) => {
558 return trans_rvalue_stmt_unadjusted(bcx, a);
560 ast::expr_inline_asm(asm, ref ins, ref outs,
561 clobs, volatile, alignstack) => {
562 let mut constraints = ~[];
563 let mut cleanups = ~[];
564 let mut aoutputs = ~[];
566 let outputs = do outs.map |&(c, out)| {
567 constraints.push(copy *c);
569 let aoutty = ty::arg {
570 mode: ast::expl(ast::by_copy),
571 ty: expr_ty(bcx, out)
573 aoutputs.push(unpack_result!(bcx, {
574 callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups,
575 None, callee::DontAutorefArg)
578 let e = match out.node {
579 ast::expr_addr_of(_, e) => e,
580 _ => fail!(~"Expression must be addr of")
583 let outty = ty::arg {
584 mode: ast::expl(ast::by_copy),
588 unpack_result!(bcx, {
589 callee::trans_arg_expr(bcx, outty, e, &mut cleanups,
590 None, callee::DontAutorefArg)
595 for cleanups.each |c| {
596 revoke_clean(bcx, *c);
600 let inputs = do ins.map |&(c, in)| {
601 constraints.push(copy *c);
604 mode: ast::expl(ast::by_copy),
608 unpack_result!(bcx, {
609 callee::trans_arg_expr(bcx, inty, in, &mut cleanups,
610 None, callee::DontAutorefArg)
615 for cleanups.each |c| {
616 revoke_clean(bcx, *c);
619 let mut constraints = str::connect(constraints, ",");
623 if constraints == ~"" {
624 constraints += *clobs;
626 constraints += ~"," + *clobs;
629 constraints += *clobs;
632 debug!("Asm Constraints: %?", constraints);
634 let output = if outputs.len() == 0 {
636 } else if outputs.len() == 1 {
639 T_struct(outputs.map(|o| val_ty(*o)))
642 let r = do str::as_c_str(*asm) |a| {
643 do str::as_c_str(constraints) |c| {
644 InlineAsmCall(bcx, a, c, inputs, output, volatile,
645 alignstack, lib::llvm::AD_ATT)
649 if outputs.len() == 1 {
650 let op = PointerCast(bcx, aoutputs[0],
651 T_ptr(val_ty(outputs[0])));
654 for aoutputs.eachi |i, o| {
655 let v = ExtractValue(bcx, r, i);
656 let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
664 bcx.tcx().sess.span_bug(
666 fmt!("trans_rvalue_stmt_unadjusted reached \
667 fall-through case: %?",
673 fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
674 dest: Dest) -> block {
676 let _icx = bcx.insn_ctxt("trans_rvalue_dps_unadjusted");
679 trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
682 ast::expr_paren(e) => {
683 return trans_rvalue_dps_unadjusted(bcx, e, dest);
685 ast::expr_path(_) => {
686 return trans_def_dps_unadjusted(bcx, expr,
687 bcx.def(expr.id), dest);
689 ast::expr_if(cond, ref thn, els) => {
690 return controlflow::trans_if(bcx, cond, thn, els, dest);
692 ast::expr_match(discr, ref arms) => {
693 return _match::trans_match(bcx, expr, discr, /*bad*/copy *arms,
696 ast::expr_block(ref blk) => {
697 return do base::with_scope(bcx, blk.info(),
698 ~"block-expr body") |bcx| {
699 controlflow::trans_block(bcx, blk, dest)
702 ast::expr_struct(_, ref fields, base) => {
703 return trans_rec_or_struct(bcx, (*fields), base, expr.id, dest);
705 ast::expr_tup(ref args) => {
706 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
707 return trans_adt(bcx, repr, 0, args.mapi(|i, arg| (i, *arg)),
710 ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => {
711 return tvec::trans_lit_str(bcx, expr, s, dest);
713 ast::expr_vstore(contents, ast::expr_vstore_slice) |
714 ast::expr_vstore(contents, ast::expr_vstore_mut_slice) => {
715 return tvec::trans_slice_vstore(bcx, expr, contents, dest);
717 ast::expr_vstore(contents, ast::expr_vstore_fixed(_)) => {
718 return tvec::trans_fixed_vstore(bcx, expr, contents, dest);
720 ast::expr_vec(*) | ast::expr_repeat(*) => {
721 return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
723 ast::expr_fn_block(ref decl, ref body) => {
724 let expr_ty = expr_ty(bcx, expr);
725 let sigil = ty::ty_closure_sigil(expr_ty);
726 debug!("translating fn_block %s with type %s",
727 expr_to_str(expr, tcx.sess.intr()),
728 ty_to_str(tcx, expr_ty));
729 return closure::trans_expr_fn(bcx, sigil, decl, body,
733 ast::expr_loop_body(blk) => {
734 let expr_ty = expr_ty(bcx, expr);
735 let sigil = ty::ty_closure_sigil(expr_ty);
737 ast::expr_fn_block(ref decl, ref body) => {
738 return closure::trans_expr_fn(bcx, sigil,
744 bcx.sess().impossible_case(
746 "loop_body has the wrong kind of contents")
750 ast::expr_do_body(blk) => {
751 return trans_into(bcx, blk, dest);
753 ast::expr_copy(a) => {
754 return trans_into(bcx, a, dest);
756 ast::expr_call(f, ref args, _) => {
757 return callee::trans_call(
758 bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
760 ast::expr_method_call(rcvr, _, _, ref args, _) => {
761 return callee::trans_method_call(bcx,
764 callee::ArgExprs(*args),
767 ast::expr_binary(_, lhs, rhs) => {
768 // if not overloaded, would be RvalueDatumExpr
769 return trans_overloaded_op(bcx, expr, lhs, ~[rhs], dest);
771 ast::expr_unary(_, subexpr) => {
772 // if not overloaded, would be RvalueDatumExpr
773 return trans_overloaded_op(bcx, expr, subexpr, ~[], dest);
775 ast::expr_index(base, idx) => {
776 // if not overloaded, would be RvalueDatumExpr
777 return trans_overloaded_op(bcx, expr, base, ~[idx], dest);
779 ast::expr_cast(val, _) => {
780 match ty::get(node_id_type(bcx, expr.id)).sty {
781 ty::ty_trait(_, _, store) => {
782 return meth::trans_trait_cast(bcx, val, expr.id, dest,
786 bcx.tcx().sess.span_bug(expr.span,
787 ~"expr_cast of non-trait");
791 ast::expr_assign_op(op, dst, src) => {
792 return trans_assign_op(bcx, expr, op, dst, src);
795 bcx.tcx().sess.span_bug(
797 fmt!("trans_rvalue_dps_unadjusted reached \
798 fall-through case: %?",
804 fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr,
805 def: ast::def, dest: Dest) -> block {
806 let _icx = bcx.insn_ctxt("trans_def_dps_unadjusted");
809 let lldest = match dest {
810 SaveIn(lldest) => lldest,
811 Ignore => { return bcx; }
815 ast::def_variant(tid, vid) => {
816 let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
817 if variant_info.args.len() > 0u {
819 let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
820 Store(bcx, fn_data.llfn, lldest);
824 let ty = expr_ty(bcx, ref_expr);
825 let repr = adt::represent_type(ccx, ty);
826 adt::trans_start_init(bcx, repr, lldest,
827 variant_info.disr_val);
831 ast::def_struct(*) => {
832 // Nothing to do here.
833 // XXX: May not be true in the case of classes with destructors.
837 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
838 "Non-DPS def %? referened by %s",
839 def, bcx.node_id_to_str(ref_expr.id)));
844 fn trans_def_datum_unadjusted(bcx: block,
845 ref_expr: @ast::expr,
846 def: ast::def) -> DatumBlock
848 let _icx = bcx.insn_ctxt("trans_def_datum_unadjusted");
851 ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
852 let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
853 return fn_data_to_datum(bcx, ref_expr, did, fn_data);
855 ast::def_static_method(impl_did, Some(trait_did), _) => {
856 let fn_data = meth::trans_static_method_callee(bcx, impl_did,
859 return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
862 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
863 "Non-DPS def %? referened by %s",
864 def, bcx.node_id_to_str(ref_expr.id)));
868 fn fn_data_to_datum(bcx: block,
869 ref_expr: @ast::expr,
871 fn_data: callee::FnData) -> DatumBlock {
874 * Translates a reference to a top-level fn item into a rust
875 * value. This is just a fn pointer.
879 let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
880 ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
882 let (rust_ty, llval) = if is_extern {
883 let rust_ty = ty::mk_ptr(
886 ty: ty::mk_mach_uint(bcx.tcx(), ast::ty_u8),
889 (rust_ty, PointerCast(bcx, fn_data.llfn, T_ptr(T_i8())))
891 let fn_ty = expr_ty(bcx, ref_expr);
892 (fn_ty, fn_data.llfn)
896 datum: Datum {val: llval,
904 fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
907 * Translates an lvalue expression, always yielding a by-ref
908 * datum. Does not apply any adjustments. */
910 let _icx = bcx.insn_ctxt("trans_lval");
913 debug!("trans_lvalue(expr=%s)", bcx.expr_to_str(expr));
914 let _indenter = indenter();
916 trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
918 let unrooted_datum = unpack_datum!(bcx, unrooted(bcx, expr));
920 // If the lvalue must remain rooted, create a scratch datum, copy
921 // the lvalue in there, and then arrange for it to be cleaned up
922 // at the end of the scope with id `scope_id`:
923 let root_key = root_map_key { id: expr.id, derefs: 0u };
924 for bcx.ccx().maps.root_map.find(&root_key).each |&root_info| {
925 bcx = unrooted_datum.root(bcx, *root_info);
928 return DatumBlock {bcx: bcx, datum: unrooted_datum};
930 fn unrooted(bcx: block, expr: @ast::expr) -> DatumBlock {
933 * Translates `expr`. Note that this version generally
934 * yields an unrooted, unmoved version. Rooting and possible
935 * moves are dealt with above in trans_lvalue_unadjusted().
937 * One exception is if `expr` refers to a local variable,
938 * in which case the source may already be FromMovedLvalue
945 ast::expr_paren(e) => {
946 return unrooted(bcx, e);
948 ast::expr_path(_) => {
949 return trans_def_lvalue(bcx, expr, bcx.def(expr.id));
951 ast::expr_field(base, ident, _) => {
952 return trans_rec_field(bcx, base, ident);
954 ast::expr_index(base, idx) => {
955 return trans_index(bcx, expr, base, idx);
957 ast::expr_unary(ast::deref, base) => {
958 let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base));
959 return basedatum.deref(bcx, base, 0);
962 bcx.tcx().sess.span_bug(
964 fmt!("trans_lvalue reached fall-through case: %?",
970 fn trans_rec_field(bcx: block,
972 field: ast::ident) -> DatumBlock {
975 * Translates `base.field`. Note that this version always
976 * yields an unrooted, unmoved version. Rooting and possible
977 * moves are dealt with above in trans_lvalue_unadjusted().
981 let _icx = bcx.insn_ctxt("trans_rec_field");
983 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
984 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
985 do with_field_tys(bcx.tcx(), base_datum.ty, None) |discr, field_tys| {
986 let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
988 datum: do base_datum.get_element(bcx,
991 adt::trans_field_ptr(bcx, repr, srcval, discr, ix)
998 fn trans_index(bcx: block,
999 index_expr: @ast::expr,
1001 idx: @ast::expr) -> DatumBlock {
1004 * Translates `base[idx]`. Note that this version always
1005 * yields an unrooted, unmoved version. Rooting and possible
1006 * moves are dealt with above in trans_lvalue_unadjusted().
1009 let _icx = bcx.insn_ctxt("trans_index");
1010 let ccx = bcx.ccx();
1011 let base_ty = expr_ty(bcx, base);
1014 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
1016 // Translate index expression and cast to a suitable LLVM integer.
1017 // Rust is less strict than LLVM in this regard.
1018 let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
1019 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
1020 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
1022 if ix_size < int_size {
1023 if ty::type_is_signed(expr_ty(bcx, idx)) {
1024 SExt(bcx, ix_val, ccx.int_type)
1025 } else { ZExt(bcx, ix_val, ccx.int_type) }
1026 } else if ix_size > int_size {
1027 Trunc(bcx, ix_val, ccx.int_type)
1033 let vt = tvec::vec_types(bcx, base_datum.ty);
1034 base::maybe_name_value(bcx.ccx(), vt.llunit_size, ~"unit_sz");
1035 let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
1036 base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");
1038 let mut (base, len) = base_datum.get_base_and_len(bcx);
1040 if ty::type_is_str(base_ty) {
1041 // acccount for null terminator in the case of string
1042 len = Sub(bcx, len, C_uint(bcx.ccx(), 1u));
1045 debug!("trans_index: base %s", val_str(bcx.ccx().tn, base));
1046 debug!("trans_index: len %s", val_str(bcx.ccx().tn, len));
1048 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
1049 let bcx = do with_cond(bcx, bounds_check) |bcx| {
1050 let unscaled_len = UDiv(bcx, len, vt.llunit_size);
1051 controlflow::trans_fail_bounds_check(bcx, index_expr.span,
1052 ix_val, unscaled_len)
1054 let elt = InBoundsGEP(bcx, base, ~[ix_val]);
1055 let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty));
1058 datum: Datum {val: elt,
1065 fn trans_def_lvalue(bcx: block,
1066 ref_expr: @ast::expr,
1072 * Translates a reference to a path. Note that this version
1073 * generally yields an unrooted, unmoved version. Rooting and
1074 * possible moves are dealt with above in
1075 * trans_lvalue_unadjusted(), with the caveat that local variables
1076 * may already be in move mode.
1079 let _icx = bcx.insn_ctxt("trans_def_lvalue");
1080 let ccx = bcx.ccx();
1082 ast::def_const(did) => {
1083 let const_ty = expr_ty(bcx, ref_expr);
1085 fn get_did(ccx: @CrateContext, did: ast::def_id)
1087 if did.crate != ast::local_crate {
1088 inline::maybe_instantiate_inline(ccx, did, true)
1094 fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t)
1096 // The LLVM global has the type of its initializer,
1097 // which may not be equal to the enum's type for
1098 // non-C-like enums.
1099 PointerCast(bcx, base::get_item_val(bcx.ccx(), did.node),
1100 T_ptr(type_of(bcx.ccx(), const_ty)))
1103 let did = get_did(ccx, did);
1104 let val = get_val(bcx, did, const_ty);
1107 datum: Datum {val: val,
1116 datum: trans_local_var(bcx, def)
1123 pub fn trans_local_var(bcx: block, def: ast::def) -> Datum {
1124 let _icx = bcx.insn_ctxt("trans_local_var");
1127 ast::def_upvar(nid, _, _, _) => {
1128 // Can't move upvars, so this is never a ZeroMemLastUse.
1129 let local_ty = node_id_type(bcx, nid);
1130 match bcx.fcx.llupvars.find(&nid) {
1140 bcx.sess().bug(fmt!(
1141 "trans_local_var: no llval for upvar %? found", nid));
1145 ast::def_arg(nid, _, _) => {
1146 take_local(bcx, bcx.fcx.llargs, nid)
1148 ast::def_local(nid, _) | ast::def_binding(nid, _) => {
1149 take_local(bcx, bcx.fcx.lllocals, nid)
1151 ast::def_self(nid, _) => {
1152 let self_info: ValSelfData = match bcx.fcx.llself {
1153 Some(ref self_info) => *self_info,
1155 bcx.sess().bug(fmt!(
1156 "trans_local_var: reference to self \
1157 out of context with id %?", nid));
1161 // This cast should not be necessary. We should cast self *once*,
1162 // but right now this conflicts with default methods.
1163 let real_self_ty = monomorphize_type(bcx, self_info.t);
1164 let llselfty = T_ptr(type_of::type_of(bcx.ccx(), real_self_ty));
1166 let casted_val = PointerCast(bcx, self_info.v, llselfty);
1175 bcx.sess().unimpl(fmt!(
1176 "unsupported def type in trans_local_var: %?", def));
1180 fn take_local(bcx: block,
1181 table: &LinearMap<ast::node_id, local_val>,
1182 nid: ast::node_id) -> Datum {
1183 let (v, mode) = match table.find(&nid) {
1184 Some(&local_mem(v)) => (v, ByRef),
1185 Some(&local_imm(v)) => (v, ByValue),
1187 bcx.sess().bug(fmt!(
1188 "trans_local_var: no llval for local/arg %? found", nid));
1191 let ty = node_id_type(bcx, nid);
1193 debug!("take_local(nid=%?, v=%s, mode=%?, ty=%s)",
1194 nid, bcx.val_str(v), mode, bcx.ty_to_str(ty));
1205 // The optional node ID here is the node ID of the path identifying the enum
1206 // variant in use. If none, this cannot possibly an enum variant (so, if it
1207 // is and `node_id_opt` is none, this function fails).
1208 pub fn with_field_tys<R>(tcx: ty::ctxt,
1210 node_id_opt: Option<ast::node_id>,
1211 op: &fn(int, (&[ty::field])) -> R) -> R {
1212 match ty::get(ty).sty {
1213 ty::ty_struct(did, ref substs) => {
1214 op(0, struct_mutable_fields(tcx, did, substs))
1217 ty::ty_enum(_, ref substs) => {
1218 // We want the *variant* ID here, not the enum ID.
1222 "cannot get field types from the enum type %s \
1224 ty_to_str(tcx, ty)));
1227 match *tcx.def_map.get(&node_id) {
1228 ast::def_variant(enum_id, variant_id) => {
1229 let variant_info = ty::enum_variant_with_id(
1230 tcx, enum_id, variant_id);
1231 op(variant_info.disr_val, struct_mutable_fields(
1232 tcx, variant_id, substs))
1235 tcx.sess.bug(~"resolve didn't map this expr to a \
1245 "cannot get field types from the type %s",
1246 ty_to_str(tcx, ty)));
1251 fn trans_rec_or_struct(bcx: block,
1252 fields: &[ast::field],
1253 base: Option<@ast::expr>,
1255 dest: Dest) -> block
1257 let _icx = bcx.insn_ctxt("trans_rec");
1260 let ty = node_id_type(bcx, id);
1261 let tcx = bcx.tcx();
1262 do with_field_tys(tcx, ty, Some(id)) |discr, field_tys| {
1263 let mut need_base = vec::from_elem(field_tys.len(), true);
1265 let numbered_fields = do fields.map |field| {
1266 let opt_pos = vec::position(field_tys, |field_ty|
1267 field_ty.ident == field.node.ident);
1270 need_base[i] = false;
1271 (i, field.node.expr)
1274 tcx.sess.span_bug(field.span,
1275 ~"Couldn't find field in struct type")
1279 let optbase = match base {
1280 Some(base_expr) => {
1281 let mut leftovers = ~[];
1282 for need_base.eachi |i, b| {
1284 leftovers.push((i, field_tys[i].mt.ty))
1287 Some(StructBaseInfo {expr: base_expr,
1288 fields: leftovers })
1291 if need_base.any(|b| *b) {
1292 // XXX should be span bug
1293 tcx.sess.bug(~"missing fields and no base expr")
1299 let repr = adt::represent_type(bcx.ccx(), ty);
1300 trans_adt(bcx, repr, discr, numbered_fields, optbase, dest)
1305 * Information that `trans_adt` needs in order to fill in the fields
1306 * of a struct copied from a base struct (e.g., from an expression
1307 * like `Foo { a: b, ..base }`.
1309 * Note that `fields` may be empty; the base expression must always be
1310 * evaluated for side-effects.
1312 struct StructBaseInfo {
1313 /// The base expression; will be evaluated after all explicit fields.
1315 /// The indices of fields to copy paired with their types.
1316 fields: ~[(uint, ty::t)]
1320 * Constructs an ADT instance:
1322 * - `fields` should be a list of field indices paired with the
1323 * expression to store into that field. The initializers will be
1324 * evaluated in the order specified by `fields`.
1326 * - `optbase` contains information on the base struct (if any) from
1327 * which remaining fields are copied; see comments on `StructBaseInfo`.
1329 fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
1330 fields: &[(uint, @ast::expr)],
1331 optbase: Option<StructBaseInfo>,
1332 dest: Dest) -> block {
1333 let _icx = bcx.insn_ctxt("trans_adt");
1335 let addr = match dest {
1337 for fields.each |&(_i, e)| {
1338 bcx = trans_into(bcx, e, Ignore);
1340 for optbase.each |sbi| {
1341 bcx = trans_into(bcx, sbi.expr, Ignore);
1347 let mut temp_cleanups = ~[];
1348 adt::trans_start_init(bcx, repr, addr, discr);
1349 for fields.each |&(i, e)| {
1350 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1351 let e_ty = expr_ty(bcx, e);
1352 bcx = trans_into(bcx, e, SaveIn(dest));
1353 add_clean_temp_mem(bcx, dest, e_ty);
1354 temp_cleanups.push(dest);
1356 for optbase.each |base| {
1357 // XXX is it sound to use the destination's repr on the base?
1358 // XXX would it ever be reasonable to be here with discr != 0?
1359 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr));
1360 for base.fields.each |&(i, t)| {
1361 let datum = do base_datum.get_element(bcx, t, ZeroMem) |srcval| {
1362 adt::trans_field_ptr(bcx, repr, srcval, discr, i)
1364 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1365 bcx = datum.store_to(bcx, base.expr.id, INIT, dest);
1369 for vec::each(temp_cleanups) |cleanup| {
1370 revoke_clean(bcx, *cleanup);
1376 fn trans_immediate_lit(bcx: block, expr: @ast::expr,
1377 lit: ast::lit) -> DatumBlock {
1378 // must not be a string constant, that is a RvalueDpsExpr
1379 let _icx = bcx.insn_ctxt("trans_immediate_lit");
1380 let ty = expr_ty(bcx, expr);
1381 immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty)
1384 fn trans_unary_datum(bcx: block,
1385 un_expr: @ast::expr,
1387 sub_expr: @ast::expr) -> DatumBlock {
1388 let _icx = bcx.insn_ctxt("trans_unary_datum");
1390 // if deref, would be LvalueExpr
1391 fail_unless!(op != ast::deref);
1393 // if overloaded, would be RvalueDpsExpr
1394 fail_unless!(!bcx.ccx().maps.method_map.contains_key(&un_expr.id));
1396 let un_ty = expr_ty(bcx, un_expr);
1397 let sub_ty = expr_ty(bcx, sub_expr);
1401 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1403 // If this is a boolean type, we must not use the LLVM Not
1404 // instruction, as that is a *bitwise* not and we want *logical*
1405 // not on our 8-bit boolean values.
1406 let llresult = match ty::get(un_ty).sty {
1408 let llcond = ICmp(bcx,
1412 Select(bcx, llcond, C_bool(true), C_bool(false))
1416 immediate_rvalue_bcx(bcx, llresult, un_ty)
1419 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1421 if ty::type_is_fp(un_ty) {
1427 immediate_rvalue_bcx(bcx, llneg, un_ty)
1430 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty,
1434 let heap = heap_for_unique(bcx, un_ty);
1435 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap)
1438 bcx.sess().bug(~"deref expressions should have been \
1439 translated using trans_lvalue(), not \
1440 trans_unary_datum()")
1444 fn trans_boxed_expr(bcx: block,
1446 contents: @ast::expr,
1448 heap: heap) -> DatumBlock {
1449 let _icx = bcx.insn_ctxt("trans_boxed_expr");
1450 let base::MallocResult { bcx, box: bx, body } =
1451 base::malloc_general(bcx, contents_ty, heap);
1452 add_clean_free(bcx, bx, heap);
1453 let bcx = trans_into(bcx, contents, SaveIn(body));
1454 revoke_clean(bcx, bx);
1455 return immediate_rvalue_bcx(bcx, bx, box_ty);
1459 fn trans_addr_of(bcx: block, expr: @ast::expr,
1460 subexpr: @ast::expr) -> DatumBlock {
1461 let _icx = bcx.insn_ctxt("trans_addr_of");
1463 let sub_datum = unpack_datum!(bcx, trans_to_datum(bcx, subexpr));
1464 let llval = sub_datum.to_ref_llval(bcx);
1465 return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
1468 // Important to get types for both lhs and rhs, because one might be _|_
1469 // and the other not.
1470 fn trans_eager_binop(bcx: block,
1471 binop_expr: @ast::expr,
1478 let _icx = bcx.insn_ctxt("trans_eager_binop");
1480 let lhs = lhs_datum.to_appropriate_llval(bcx);
1481 let lhs_t = lhs_datum.ty;
1483 let rhs = rhs_datum.to_appropriate_llval(bcx);
1484 let rhs_t = rhs_datum.ty;
1487 if ty::type_is_bot(lhs_t) { rhs_t }
1490 let is_float = ty::type_is_fp(intype);
1492 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1495 let val = match op {
1497 if is_float { FAdd(bcx, lhs, rhs) }
1498 else { Add(bcx, lhs, rhs) }
1501 if is_float { FSub(bcx, lhs, rhs) }
1502 else { Sub(bcx, lhs, rhs) }
1505 if is_float { FMul(bcx, lhs, rhs) }
1506 else { Mul(bcx, lhs, rhs) }
1512 // Only zero-check integers; fp /0 is NaN
1513 bcx = base::fail_if_zero(bcx, binop_expr.span,
1515 if ty::type_is_signed(intype) {
1526 // Only zero-check integers; fp %0 is NaN
1527 bcx = base::fail_if_zero(bcx, binop_expr.span,
1529 if ty::type_is_signed(intype) {
1536 ast::bitor => Or(bcx, lhs, rhs),
1537 ast::bitand => And(bcx, lhs, rhs),
1538 ast::bitxor => Xor(bcx, lhs, rhs),
1539 ast::shl => Shl(bcx, lhs, rhs),
1541 if ty::type_is_signed(intype) {
1543 } else { LShr(bcx, lhs, rhs) }
1545 ast::eq | ast::ne | ast::lt | ast::ge | ast::le | ast::gt => {
1546 if ty::type_is_bot(rhs_t) {
1549 if !ty::type_is_scalar(rhs_t) {
1550 bcx.tcx().sess.span_bug(binop_expr.span,
1551 ~"non-scalar comparison");
1553 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1555 ZExt(bcx, cmpr.val, T_i8())
1559 bcx.tcx().sess.span_bug(binop_expr.span, ~"unexpected binop");
1563 return immediate_rvalue_bcx(bcx, val, binop_ty);
1566 // refinement types would obviate the need for this
1567 enum lazy_binop_ty { lazy_and, lazy_or }
1569 fn trans_lazy_binop(bcx: block,
1570 binop_expr: @ast::expr,
1573 b: @ast::expr) -> DatumBlock {
1574 let _icx = bcx.insn_ctxt("trans_lazy_binop");
1575 let binop_ty = expr_ty(bcx, binop_expr);
1578 let Result {bcx: past_lhs, val: lhs} = {
1579 do base::with_scope_result(bcx, a.info(), ~"lhs") |bcx| {
1580 trans_to_datum(bcx, a).to_result()
1584 if past_lhs.unreachable {
1585 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty);
1588 let join = base::sub_block(bcx, ~"join");
1589 let before_rhs = base::sub_block(bcx, ~"rhs");
1591 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1593 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1594 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1597 let Result {bcx: past_rhs, val: rhs} = {
1598 do base::with_scope_result(before_rhs, b.info(), ~"rhs") |bcx| {
1599 trans_to_datum(bcx, b).to_result()
1603 if past_rhs.unreachable {
1604 return immediate_rvalue_bcx(join, lhs, binop_ty);
1607 Br(past_rhs, join.llbb);
1608 let phi = Phi(join, T_bool(), ~[lhs, rhs], ~[past_lhs.llbb,
1611 return immediate_rvalue_bcx(join, phi, binop_ty);
1614 fn trans_binary(bcx: block,
1615 binop_expr: @ast::expr,
1618 rhs: @ast::expr) -> DatumBlock
1620 let _icx = bcx.insn_ctxt("trans_binary");
1624 trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
1627 trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
1631 let lhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, lhs));
1632 let rhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, rhs));
1633 let binop_ty = expr_ty(bcx, binop_expr);
1634 trans_eager_binop(bcx, binop_expr, binop_ty, op,
1635 &lhs_datum, &rhs_datum)
1640 fn trans_overloaded_op(bcx: block,
1643 +args: ~[@ast::expr],
1644 dest: Dest) -> block
1646 let origin = *bcx.ccx().maps.method_map.get(&expr.id);
1647 let fty = node_id_type(bcx, expr.callee_id);
1648 return callee::trans_call_inner(
1649 bcx, expr.info(), fty,
1651 |bcx| meth::trans_method_callee(bcx, expr.callee_id, rcvr, origin),
1652 callee::ArgExprs(args), dest, DoAutorefArg);
1655 fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
1656 llsrc: ValueRef, signed: bool) -> ValueRef {
1657 let _icx = bcx.insn_ctxt("int_cast");
1659 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype);
1660 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype);
1661 return if dstsz == srcsz {
1662 BitCast(bcx, llsrc, lldsttype)
1663 } else if srcsz > dstsz {
1664 TruncOrBitCast(bcx, llsrc, lldsttype)
1666 SExtOrBitCast(bcx, llsrc, lldsttype)
1668 ZExtOrBitCast(bcx, llsrc, lldsttype)
1673 fn float_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
1674 llsrc: ValueRef) -> ValueRef {
1675 let _icx = bcx.insn_ctxt("float_cast");
1676 let srcsz = lib::llvm::float_width(llsrctype);
1677 let dstsz = lib::llvm::float_width(lldsttype);
1678 return if dstsz > srcsz {
1679 FPExt(bcx, llsrc, lldsttype)
1680 } else if srcsz > dstsz {
1681 FPTrunc(bcx, llsrc, lldsttype)
1685 pub enum cast_kind {
1693 impl cmp::Eq for cast_kind {
1694 fn eq(&self, other: &cast_kind) -> bool {
1695 match ((*self), (*other)) {
1696 (cast_pointer, cast_pointer) => true,
1697 (cast_integral, cast_integral) => true,
1698 (cast_float, cast_float) => true,
1699 (cast_enum, cast_enum) => true,
1700 (cast_other, cast_other) => true,
1701 (cast_pointer, _) => false,
1702 (cast_integral, _) => false,
1703 (cast_float, _) => false,
1704 (cast_enum, _) => false,
1705 (cast_other, _) => false,
1708 fn ne(&self, other: &cast_kind) -> bool { !(*self).eq(other) }
1711 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1712 match ty::get(t).sty {
1713 ty::ty_float(*) => cast_float,
1714 ty::ty_ptr(*) => cast_pointer,
1715 ty::ty_rptr(*) => cast_pointer,
1716 ty::ty_int(*) => cast_integral,
1717 ty::ty_uint(*) => cast_integral,
1718 ty::ty_bool => cast_integral,
1719 ty::ty_enum(*) => cast_enum,
1724 fn trans_imm_cast(bcx: block, expr: @ast::expr,
1725 id: ast::node_id) -> DatumBlock {
1726 let _icx = bcx.insn_ctxt("trans_cast");
1727 let ccx = bcx.ccx();
1729 let t_out = node_id_type(bcx, id);
1732 let llexpr = unpack_result!(bcx, trans_to_datum(bcx, expr).to_result());
1733 let ll_t_in = val_ty(llexpr);
1734 let t_in = expr_ty(bcx, expr);
1735 let ll_t_out = type_of::type_of(ccx, t_out);
1737 let k_in = cast_type_kind(t_in);
1738 let k_out = cast_type_kind(t_out);
1739 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1742 match (k_in, k_out) {
1743 (cast_integral, cast_integral) => {
1744 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1746 (cast_float, cast_float) => {
1747 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1749 (cast_integral, cast_float) => {
1751 SIToFP(bcx, llexpr, ll_t_out)
1752 } else { UIToFP(bcx, llexpr, ll_t_out) }
1754 (cast_float, cast_integral) => {
1755 if ty::type_is_signed(t_out) {
1756 FPToSI(bcx, llexpr, ll_t_out)
1757 } else { FPToUI(bcx, llexpr, ll_t_out) }
1759 (cast_integral, cast_pointer) => {
1760 IntToPtr(bcx, llexpr, ll_t_out)
1762 (cast_pointer, cast_integral) => {
1763 PtrToInt(bcx, llexpr, ll_t_out)
1765 (cast_pointer, cast_pointer) => {
1766 PointerCast(bcx, llexpr, ll_t_out)
1768 (cast_enum, cast_integral) |
1769 (cast_enum, cast_float) => {
1771 let repr = adt::represent_type(ccx, t_in);
1772 let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr);
1774 cast_integral => int_cast(bcx, ll_t_out,
1775 val_ty(lldiscrim_a),
1777 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1778 _ => ccx.sess.bug(~"translating unsupported cast.")
1781 _ => ccx.sess.bug(~"translating unsupported cast.")
1783 return immediate_rvalue_bcx(bcx, newval, t_out);
1786 fn trans_assign_op(bcx: block,
1790 src: @ast::expr) -> block
1792 let _icx = bcx.insn_ctxt("trans_assign_op");
1795 debug!("trans_assign_op(expr=%s)", bcx.expr_to_str(expr));
1797 // Evaluate LHS (destination), which should be an lvalue
1798 let dst_datum = unpack_datum!(bcx, trans_lvalue_unadjusted(bcx, dst));
1800 // A user-defined operator method
1801 if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
1802 // FIXME(#2528) evaluates the receiver twice!!
1803 let scratch = scratch_datum(bcx, dst_datum.ty, false);
1804 let bcx = trans_overloaded_op(bcx, expr, dst, ~[src],
1805 SaveIn(scratch.val));
1806 return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
1809 // Evaluate RHS (source)
1810 let src_datum = unpack_datum!(bcx, trans_to_datum(bcx, src));
1812 // Perform computation and store the result
1816 bcx, expr, dst_datum.ty, op,
1817 &dst_datum, &src_datum));
1818 return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
1821 // NOTE: Mode neccessary here?
1822 fn shorten(+x: ~str) -> ~str {
1823 if x.len() > 60 { x.substr(0, 60).to_owned() } else { x }