Skip to content

Commit 402e9ef

Browse files
committed
rustc_codegen_ssa: only create backend BasicBlocks as-needed.
1 parent 7dc9ff5 commit 402e9ef

File tree

7 files changed

+50
-51
lines changed

7 files changed

+50
-51
lines changed

compiler/rustc_codegen_llvm/src/builder.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1148,10 +1148,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
11481148
self.cx
11491149
}
11501150

1151-
unsafe fn delete_basic_block(&mut self, bb: &'ll BasicBlock) {
1152-
llvm::LLVMDeleteBasicBlock(bb);
1153-
}
1154-
11551151
fn do_not_inline(&mut self, llret: &'ll Value) {
11561152
llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret);
11571153
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,6 @@ extern "C" {
10791079
Fn: &'a Value,
10801080
Name: *const c_char,
10811081
) -> &'a BasicBlock;
1082-
pub fn LLVMDeleteBasicBlock(BB: &BasicBlock);
10831082

10841083
// Operations on instructions
10851084
pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>;

compiler/rustc_codegen_ssa/src/mir/block.rs

+21-7
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
6868
target: mir::BasicBlock,
6969
) -> (Bx::BasicBlock, bool) {
7070
let span = self.terminator.source_info.span;
71-
let lltarget = fx.blocks[target];
71+
let lltarget = fx.llbb(target);
7272
let target_funclet = fx.cleanup_kinds[target].funclet_bb(target);
7373
match (self.funclet_bb, target_funclet) {
7474
(None, None) => (lltarget, false),
@@ -133,13 +133,13 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
133133
// If there is a cleanup block and the function we're calling can unwind, then
134134
// do an invoke, otherwise do a call.
135135
if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
136-
let ret_bx = if let Some((_, target)) = destination {
137-
fx.blocks[target]
136+
let ret_llbb = if let Some((_, target)) = destination {
137+
fx.llbb(target)
138138
} else {
139139
fx.unreachable_block()
140140
};
141141
let invokeret =
142-
bx.invoke(fn_ptr, &llargs, ret_bx, self.llblock(fx, cleanup), self.funclet(fx));
142+
bx.invoke(fn_ptr, &llargs, ret_llbb, self.llblock(fx, cleanup), self.funclet(fx));
143143
bx.apply_attrs_callsite(&fn_abi, invokeret);
144144

145145
if let Some((ret_dest, target)) = destination {
@@ -1205,7 +1205,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12051205

12061206
// FIXME(eddyb) rename this to `eh_pad_for_uncached`.
12071207
fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock {
1208-
let llbb = self.blocks[bb];
1208+
let llbb = self.llbb(bb);
12091209
if base::wants_msvc_seh(self.cx.sess()) {
12101210
let funclet;
12111211
let ret_llbb;
@@ -1293,9 +1293,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12931293
Bx::new_block(self.cx, self.llfn, name)
12941294
}
12951295

1296-
pub fn build_block(&self, bb: mir::BasicBlock) -> Bx {
1296+
/// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already
1297+
/// cached in `self.cached_llbbs`, or created on demand (and cached).
1298+
// FIXME(eddyb) rename `llbb` and other `ll`-prefixed things to use a
1299+
// more backend-agnostic prefix such as `cg` (i.e. this would be `cgbb`).
1300+
pub fn llbb(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock {
1301+
self.cached_llbbs[bb].unwrap_or_else(|| {
1302+
// FIXME(eddyb) only name the block if `fewer_names` is `false`.
1303+
// FIXME(eddyb) create the block directly, without a builder.
1304+
let llbb = self.new_block(&format!("{:?}", bb)).llbb();
1305+
self.cached_llbbs[bb] = Some(llbb);
1306+
llbb
1307+
})
1308+
}
1309+
1310+
pub fn build_block(&mut self, bb: mir::BasicBlock) -> Bx {
12971311
let mut bx = Bx::with_cx(self.cx);
1298-
bx.position_at_end(self.blocks[bb]);
1312+
bx.position_at_end(self.llbb(bb));
12991313
bx
13001314
}
13011315

compiler/rustc_codegen_ssa/src/mir/mod.rs

+20-32
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
4040
/// then later loaded when generating the DIVERGE_BLOCK.
4141
personality_slot: Option<PlaceRef<'tcx, Bx::Value>>,
4242

43-
/// A `Block` for each MIR `BasicBlock`
44-
blocks: IndexVec<mir::BasicBlock, Bx::BasicBlock>,
43+
/// A backend `BasicBlock` for each MIR `BasicBlock`, created lazily
44+
/// as-needed (e.g. RPO reaching it or another block branching to it).
45+
// FIXME(eddyb) rename `llbbs` and other `ll`-prefixed things to use a
46+
// more backend-agnostic prefix such as `cg` (i.e. this would be `cgbbs`).
47+
cached_llbbs: IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>>,
4548

4649
/// The funclet status of each basic block
4750
cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
@@ -151,17 +154,17 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
151154
// Allocate a `Block` for every basic block, except
152155
// the start block, if nothing loops back to it.
153156
let reentrant_start_block = !mir.predecessors()[mir::START_BLOCK].is_empty();
154-
let block_bxs: IndexVec<mir::BasicBlock, Bx::BasicBlock> = mir
155-
.basic_blocks()
156-
.indices()
157-
.map(|bb| {
158-
if bb == mir::START_BLOCK && !reentrant_start_block {
159-
bx.llbb()
160-
} else {
161-
bx.build_sibling_block(&format!("{:?}", bb)).llbb()
162-
}
163-
})
164-
.collect();
157+
let cached_llbbs: IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>> =
158+
mir.basic_blocks()
159+
.indices()
160+
.map(|bb| {
161+
if bb == mir::START_BLOCK && !reentrant_start_block {
162+
Some(bx.llbb())
163+
} else {
164+
None
165+
}
166+
})
167+
.collect();
165168

166169
let mut fx = FunctionCx {
167170
instance,
@@ -170,7 +173,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
170173
fn_abi,
171174
cx,
172175
personality_slot: None,
173-
blocks: block_bxs,
176+
cached_llbbs,
174177
unreachable_block: None,
175178
cleanup_kinds,
176179
landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
@@ -245,29 +248,14 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
245248

246249
// Branch to the START block, if it's not the entry block.
247250
if reentrant_start_block {
248-
bx.br(fx.blocks[mir::START_BLOCK]);
251+
bx.br(fx.llbb(mir::START_BLOCK));
249252
}
250253

251-
let rpo = traversal::reverse_postorder(&mir);
252-
let mut visited = BitSet::new_empty(mir.basic_blocks().len());
253-
254254
// Codegen the body of each block using reverse postorder
255-
for (bb, _) in rpo {
256-
visited.insert(bb.index());
255+
// FIXME(eddyb) reuse RPO iterator between `analysis` and this.
256+
for (bb, _) in traversal::reverse_postorder(&mir) {
257257
fx.codegen_block(bb);
258258
}
259-
260-
// Remove blocks that haven't been visited, or have no
261-
// predecessors.
262-
for bb in mir.basic_blocks().indices() {
263-
// Unreachable block
264-
if !visited.contains(bb.index()) {
265-
debug!("codegen_mir: block {:?} was not visited", bb);
266-
unsafe {
267-
bx.delete_basic_block(fx.blocks[bb]);
268-
}
269-
}
270-
}
271259
}
272260

273261
/// Produces, for each argument, a `Value` pointing at the

compiler/rustc_codegen_ssa/src/traits/builder.rs

-1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,5 @@ pub trait BuilderMethods<'a, 'tcx>:
291291
) -> Self::Value;
292292
fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
293293

294-
unsafe fn delete_basic_block(&mut self, bb: Self::BasicBlock);
295294
fn do_not_inline(&mut self, llret: Self::Value);
296295
}

src/test/codegen/drop.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ pub fn droppy() {
2323
// FIXME(eddyb) the `void @` forces a match on the instruction, instead of the
2424
// comment, that's `; call core::ptr::drop_in_place::<drop::SomeUniqueName>`
2525
// for the `v0` mangling, should switch to matching on that once `legacy` is gone.
26-
// CHECK-NOT: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
27-
// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
28-
// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
2926
// CHECK-NOT: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
3027
// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
3128
// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
29+
// CHECK-NOT: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
30+
// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
31+
// CHECK-NOT: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
3232
// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
33+
// CHECK-NOT: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
34+
// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
35+
// CHECK-NOT: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
3336
// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
3437
// CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
3538
// The next line checks for the } that ends the function definition

src/test/codegen/match.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ pub fn exhaustive_match(e: E) -> u8 {
1414
// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]]
1515
// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]]
1616
// CHECK-NEXT: ]
17-
// CHECK: [[B]]:
18-
// CHECK-NEXT: store i8 1, i8* %1, align 1
19-
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
2017
// CHECK: [[OTHERWISE]]:
2118
// CHECK-NEXT: unreachable
2219
// CHECK: [[A]]:
2320
// CHECK-NEXT: store i8 0, i8* %1, align 1
21+
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
22+
// CHECK: [[B]]:
23+
// CHECK-NEXT: store i8 1, i8* %1, align 1
2424
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
2525
match e {
2626
E::A => 0,

0 commit comments

Comments
 (0)