Skip to content

Commit

Permalink
Cranelift: add support for cold blocks.
Browse files Browse the repository at this point in the history
This PR adds a flag to each block that can be set via the frontend/builder
interface that indicates that the block will not be frequently
executed. As such, the compiler backend should place the block "out of
line" in the final machine code, so that the ordinary, more frequent
execution path that excludes the block does not have to jump around it.

This is useful for adding handlers for exceptional conditions
(slow-paths, guard violations) in a way that minimizes performance cost.
  • Loading branch information
cfallin committed Jan 19, 2022
1 parent e2b37a5 commit 9f9be99
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
12 changes: 12 additions & 0 deletions cranelift/codegen/src/ir/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,17 @@ impl Layout {
pub fn next_block(&self, block: Block) -> Option<Block> {
self.blocks[block].next.expand()
}

/// Mark a block as "cold". This will try to move it out of the
/// ordinary path of execution when lowered to machine code.
pub fn mark_cold_block(&mut self, block: Block) {
self.blocks[block].cold = true;
}

/// Is the given block cold?
pub fn is_cold(&self, block: Block) -> bool {
self.blocks[block].cold
}
}

#[derive(Clone, Debug, Default)]
Expand All @@ -478,6 +489,7 @@ struct BlockNode {
first_inst: PackedOption<Inst>,
last_inst: PackedOption<Inst>,
seq: SequenceNumber,
cold: bool,
}

/// Iterate over blocks in layout order. See [crate::ir::layout::Layout::blocks].
Expand Down
15 changes: 14 additions & 1 deletion cranelift/codegen/src/machinst/blockorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,24 @@ impl BlockLoweringOrder {

postorder.reverse();
let mut rpo = postorder;

// Step 3: sink any cold blocks to the end of the
// function. Put the "deferred last" block truly at the end;
// this is a correctness requirement (for fallthrough
// returns).
rpo.sort_by_key(|block| {
block
.0
.orig_block()
.map(|block| f.layout.is_cold(block))
.unwrap_or(false)
});

if let Some(d) = deferred_last {
rpo.push(d);
}

// Step 3: now that we have RPO, build the BlockIndex/BB fwd/rev maps.
// Step 4: now that we have RPO, build the BlockIndex/BB fwd/rev maps.
let mut lowered_order = vec![];
let mut lowered_succ_ranges = vec![];
let mut lb_to_bindex = FxHashMap::default();
Expand Down
5 changes: 5 additions & 0 deletions cranelift/frontend/src/frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ impl<'a> FunctionBuilder<'a> {
block
}

/// Mark a block as cold.
pub fn mark_cold_block(&mut self, block: Block) {
self.func.layout.mark_cold_block(block);
}

/// Insert `block` in the layout *after* the existing block `after`.
pub fn insert_block_after(&mut self, block: Block, after: Block) {
self.func.layout.insert_block_after(block, after);
Expand Down

0 comments on commit 9f9be99

Please sign in to comment.