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:
26
cranelift/filetests/verifier/return_at_end.cton
Normal file
26
cranelift/filetests/verifier/return_at_end.cton
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
test verifier
|
||||||
|
set return_at_end
|
||||||
|
|
||||||
|
; The verifier doesn't have an API for verifying with flags without also
|
||||||
|
; setting an ISA.
|
||||||
|
isa riscv
|
||||||
|
|
||||||
|
function %ok(i32) {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
brnz v0, ebb1
|
||||||
|
trap
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
trapz v0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
function %bad(i32) {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
brnz v0, ebb1
|
||||||
|
return ; error: Internal return not allowed
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
trapz v0
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -28,6 +28,16 @@ enable_verifier = BoolSetting(
|
|||||||
|
|
||||||
is_64bit = BoolSetting("Enable 64-bit code generation")
|
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")
|
is_compressed = BoolSetting("Enable compressed instructions")
|
||||||
|
|
||||||
enable_float = BoolSetting(
|
enable_float = BoolSetting(
|
||||||
|
|||||||
@@ -374,6 +374,11 @@ impl Layout {
|
|||||||
self.first_ebb
|
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.
|
/// Get the block following `ebb` in the layout order.
|
||||||
pub fn next_ebb(&self, ebb: Ebb) -> Option<Ebb> {
|
pub fn next_ebb(&self, ebb: Ebb) -> Option<Ebb> {
|
||||||
self.ebbs[ebb].next.expand()
|
self.ebbs[ebb].next.expand()
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ mod tests {
|
|||||||
opt_level = \"default\"\n\
|
opt_level = \"default\"\n\
|
||||||
enable_verifier = false\n\
|
enable_verifier = false\n\
|
||||||
is_64bit = false\n\
|
is_64bit = false\n\
|
||||||
|
return_at_end = false\n\
|
||||||
is_compressed = false\n\
|
is_compressed = false\n\
|
||||||
enable_float = true\n\
|
enable_float = true\n\
|
||||||
enable_simd = true\n\
|
enable_simd = true\n\
|
||||||
|
|||||||
@@ -942,6 +942,21 @@ impl<'a> Verifier<'a> {
|
|||||||
Ok(())
|
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 {
|
pub fn run(&self) -> Result {
|
||||||
self.verify_global_vars()?;
|
self.verify_global_vars()?;
|
||||||
self.typecheck_entry_block_arguments()?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user