2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-07-07 19:58:01 -05:00
|
|
|
use llvm::*;
|
2014-05-06 06:38:01 -05:00
|
|
|
use driver::config::FullDebugInfo;
|
2014-05-14 14:31:30 -05:00
|
|
|
use middle::def;
|
2013-07-15 22:42:13 -05:00
|
|
|
use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
|
2014-07-21 22:54:28 -05:00
|
|
|
use middle::trans::_match;
|
|
|
|
use middle::trans::adt;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::base::*;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::build::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::callee;
|
2014-05-26 12:33:18 -05:00
|
|
|
use middle::trans::cleanup::CleanupMethods;
|
|
|
|
use middle::trans::cleanup;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::common::*;
|
Modify failure lang items to take less pointers.
Divide-by-zero before:
```
leaq "str\"str\"(1762)"(%rip), %rax
movq %rax, 16(%rsp)
movq $27, 24(%rsp)
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, (%rsp)
movq $19, 8(%rsp)
leaq 16(%rsp), %rdi
leaq (%rsp), %rsi
movl $32, %edx
callq _ZN7failure5fail_20hc04408f955ce60aaqWjE@PLT
```
After:
```
leaq .Lconst(%rip), %rdi
callq _ZN7failure5fail_20haf918a97c8f7f2bfqWjE@PLT
```
Bounds check before:
```
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, 8(%rsp)
movq $19, 16(%rsp)
leaq 8(%rsp), %rdi
movl $38, %esi
movl $1, %edx
movl $1, %ecx
callq _ZN7failure17fail_bounds_check20hf4bc3c69e96caf41RXjE@PLT
```
Bounds check after:
```
leaq .Lconst2(%rip), %rdi
movl $1, %esi
movl $1, %edx
callq _ZN7failure17fail_bounds_check20h5267276a537a7de22XjE@PLT
```
Size before:
21277995 librustc-4e7c5e5c.s
```
text data
12554881 6089335
```
Size after:
21247617 librustc-4e7c5e5c.so
```
text data
12518497 6095748
```
2014-07-29 18:40:59 -05:00
|
|
|
use middle::trans::consts;
|
2014-07-21 22:54:28 -05:00
|
|
|
use middle::trans::datum;
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 01:49:38 -05:00
|
|
|
use middle::trans::debuginfo;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::expr;
|
2014-07-21 22:54:28 -05:00
|
|
|
use middle::trans::meth;
|
|
|
|
use middle::trans::type_::Type;
|
2014-08-12 22:31:30 -05:00
|
|
|
use middle::trans;
|
2014-04-07 17:03:13 -05:00
|
|
|
use middle::ty;
|
2014-07-21 22:54:28 -05:00
|
|
|
use middle::typeck::MethodCall;
|
2014-01-15 13:39:08 -06:00
|
|
|
use util::ppaux::Repr;
|
2014-07-21 22:54:28 -05:00
|
|
|
use util::ppaux;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::ast;
|
2014-02-15 02:54:32 -06:00
|
|
|
use syntax::ast::Ident;
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::ast_util;
|
2013-08-31 11:13:04 -05:00
|
|
|
use syntax::codemap::Span;
|
2014-01-10 16:02:36 -06:00
|
|
|
use syntax::parse::token::InternedString;
|
|
|
|
use syntax::parse::token;
|
2013-09-24 20:18:40 -05:00
|
|
|
use syntax::visit::Visitor;
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|
|
|
s: &ast::Stmt)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-01-15 13:39:08 -06:00
|
|
|
let _icx = push_ctxt("trans_stmt");
|
|
|
|
let fcx = cx.fcx;
|
|
|
|
debug!("trans_stmt({})", s.repr(cx.tcx()));
|
|
|
|
|
|
|
|
if cx.sess().asm_comments() {
|
2014-05-09 20:45:36 -05:00
|
|
|
add_span_comment(cx, s.span, s.repr(cx.tcx()).as_slice());
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut bcx = cx;
|
|
|
|
|
|
|
|
let id = ast_util::stmt_id(s);
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 01:49:38 -05:00
|
|
|
let cleanup_debug_loc =
|
|
|
|
debuginfo::get_cleanup_debug_loc_for_ast_node(id, s.span, false);
|
|
|
|
fcx.push_ast_cleanup_scope(cleanup_debug_loc);
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
match s.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::StmtExpr(ref e, _) | ast::StmtSemi(ref e, _) => {
|
|
|
|
bcx = trans_stmt_semi(bcx, &**e);
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::StmtDecl(ref d, _) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
match d.node {
|
|
|
|
ast::DeclLocal(ref local) => {
|
2014-05-16 12:15:33 -05:00
|
|
|
bcx = init_local(bcx, &**local);
|
2014-03-05 02:51:47 -06:00
|
|
|
if cx.sess().opts.debuginfo == FullDebugInfo {
|
2014-08-12 22:31:30 -05:00
|
|
|
trans::debuginfo::create_local_var_metadata(bcx,
|
|
|
|
&**local);
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
}
|
2014-08-12 11:19:47 -05:00
|
|
|
// Inner items are visited by `trans_item`/`trans_meth`.
|
|
|
|
ast::DeclItem(_) => {},
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
|
|
|
|
}
|
|
|
|
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 01:49:38 -05:00
|
|
|
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, ast_util::stmt_id(s));
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-04-07 17:03:13 -05:00
|
|
|
let _icx = push_ctxt("trans_stmt_semi");
|
|
|
|
let ty = expr_ty(cx, e);
|
|
|
|
if ty::type_needs_drop(cx.tcx(), ty) {
|
|
|
|
expr::trans_to_lvalue(cx, e, "stmt").bcx
|
|
|
|
} else {
|
|
|
|
expr::trans_into(cx, e, expr::Ignore)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
b: &ast::Block,
|
|
|
|
mut dest: expr::Dest)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_block");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut bcx = bcx;
|
2014-01-15 13:39:08 -06:00
|
|
|
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 01:49:38 -05:00
|
|
|
let cleanup_debug_loc =
|
|
|
|
debuginfo::get_cleanup_debug_loc_for_ast_node(b.id, b.span, true);
|
|
|
|
fcx.push_ast_cleanup_scope(cleanup_debug_loc);
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2013-08-03 11:45:23 -05:00
|
|
|
for s in b.stmts.iter() {
|
2014-05-16 12:15:33 -05:00
|
|
|
bcx = trans_stmt(bcx, &**s);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-02-07 14:00:31 -06:00
|
|
|
|
|
|
|
if dest != expr::Ignore {
|
|
|
|
let block_ty = node_id_type(bcx, b.id);
|
|
|
|
if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) {
|
|
|
|
dest = expr::Ignore;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-16 13:08:35 -05:00
|
|
|
match b.expr {
|
2014-05-16 12:15:33 -05:00
|
|
|
Some(ref e) => {
|
|
|
|
bcx = expr::trans_into(bcx, &**e, dest);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
None => {
|
2013-12-18 16:54:42 -06:00
|
|
|
assert!(dest == expr::Ignore || bcx.unreachable.get());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, b.id);
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
if_id: ast::NodeId,
|
|
|
|
cond: &ast::Expr,
|
2014-09-07 12:09:06 -05:00
|
|
|
thn: &ast::Block,
|
|
|
|
els: Option<&ast::Expr>,
|
2014-09-06 11:13:04 -05:00
|
|
|
dest: expr::Dest)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("trans_if(bcx={}, if_id={}, cond={}, thn={:?}, dest={})",
|
2014-06-21 05:39:03 -05:00
|
|
|
bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id,
|
|
|
|
dest.to_string(bcx.ccx()));
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_if");
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
2013-07-17 03:13:41 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
|
2013-07-25 03:53:27 -05:00
|
|
|
|
|
|
|
// Drop branches that are known to be impossible
|
|
|
|
if is_const(cond_val) && !is_undef(cond_val) {
|
|
|
|
if const_to_uint(cond_val) == 1 {
|
2013-09-24 20:18:40 -05:00
|
|
|
match els {
|
|
|
|
Some(elexpr) => {
|
|
|
|
let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
|
2014-09-12 05:10:30 -05:00
|
|
|
trans.visit_expr(&*elexpr);
|
2013-09-24 20:18:40 -05:00
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
2013-07-25 03:53:27 -05:00
|
|
|
// if true { .. } [else { .. }]
|
2014-05-16 12:15:33 -05:00
|
|
|
bcx = trans_block(bcx, &*thn, dest);
|
2014-08-12 22:31:30 -05:00
|
|
|
trans::debuginfo::clear_source_location(bcx.fcx);
|
2013-07-25 03:53:27 -05:00
|
|
|
} else {
|
2013-09-24 20:18:40 -05:00
|
|
|
let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
|
2014-09-12 05:10:30 -05:00
|
|
|
trans.visit_block(&*thn);
|
2013-09-24 20:18:40 -05:00
|
|
|
|
2013-07-25 03:53:27 -05:00
|
|
|
match els {
|
|
|
|
// if false { .. } else { .. }
|
|
|
|
Some(elexpr) => {
|
2014-05-16 12:15:33 -05:00
|
|
|
bcx = expr::trans_into(bcx, &*elexpr, dest);
|
2014-08-12 22:31:30 -05:00
|
|
|
trans::debuginfo::clear_source_location(bcx.fcx);
|
2013-07-17 03:13:41 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2013-07-25 03:53:27 -05:00
|
|
|
// if false { .. }
|
2014-01-15 13:39:08 -06:00
|
|
|
None => { }
|
2013-07-17 03:13:41 -05:00
|
|
|
}
|
2013-07-25 03:53:27 -05:00
|
|
|
}
|
2013-07-17 03:13:41 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
return bcx;
|
|
|
|
}
|
2013-02-06 16:28:02 -06:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let name = format!("then-block-{}-", thn.id);
|
2014-05-16 12:45:16 -05:00
|
|
|
let then_bcx_in = bcx.fcx.new_id_block(name.as_slice(), thn.id);
|
2014-05-16 12:15:33 -05:00
|
|
|
let then_bcx_out = trans_block(then_bcx_in, &*thn, dest);
|
2014-08-12 22:31:30 -05:00
|
|
|
trans::debuginfo::clear_source_location(bcx.fcx);
|
2013-07-12 21:10:41 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let next_bcx;
|
|
|
|
match els {
|
|
|
|
Some(elexpr) => {
|
|
|
|
let else_bcx_in = bcx.fcx.new_id_block("else-block", elexpr.id);
|
2014-05-16 12:15:33 -05:00
|
|
|
let else_bcx_out = expr::trans_into(else_bcx_in, &*elexpr, dest);
|
2014-01-15 13:39:08 -06:00
|
|
|
next_bcx = bcx.fcx.join_blocks(if_id,
|
|
|
|
[then_bcx_out, else_bcx_out]);
|
|
|
|
CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
|
2013-11-30 02:26:21 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
None => {
|
|
|
|
next_bcx = bcx.fcx.new_id_block("next-block", if_id);
|
|
|
|
Br(then_bcx_out, next_bcx.llbb);
|
|
|
|
CondBr(bcx, cond_val, then_bcx_in.llbb, next_bcx.llbb);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
// Clear the source location because it is still set to whatever has been translated
|
|
|
|
// right before.
|
2014-08-12 22:31:30 -05:00
|
|
|
trans::debuginfo::clear_source_location(next_bcx.fcx);
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
next_bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
loop_id: ast::NodeId,
|
|
|
|
cond: &ast::Expr,
|
|
|
|
body: &ast::Block)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_while");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// bcx
|
|
|
|
// |
|
|
|
|
// cond_bcx_in <--------+
|
|
|
|
// | |
|
|
|
|
// cond_bcx_out |
|
|
|
|
// | | |
|
|
|
|
// | body_bcx_in |
|
2014-01-15 13:39:08 -06:00
|
|
|
// cleanup_blk | |
|
2012-08-28 17:54:45 -05:00
|
|
|
// | body_bcx_out --+
|
2014-01-15 13:39:08 -06:00
|
|
|
// next_bcx_in
|
|
|
|
|
|
|
|
let next_bcx_in = fcx.new_id_block("while_exit", loop_id);
|
|
|
|
let cond_bcx_in = fcx.new_id_block("while_cond", cond.id);
|
|
|
|
let body_bcx_in = fcx.new_id_block("while_body", body.id);
|
|
|
|
|
|
|
|
fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, cond_bcx_in]);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
Br(bcx, cond_bcx_in.llbb);
|
|
|
|
|
|
|
|
// compile the block where we will handle loop cleanups
|
|
|
|
let cleanup_llbb = fcx.normal_exit_block(loop_id, cleanup::EXIT_BREAK);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// compile the condition
|
|
|
|
let Result {bcx: cond_bcx_out, val: cond_val} =
|
2014-01-15 13:39:08 -06:00
|
|
|
expr::trans(cond_bcx_in, cond).to_llbool();
|
|
|
|
CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, cleanup_llbb);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// loop body:
|
|
|
|
let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
|
2014-01-15 13:39:08 -06:00
|
|
|
Br(body_bcx_out, cond_bcx_in.llbb);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
fcx.pop_loop_cleanup_scope(loop_id);
|
|
|
|
return next_bcx_in;
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-07-21 22:54:28 -05:00
|
|
|
/// Translates a `for` loop.
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|
|
|
loop_info: NodeInfo,
|
2014-09-07 12:09:06 -05:00
|
|
|
pat: &ast::Pat,
|
2014-09-06 11:13:04 -05:00
|
|
|
head: &ast::Expr,
|
|
|
|
body: &ast::Block)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-07-21 22:54:28 -05:00
|
|
|
let _icx = push_ctxt("trans_for");
|
|
|
|
|
|
|
|
// bcx
|
|
|
|
// |
|
|
|
|
// loopback_bcx_in <-------+
|
|
|
|
// | |
|
|
|
|
// loopback_bcx_out |
|
|
|
|
// | | |
|
|
|
|
// | body_bcx_in |
|
|
|
|
// cleanup_blk | |
|
|
|
|
// | body_bcx_out --+
|
|
|
|
// next_bcx_in
|
|
|
|
|
|
|
|
// Codegen the head to create the iterator value.
|
|
|
|
let iterator_datum =
|
|
|
|
unpack_datum!(bcx, expr::trans_to_lvalue(bcx, head, "for_head"));
|
|
|
|
let iterator_type = node_id_type(bcx, head.id);
|
|
|
|
debug!("iterator type is {}, datum type is {}",
|
|
|
|
ppaux::ty_to_string(bcx.tcx(), iterator_type),
|
|
|
|
ppaux::ty_to_string(bcx.tcx(), iterator_datum.ty));
|
|
|
|
let lliterator = load_ty(bcx, iterator_datum.val, iterator_datum.ty);
|
|
|
|
|
|
|
|
// Create our basic blocks and set up our loop cleanups.
|
|
|
|
let next_bcx_in = bcx.fcx.new_id_block("for_exit", loop_info.id);
|
|
|
|
let loopback_bcx_in = bcx.fcx.new_id_block("for_loopback", head.id);
|
|
|
|
let body_bcx_in = bcx.fcx.new_id_block("for_body", body.id);
|
|
|
|
bcx.fcx.push_loop_cleanup_scope(loop_info.id,
|
|
|
|
[next_bcx_in, loopback_bcx_in]);
|
|
|
|
Br(bcx, loopback_bcx_in.llbb);
|
|
|
|
let cleanup_llbb = bcx.fcx.normal_exit_block(loop_info.id,
|
|
|
|
cleanup::EXIT_BREAK);
|
|
|
|
|
|
|
|
// Set up the method call (to `.next()`).
|
|
|
|
let method_call = MethodCall::expr(loop_info.id);
|
|
|
|
let method_type = loopback_bcx_in.tcx()
|
|
|
|
.method_map
|
|
|
|
.borrow()
|
|
|
|
.get(&method_call)
|
|
|
|
.ty;
|
|
|
|
let method_type = monomorphize_type(loopback_bcx_in, method_type);
|
|
|
|
let method_result_type = ty::ty_fn_ret(method_type);
|
|
|
|
let option_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
|
|
|
|
let option_cleanup_scope_id = cleanup::CustomScope(option_cleanup_scope);
|
|
|
|
|
|
|
|
// Compile the method call (to `.next()`).
|
|
|
|
let mut loopback_bcx_out = loopback_bcx_in;
|
|
|
|
let option_datum =
|
|
|
|
unpack_datum!(loopback_bcx_out,
|
|
|
|
datum::lvalue_scratch_datum(loopback_bcx_out,
|
|
|
|
method_result_type,
|
|
|
|
"loop_option",
|
|
|
|
false,
|
|
|
|
option_cleanup_scope_id,
|
|
|
|
(),
|
|
|
|
|(), bcx, lloption| {
|
|
|
|
let Result {
|
|
|
|
bcx: bcx,
|
|
|
|
val: _
|
|
|
|
} = callee::trans_call_inner(bcx,
|
|
|
|
Some(loop_info),
|
|
|
|
method_type,
|
|
|
|
|bcx, arg_cleanup_scope| {
|
|
|
|
meth::trans_method_callee(
|
|
|
|
bcx,
|
|
|
|
method_call,
|
|
|
|
None,
|
|
|
|
arg_cleanup_scope)
|
|
|
|
},
|
|
|
|
callee::ArgVals([lliterator]),
|
|
|
|
Some(expr::SaveIn(lloption)));
|
|
|
|
bcx
|
|
|
|
}));
|
|
|
|
|
|
|
|
// Check the discriminant; if the `None` case, exit the loop.
|
|
|
|
let option_representation = adt::represent_type(loopback_bcx_out.ccx(),
|
|
|
|
method_result_type);
|
|
|
|
let lldiscriminant = adt::trans_get_discr(loopback_bcx_out,
|
|
|
|
&*option_representation,
|
|
|
|
option_datum.val,
|
2014-08-15 05:56:24 -05:00
|
|
|
None);
|
|
|
|
let i1_type = Type::i1(loopback_bcx_out.ccx());
|
|
|
|
let llcondition = Trunc(loopback_bcx_out, lldiscriminant, i1_type);
|
2014-07-21 22:54:28 -05:00
|
|
|
CondBr(loopback_bcx_out, llcondition, body_bcx_in.llbb, cleanup_llbb);
|
|
|
|
|
|
|
|
// Now we're in the body. Unpack the `Option` value into the programmer-
|
|
|
|
// supplied pattern.
|
|
|
|
let llpayload = adt::trans_field_ptr(body_bcx_in,
|
|
|
|
&*option_representation,
|
|
|
|
option_datum.val,
|
|
|
|
1,
|
|
|
|
0);
|
|
|
|
let binding_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
|
|
|
|
let binding_cleanup_scope_id =
|
|
|
|
cleanup::CustomScope(binding_cleanup_scope);
|
|
|
|
let mut body_bcx_out =
|
|
|
|
_match::store_for_loop_binding(body_bcx_in,
|
|
|
|
pat,
|
|
|
|
llpayload,
|
|
|
|
binding_cleanup_scope_id);
|
|
|
|
|
|
|
|
// Codegen the body.
|
|
|
|
body_bcx_out = trans_block(body_bcx_out, body, expr::Ignore);
|
2014-09-13 17:35:21 -05:00
|
|
|
body_bcx_out =
|
|
|
|
body_bcx_out.fcx
|
|
|
|
.pop_and_trans_custom_cleanup_scope(body_bcx_out,
|
|
|
|
binding_cleanup_scope);
|
2014-07-21 22:54:28 -05:00
|
|
|
body_bcx_out =
|
|
|
|
body_bcx_out.fcx
|
|
|
|
.pop_and_trans_custom_cleanup_scope(body_bcx_out,
|
|
|
|
option_cleanup_scope);
|
|
|
|
Br(body_bcx_out, loopback_bcx_in.llbb);
|
|
|
|
|
|
|
|
// Codegen cleanups and leave.
|
|
|
|
next_bcx_in.fcx.pop_loop_cleanup_scope(loop_info.id);
|
|
|
|
next_bcx_in
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
loop_id: ast::NodeId,
|
|
|
|
body: &ast::Block)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_loop");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
|
|
|
|
|
|
|
// bcx
|
|
|
|
// |
|
|
|
|
// body_bcx_in
|
|
|
|
// |
|
|
|
|
// body_bcx_out
|
|
|
|
//
|
|
|
|
// next_bcx
|
|
|
|
//
|
|
|
|
// Links between body_bcx_in and next_bcx are created by
|
|
|
|
// break statements.
|
|
|
|
|
|
|
|
let next_bcx_in = bcx.fcx.new_id_block("loop_exit", loop_id);
|
|
|
|
let body_bcx_in = bcx.fcx.new_id_block("loop_body", body.id);
|
|
|
|
|
|
|
|
fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, body_bcx_in]);
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
Br(bcx, body_bcx_in.llbb);
|
|
|
|
let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
|
2014-01-15 13:39:08 -06:00
|
|
|
Br(body_bcx_out, body_bcx_in.llbb);
|
|
|
|
|
|
|
|
fcx.pop_loop_cleanup_scope(loop_id);
|
|
|
|
|
2014-06-04 11:24:58 -05:00
|
|
|
if ty::type_is_bot(node_id_type(bcx, loop_id)) {
|
|
|
|
Unreachable(next_bcx_in);
|
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
return next_bcx_in;
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr_id: ast::NodeId,
|
|
|
|
opt_label: Option<Ident>,
|
|
|
|
exit: uint)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_break_cont");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
|
|
|
|
|
|
|
if bcx.unreachable.get() {
|
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Locate loop that we will break to
|
|
|
|
let loop_id = match opt_label {
|
|
|
|
None => fcx.top_loop_scope(),
|
|
|
|
Some(_) => {
|
2014-03-20 21:49:20 -05:00
|
|
|
match bcx.tcx().def_map.borrow().find(&expr_id) {
|
2014-05-14 14:31:30 -05:00
|
|
|
Some(&def::DefLabel(loop_id)) => loop_id,
|
2014-01-15 13:39:08 -06:00
|
|
|
ref r => {
|
2014-05-16 12:45:16 -05:00
|
|
|
bcx.tcx().sess.bug(format!("{:?} in def-map for label",
|
|
|
|
r).as_slice())
|
Implement scopes independent of LLVM basic blocks
Currently, scopes are tied to LLVM basic blocks. For each scope, there
are two new basic blocks, which means two extra jumps in the unoptimized
IR. These blocks aren't actually required, but only used to act as the
boundary for cleanups.
By keeping track of the current scope within a single basic block, we
can avoid those extra blocks and jumps, shrinking the pre-optimization
IR quite considerably. For example, the IR for trans_intrinsic goes
from ~22k lines to ~16k lines, almost 30% less.
The impact on the build times of optimized builds is rather small (about
1%), but unoptimized builds are about 11% faster. The testsuite for
unoptimized builds runs between 15% (CPU time) and 7.5% (wallclock time on
my i7) faster.
Also, in some situations this helps LLVM to generate better code by
inlining functions that it previously considered to be too large.
Likely because of the pointless blocks/jumps that were still present at
the time the inlining pass runs.
Refs #7462
2013-07-07 07:53:57 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
// Generate appropriate cleanup code and branch
|
|
|
|
let cleanup_llbb = fcx.normal_exit_block(loop_id, exit);
|
|
|
|
Br(bcx, cleanup_llbb);
|
|
|
|
Unreachable(bcx); // anything afterwards should be ignored
|
2012-08-28 17:54:45 -05:00
|
|
|
return bcx;
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_break<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr_id: ast::NodeId,
|
|
|
|
label_opt: Option<Ident>)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-01-15 13:39:08 -06:00
|
|
|
return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_BREAK);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr_id: ast::NodeId,
|
|
|
|
label_opt: Option<Ident>)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-01-15 13:39:08 -06:00
|
|
|
return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_LOOP);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
2014-09-07 12:09:06 -05:00
|
|
|
e: Option<&ast::Expr>)
|
2014-09-06 11:13:04 -05:00
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_ret");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut bcx = bcx;
|
2014-07-29 14:25:06 -05:00
|
|
|
let dest = match (fcx.llretslotptr.get(), e) {
|
|
|
|
(Some(_), Some(e)) => {
|
|
|
|
let ret_ty = expr_ty(bcx, &*e);
|
2014-08-11 21:16:00 -05:00
|
|
|
expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot"))
|
2014-07-29 14:25:06 -05:00
|
|
|
}
|
|
|
|
_ => expr::Ignore,
|
2012-08-28 17:54:45 -05:00
|
|
|
};
|
|
|
|
match e {
|
2013-08-11 20:12:57 -05:00
|
|
|
Some(x) => {
|
2014-05-16 12:15:33 -05:00
|
|
|
bcx = expr::trans_into(bcx, &*x, dest);
|
2014-07-29 14:25:06 -05:00
|
|
|
match dest {
|
2014-08-11 21:16:00 -05:00
|
|
|
expr::SaveIn(slot) if fcx.needs_ret_allocas => {
|
2014-07-29 14:25:06 -05:00
|
|
|
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2013-08-11 20:12:57 -05:00
|
|
|
}
|
2014-01-27 06:18:36 -06:00
|
|
|
_ => {}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
let cleanup_llbb = fcx.return_exit_block();
|
|
|
|
Br(bcx, cleanup_llbb);
|
2012-08-28 17:54:45 -05:00
|
|
|
Unreachable(bcx);
|
|
|
|
return bcx;
|
|
|
|
}
|
2013-01-29 19:57:02 -06:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
sp: Span,
|
|
|
|
fail_str: InternedString)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
2014-03-16 13:56:24 -05:00
|
|
|
let _icx = push_ctxt("trans_fail_value");
|
2014-05-26 12:33:18 -05:00
|
|
|
|
Modify failure lang items to take less pointers.
Divide-by-zero before:
```
leaq "str\"str\"(1762)"(%rip), %rax
movq %rax, 16(%rsp)
movq $27, 24(%rsp)
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, (%rsp)
movq $19, 8(%rsp)
leaq 16(%rsp), %rdi
leaq (%rsp), %rsi
movl $32, %edx
callq _ZN7failure5fail_20hc04408f955ce60aaqWjE@PLT
```
After:
```
leaq .Lconst(%rip), %rdi
callq _ZN7failure5fail_20haf918a97c8f7f2bfqWjE@PLT
```
Bounds check before:
```
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, 8(%rsp)
movq $19, 16(%rsp)
leaq 8(%rsp), %rdi
movl $38, %esi
movl $1, %edx
movl $1, %ecx
callq _ZN7failure17fail_bounds_check20hf4bc3c69e96caf41RXjE@PLT
```
Bounds check after:
```
leaq .Lconst2(%rip), %rdi
movl $1, %esi
movl $1, %edx
callq _ZN7failure17fail_bounds_check20h5267276a537a7de22XjE@PLT
```
Size before:
21277995 librustc-4e7c5e5c.s
```
text data
12554881 6089335
```
Size after:
21247617 librustc-4e7c5e5c.so
```
text data
12518497 6095748
```
2014-07-29 18:40:59 -05:00
|
|
|
let v_str = C_str_slice(ccx, fail_str);
|
2014-03-16 13:56:24 -05:00
|
|
|
let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
|
2014-05-26 12:33:18 -05:00
|
|
|
let filename = token::intern_and_get_ident(loc.file.name.as_slice());
|
Modify failure lang items to take less pointers.
Divide-by-zero before:
```
leaq "str\"str\"(1762)"(%rip), %rax
movq %rax, 16(%rsp)
movq $27, 24(%rsp)
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, (%rsp)
movq $19, 8(%rsp)
leaq 16(%rsp), %rdi
leaq (%rsp), %rsi
movl $32, %edx
callq _ZN7failure5fail_20hc04408f955ce60aaqWjE@PLT
```
After:
```
leaq .Lconst(%rip), %rdi
callq _ZN7failure5fail_20haf918a97c8f7f2bfqWjE@PLT
```
Bounds check before:
```
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, 8(%rsp)
movq $19, 16(%rsp)
leaq 8(%rsp), %rdi
movl $38, %esi
movl $1, %edx
movl $1, %ecx
callq _ZN7failure17fail_bounds_check20hf4bc3c69e96caf41RXjE@PLT
```
Bounds check after:
```
leaq .Lconst2(%rip), %rdi
movl $1, %esi
movl $1, %edx
callq _ZN7failure17fail_bounds_check20h5267276a537a7de22XjE@PLT
```
Size before:
21277995 librustc-4e7c5e5c.s
```
text data
12554881 6089335
```
Size after:
21247617 librustc-4e7c5e5c.so
```
text data
12518497 6095748
```
2014-07-29 18:40:59 -05:00
|
|
|
let filename = C_str_slice(ccx, filename);
|
|
|
|
let line = C_int(ccx, loc.line as int);
|
|
|
|
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
|
2014-08-06 04:59:40 -05:00
|
|
|
let expr_file_line = consts::const_addr_of(ccx, expr_file_line_const, ast::MutImmutable);
|
Modify failure lang items to take less pointers.
Divide-by-zero before:
```
leaq "str\"str\"(1762)"(%rip), %rax
movq %rax, 16(%rsp)
movq $27, 24(%rsp)
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, (%rsp)
movq $19, 8(%rsp)
leaq 16(%rsp), %rdi
leaq (%rsp), %rsi
movl $32, %edx
callq _ZN7failure5fail_20hc04408f955ce60aaqWjE@PLT
```
After:
```
leaq .Lconst(%rip), %rdi
callq _ZN7failure5fail_20haf918a97c8f7f2bfqWjE@PLT
```
Bounds check before:
```
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, 8(%rsp)
movq $19, 16(%rsp)
leaq 8(%rsp), %rdi
movl $38, %esi
movl $1, %edx
movl $1, %ecx
callq _ZN7failure17fail_bounds_check20hf4bc3c69e96caf41RXjE@PLT
```
Bounds check after:
```
leaq .Lconst2(%rip), %rdi
movl $1, %esi
movl $1, %edx
callq _ZN7failure17fail_bounds_check20h5267276a537a7de22XjE@PLT
```
Size before:
21277995 librustc-4e7c5e5c.s
```
text data
12554881 6089335
```
Size after:
21247617 librustc-4e7c5e5c.so
```
text data
12518497 6095748
```
2014-07-29 18:40:59 -05:00
|
|
|
let args = vec!(expr_file_line);
|
2014-02-28 20:21:22 -06:00
|
|
|
let did = langcall(bcx, Some(sp), "", FailFnLangItem);
|
2014-03-08 14:36:22 -06:00
|
|
|
let bcx = callee::trans_lang_call(bcx,
|
|
|
|
did,
|
|
|
|
args.as_slice(),
|
|
|
|
Some(expr::Ignore)).bcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
Unreachable(bcx);
|
|
|
|
return bcx;
|
|
|
|
}
|
2012-09-29 06:34:11 -05:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
sp: Span,
|
|
|
|
index: ValueRef,
|
|
|
|
len: ValueRef)
|
|
|
|
-> Block<'blk, 'tcx> {
|
Modify failure lang items to take less pointers.
Divide-by-zero before:
```
leaq "str\"str\"(1762)"(%rip), %rax
movq %rax, 16(%rsp)
movq $27, 24(%rsp)
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, (%rsp)
movq $19, 8(%rsp)
leaq 16(%rsp), %rdi
leaq (%rsp), %rsi
movl $32, %edx
callq _ZN7failure5fail_20hc04408f955ce60aaqWjE@PLT
```
After:
```
leaq .Lconst(%rip), %rdi
callq _ZN7failure5fail_20haf918a97c8f7f2bfqWjE@PLT
```
Bounds check before:
```
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, 8(%rsp)
movq $19, 16(%rsp)
leaq 8(%rsp), %rdi
movl $38, %esi
movl $1, %edx
movl $1, %ecx
callq _ZN7failure17fail_bounds_check20hf4bc3c69e96caf41RXjE@PLT
```
Bounds check after:
```
leaq .Lconst2(%rip), %rdi
movl $1, %esi
movl $1, %edx
callq _ZN7failure17fail_bounds_check20h5267276a537a7de22XjE@PLT
```
Size before:
21277995 librustc-4e7c5e5c.s
```
text data
12554881 6089335
```
Size after:
21247617 librustc-4e7c5e5c.so
```
text data
12518497 6095748
```
2014-07-29 18:40:59 -05:00
|
|
|
let ccx = bcx.ccx();
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_fail_bounds_check");
|
2014-05-26 12:33:18 -05:00
|
|
|
|
|
|
|
// Extract the file/line from the span
|
|
|
|
let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
|
|
|
|
let filename = token::intern_and_get_ident(loc.file.name.as_slice());
|
|
|
|
|
|
|
|
// Invoke the lang item
|
Modify failure lang items to take less pointers.
Divide-by-zero before:
```
leaq "str\"str\"(1762)"(%rip), %rax
movq %rax, 16(%rsp)
movq $27, 24(%rsp)
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, (%rsp)
movq $19, 8(%rsp)
leaq 16(%rsp), %rdi
leaq (%rsp), %rsi
movl $32, %edx
callq _ZN7failure5fail_20hc04408f955ce60aaqWjE@PLT
```
After:
```
leaq .Lconst(%rip), %rdi
callq _ZN7failure5fail_20haf918a97c8f7f2bfqWjE@PLT
```
Bounds check before:
```
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, 8(%rsp)
movq $19, 16(%rsp)
leaq 8(%rsp), %rdi
movl $38, %esi
movl $1, %edx
movl $1, %ecx
callq _ZN7failure17fail_bounds_check20hf4bc3c69e96caf41RXjE@PLT
```
Bounds check after:
```
leaq .Lconst2(%rip), %rdi
movl $1, %esi
movl $1, %edx
callq _ZN7failure17fail_bounds_check20h5267276a537a7de22XjE@PLT
```
Size before:
21277995 librustc-4e7c5e5c.s
```
text data
12554881 6089335
```
Size after:
21247617 librustc-4e7c5e5c.so
```
text data
12518497 6095748
```
2014-07-29 18:40:59 -05:00
|
|
|
let filename = C_str_slice(ccx, filename);
|
|
|
|
let line = C_int(ccx, loc.line as int);
|
|
|
|
let file_line_const = C_struct(ccx, &[filename, line], false);
|
2014-08-06 04:59:40 -05:00
|
|
|
let file_line = consts::const_addr_of(ccx, file_line_const, ast::MutImmutable);
|
Modify failure lang items to take less pointers.
Divide-by-zero before:
```
leaq "str\"str\"(1762)"(%rip), %rax
movq %rax, 16(%rsp)
movq $27, 24(%rsp)
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, (%rsp)
movq $19, 8(%rsp)
leaq 16(%rsp), %rdi
leaq (%rsp), %rsi
movl $32, %edx
callq _ZN7failure5fail_20hc04408f955ce60aaqWjE@PLT
```
After:
```
leaq .Lconst(%rip), %rdi
callq _ZN7failure5fail_20haf918a97c8f7f2bfqWjE@PLT
```
Bounds check before:
```
leaq "str\"str\"(1542)"(%rip), %rax
movq %rax, 8(%rsp)
movq $19, 16(%rsp)
leaq 8(%rsp), %rdi
movl $38, %esi
movl $1, %edx
movl $1, %ecx
callq _ZN7failure17fail_bounds_check20hf4bc3c69e96caf41RXjE@PLT
```
Bounds check after:
```
leaq .Lconst2(%rip), %rdi
movl $1, %esi
movl $1, %edx
callq _ZN7failure17fail_bounds_check20h5267276a537a7de22XjE@PLT
```
Size before:
21277995 librustc-4e7c5e5c.s
```
text data
12554881 6089335
```
Size after:
21247617 librustc-4e7c5e5c.so
```
text data
12518497 6095748
```
2014-07-29 18:40:59 -05:00
|
|
|
let args = vec!(file_line, index, len);
|
2013-07-15 22:42:13 -05:00
|
|
|
let did = langcall(bcx, Some(sp), "", FailBoundsCheckFnLangItem);
|
2014-03-08 14:36:22 -06:00
|
|
|
let bcx = callee::trans_lang_call(bcx,
|
|
|
|
did,
|
|
|
|
args.as_slice(),
|
|
|
|
Some(expr::Ignore)).bcx;
|
2012-09-29 06:34:11 -05:00
|
|
|
Unreachable(bcx);
|
|
|
|
return bcx;
|
|
|
|
}
|