From 25af6d380bed202e4597a8a3470508dd7fc9379b Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Mon, 11 Sep 2017 11:04:38 -0700 Subject: [PATCH] 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. --- .../filetests/verifier/return_at_end.cton | 26 +++++++++++++++++++ lib/cretonne/meta/base/settings.py | 10 +++++++ lib/cretonne/src/ir/layout.rs | 5 ++++ lib/cretonne/src/settings.rs | 1 + lib/cretonne/src/verifier/mod.rs | 19 ++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 cranelift/filetests/verifier/return_at_end.cton diff --git a/cranelift/filetests/verifier/return_at_end.cton b/cranelift/filetests/verifier/return_at_end.cton new file mode 100644 index 0000000000..b0fe05889a --- /dev/null +++ b/cranelift/filetests/verifier/return_at_end.cton @@ -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 +} diff --git a/lib/cretonne/meta/base/settings.py b/lib/cretonne/meta/base/settings.py index 46ff16d851..2baf9927ce 100644 --- a/lib/cretonne/meta/base/settings.py +++ b/lib/cretonne/meta/base/settings.py @@ -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( diff --git a/lib/cretonne/src/ir/layout.rs b/lib/cretonne/src/ir/layout.rs index 6d16b004e1..5c908812cf 100644 --- a/lib/cretonne/src/ir/layout.rs +++ b/lib/cretonne/src/ir/layout.rs @@ -374,6 +374,11 @@ impl Layout { self.first_ebb } + /// Get the last EBB in the layout. + pub fn last_ebb(&self) -> Option { + self.last_ebb + } + /// Get the block following `ebb` in the layout order. pub fn next_ebb(&self, ebb: Ebb) -> Option { self.ebbs[ebb].next.expand() diff --git a/lib/cretonne/src/settings.rs b/lib/cretonne/src/settings.rs index 999d305439..e45dba395c 100644 --- a/lib/cretonne/src/settings.rs +++ b/lib/cretonne/src/settings.rs @@ -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\ diff --git a/lib/cretonne/src/verifier/mod.rs b/lib/cretonne/src/verifier/mod.rs index e6f9ea933e..f3952606ca 100644 --- a/lib/cretonne/src/verifier/mod.rs +++ b/lib/cretonne/src/verifier/mod.rs @@ -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(()) } }