diff --git a/lib/frontend/src/frontend.rs b/lib/frontend/src/frontend.rs index 1c41e18994..fc7e8a90b2 100644 --- a/lib/frontend/src/frontend.rs +++ b/lib/frontend/src/frontend.rs @@ -300,6 +300,17 @@ where self.handle_ssa_side_effects(side_effects); } + /// Effectively calls seal_block on all blocks in the function. + /// + /// It's more efficient to seal `Ebb`s as soon as possible, during + /// translation, but for frontends where this is impractical to do, this + /// function can be used at the end of translating all blocks to ensure + /// that everything is sealed. + pub fn seal_all_blocks(&mut self) { + let side_effects = self.builder.ssa.seal_all_ebb_header_blocks(self.func); + self.handle_ssa_side_effects(side_effects); + } + /// In order to use a variable in a `use_var`, you need to declare its type with this method. pub fn declare_var(&mut self, var: Variable, ty: Type) { self.builder.types[var] = ty; @@ -679,8 +690,7 @@ mod tests { } } - #[test] - fn sample_function() { + fn sample_function(lazy_seal: bool) { let mut sig = Signature::new(CallConv::Native); sig.returns.push(AbiParam::new(I32)); sig.params.push(AbiParam::new(I32)); @@ -701,7 +711,9 @@ mod tests { builder.declare_var(z, I32); builder.switch_to_block(block0, &[]); - builder.seal_block(block0); + if !lazy_seal { + builder.seal_block(block0); + } { let tmp = builder.param_value(0); builder.def_var(x, tmp); @@ -741,7 +753,9 @@ mod tests { } builder.switch_to_block(block2, &[]); - builder.seal_block(block2); + if !lazy_seal { + builder.seal_block(block2); + } { let arg1 = builder.use_var(y); @@ -750,7 +764,13 @@ mod tests { builder.def_var(y, tmp); } builder.ins().jump(block1, &[]); - builder.seal_block(block1); + if !lazy_seal { + builder.seal_block(block1); + } + + if lazy_seal { + builder.seal_all_blocks(); + } } let flags = settings::Flags::new(&settings::builder()); @@ -761,4 +781,14 @@ mod tests { Err(err) => panic!("{}{}", func.display(None), err), } } + + #[test] + fn sample() { + sample_function(false) + } + + #[test] + fn sample_with_lazy_seal() { + sample_function(true) + } } diff --git a/lib/frontend/src/ssa.rs b/lib/frontend/src/ssa.rs index 12e77170d0..f8018ad415 100644 --- a/lib/frontend/src/ssa.rs +++ b/lib/frontend/src/ssa.rs @@ -409,6 +409,29 @@ where /// /// Returns the list of newly created ebbs for critical edge splitting. pub fn seal_ebb_header_block(&mut self, ebb: Ebb, func: &mut Function) -> SideEffects { + self.seal_one_ebb_header_block(ebb, func); + mem::replace(&mut self.side_effects, SideEffects::new()) + } + + /// Completes the global value numbering for all `Ebb`s in `func`. + /// + /// It's more efficient to seal `Ebb`s as soon as possible, during + /// translation, but for frontends where this is impractical to do, this + /// function can be used at the end of translating all blocks to ensure + /// that everything is sealed. + pub fn seal_all_ebb_header_blocks(&mut self, func: &mut Function) -> SideEffects { + // Seal all `Ebb`s currently in the function. This can entail splitting + // and creation of new blocks, however such new blocks are sealed on + // the fly, so we don't need to accout for them here. + for ebb in self.ebb_headers.keys() { + self.seal_one_ebb_header_block(ebb, func); + } + mem::replace(&mut self.side_effects, SideEffects::new()) + } + + /// Helper function for `seal_ebb_header_block` and + /// `seal_all_ebb_header_blocks`. + fn seal_one_ebb_header_block(&mut self, ebb: Ebb, func: &mut Function) { let block = self.header_block(ebb); let (undef_vars, ebb): (Vec<(Variable, Value)>, Ebb) = match self.blocks[block] { @@ -429,7 +452,6 @@ where self.predecessors_lookup(func, val, var, ty, ebb); } self.mark_ebb_header_block_sealed(block); - mem::replace(&mut self.side_effects, SideEffects::new()) } /// Set the `sealed` flag for `block`.