Simplify ssa builder (#1340)

* Simplify SSABuilder with basic block

* Simplify FunctionBuilder with basic block

* Update SSABuilder test

* Update SSABuilder doc
This commit is contained in:
Y-Nak
2020-03-21 03:54:44 +09:00
committed by GitHub
parent adff432767
commit bcddce5fe0
2 changed files with 456 additions and 516 deletions

View File

@@ -1,5 +1,5 @@
//! A frontend for building Cranelift IR from other languages. //! A frontend for building Cranelift IR from other languages.
use crate::ssa::{SSABlock, SSABuilder, SideEffects}; use crate::ssa::{SSABuilder, SideEffects};
use crate::variable::Variable; use crate::variable::Variable;
use cranelift_codegen::cursor::{Cursor, FuncCursor}; use cranelift_codegen::cursor::{Cursor, FuncCursor};
use cranelift_codegen::entity::{EntitySet, SecondaryMap}; use cranelift_codegen::entity::{EntitySet, SecondaryMap};
@@ -35,7 +35,7 @@ pub struct FunctionBuilder<'a> {
srcloc: ir::SourceLoc, srcloc: ir::SourceLoc,
func_ctx: &'a mut FunctionBuilderContext, func_ctx: &'a mut FunctionBuilderContext,
position: Position, position: PackedOption<Block>,
} }
#[derive(Clone, Default)] #[derive(Clone, Default)]
@@ -54,25 +54,6 @@ struct BlockData {
user_param_count: usize, user_param_count: usize,
} }
#[derive(Default)]
struct Position {
block: PackedOption<Block>,
basic_block: PackedOption<SSABlock>,
}
impl Position {
fn at(block: Block, basic_block: SSABlock) -> Self {
Self {
block: PackedOption::from(block),
basic_block: PackedOption::from(basic_block),
}
}
fn is_default(&self) -> bool {
self.block.is_none() && self.basic_block.is_none()
}
}
impl FunctionBuilderContext { impl FunctionBuilderContext {
/// Creates a FunctionBuilderContext structure. The structure is automatically cleared after /// Creates a FunctionBuilderContext structure. The structure is automatically cleared after
/// each [`FunctionBuilder`](struct.FunctionBuilder.html) completes translating a function. /// each [`FunctionBuilder`](struct.FunctionBuilder.html) completes translating a function.
@@ -158,25 +139,22 @@ impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> {
.iter() .iter()
.filter(|&dest_block| unique.insert(*dest_block)) .filter(|&dest_block| unique.insert(*dest_block))
{ {
// Call `declare_block_predecessor` instead of `declare_successor` for
// avoiding the borrow checker.
self.builder.func_ctx.ssa.declare_block_predecessor( self.builder.func_ctx.ssa.declare_block_predecessor(
*dest_block, *dest_block,
self.builder.position.basic_block.unwrap(), self.builder.position.unwrap(),
inst, inst,
); );
} }
self.builder.func_ctx.ssa.declare_block_predecessor( self.builder.declare_successor(destination, inst);
destination,
self.builder.position.basic_block.unwrap(),
inst,
);
} }
} }
} }
} }
if data.opcode().is_terminator() { if data.opcode().is_terminator() {
self.builder.fill_current_block() self.builder.fill_current_block()
} else if data.opcode().is_branch() {
self.builder.move_to_next_basic_block()
} }
(inst, &mut self.builder.func.dfg) (inst, &mut self.builder.func.dfg)
} }
@@ -224,7 +202,7 @@ impl<'a> FunctionBuilder<'a> {
func, func,
srcloc: Default::default(), srcloc: Default::default(),
func_ctx, func_ctx,
position: Position::default(), position: Default::default(),
} }
} }
@@ -236,7 +214,7 @@ impl<'a> FunctionBuilder<'a> {
/// Creates a new `Block` and returns its reference. /// Creates a new `Block` and returns its reference.
pub fn create_block(&mut self) -> Block { pub fn create_block(&mut self) -> Block {
let block = self.func.dfg.make_block(); let block = self.func.dfg.make_block();
self.func_ctx.ssa.declare_block_header_block(block); self.func_ctx.ssa.declare_block(block);
self.func_ctx.blocks[block] = BlockData { self.func_ctx.blocks[block] = BlockData {
filled: false, filled: false,
pristine: true, pristine: true,
@@ -255,7 +233,7 @@ impl<'a> FunctionBuilder<'a> {
pub fn switch_to_block(&mut self, block: Block) { pub fn switch_to_block(&mut self, block: Block) {
// First we check that the previous block has been filled. // First we check that the previous block has been filled.
debug_assert!( debug_assert!(
self.position.is_default() self.position.is_none()
|| self.is_unreachable() || self.is_unreachable()
|| self.is_pristine() || self.is_pristine()
|| self.is_filled(), || self.is_filled(),
@@ -267,9 +245,8 @@ impl<'a> FunctionBuilder<'a> {
"you cannot switch to a block which is already filled" "you cannot switch to a block which is already filled"
); );
let basic_block = self.func_ctx.ssa.header_block(block);
// Then we change the cursor position. // Then we change the cursor position.
self.position = Position::at(block, basic_block); self.position = PackedOption::from(block);
} }
/// Declares that all the predecessors of this block are known. /// Declares that all the predecessors of this block are known.
@@ -278,7 +255,7 @@ impl<'a> FunctionBuilder<'a> {
/// created. Forgetting to call this method on every block will cause inconsistencies in the /// created. Forgetting to call this method on every block will cause inconsistencies in the
/// produced functions. /// produced functions.
pub fn seal_block(&mut self, block: Block) { pub fn seal_block(&mut self, block: Block) {
let side_effects = self.func_ctx.ssa.seal_block_header_block(block, self.func); let side_effects = self.func_ctx.ssa.seal_block(block, self.func);
self.handle_ssa_side_effects(side_effects); self.handle_ssa_side_effects(side_effects);
} }
@@ -289,7 +266,7 @@ impl<'a> FunctionBuilder<'a> {
/// function can be used at the end of translating all blocks to ensure /// function can be used at the end of translating all blocks to ensure
/// that everything is sealed. /// that everything is sealed.
pub fn seal_all_blocks(&mut self) { pub fn seal_all_blocks(&mut self) {
let side_effects = self.func_ctx.ssa.seal_all_block_header_blocks(self.func); let side_effects = self.func_ctx.ssa.seal_all_blocks(self.func);
self.handle_ssa_side_effects(side_effects); self.handle_ssa_side_effects(side_effects);
} }
@@ -310,7 +287,7 @@ impl<'a> FunctionBuilder<'a> {
}); });
self.func_ctx self.func_ctx
.ssa .ssa
.use_var(self.func, var, ty, self.position.basic_block.unwrap()) .use_var(self.func, var, ty, self.position.unwrap())
}; };
self.handle_ssa_side_effects(side_effects); self.handle_ssa_side_effects(side_effects);
val val
@@ -330,9 +307,7 @@ impl<'a> FunctionBuilder<'a> {
val val
); );
self.func_ctx self.func_ctx.ssa.def_var(var, val, self.position.unwrap());
.ssa
.def_var(var, val, self.position.basic_block.unwrap());
} }
/// Set label for Value /// Set label for Value
@@ -395,14 +370,13 @@ impl<'a> FunctionBuilder<'a> {
pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> { pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> {
let block = self let block = self
.position .position
.block
.expect("Please call switch_to_block before inserting instructions"); .expect("Please call switch_to_block before inserting instructions");
FuncInstBuilder::new(self, block) FuncInstBuilder::new(self, block)
} }
/// Make sure that the current block is inserted in the layout. /// Make sure that the current block is inserted in the layout.
pub fn ensure_inserted_block(&mut self) { pub fn ensure_inserted_block(&mut self) {
let block = self.position.block.unwrap(); let block = self.position.unwrap();
if self.func_ctx.blocks[block].pristine { if self.func_ctx.blocks[block].pristine {
if !self.func.layout.is_block_inserted(block) { if !self.func.layout.is_block_inserted(block) {
self.func.layout.append_block(block); self.func.layout.append_block(block);
@@ -424,7 +398,7 @@ impl<'a> FunctionBuilder<'a> {
self.ensure_inserted_block(); self.ensure_inserted_block();
FuncCursor::new(self.func) FuncCursor::new(self.func)
.with_srcloc(self.srcloc) .with_srcloc(self.srcloc)
.at_bottom(self.position.block.unwrap()) .at_bottom(self.position.unwrap())
} }
/// Append parameters to the given `Block` corresponding to the function /// Append parameters to the given `Block` corresponding to the function
@@ -495,7 +469,7 @@ impl<'a> FunctionBuilder<'a> {
// Reset srcloc and position to initial states. // Reset srcloc and position to initial states.
self.srcloc = Default::default(); self.srcloc = Default::default();
self.position = Position::default(); self.position = Default::default();
} }
} }
@@ -560,26 +534,26 @@ impl<'a> FunctionBuilder<'a> {
pub fn is_unreachable(&self) -> bool { pub fn is_unreachable(&self) -> bool {
let is_entry = match self.func.layout.entry_block() { let is_entry = match self.func.layout.entry_block() {
None => false, None => false,
Some(entry) => self.position.block.unwrap() == entry, Some(entry) => self.position.unwrap() == entry,
}; };
!is_entry !is_entry
&& self.func_ctx.ssa.is_sealed(self.position.block.unwrap()) && self.func_ctx.ssa.is_sealed(self.position.unwrap())
&& !self && !self
.func_ctx .func_ctx
.ssa .ssa
.has_any_predecessors(self.position.block.unwrap()) .has_any_predecessors(self.position.unwrap())
} }
/// Returns `true` if and only if no instructions have been added since the last call to /// Returns `true` if and only if no instructions have been added since the last call to
/// `switch_to_block`. /// `switch_to_block`.
pub fn is_pristine(&self) -> bool { pub fn is_pristine(&self) -> bool {
self.func_ctx.blocks[self.position.block.unwrap()].pristine self.func_ctx.blocks[self.position.unwrap()].pristine
} }
/// Returns `true` if and only if a terminator instruction has been inserted since the /// Returns `true` if and only if a terminator instruction has been inserted since the
/// last call to `switch_to_block`. /// last call to `switch_to_block`.
pub fn is_filled(&self) -> bool { pub fn is_filled(&self) -> bool {
self.func_ctx.blocks[self.position.block.unwrap()].filled self.func_ctx.blocks[self.position.unwrap()].filled
} }
/// Returns a displayable object for the function as it is. /// Returns a displayable object for the function as it is.
@@ -824,25 +798,15 @@ fn greatest_divisible_power_of_two(size: u64) -> u64 {
// Helper functions // Helper functions
impl<'a> FunctionBuilder<'a> { impl<'a> FunctionBuilder<'a> {
fn move_to_next_basic_block(&mut self) {
self.position.basic_block = PackedOption::from(
self.func_ctx
.ssa
.declare_block_body_block(self.position.basic_block.unwrap()),
);
}
/// A Block is 'filled' when a terminator instruction is present. /// A Block is 'filled' when a terminator instruction is present.
fn fill_current_block(&mut self) { fn fill_current_block(&mut self) {
self.func_ctx.blocks[self.position.block.unwrap()].filled = true; self.func_ctx.blocks[self.position.unwrap()].filled = true;
} }
fn declare_successor(&mut self, dest_block: Block, jump_inst: Inst) { fn declare_successor(&mut self, dest_block: Block, jump_inst: Inst) {
self.func_ctx.ssa.declare_block_predecessor( self.func_ctx
dest_block, .ssa
self.position.basic_block.unwrap(), .declare_block_predecessor(dest_block, self.position.unwrap(), jump_inst);
jump_inst,
);
} }
fn handle_ssa_side_effects(&mut self, side_effects: SideEffects) { fn handle_ssa_side_effects(&mut self, side_effects: SideEffects) {

File diff suppressed because it is too large Load Diff