Add a return_at_end setting.
The flag guarantees that the generated function does not have any internal return instructions. If the function returns at all, the return must be the last instruction. For now just implement a verifier check for this property. When we get CFG simplifiers and block layout optimizations, they will need to heed the flag.
This commit is contained in:
@@ -28,6 +28,16 @@ enable_verifier = BoolSetting(
|
||||
|
||||
is_64bit = BoolSetting("Enable 64-bit code generation")
|
||||
|
||||
return_at_end = BoolSetting(
|
||||
"""
|
||||
Generate functions with at most a single return instruction at the
|
||||
end of the function.
|
||||
|
||||
This guarantees that functions do not have any internal return
|
||||
instructions. Either they never return, or they have a single return
|
||||
instruction at the end.
|
||||
""")
|
||||
|
||||
is_compressed = BoolSetting("Enable compressed instructions")
|
||||
|
||||
enable_float = BoolSetting(
|
||||
|
||||
@@ -374,6 +374,11 @@ impl Layout {
|
||||
self.first_ebb
|
||||
}
|
||||
|
||||
/// Get the last EBB in the layout.
|
||||
pub fn last_ebb(&self) -> Option<Ebb> {
|
||||
self.last_ebb
|
||||
}
|
||||
|
||||
/// Get the block following `ebb` in the layout order.
|
||||
pub fn next_ebb(&self, ebb: Ebb) -> Option<Ebb> {
|
||||
self.ebbs[ebb].next.expand()
|
||||
|
||||
@@ -319,6 +319,7 @@ mod tests {
|
||||
opt_level = \"default\"\n\
|
||||
enable_verifier = false\n\
|
||||
is_64bit = false\n\
|
||||
return_at_end = false\n\
|
||||
is_compressed = false\n\
|
||||
enable_float = true\n\
|
||||
enable_simd = true\n\
|
||||
|
||||
@@ -942,6 +942,21 @@ impl<'a> Verifier<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify the `return_at_end` property which requires that there are no internal return
|
||||
/// instructions.
|
||||
fn verify_return_at_end(&self) -> Result {
|
||||
for ebb in self.func.layout.ebbs() {
|
||||
let inst = self.func.layout.last_inst(ebb).unwrap();
|
||||
if self.func.dfg[inst].opcode().is_return() &&
|
||||
Some(ebb) != self.func.layout.last_ebb()
|
||||
{
|
||||
return err!(inst, "Internal return not allowed with return_at_end=1");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Result {
|
||||
self.verify_global_vars()?;
|
||||
self.typecheck_entry_block_arguments()?;
|
||||
@@ -954,6 +969,10 @@ impl<'a> Verifier<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if self.isa.map(|isa| isa.flags().return_at_end()) == Some(true) {
|
||||
self.verify_return_at_end()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user