Skip to content

Commit 205baa6

Browse files
committed
Avoid blocks for static allocas and loading the closure environment
These blocks were required because previously we could only insert instructions at the end of blocks, but we wanted to have all allocas in one place, so they can be collapse. But now we have "direct" access the the LLVM IR builder and can position it freely. This allows us to use the same trick that clang uses, which means that we insert a dummy "marker" instruction to identify the spot at which we want to insert allocas. We can then later position the IR builder at that spot and insert the alloca instruction, without any dedicated block. The block for loading the closure environment can now also go away, because the function context now provides the toplevel block, and the translation of the loading happens first, so that's good enough. Makes the LLVM IR a bit more readable, saving a bunch of branches in the unoptimized code, which benefits unoptimized builds.
1 parent 565a9bf commit 205baa6

File tree

9 files changed

+79
-112
lines changed

9 files changed

+79
-112
lines changed

src/librustc/lib/llvm.rs

+2
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,8 @@ pub mod llvm {
984984
pub unsafe fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef;
985985
#[fast_ffi]
986986
pub unsafe fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef;
987+
#[fast_ffi]
988+
pub unsafe fn LLVMInstructionEraseFromParent(Inst: ValueRef);
987989

988990
/* Operations on call sites */
989991
#[fast_ffi]

src/librustc/middle/trans/base.rs

+40-51
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use middle::trans::_match;
4141
use middle::trans::adt;
4242
use middle::trans::base;
4343
use middle::trans::build::*;
44-
use middle::trans::builder::noname;
44+
use middle::trans::builder::{Builder, noname};
4545
use middle::trans::callee;
4646
use middle::trans::common::*;
4747
use middle::trans::consts;
@@ -1503,34 +1503,35 @@ pub fn memcpy_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) {
15031503
}
15041504

15051505
pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) {
1506+
if cx.unreachable { return; }
15061507
let _icx = push_ctxt("zero_mem");
15071508
let bcx = cx;
15081509
let ccx = cx.ccx();
15091510
let llty = type_of::type_of(ccx, t);
1510-
memzero(bcx, llptr, llty);
1511+
memzero(&B(bcx), llptr, llty);
15111512
}
15121513

15131514
// Always use this function instead of storing a zero constant to the memory
15141515
// in question. If you store a zero constant, LLVM will drown in vreg
15151516
// allocation for large data structures, and the generated code will be
15161517
// awful. (A telltale sign of this is large quantities of
15171518
// `mov [byte ptr foo],0` in the generated code.)
1518-
pub fn memzero(cx: block, llptr: ValueRef, ty: Type) {
1519+
pub fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
15191520
let _icx = push_ctxt("memzero");
1520-
let ccx = cx.ccx();
1521+
let ccx = b.ccx;
15211522

15221523
let intrinsic_key = match ccx.sess.targ_cfg.arch {
15231524
X86 | Arm | Mips => "llvm.memset.p0i8.i32",
15241525
X86_64 => "llvm.memset.p0i8.i64"
15251526
};
15261527

15271528
let llintrinsicfn = ccx.intrinsics.get_copy(&intrinsic_key);
1528-
let llptr = PointerCast(cx, llptr, Type::i8().ptr_to());
1529+
let llptr = b.pointercast(llptr, Type::i8().ptr_to());
15291530
let llzeroval = C_u8(0);
1530-
let size = IntCast(cx, machine::llsize_of(ccx, ty), ccx.int_type);
1531+
let size = machine::llsize_of(ccx, ty);
15311532
let align = C_i32(llalign_of_min(ccx, ty) as i32);
15321533
let volatile = C_i1(false);
1533-
Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
1534+
b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
15341535
}
15351536

15361537
pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef {
@@ -1553,9 +1554,12 @@ pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> Value
15531554
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
15541555
}
15551556
}
1556-
let initcx = base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas());
1557-
let p = Alloca(initcx, ty, name);
1558-
if zero { memzero(initcx, p, ty); }
1557+
let p = Alloca(cx, ty, name);
1558+
if zero {
1559+
let b = cx.fcx.ccx.builder();
1560+
b.position_before(cx.fcx.alloca_insert_pt.get());
1561+
memzero(&b, p, ty);
1562+
}
15591563
p
15601564
}
15611565

@@ -1566,7 +1570,7 @@ pub fn arrayalloca(cx: block, ty: Type, v: ValueRef) -> ValueRef {
15661570
return llvm::LLVMGetUndef(ty.to_ref());
15671571
}
15681572
}
1569-
return ArrayAlloca(base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas()), ty, v);
1573+
return ArrayAlloca(cx, ty, v);
15701574
}
15711575

