Files
wasmtime/lib/frontend/src/lib.rs
Jakob Stoklund Olesen 7f3b807597 Add a calling convention to all function signatures.
A CallConv enum on every function signature makes it possible to
generate calls to functions with different calling conventions within
the same ISA / within a single function.

The calling conventions also serve as a way of customizing Cretonne's
behavior when embedded inside a VM. As an example, the SpiderWASM
calling convention is used to compile WebAssembly functions that run
inside the SpiderMonkey virtual machine.

All function signatures must have a calling convention at the end, so
this changes the textual IL syntax.

Before:

    sig1 = signature(i32, f64) -> f64

After

    sig1 = (i32, f64) -> f64 native
    sig2 = (i32) spiderwasm

When printing functions, the signature goes after the return types:

    function %r1() -> i32, f32 spiderwasm {
    ebb1:
        ...
    }

In the parser, this calling convention is optional and defaults to
"native". This is mostly to avoid updating all the existing test cases
under filetests/. When printing a function, the calling convention is
always included, including for "native" functions.
2017-08-03 11:40:24 -07:00

153 lines
4.6 KiB
Rust

//! Cretonne IL builder library.
//!
//! Provides a straightforward way to create a Cretonne IL function and fill it with instructions
//! translated from another language. Contains a SSA construction module that lets you translate
//! your non-SSA variables into SSA Cretonne IL values via `use_var` and `def_var` calls.
//!
//! To get started, create an [`IlBuilder`](struct.ILBuilder.html) and pass it as an argument
//! to a [`FunctionBuilder`](struct.FunctionBuilder.html).
//!
//! # Example
//!
//! Here is a pseudo-program we want to transform into Cretonne IL:
//!
//! ```cton
//! function(x) {
//! x, y, z : i32
//! block0:
//! y = 2;
//! z = x + y;
//! jump block1
//! block1:
//! z = z + y;
//! brnz y, block2;
//! z = z - x;
//! return y
//! block2:
//! y = y - x
//! jump block1
//! }
//! ```
//!
//! Here is how you build the corresponding Cretonne IL function using `ILBuilder`:
//!
//! ```rust
//! extern crate cretonne;
//! extern crate cton_frontend;
//!
//! use cretonne::entity_ref::EntityRef;
//! use cretonne::ir::{FunctionName, CallConv, Function, Signature, ArgumentType, InstBuilder};
//! use cretonne::ir::types::*;
//! use cton_frontend::{ILBuilder, FunctionBuilder};
//! use cretonne::verifier::verify_function;
//! use std::u32;
//!
//! // An opaque reference to variable.
//! #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
//! pub struct Variable(u32);
//! impl EntityRef for Variable {
//! fn new(index: usize) -> Self {
//! assert!(index < (u32::MAX as usize));
//! Variable(index as u32)
//! }
//!
//! fn index(self) -> usize {
//! self.0 as usize
//! }
//! }
//! impl Default for Variable {
//! fn default() -> Variable {
//! Variable(u32::MAX)
//! }
//! }
//!
//! fn main() {
//! let mut sig = Signature::new(CallConv::Native);
//! sig.return_types.push(ArgumentType::new(I32));
//! sig.argument_types.push(ArgumentType::new(I32));
//! let mut il_builder = ILBuilder::<Variable>::new();
//! let mut func = Function::with_name_signature(FunctionName::new("sample_function"), sig);
//! {
//! let mut builder = FunctionBuilder::<Variable>::new(&mut func, &mut il_builder);
//!
//! let block0 = builder.create_ebb();
//! let block1 = builder.create_ebb();
//! let block2 = builder.create_ebb();
//! let x = Variable(0);
//! let y = Variable(1);
//! let z = Variable(2);
//! builder.declare_var(x, I32);
//! builder.declare_var(y, I32);
//! builder.declare_var(z, I32);
//!
//! builder.switch_to_block(block0, &[]);
//! builder.seal_block(block0);
//! {
//! let tmp = builder.arg_value(0);
//! builder.def_var(x, tmp);
//! }
//! {
//! let tmp = builder.ins().iconst(I32, 2);
//! builder.def_var(y, tmp);
//! }
//! {
//! let arg1 = builder.use_var(x);
//! let arg2 = builder.use_var(y);
//! let tmp = builder.ins().iadd(arg1, arg2);
//! builder.def_var(z, tmp);
//! }
//! builder.ins().jump(block1, &[]);
//!
//! builder.switch_to_block(block1, &[]);
//! {
//! let arg1 = builder.use_var(y);
//! let arg2 = builder.use_var(z);
//! let tmp = builder.ins().iadd(arg1, arg2);
//! builder.def_var(z, tmp);
//! }
//! {
//! let arg = builder.use_var(y);
//! builder.ins().brnz(arg, block2, &[]);
//! }
//! {
//! let arg1 = builder.use_var(z);
//! let arg2 = builder.use_var(x);
//! let tmp = builder.ins().isub(arg1, arg2);
//! builder.def_var(z, tmp);
//! }
//! {
//! let arg = builder.use_var(y);
//! builder.ins().return_(&[arg]);
//! }
//!
//! builder.switch_to_block(block2, &[]);
//! builder.seal_block(block2);
//!
//! {
//! let arg1 = builder.use_var(y);
//! let arg2 = builder.use_var(x);
//! let tmp = builder.ins().isub(arg1, arg2);
//! builder.def_var(y, tmp);
//! }
//! builder.ins().jump(block1, &[]);
//! builder.seal_block(block1);
//! }
//!
//! let res = verify_function(&func, None);
//! println!("{}", func.display(None));
//! match res {
//! Ok(_) => {}
//! Err(err) => panic!("{}", err),
//! }
//! }
//! ```
#![deny(missing_docs)]
extern crate cretonne;
pub use frontend::{ILBuilder, FunctionBuilder};
mod frontend;
mod ssa;