Files
wasmtime/cranelift/filetests/src/function_runner.rs
Ryan Hunt 832666c45e Mass rename Ebb and relatives to Block (#1365)
* Manually rename BasicBlock to BlockPredecessor

BasicBlock is a pair of (Ebb, Inst) that is used to represent the
basic block subcomponent of an Ebb that is a predecessor to an Ebb.

Eventually we will be able to remove this struct, but for now it
makes sense to give it a non-conflicting name so that we can start
to transition Ebb to represent a basic block.

I have not updated any comments that refer to BasicBlock, as
eventually we will remove BlockPredecessor and replace with Block,
which is a basic block, so the comments will become correct.

* Manually rename SSABuilder block types to avoid conflict

SSABuilder has its own Block and BlockData types. These along with
associated identifier will cause conflicts in a later commit, so
they are renamed to be more verbose here.

* Automatically rename 'Ebb' to 'Block' in *.rs

* Automatically rename 'EBB' to 'block' in *.rs

* Automatically rename 'ebb' to 'block' in *.rs

* Automatically rename 'extended basic block' to 'basic block' in *.rs

* Automatically rename 'an basic block' to 'a basic block' in *.rs

* Manually update comment for `Block`

`Block`'s wikipedia article required an update.

* Automatically rename 'an `Block`' to 'a `Block`' in *.rs

* Automatically rename 'extended_basic_block' to 'basic_block' in *.rs

* Automatically rename 'ebb' to 'block' in *.clif

* Manually rename clif constant that contains 'ebb' as substring to avoid conflict

* Automatically rename filecheck uses of 'EBB' to 'BB'

'regex: EBB' -> 'regex: BB'
'$EBB' -> '$BB'

* Automatically rename 'EBB' 'Ebb' to 'block' in *.clif

* Automatically rename 'an block' to 'a block' in *.clif

* Fix broken testcase when function name length increases

Test function names are limited to 16 characters. This causes
the new longer name to be truncated and fail a filecheck test. An
outdated comment was also fixed.
2020-02-07 10:46:47 -06:00

118 lines
4.0 KiB
Rust

use core::mem;
use cranelift_codegen::binemit::{NullRelocSink, NullStackmapSink, NullTrapSink};
use cranelift_codegen::ir::Function;
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{settings, Context};
use cranelift_native::builder as host_isa_builder;
use memmap::MmapMut;
/// Run a function on a host
pub struct FunctionRunner {
function: Function,
isa: Box<dyn TargetIsa>,
}
impl FunctionRunner {
/// Build a function runner from a function and the ISA to run on (must be the host machine's ISA)
pub fn new(function: Function, isa: Box<dyn TargetIsa>) -> Self {
Self { function, isa }
}
/// Build a function runner using the host machine's ISA and the passed flags
pub fn with_host_isa(function: Function, flags: settings::Flags) -> Self {
let builder = host_isa_builder().expect("Unable to build a TargetIsa for the current host");
let isa = builder.finish(flags);
Self::new(function, isa)
}
/// Build a function runner using the host machine's ISA and the default flags for this ISA
pub fn with_default_host_isa(function: Function) -> Self {
let flags = settings::Flags::new(settings::builder());
Self::with_host_isa(function, flags)
}
/// Compile and execute a single function, expecting a boolean to be returned; a 'true' value is
/// interpreted as a successful test execution and mapped to Ok whereas a 'false' value is
/// interpreted as a failed test and mapped to Err.
pub fn run(&self) -> Result<(), String> {
let func = self.function.clone();
if !(func.signature.params.is_empty()
&& func.signature.returns.len() == 1
&& func.signature.returns.first().unwrap().value_type.is_bool())
{
return Err(String::from(
"Functions must have a signature like: () -> boolean",
));
}
if func.signature.call_conv != self.isa.default_call_conv() {
return Err(String::from(
"Functions only run on the host's default calling convention; remove the specified calling convention in the function signature to use the host's default.",
));
}
// set up the context
let mut context = Context::new();
context.func = func;
// compile and encode the result to machine code
let relocs = &mut NullRelocSink {};
let traps = &mut NullTrapSink {};
let stackmaps = &mut NullStackmapSink {};
let code_info = context
.compile(self.isa.as_ref())
.map_err(|e| e.to_string())?;
let mut code_page =
MmapMut::map_anon(code_info.total_size as usize).map_err(|e| e.to_string())?;
unsafe {
context.emit_to_memory(
self.isa.as_ref(),
code_page.as_mut_ptr(),
relocs,
traps,
stackmaps,
);
};
let code_page = code_page.make_exec().map_err(|e| e.to_string())?;
let callable_fn: fn() -> bool = unsafe { mem::transmute(code_page.as_ptr()) };
// execute
if callable_fn() {
Ok(())
} else {
Err(format!("Failed: {}", context.func.name.to_string()))
}
}
}
#[cfg(test)]
mod test {
use super::*;
use cranelift_reader::{parse_test, ParseOptions};
#[test]
fn nop() {
let code = String::from(
"
test run
function %test() -> b8 {
block0:
nop
v1 = bconst.b8 true
return v1
}",
);
// extract function
let test_file = parse_test(code.as_str(), ParseOptions::default()).unwrap();
assert_eq!(1, test_file.functions.len());
let function = test_file.functions[0].0.clone();
// execute function
let runner = FunctionRunner::with_default_host_isa(function);
runner.run().unwrap() // will panic if execution fails
}
}