15721576
pub struct BasicBlocks {
@@ -1597,8 +1601,8 @@ pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
15971601
llvm::LLVMGetParam(fcx.llfn, 0)
15981602
} else {
15991603
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
1600-
alloca(raw_block(fcx, false, fcx.get_llstaticallocas()), lloutputtype,
1601-
"__make_return_pointer")
1604+
let bcx = fcx.entry_bcx.get();
1605+
Alloca(bcx, lloutputtype, "__make_return_pointer")
16021606
}
16031607
}
16041608
}
@@ -1616,6 +1620,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
16161620
output_type: ty::t,
16171621
skip_retptr: bool,
16181622
param_substs: Option<@param_substs>,
1623+
opt_node_info: Option<NodeInfo>,
16191624
sp: Option<span>)
16201625
-> fn_ctxt {
16211626
for param_substs.iter().advance |p| { p.validate(); }
@@ -1639,8 +1644,8 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
16391644
llvm::LLVMGetUndef(Type::i8p().to_ref())
16401645
},
16411646
llretptr: None,
1642-
llstaticallocas: None,
1643-
llloadenv: None,
1647+
entry_bcx: None,
1648+
alloca_insert_pt: None,
16441649
llreturn: None,
16451650
llself: None,
16461651
personality: None,
@@ -1658,6 +1663,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
16581663
fcx.llenv = unsafe {
16591664
llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
16601665
};
1666+
1667+
unsafe {
1668+
let entry_bcx = top_scope_block(fcx, opt_node_info);
1669+
Load(entry_bcx, C_null(Type::i8p()));
1670+
1671+
fcx.entry_bcx = Some(entry_bcx);
1672+
fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
1673+
}
1674+
16611675
if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
16621676
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
16631677
}
@@ -1670,7 +1684,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
16701684
output_type: ty::t,
16711685
sp: Option<span>)
16721686
-> fn_ctxt {
1673-
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, sp)
1687+
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, None, sp)
16741688
}
16751689

16761690
// NB: must keep 4 fns in sync:
@@ -1785,9 +1799,8 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
17851799

17861800
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
17871801
// and builds the return block.
1788-
pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
1802+
pub fn finish_fn(fcx: fn_ctxt, last_bcx: block) {
17891803
let _icx = push_ctxt("finish_fn");
1790-
tie_up_header_blocks(fcx, lltop);
17911804

17921805
let ret_cx = match fcx.llreturn {
17931806
Some(llreturn) => {
@@ -1799,6 +1812,7 @@ pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
17991812
None => last_bcx
18001813
};
18011814
build_return_block(fcx, ret_cx);
1815+
fcx.cleanup();
18021816
}
18031817

18041818
// Builds the return block for a function.
@@ -1811,29 +1825,6 @@ pub fn build_return_block(fcx: fn_ctxt, ret_cx: block) {
18111825
}
18121826
}
18131827

1814-
pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
1815-
let _icx = push_ctxt("tie_up_header_blocks");
1816-
let llnext = match fcx.llloadenv {
1817-
Some(ll) => {
1818-
unsafe {
1819-
llvm::LLVMMoveBasicBlockBefore(ll, lltop);
1820-
}
1821-
Br(raw_block(fcx, false, ll), lltop);
1822-
ll
1823-
}
1824-
None => lltop
1825-
};
1826-
match fcx.llstaticallocas {
1827-
Some(ll) => {
1828-
unsafe {
1829-
llvm::LLVMMoveBasicBlockBefore(ll, llnext);
1830-
}
1831-
Br(raw_block(fcx, false, ll), llnext);
1832-
}
1833-
None => ()
1834-
}
1835-
}
1836-
18371828
pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
18381829

18391830
// trans_closure: Builds an LLVM function out of a source function.
@@ -1866,6 +1857,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
18661857
output_type,
18671858
false,
18681859
param_substs,
1860+
body.info(),
18691861
Some(body.span));
18701862
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
18711863

@@ -1877,9 +1869,8 @@ pub fn trans_closure(ccx: @mut CrateContext,
18771869

18781870
// Create the first basic block in the function and keep a handle on it to
18791871
// pass to finish_fn later.
1880-
let bcx_top = top_scope_block(fcx, body.info());
1872+
let bcx_top = fcx.entry_bcx.get();
18811873
let mut bcx = bcx_top;
1882-
let lltop = bcx.llbb;
18831874
let block_ty = node_id_type(bcx, body.id);
18841875

18851876
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
@@ -1915,7 +1906,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
19151906
}
19161907

19171908
// Insert the mandatory first few basic blocks before lltop.
1918-
finish_fn(fcx, lltop, bcx);
1909+
finish_fn(fcx, bcx);
19191910
}
19201911

19211912
// trans_fn: creates an LLVM function corresponding to a source language
@@ -2085,12 +2076,12 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
20852076
result_ty,
20862077
false,
20872078
param_substs,
2079+
None,
20882080
None);
20892081

20902082
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
20912083

2092-
let bcx = top_scope_block(fcx, None);
2093-
let lltop = bcx.llbb;
2084+
let bcx = fcx.entry_bcx.get();
20942085
let arg_tys = ty::ty_fn_args(ctor_ty);
20952086

20962087
insert_synthetic_type_entries(bcx, fn_args, arg_tys);
@@ -2108,7 +2099,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
21082099
let arg_ty = arg_tys[i];
21092100
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
21102101
}
2111-
finish_fn(fcx, lltop, bcx);
2102+
finish_fn(fcx, bcx);
21122103
}
21132104

21142105
pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
@@ -2336,9 +2327,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
23362327
// be updated if this assertion starts to fail.
23372328
assert!(fcx.has_immediate_return_value);
23382329

2339-
let bcx = top_scope_block(fcx, None);
2340-
let lltop = bcx.llbb;
2341-
2330+
let bcx = fcx.entry_bcx.get();
23422331
// Call main.
23432332
let llenvarg = unsafe {
23442333
let env_arg = fcx.env_arg_pos();
@@ -2347,7 +2336,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
23472336
let args = ~[llenvarg];
23482337
Call(bcx, main_llfn, args);
23492338

2350-
finish_fn(fcx, lltop, bcx);
2339+
finish_fn(fcx, bcx);
23512340
return llfdecl;
23522341
}
23532342

src/librustc/middle/trans/build.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -318,14 +318,18 @@ pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef {
318318
pub fn Alloca(cx: block, Ty: Type, name: &str) -> ValueRef {
319319
unsafe {
320320
if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); }
321-
B(cx).alloca(Ty, name)
321+
let b = cx.fcx.ccx.builder();
322+
b.position_before(cx.fcx.alloca_insert_pt.get());
323+
b.alloca(Ty, name)
322324
}
323325
}
324326

325327
pub fn ArrayAlloca(cx: block, Ty: Type, Val: ValueRef) -> ValueRef {
326328
unsafe {
327329
if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); }
328-
B(cx).array_alloca(Ty, Val)
330+
let b = cx.fcx.ccx.builder();
331+
b.position_before(cx.fcx.alloca_insert_pt.get());
332+
b.array_alloca(Ty, Val)
329333
}
330334
}
331335

src/librustc/middle/trans/closure.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
use back::abi;
1313
use back::link::{mangle_internal_name_by_path_and_seq};
14-
use lib::llvm::{llvm, ValueRef};
14+
use lib::llvm::ValueRef;
1515
use middle::moves;
1616
use middle::trans::base::*;
1717
use middle::trans::build::*;
@@ -25,7 +25,6 @@ use util::ppaux::ty_to_str;
2525

2626
use middle::trans::type_::Type;
2727

28-
use std::str;
2928
use std::vec;
3029
use syntax::ast;
3130
use syntax::ast_map::path_name;
@@ -331,23 +330,7 @@ pub fn load_environment(fcx: fn_ctxt,
331330
return;
332331
}
333332

334-
let llloadenv = match fcx.llloadenv {
335-
Some(ll) => ll,
336-
None => {
337-
let ll =
338-
str::as_c_str("load_env",
339-
|buf|
340-
unsafe {
341-
llvm::LLVMAppendBasicBlockInContext(fcx.ccx.llcx,
342-
fcx.llfn,
343-
buf)
344-
});
345-
fcx.llloadenv = Some(ll);
346-
ll
347-
}
348-
};
349-
350-
let bcx = raw_block(fcx, false, llloadenv);
333+
let bcx = fcx.entry_bcx.get();
351334

352335
// Load a pointer to the closure data, skipping over the box header:
353336
let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv);

src/librustc/middle/trans/common.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,14 @@ pub struct fn_ctxt_ {
174174
// always be Some.
175175
llretptr: Option<ValueRef>,
176176

177+
entry_bcx: Option<block>,
178+
177179
// These elements: "hoisted basic blocks" containing
178180
// administrative activities that have to happen in only one place in
179181
// the function, due to LLVM's quirks.
180-
// A block for all the function's static allocas, so that LLVM
181-
// will coalesce them into a single alloca call.
182-
llstaticallocas: Option<BasicBlockRef>,
183-
// A block containing code that copies incoming arguments to space
184-
// already allocated by code in one of the llallocas blocks.
185-
// (LLVM requires that arguments be copied to local allocas before
186-
// allowing most any operation to be performed on them.)
187-
llloadenv: Option<BasicBlockRef>,
182+
// A marker for the place where we want to insert the function's static
183+
// allocas, so that LLVM will coalesce them into a single alloca call.
184+
alloca_insert_pt: Option<ValueRef>,
188185
llreturn: Option<BasicBlockRef>,
189186
// The 'self' value currently in use in this function, if there
190187
// is one.
@@ -252,12 +249,12 @@ impl fn_ctxt_ {
252249
}
253250
}
254251

255-
pub fn get_llstaticallocas(&mut self) -> BasicBlockRef {
256-
if self.llstaticallocas.is_none() {
257-
self.llstaticallocas = Some(base::mk_staticallocas_basic_block(self.llfn));
252+
pub fn cleanup(&mut self) {
253+
unsafe {
254+
llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt.get());
258255
}
259-
260-
self.llstaticallocas.get()
256+
// Remove the cycle between fcx and bcx, so memory can be freed
257+
self.entry_bcx = None;
261258
}
262259

263260
pub fn get_llreturn(&mut self) -> BasicBlockRef {

0 commit comments

Comments
 (0)