Update Cranelift's documentation after the merger. (#1238)
Update the documentation for the merger, and also for various changes in Cranelift. Remove some old obsolete documentation, and convert the remaining Sphinx files to Markdown. Some of the remaining content is still out of date, but this is a step forward.
This commit is contained in:
@@ -4,7 +4,7 @@ version = "0.12.0"
|
||||
authors = ["The Wasmtime Project Developers"]
|
||||
description = "Command-line interface for Wasmtime"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://bytecodealliance.github.io/wasmtime/cli.html"
|
||||
categories = ["wasm"]
|
||||
keywords = ["webassembly", "wasm"]
|
||||
repository = "https://github.com/bytecodealliance/wasmtime"
|
||||
|
||||
@@ -65,7 +65,7 @@ Hello, world!
|
||||
with your needs. It fits on tiny chips as well as makes use of huge servers.
|
||||
Wasmtime can be embedded into almost any application too.
|
||||
|
||||
* **Fast**. Wasmtime is built on the optimizing Cranelift code generator to
|
||||
* **Fast**. Wasmtime is built on the optimizing [Cranelift] code generator to
|
||||
quickly generate high-quality machine code at runtime.
|
||||
|
||||
* **Configurable**. Whether you need to precompile your wasm ahead of time,
|
||||
@@ -82,6 +82,8 @@ Hello, world!
|
||||
well. Wasmtime developers are intimately engaged with the WebAssembly
|
||||
standards process all along the way too.
|
||||
|
||||
[Cranelift]: https://github.com/bytecodealliance/wasmtime/blob/master/cranelift/README.md
|
||||
|
||||
## Documentation
|
||||
|
||||
[📚 Read the Wasmtime guide here! 📚][guide]
|
||||
|
||||
@@ -4,7 +4,7 @@ authors = ["The Cranelift Project Developers"]
|
||||
version = "0.59.0"
|
||||
description = "Binaries for testing the Cranelift libraries"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://github.com/bytecodealliance/wasmtime/blob/master/cranelift/docs/index.md"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
publish = false
|
||||
edition = "2018"
|
||||
|
||||
@@ -4,19 +4,16 @@ Cranelift Code Generator
|
||||
**A [Bytecode Alliance][BA] project**
|
||||
|
||||
Cranelift is a low-level retargetable code generator. It translates a
|
||||
[target-independent intermediate
|
||||
representation](https://cranelift.readthedocs.io/en/latest/ir.html)
|
||||
[target-independent intermediate representation](docs/ir.md)
|
||||
into executable machine code.
|
||||
|
||||
[BA]: https://bytecodealliance.org/
|
||||
[](https://cranelift.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://github.com/bytecodealliance/cranelift/actions)
|
||||
[](https://app.fuzzit.dev/orgs/bytecodealliance/dashboard)
|
||||
[](https://bytecodealliance.zulipchat.com/#narrow/stream/217117-cranelift/topic/general)
|
||||

|
||||
|
||||
For more information, see [the
|
||||
documentation](https://cranelift.readthedocs.io/en/latest/?badge=latest).
|
||||
For more information, see [the documentation](docs/index.md).
|
||||
|
||||
For an example of how to use the JIT, see the [SimpleJIT Demo], which
|
||||
implements a toy language.
|
||||
@@ -160,21 +157,6 @@ features = ["release_max_level_warn"]
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Building the documentation</summary>
|
||||
|
||||
Cranelift's documentation is [published online](https://cranelift.readthedocs.io/).
|
||||
|
||||
To build the documentation locally, you need the [Sphinx documentation
|
||||
generator](http://www.sphinx-doc.org/) as well as Python 3::
|
||||
|
||||
$ pip install sphinx sphinx-autobuild sphinx_rtd_theme
|
||||
$ cd cranelift/docs
|
||||
$ make html
|
||||
$ open _build/html/index.html
|
||||
|
||||
</details>
|
||||
|
||||
Editor Support
|
||||
--------------
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ name = "cranelift-bforest"
|
||||
version = "0.59.0"
|
||||
description = "A forest of B+-trees"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-bforest"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -4,7 +4,7 @@ name = "cranelift-codegen"
|
||||
version = "0.59.0"
|
||||
description = "Low-level code generator library"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-codegen"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -20,7 +20,7 @@ pub enum CodegenError {
|
||||
/// Cranelift can compile very large and complicated functions, but the [implementation has
|
||||
/// limits][limits] that cause compilation to fail when they are exceeded.
|
||||
///
|
||||
/// [limits]: https://cranelift.readthedocs.io/en/latest/ir.html#implementation-limits
|
||||
/// [limits]: https://github.com/bytecodealliance/wasmtime/blob/master/cranelift/docs/ir.md#implementation-limits
|
||||
#[error("Implementation limit exceeded")]
|
||||
ImplLimitExceeded,
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXABUILD = sphinx-autobuild
|
||||
SPHINXPROJ = cranelift
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
autohtml: html
|
||||
$(SPHINXABUILD) -z ../cranelift-codegen/meta-python --ignore '.*' -b html -E $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@@ -1,16 +0,0 @@
|
||||
test verifier
|
||||
|
||||
function %gcd(i32 uext, i32 uext) -> i32 uext system_v {
|
||||
fn0 = %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext
|
||||
|
||||
block1(v0: i32, v1: i32):
|
||||
brz v1, block3
|
||||
jump block2
|
||||
|
||||
block2:
|
||||
v2, v3 = call fn0(v0, v1)
|
||||
return v2
|
||||
|
||||
block3:
|
||||
return v0
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Pygments lexer for Cranelift.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from pygments.lexer import RegexLexer, bygroups, words
|
||||
from pygments.token import Comment, String, Keyword, Whitespace, Number, Name
|
||||
from pygments.token import Operator, Punctuation, Text
|
||||
|
||||
|
||||
def keywords(*args):
|
||||
return words(args, prefix=r'\b', suffix=r'\b')
|
||||
|
||||
|
||||
class CraneliftLexer(RegexLexer):
|
||||
name = 'Cranelift'
|
||||
aliases = ['clif']
|
||||
filenames = ['*.clif']
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
# Test header lines.
|
||||
(r'^(test|isa|set)(?:( +)([-\w]+)' +
|
||||
r'(?:(=)(?:(\d+)|(yes|no|true|false|on|off)|(\w+)))?)*' +
|
||||
r'( *)$',
|
||||
bygroups(Keyword.Namespace, Whitespace, Name.Attribute,
|
||||
Operator, Number.Integer, Keyword.Constant,
|
||||
Name.Constant, Whitespace)),
|
||||
# Comments with filecheck or other test directive.
|
||||
(r'(; *)([a-z]+:)(.*?)$',
|
||||
bygroups(Comment.Single, Comment.Special, Comment.Single)),
|
||||
# Plain comments.
|
||||
(r';.*?$', Comment.Single),
|
||||
# Strings are prefixed by % or # with hex.
|
||||
(r'%\w+|#[0-9a-fA-F]*', String),
|
||||
# Numbers.
|
||||
(r'[-+]?0[xX][0-9a-fA-F_]+', Number.Hex),
|
||||
(r'[-+]?0[xX][0-9a-fA-F_]*\.[0-9a-fA-F_]*([pP]\d+)?', Number.Hex),
|
||||
(r'[-+]?([0-9_]+\.[0-9_]+([eE]\d+)?|s?NaN|Inf)', Number.Float),
|
||||
(r'[-+]?[0-9_]+', Number.Integer),
|
||||
# Known attributes.
|
||||
(keywords('uext', 'sext'), Name.Attribute),
|
||||
# Well known value types.
|
||||
(r'\b(b\d+|i\d+|f32|f64)(x\d+)?\b', Keyword.Type),
|
||||
# v<nn> = value
|
||||
# ss<nn> = stack slot
|
||||
# jt<nn> = jump table
|
||||
(r'(v|ss|gv|jt|fn|sig|heap)\d+', Name.Variable),
|
||||
# ebb<nn> = extended basic block
|
||||
(r'(ebb)\d+', Name.Label),
|
||||
# Match instruction names in context.
|
||||
(r'(=)( *)([a-z]\w*)',
|
||||
bygroups(Operator, Whitespace, Name.Function)),
|
||||
(r'^( *)([a-z]\w*\b)(?! *[,=])',
|
||||
bygroups(Whitespace, Name.Function)),
|
||||
# Other names: results and arguments
|
||||
(r'[a-z]\w*', Name),
|
||||
(r'->|=|:', Operator),
|
||||
(r'[{}(),.]', Punctuation),
|
||||
(r'[ \t]+', Text),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def setup(app):
|
||||
"""Setup Sphinx extension."""
|
||||
app.add_lexer('clif', CraneliftLexer())
|
||||
|
||||
return {'version': '0.1'}
|
||||
@@ -1,19 +1,17 @@
|
||||
**************************
|
||||
Cranelift compared to LLVM
|
||||
**************************
|
||||
# Cranelift compared to LLVM
|
||||
|
||||
`LLVM <https://llvm.org>`_ is a collection of compiler components implemented as
|
||||
[LLVM](https://llvm.org) is a collection of compiler components implemented as
|
||||
a set of C++ libraries. It can be used to build both JIT compilers and static
|
||||
compilers like `Clang <https://clang.llvm.org>`_, and it is deservedly very
|
||||
popular. `Chris Lattner's chapter about LLVM
|
||||
<https://www.aosabook.org/en/llvm.html>`_ in the `Architecture of Open Source
|
||||
Applications <https://aosabook.org/en/index.html>`_ book gives an excellent
|
||||
compilers like [Clang](https://clang.llvm.org), and it is deservedly very
|
||||
popular. [Chris Lattner's chapter about LLVM]
|
||||
(https://www.aosabook.org/en/llvm.html) in the [Architecture of Open Source
|
||||
Applications](https://aosabook.org/en/index.html>) book gives an excellent
|
||||
overview of the architecture and design of LLVM.
|
||||
|
||||
Cranelift and LLVM are superficially similar projects, so it is worth
|
||||
highlighting some of the differences and similarities. Both projects:
|
||||
|
||||
- Use an ISA-agnostic input language in order to mostly abstract away the
|
||||
- Use a mostly-ISA-agnostic input language in order to mostly abstract away the
|
||||
differences between target instruction set architectures.
|
||||
- Depend extensively on SSA form.
|
||||
- Have both textual and in-memory forms of their primary intermediate
|
||||
@@ -23,13 +21,12 @@ highlighting some of the differences and similarities. Both projects:
|
||||
|
||||
However, there are also some major differences, described in the following sections.
|
||||
|
||||
Intermediate representations
|
||||
============================
|
||||
## Intermediate representations
|
||||
|
||||
LLVM uses multiple intermediate representations as it translates a program to
|
||||
binary machine code:
|
||||
|
||||
`LLVM IR <https://llvm.org/docs/LangRef.html>`_
|
||||
[LLVM IR](https://llvm.org/docs/LangRef.html):
|
||||
This is the primary intermediate representation which has textual, binary, and
|
||||
in-memory forms. It serves two main purposes:
|
||||
|
||||
@@ -38,7 +35,7 @@ binary machine code:
|
||||
- Intermediate representation for common mid-level optimizations. A large
|
||||
library of code analysis and transformation passes operate on LLVM IR.
|
||||
|
||||
`SelectionDAG <https://llvm.org/docs/CodeGenerator.html#instruction-selection-section>`_
|
||||
[SelectionDAG](https://llvm.org/docs/CodeGenerator.html#instruction-selection-section):
|
||||
A graph-based representation of the code in a single basic block is used by
|
||||
the instruction selector. It has both ISA-agnostic and ISA-specific
|
||||
opcodes. These main passes are run on the SelectionDAG representation:
|
||||
@@ -54,7 +51,7 @@ binary machine code:
|
||||
The SelectionDAG representation automatically eliminates common
|
||||
subexpressions and dead code.
|
||||
|
||||
`MachineInstr <https://llvm.org/docs/CodeGenerator.html#machine-code-representation>`_
|
||||
[MachineInstr](https://llvm.org/docs/CodeGenerator.html#machine-code-representation):
|
||||
A linear representation of ISA-specific instructions that initially is in
|
||||
SSA form, but it can also represent non-SSA form during and after register
|
||||
allocation. Many low-level optimizations run on MI code. The most important
|
||||
@@ -63,7 +60,7 @@ binary machine code:
|
||||
- Scheduling.
|
||||
- Register allocation.
|
||||
|
||||
`MC <https://llvm.org/docs/CodeGenerator.html#the-mc-layer>`_
|
||||
[MC](https://llvm.org/docs/CodeGenerator.html#the-mc-layer)
|
||||
MC serves as the output abstraction layer and is the basis for LLVM's
|
||||
integrated assembler. It is used for:
|
||||
|
||||
@@ -78,7 +75,7 @@ representation. Some target ISAs have a fast instruction selector that can
|
||||
translate simple code directly to MachineInstrs, bypassing SelectionDAG when
|
||||
possible.
|
||||
|
||||
:doc:`Cranelift <ir>` uses a single intermediate representation to cover
|
||||
[Cranelift IR](ir.md) uses a single intermediate representation to cover
|
||||
these levels of abstraction. This is possible in part because of Cranelift's
|
||||
smaller scope.
|
||||
|
||||
@@ -109,22 +106,21 @@ low-level optimizations are sufficient.
|
||||
|
||||
And, it removes some constraints in the mid-level optimize IR design space,
|
||||
making it more feasible to consider ideas such as using a
|
||||
`VSDG-based IR <https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-705.pdf>`_.
|
||||
[VSDG-based IR](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-705.pdf).
|
||||
|
||||
Program structure
|
||||
-----------------
|
||||
### Program structure
|
||||
|
||||
In LLVM IR, the largest representable unit is the *module* which corresponds
|
||||
more or less to a C translation unit. It is a collection of functions and
|
||||
global variables that may contain references to external symbols too.
|
||||
|
||||
In `Cranelift's IR <https://cranelift.readthedocs.io/en/latest/ir.html>`_,
|
||||
used by the `cranelift-codegen <https://docs.rs/cranelift-codegen/>`_ crate,
|
||||
In [Cranelift's IR](ir.md)
|
||||
used by the [cranelift-codegen](https://docs.rs/cranelift-codegen/) crate,
|
||||
functions are self-contained, allowing them to be compiled independently. At
|
||||
this level, there is no explicit module that contains the functions.
|
||||
|
||||
Module functionality in Cranelift is provided as an optional library layer, in
|
||||
the `cranelift-module <https://docs.rs/cranelift-module/>`_ crate. It provides
|
||||
the [cranelift-module](https://docs.rs/cranelift-module/) crate. It provides
|
||||
facilities for working with modules, which can contain multiple functions as
|
||||
well as data objects, and it links them together.
|
||||
|
||||
@@ -136,8 +132,8 @@ only has a single target and falls through to the next instruction when its
|
||||
condition is false. The Cranelift representation is closer to how machine code
|
||||
works; LLVM's representation is more abstract.
|
||||
|
||||
LLVM uses `phi instructions
|
||||
<https://llvm.org/docs/LangRef.html#phi-instruction>`_ in its SSA
|
||||
LLVM uses [phi instructions]
|
||||
(https://llvm.org/docs/LangRef.html#phi-instruction) in its SSA
|
||||
representation. Cranelift passes arguments to EBBs instead. The two
|
||||
representations are equivalent, but the EBB arguments are better suited to
|
||||
handle EBBs that may contain multiple branches to the same destination block
|
||||
@@ -145,16 +141,15 @@ with different arguments. Passing arguments to an EBB looks a lot like passing
|
||||
arguments to a function call, and the register allocator treats them very
|
||||
similarly. Arguments are assigned to registers or stack locations.
|
||||
|
||||
Value types
|
||||
-----------
|
||||
### Value types
|
||||
|
||||
:ref:`Cranelift's type system <value-types>` is mostly a subset of LLVM's type
|
||||
[Cranelift's type system](ir.md#value-types) is mostly a subset of LLVM's type
|
||||
system. It is less abstract and closer to the types that common ISA registers
|
||||
can hold.
|
||||
|
||||
- Integer types are limited to powers of two from :clif:type:`i8` to
|
||||
:clif:type:`i64`. LLVM can represent integer types of arbitrary bit width.
|
||||
- Floating point types are limited to :clif:type:`f32` and :clif:type:`f64`
|
||||
- Integer types are limited to powers of two from `i8` to
|
||||
`i64`. LLVM can represent integer types of arbitrary bit width.
|
||||
- Floating point types are limited to `f32` and `f64`
|
||||
which is what WebAssembly provides. It is possible that 16-bit and 128-bit
|
||||
types will be added in the future.
|
||||
- Addresses are represented as integers---There are no Cranelift pointer types.
|
||||
@@ -167,14 +162,13 @@ can hold.
|
||||
well as array types.
|
||||
|
||||
Cranelift has multiple boolean types, whereas LLVM simply uses `i1`. The sized
|
||||
Cranelift boolean types are used to represent SIMD vector masks like ``b32x4``
|
||||
Cranelift boolean types are used to represent SIMD vector masks like `b32x4`
|
||||
where each lane is either all 0 or all 1 bits.
|
||||
|
||||
Cranelift instructions and function calls can return multiple result values. LLVM
|
||||
instead models this by returning a single value of an aggregate type.
|
||||
|
||||
Instruction set
|
||||
---------------
|
||||
### Instruction set
|
||||
|
||||
LLVM has a small well-defined basic instruction set and a large number of
|
||||
intrinsics, some of which are ISA-specific. Cranelift has a larger instruction
|
||||
@@ -183,28 +177,7 @@ set and no intrinsics. Some Cranelift instructions are ISA-specific.
|
||||
Since Cranelift instructions are used all the way until the binary machine code
|
||||
is emitted, there are opcodes for every native instruction that can be
|
||||
generated. There is a lot of overlap between different ISAs, so for example the
|
||||
:clif:inst:`iadd_imm` instruction is used by every ISA that can add an
|
||||
`iadd_imm` instruction is used by every ISA that can add an
|
||||
immediate integer to a register. A simple RISC ISA like RISC-V can be defined
|
||||
with only shared instructions, while x86 needs a number of specific
|
||||
instructions to model addressing modes.
|
||||
|
||||
Undefined behavior
|
||||
==================
|
||||
|
||||
Cranelift does not generally exploit undefined behavior in its optimizations.
|
||||
LLVM's mid-level optimizations do, but it should be noted that LLVM's low-level code
|
||||
generator rarely needs to make use of undefined behavior either.
|
||||
|
||||
LLVM provides ``nsw`` and ``nuw`` flags for its arithmetic that invoke
|
||||
undefined behavior on overflow. Cranelift does not provide this functionality.
|
||||
Its arithmetic instructions either produce a value or a trap.
|
||||
|
||||
LLVM has an ``unreachable`` instruction which is used to indicate impossible
|
||||
code paths. Cranelift only has an explicit :clif:inst:`trap` instruction.
|
||||
|
||||
Cranelift does make assumptions about aliasing. For example, it assumes that it
|
||||
has full control of the stack objects in a function, and that they can only be
|
||||
modified by function calls if their address have escaped. It is quite likely
|
||||
that Cranelift will admit more detailed aliasing annotations on load/store
|
||||
instructions in the future. When these annotations are incorrect, undefined
|
||||
behavior ensues.
|
||||
@@ -1,169 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# cranelift documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Mar 2 12:49:24 2018.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# We don't support Sphinx versions before 1.4 since the format of index
|
||||
# tuples has changed.
|
||||
needs_sphinx = '1.4'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.ifconfig',
|
||||
'sphinx.ext.graphviz',
|
||||
'sphinx.ext.inheritance_diagram',
|
||||
'clif_lexer',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'cranelift'
|
||||
copyright = u'2019, Cranelift Developers'
|
||||
author = u'Cranelift Developers'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'0.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'0.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#
|
||||
# html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'craneliftdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'cranelift.tex', u'cranelift Documentation',
|
||||
author, 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'cranelift', u'cranelift Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'cranelift', u'cranelift Documentation',
|
||||
author, 'cranelift', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Graphviz -------------------------------------------------
|
||||
|
||||
graphviz_output_format = 'svg'
|
||||
|
||||
inheritance_graph_attrs = dict(rankdir='TD')
|
||||
@@ -1,8 +0,0 @@
|
||||
float
|
||||
average(const float *array, size_t count)
|
||||
{
|
||||
double sum = 0;
|
||||
for (size_t i = 0; i < count; i++)
|
||||
sum += array[i];
|
||||
return sum / count;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
test verifier
|
||||
|
||||
function %average(i32, i32) -> f32 system_v {
|
||||
ss0 = explicit_slot 8 ; Stack slot for ``sum``.
|
||||
|
||||
block1(v0: i32, v1: i32):
|
||||
v2 = f64const 0x0.0
|
||||
stack_store v2, ss0
|
||||
brz v1, block5 ; Handle count == 0.
|
||||
jump block2
|
||||
|
||||
block2:
|
||||
v3 = iconst.i32 0
|
||||
jump block3(v3)
|
||||
|
||||
block3(v4: i32):
|
||||
v5 = imul_imm v4, 4
|
||||
v6 = iadd v0, v5
|
||||
v7 = load.f32 v6 ; array[i]
|
||||
v8 = fpromote.f64 v7
|
||||
v9 = stack_load.f64 ss0
|
||||
v10 = fadd v8, v9
|
||||
stack_store v10, ss0
|
||||
v11 = iadd_imm v4, 1
|
||||
v12 = icmp ult v11, v1
|
||||
brnz v12, block3(v11) ; Loop backedge.
|
||||
jump block4
|
||||
|
||||
block4:
|
||||
v13 = stack_load.f64 ss0
|
||||
v14 = fcvt_from_uint.f64 v1
|
||||
v15 = fdiv v13, v14
|
||||
v16 = fdemote.f32 v15
|
||||
return v16
|
||||
|
||||
block5:
|
||||
v100 = f32const +NaN
|
||||
return v100
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
test verifier
|
||||
|
||||
function %add_members(i32, i64 vmctx) -> f32 baldrdash_system_v {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0+64
|
||||
gv2 = load.i32 notrap aligned gv0+72
|
||||
heap0 = dynamic gv1, min 0x1000, bound gv2, offset_guard 0
|
||||
|
||||
block0(v0: i32, v6: i64):
|
||||
v1 = heap_addr.i64 heap0, v0, 20
|
||||
v2 = load.f32 v1+16
|
||||
v3 = heap_addr.i64 heap0, v0, 24
|
||||
v4 = load.f32 v3+20
|
||||
v5 = fadd v2, v4
|
||||
return v5
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
test verifier
|
||||
|
||||
function %add_members(i32, i32 vmctx) -> f32 baldrdash_system_v {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i32 notrap aligned gv0+64
|
||||
heap0 = static gv1, min 0x1000, bound 0x10_0000, offset_guard 0x1000
|
||||
|
||||
block0(v0: i32, v5: i32):
|
||||
v1 = heap_addr.i32 heap0, v0, 1
|
||||
v2 = load.f32 v1+16
|
||||
v3 = load.f32 v1+20
|
||||
v4 = fadd v2, v3
|
||||
return v4
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
test verifier
|
||||
|
||||
function %add_members(i32, i64 vmctx) -> f32 baldrdash_system_v {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0+64
|
||||
heap0 = static gv1, min 0x1000, bound 0x1_0000_0000, offset_guard 0x8000_0000
|
||||
|
||||
block0(v0: i32, v5: i64):
|
||||
v1 = heap_addr.i64 heap0, v0, 1
|
||||
v2 = load.f32 v1+16
|
||||
v3 = load.f32 v1+20
|
||||
v4 = fadd v2, v3
|
||||
return v4
|
||||
}
|
||||
@@ -1,73 +1,62 @@
|
||||
Cranelift Code Generator
|
||||
========================
|
||||
# Cranelift Documentation
|
||||
|
||||
Contents:
|
||||
## Miscellaneous documentation pages:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
- [Cranelift IR](ir.md)
|
||||
Cranelift IR is the data structure that most of the compiler operates on.
|
||||
|
||||
ir
|
||||
meta
|
||||
testing
|
||||
regalloc
|
||||
compare-llvm
|
||||
- [Testing Cranelift](testing.md)
|
||||
This page documents Cranelift's testing frameworks.
|
||||
|
||||
Rust Crate Documentation
|
||||
========================
|
||||
- [Cranelift compared to LLVM](compare-llvm.md)
|
||||
LLVM and Cranelift have similarities and differences.
|
||||
|
||||
`cranelift <https://docs.rs/cranelift-codegen/>`_
|
||||
- [Cranelift's register allocator](regalloc.md)
|
||||
This page document Cranelift's current register allocator.
|
||||
|
||||
## Cranelift crate documentation:
|
||||
|
||||
- [cranelift](https://docs.rs/cranelift-codegen)
|
||||
This is an umbrella crate that re-exports the codegen and frontend crates,
|
||||
to make them easier to use.
|
||||
|
||||
`cranelift-codegen <https://docs.rs/cranelift-codegen/>`_
|
||||
- [cranelift-codegen](https://docs.rs/cranelift-codegen)
|
||||
This is the core code generator crate. It takes Cranelift IR as input
|
||||
and emits encoded machine instructions, along with symbolic relocations,
|
||||
as output.
|
||||
|
||||
`cranelift-codegen-meta <https://docs.rs/cranelift-codegen-meta/>`_
|
||||
- [cranelift-codegen-meta](https://docs.rs/cranelift-codegen-meta)
|
||||
This crate contains the meta-language utilities and descriptions used by the
|
||||
code generator.
|
||||
|
||||
`cranelift-wasm <https://docs.rs/cranelift-wasm/>`_
|
||||
- [cranelift-wasm](https://docs.rs/cranelift-wasm)
|
||||
This crate translates WebAssembly code into Cranelift IR.
|
||||
|
||||
`cranelift-frontend <https://docs.rs/cranelift-frontend/>`_
|
||||
- [cranelift-frontend](https://docs.rs/cranelift-frontend)
|
||||
This crate provides utilities for translating code into Cranelift IR.
|
||||
|
||||
`cranelift-native <https://docs.rs/cranelift-native/>`_
|
||||
- [cranelift-native](https://docs.rs/cranelift-native)
|
||||
This crate performs auto-detection of the host, allowing Cranelift to
|
||||
generate code optimized for the machine it's running on.
|
||||
|
||||
`cranelift-reader <https://docs.rs/cranelift-reader/>`_
|
||||
- [cranelift-reader](https://docs.rs/cranelift-reader)
|
||||
This crate translates from Cranelift IR's text format into Cranelift IR
|
||||
in in-memory data structures.
|
||||
|
||||
`cranelift-module <https://docs.rs/cranelift-module/>`_
|
||||
- [cranelift-module](https://docs.rs/cranelift-module)
|
||||
This crate manages compiling multiple functions and data objects
|
||||
together.
|
||||
|
||||
`cranelift-object <https://docs.rs/cranelift-object/>`_
|
||||
- [cranelift-object](https://docs.rs/cranelift-object)
|
||||
This crate provides a object-based backend for `cranelift-module`, which
|
||||
emits native object files using the
|
||||
`object <https://github.com/gimli-rs/object>`_ library.
|
||||
|
||||
`cranelift-faerie <https://docs.rs/cranelift-faerie/>`_
|
||||
- [cranelift-faerie](https://docs.rs/cranelift-faerie)
|
||||
This crate provides a faerie-based backend for `cranelift-module`, which
|
||||
emits native object files using the
|
||||
`faerie <https://github.com/m4b/faerie>`_ library.
|
||||
|
||||
`cranelift-simplejit <https://docs.rs/cranelift-simplejit/>`_
|
||||
- [cranelift-simplejit](https://docs.rs/cranelift-simplejit)
|
||||
This crate provides a simple JIT backend for `cranelift-module`, which
|
||||
emits code and data into memory.
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
Todo list
|
||||
=========
|
||||
|
||||
.. todolist::
|
||||
@@ -1,57 +1,99 @@
|
||||
**********************
|
||||
Cranelift IR Reference
|
||||
**********************
|
||||
# Cranelift IR Reference
|
||||
|
||||
.. default-domain:: clif
|
||||
.. highlight:: clif
|
||||
|
||||
.. todo:: Update the IR reference
|
||||
## Forward
|
||||
|
||||
This document is likely to be outdated and missing some important
|
||||
information. It is recommended to look at the list of instructions as
|
||||
documented in the `InstBuilder` documentation:
|
||||
https://docs.rs/cranelift-codegen/latest/cranelift_codegen/ir/trait.InstBuilder.html
|
||||
documented in [the `InstBuilder` documentation].
|
||||
|
||||
The Cranelift intermediate representation (:term:`IR`) has two primary forms:
|
||||
[the `InstBuilder` documentation]: https://docs.rs/cranelift-codegen/latest/cranelift_codegen/ir/trait.InstBuilder.html
|
||||
|
||||
## Intro
|
||||
|
||||
The Cranelift intermediate representation ([IR]) has two primary forms:
|
||||
an *in-memory data structure* that the code generator library is using, and a
|
||||
*text format* which is used for test cases and debug output.
|
||||
Files containing Cranelift textual IR have the ``.clif`` filename extension.
|
||||
Files containing Cranelift textual IR have the `.clif` filename extension.
|
||||
|
||||
This reference uses the text format to describe IR semantics but glosses over
|
||||
the finer details of the lexical and syntactic structure of the format.
|
||||
|
||||
## Overall structure
|
||||
|
||||
Overall structure
|
||||
=================
|
||||
|
||||
Cranelift compiles functions independently. A ``.clif`` IR file may contain
|
||||
Cranelift compiles functions independently. A `.clif` IR file may contain
|
||||
multiple functions, and the programmatic API can create multiple function
|
||||
handles at the same time, but the functions don't share any data or reference
|
||||
each other directly.
|
||||
|
||||
This is a simple C function that computes the average of an array of floats:
|
||||
|
||||
.. literalinclude:: example.c
|
||||
:language: c
|
||||
```c
|
||||
float
|
||||
average(const float *array, size_t count)
|
||||
{
|
||||
double sum = 0;
|
||||
for (size_t i = 0; i < count; i++)
|
||||
sum += array[i];
|
||||
return sum / count;
|
||||
}
|
||||
```
|
||||
|
||||
Here is the same function compiled into Cranelift IR:
|
||||
|
||||
.. literalinclude:: example.clif
|
||||
:language: clif
|
||||
:lines: 2-
|
||||
```
|
||||
test verifier
|
||||
|
||||
function %average(i32, i32) -> f32 system_v {
|
||||
ss0 = explicit_slot 8 ; Stack slot for `sum`.
|
||||
|
||||
block1(v0: i32, v1: i32):
|
||||
v2 = f64const 0x0.0
|
||||
stack_store v2, ss0
|
||||
brz v1, block5 ; Handle count == 0.
|
||||
jump block2
|
||||
|
||||
block2:
|
||||
v3 = iconst.i32 0
|
||||
jump block3(v3)
|
||||
|
||||
block3(v4: i32):
|
||||
v5 = imul_imm v4, 4
|
||||
v6 = iadd v0, v5
|
||||
v7 = load.f32 v6 ; array[i]
|
||||
v8 = fpromote.f64 v7
|
||||
v9 = stack_load.f64 ss0
|
||||
v10 = fadd v8, v9
|
||||
stack_store v10, ss0
|
||||
v11 = iadd_imm v4, 1
|
||||
v12 = icmp ult v11, v1
|
||||
brnz v12, block3(v11) ; Loop backedge.
|
||||
jump block4
|
||||
|
||||
block4:
|
||||
v13 = stack_load.f64 ss0
|
||||
v14 = fcvt_from_uint.f64 v1
|
||||
v15 = fdiv v13, v14
|
||||
v16 = fdemote.f32 v15
|
||||
return v16
|
||||
|
||||
block5:
|
||||
v100 = f32const +NaN
|
||||
return v100
|
||||
}
|
||||
```
|
||||
|
||||
The first line of a function definition provides the function *name* and
|
||||
the :term:`function signature` which declares the parameter and return types.
|
||||
Then follows the :term:`function preamble` which declares a number of entities
|
||||
the [function signature] which declares the parameter and return types.
|
||||
Then follows the [function preamble] which declares a number of entities
|
||||
that can be referenced inside the function. In the example above, the preamble
|
||||
declares a single explicit stack slot, ``ss0``.
|
||||
declares a single explicit stack slot, `ss0`.
|
||||
|
||||
After the preamble follows the :term:`function body` which consists of
|
||||
:term:`extended basic block`\s (EBBs), the first of which is the
|
||||
:term:`entry block`. Every EBB ends with a :term:`terminator instruction`, so
|
||||
After the preamble follows the [function body] which consists of
|
||||
[extended basic block]s (EBBs), the first of which is the
|
||||
[entry block]. Every EBB ends with a [terminator instruction], so
|
||||
execution can never fall through to the next EBB without an explicit branch.
|
||||
|
||||
A ``.clif`` file consists of a sequence of independent function definitions:
|
||||
A `.clif` file consists of a sequence of independent function definitions:
|
||||
|
||||
.. productionlist::
|
||||
function_list : { function }
|
||||
@@ -59,14 +101,13 @@ A ``.clif`` file consists of a sequence of independent function definitions:
|
||||
preamble : { preamble_decl }
|
||||
function_body : { extended_basic_block }
|
||||
|
||||
Static single assignment form
|
||||
-----------------------------
|
||||
### Static single assignment form
|
||||
|
||||
The instructions in the function body use and produce *values* in SSA form. This
|
||||
means that every value is defined exactly once, and every use of a value must be
|
||||
dominated by the definition.
|
||||
|
||||
Cranelift does not have phi instructions but uses :term:`EBB parameter`\s
|
||||
Cranelift does not have phi instructions but uses [EBB parameter]s
|
||||
instead. An EBB can be defined with a list of typed parameters. Whenever control
|
||||
is transferred to the EBB, argument values for the parameters must be provided.
|
||||
When entering a function, the incoming function parameters are passed as
|
||||
@@ -75,32 +116,28 @@ arguments to the entry EBB's parameters.
|
||||
Instructions define zero, one, or more result values. All SSA values are either
|
||||
EBB parameters or instruction results.
|
||||
|
||||
In the example above, the loop induction variable ``i`` is represented as three
|
||||
SSA values: In the entry block, ``v4`` is the initial value. In the loop block
|
||||
``ebb2``, the EBB parameter ``v5`` represents the value of the induction
|
||||
variable during each iteration. Finally, ``v12`` is computed as the induction
|
||||
In the example above, the loop induction variable `i` is represented as three
|
||||
SSA values: In the entry block, `v4` is the initial value. In the loop block
|
||||
`ebb2`, the EBB parameter `v5` represents the value of the induction
|
||||
variable during each iteration. Finally, `v12` is computed as the induction
|
||||
variable value for the next iteration.
|
||||
|
||||
The `cranelift_frontend` crate contains utilities for translating from programs
|
||||
containing multiple assignments to the same variables into SSA form for
|
||||
Cranelift :term:`IR`.
|
||||
Cranelift [IR].
|
||||
|
||||
Such variables can also be presented to Cranelift as :term:`stack slot`\s.
|
||||
Such variables can also be presented to Cranelift as [stack slot]s.
|
||||
Stack slots are accessed with the `stack_store` and `stack_load` instructions,
|
||||
and can have their address taken with `stack_addr`, which supports C-like
|
||||
programming languages where local variables can have their address taken.
|
||||
|
||||
.. _value-types:
|
||||
|
||||
Value types
|
||||
===========
|
||||
## Value types
|
||||
|
||||
All SSA values have a type which determines the size and shape (for SIMD
|
||||
vectors) of the value. Many instructions are polymorphic -- they can operate on
|
||||
different types.
|
||||
|
||||
Boolean types
|
||||
-------------
|
||||
### Boolean types
|
||||
|
||||
Boolean values are either true or false.
|
||||
|
||||
@@ -119,8 +156,7 @@ zero bits or all one bits.
|
||||
- b32
|
||||
- b64
|
||||
|
||||
Integer types
|
||||
-------------
|
||||
### Integer types
|
||||
|
||||
Integer values have a fixed size and can be interpreted as either signed or
|
||||
unsigned. Some instructions will interpret an operand as a signed or unsigned
|
||||
@@ -133,8 +169,7 @@ The support for i8 and i16 arithmetic is incomplete and use could lead to bugs.
|
||||
- i32
|
||||
- i64
|
||||
|
||||
Floating point types
|
||||
--------------------
|
||||
### Floating point types
|
||||
|
||||
The floating point types have the IEEE 754 semantics that are supported by most
|
||||
hardware, except that non-default rounding modes, unmasked exceptions, and
|
||||
@@ -162,8 +197,7 @@ instructions are encoded as follows:
|
||||
- f32
|
||||
- f64
|
||||
|
||||
CPU flags types
|
||||
---------------
|
||||
### CPU flags types
|
||||
|
||||
Some target ISAs use CPU flags to represent the result of a comparison. These
|
||||
CPU flags are represented as two value types depending on the type of values
|
||||
@@ -181,8 +215,7 @@ instructions either. The verifier enforces these rules.
|
||||
- iflags
|
||||
- fflags
|
||||
|
||||
SIMD vector types
|
||||
-----------------
|
||||
### SIMD vector types
|
||||
|
||||
A SIMD vector type represents a vector of values from one of the scalar types
|
||||
(boolean, integer, and floating point). Each scalar value in a SIMD type is
|
||||
@@ -221,8 +254,7 @@ b1x%N
|
||||
|
||||
Like the `b1` type, a boolean vector cannot be stored in memory.
|
||||
|
||||
Pseudo-types and type classes
|
||||
-----------------------------
|
||||
### Pseudo-types and type classes
|
||||
|
||||
These are not concrete types, but convenient names used to refer to real types
|
||||
in this reference.
|
||||
@@ -254,8 +286,7 @@ Mem
|
||||
Testable
|
||||
Either `b1` or `iN`.
|
||||
|
||||
Immediate operand types
|
||||
-----------------------
|
||||
### Immediate operand types
|
||||
|
||||
These types are not part of the normal SSA type system. They are used to
|
||||
indicate the different kinds of immediate operands on an instruction.
|
||||
@@ -295,43 +326,42 @@ floatcc
|
||||
A floating point condition code. See the `fcmp` instruction for details.
|
||||
|
||||
The two IEEE floating point immediate types `ieee32` and `ieee64`
|
||||
are displayed as hexadecimal floating point literals in the textual :term:`IR`
|
||||
are displayed as hexadecimal floating point literals in the textual [IR]
|
||||
format. Decimal floating point literals are not allowed because some computer
|
||||
systems can round differently when converting to binary. The hexadecimal
|
||||
floating point format is mostly the same as the one used by C99, but extended
|
||||
to represent all NaN bit patterns:
|
||||
|
||||
Normal numbers
|
||||
Compatible with C99: ``-0x1.Tpe`` where ``T`` are the trailing
|
||||
significand bits encoded as hexadecimal, and ``e`` is the unbiased exponent
|
||||
Compatible with C99: `-0x1.Tpe` where `T` are the trailing
|
||||
significand bits encoded as hexadecimal, and `e` is the unbiased exponent
|
||||
as a decimal number. `ieee32` has 23 trailing significand bits. They
|
||||
are padded with an extra LSB to produce 6 hexadecimal digits. This is not
|
||||
necessary for `ieee64` which has 52 trailing significand bits
|
||||
forming 13 hexadecimal digits with no padding.
|
||||
|
||||
Zeros
|
||||
Positive and negative zero are displayed as ``0.0`` and ``-0.0`` respectively.
|
||||
Positive and negative zero are displayed as `0.0` and `-0.0` respectively.
|
||||
|
||||
Subnormal numbers
|
||||
Compatible with C99: ``-0x0.Tpemin`` where ``T`` are the trailing
|
||||
significand bits encoded as hexadecimal, and ``emin`` is the minimum exponent
|
||||
Compatible with C99: `-0x0.Tpemin` where `T` are the trailing
|
||||
significand bits encoded as hexadecimal, and `emin` is the minimum exponent
|
||||
as a decimal number.
|
||||
|
||||
Infinities
|
||||
Either ``-Inf`` or ``Inf``.
|
||||
Either `-Inf` or `Inf`.
|
||||
|
||||
Quiet NaNs
|
||||
Quiet NaNs have the MSB of the trailing significand set. If the remaining
|
||||
bits of the trailing significand are all zero, the value is displayed as
|
||||
``-NaN`` or ``NaN``. Otherwise, ``-NaN:0xT`` where ``T`` are the trailing
|
||||
`-NaN` or `NaN`. Otherwise, `-NaN:0xT` where `T` are the trailing
|
||||
significand bits encoded as hexadecimal.
|
||||
|
||||
Signaling NaNs
|
||||
Displayed as ``-sNaN:0xT``.
|
||||
Displayed as `-sNaN:0xT`.
|
||||
|
||||
|
||||
Control flow
|
||||
============
|
||||
## Control flow
|
||||
|
||||
Branches transfer control to a new EBB and provide values for the target EBB's
|
||||
arguments, if it has any. Conditional branches only take the branch if their
|
||||
@@ -339,7 +369,7 @@ condition is satisfied, otherwise execution continues at the following
|
||||
instruction in the EBB.
|
||||
|
||||
JT = jump_table [EBB0, EBB1, ..., EBBn]
|
||||
Declare a jump table in the :term:`function preamble`.
|
||||
Declare a jump table in the [function preamble].
|
||||
|
||||
This declares a jump table for use by the `br_table` indirect branch
|
||||
instruction. Entries in the table are EBB names.
|
||||
@@ -347,9 +377,9 @@ JT = jump_table [EBB0, EBB1, ..., EBBn]
|
||||
The EBBs listed must belong to the current function, and they can't have
|
||||
any arguments.
|
||||
|
||||
:arg EBB0: Target EBB when ``x = 0``.
|
||||
:arg EBB1: Target EBB when ``x = 1``.
|
||||
:arg EBBn: Target EBB when ``x = n``.
|
||||
:arg EBB0: Target EBB when `x = 0`.
|
||||
:arg EBB1: Target EBB when `x = 1`.
|
||||
:arg EBBn: Target EBB when `x = n`.
|
||||
:result: A jump table identifier. (Not an SSA value).
|
||||
|
||||
Traps stop the program because something went wrong. The exact behavior depends
|
||||
@@ -359,10 +389,9 @@ traps for certain input value. For example, `udiv` traps when the divisor
|
||||
is zero.
|
||||
|
||||
|
||||
Function calls
|
||||
==============
|
||||
## Function calls
|
||||
|
||||
A function call needs a target function and a :term:`function signature`. The
|
||||
A function call needs a target function and a [function signature]. The
|
||||
target function may be determined dynamically at runtime, but the signature must
|
||||
be known when the function call is compiled. The function signature describes
|
||||
how to call the function, including parameters, return values, and the calling
|
||||
@@ -383,28 +412,24 @@ depend on both the instruction set /// architecture and possibly the operating
|
||||
system, a function's calling convention is only fully determined by a
|
||||
`(TargetIsa, CallConv)` tuple.
|
||||
|
||||
=========== ===========================================
|
||||
Name Description
|
||||
=========== ===========================================
|
||||
sret pointer to a return value in memory
|
||||
link return address
|
||||
fp the initial value of the frame pointer
|
||||
csr callee-saved register
|
||||
vmctx VM context pointer, which may contain pointers to heaps etc.
|
||||
sigid signature id, for checking caller/callee signature compatibility
|
||||
stack_limit limit value for the size of the stack
|
||||
=========== ===========================================
|
||||
| Name | Description |
|
||||
| ----------| ---------- |
|
||||
| sret | pointer to a return value in memory |
|
||||
| link | return address |
|
||||
| fp | the initial value of the frame pointer |
|
||||
| csr | callee-saved register |
|
||||
| vmctx | VM context pointer, which may contain pointers to heaps etc. |
|
||||
| sigid | signature id, for checking caller/callee signature compatibility |
|
||||
| stack_limit | limit value for the size of the stack |
|
||||
|
||||
========== ===========================================
|
||||
Name Description
|
||||
========== ===========================================
|
||||
fast not-ABI-stable convention for best performance
|
||||
cold not-ABI-stable convention for infrequently executed code
|
||||
system_v System V-style convention used on many platforms
|
||||
fastcall Windows "fastcall" convention, also used for x64 and ARM
|
||||
baldrdash_system_v SpiderMonkey WebAssembly convention on platforms natively using SystemV.
|
||||
baldrdash_windows SpiderMonkey WebAssembly convention on platforms natively using Windows.
|
||||
========== ===========================================
|
||||
| Name | Description |
|
||||
| --------- | ----------- |
|
||||
| fast | not-ABI-stable convention for best performance |
|
||||
| cold | not-ABI-stable convention for infrequently executed code |
|
||||
| system_v | System V-style convention used on many platforms |
|
||||
| fastcall | Windows "fastcall" convention, also used for x64 and ARM |
|
||||
| baldrdash_system_v | SpiderMonkey WebAssembly convention on platforms natively using SystemV. |
|
||||
| baldrdash_windows | SpiderMonkey WebAssembly convention on platforms natively using Windows. |
|
||||
|
||||
The "not-ABI-stable" conventions do not follow an external specification and
|
||||
may change between versions of Cranelift.
|
||||
@@ -415,8 +440,7 @@ Parameters and return values have flags whose meaning is mostly target
|
||||
dependent. These flags support interfacing with code produced by other
|
||||
compilers.
|
||||
|
||||
Functions that are called directly must be declared in the :term:`function
|
||||
preamble`:
|
||||
Functions that are called directly must be declared in the [function preamble]:
|
||||
|
||||
FN = [colocated] NAME signature
|
||||
Declare a function so it can be called directly.
|
||||
@@ -431,61 +455,66 @@ FN = [colocated] NAME signature
|
||||
|
||||
This simple example illustrates direct function calls and signatures:
|
||||
|
||||
.. literalinclude:: callex.clif
|
||||
:language: clif
|
||||
:lines: 3-
|
||||
```
|
||||
test verifier
|
||||
|
||||
function %gcd(i32 uext, i32 uext) -> i32 uext system_v {
|
||||
fn0 = %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext
|
||||
|
||||
block1(v0: i32, v1: i32):
|
||||
brz v1, block3
|
||||
jump block2
|
||||
|
||||
block2:
|
||||
v2, v3 = call fn0(v0, v1)
|
||||
return v2
|
||||
|
||||
block3:
|
||||
return v0
|
||||
}
|
||||
```
|
||||
|
||||
Indirect function calls use a signature declared in the preamble.
|
||||
|
||||
.. _memory:
|
||||
|
||||
Memory
|
||||
======
|
||||
## Memory
|
||||
|
||||
Cranelift provides fully general `load` and `store` instructions for accessing
|
||||
memory, as well as :ref:`extending loads and truncating stores
|
||||
<extload-truncstore>`.
|
||||
memory, as well as [extending loads and truncating stores](#extending-loads-and-truncating-stores).
|
||||
|
||||
If the memory at the given address is not :term:`addressable`, the behavior of
|
||||
If the memory at the given address is not [addressable], the behavior of
|
||||
these instructions is undefined. If it is addressable but not
|
||||
:term:`accessible`, they :term:`trap`.
|
||||
[accessible], they [trap].
|
||||
|
||||
There are also more restricted operations for accessing specific types of memory
|
||||
objects.
|
||||
|
||||
Additionally, instructions are provided for handling multi-register addressing.
|
||||
|
||||
Memory operation flags
|
||||
----------------------
|
||||
### Memory operation flags
|
||||
|
||||
Loads and stores can have flags that loosen their semantics in order to enable
|
||||
optimizations.
|
||||
|
||||
======== ===========================================
|
||||
Flag Description
|
||||
======== ===========================================
|
||||
notrap Memory is assumed to be :term:`accessible`.
|
||||
aligned Trapping allowed for misaligned accesses.
|
||||
readonly The data at the specified address will not
|
||||
modified between when this function is
|
||||
called and exited.
|
||||
======== ===========================================
|
||||
| Flag | Description |
|
||||
| -------- | ----------- |
|
||||
| notrap | Memory is assumed to be [accessible]. |
|
||||
| aligned | Trapping allowed for misaligned accesses. |
|
||||
| readonly | The data at the specified address will not modified between when this function is called and exited. |
|
||||
|
||||
When the ``accessible`` flag is set, the behavior is undefined if the memory
|
||||
is not :term:`accessible`.
|
||||
When the `accessible` flag is set, the behavior is undefined if the memory
|
||||
is not [accessible].
|
||||
|
||||
Loads and stores are *misaligned* if the resultant address is not a multiple of
|
||||
the expected alignment. By default, misaligned loads and stores are allowed,
|
||||
but when the ``aligned`` flag is set, a misaligned memory access is allowed to
|
||||
:term:`trap`.
|
||||
but when the `aligned` flag is set, a misaligned memory access is allowed to
|
||||
[trap].
|
||||
|
||||
Explicit Stack Slots
|
||||
--------------------
|
||||
### Explicit Stack Slots
|
||||
|
||||
One set of restricted memory operations access the current function's stack
|
||||
frame. The stack frame is divided into fixed-size stack slots that are
|
||||
allocated in the :term:`function preamble`. Stack slots are not typed, they
|
||||
simply represent a contiguous sequence of :term:`accessible` bytes in the stack
|
||||
allocated in the [function preamble]. Stack slots are not typed, they
|
||||
simply represent a contiguous sequence of [accessible] bytes in the stack
|
||||
frame.
|
||||
|
||||
SS = explicit_slot Bytes, Flags...
|
||||
@@ -504,10 +533,10 @@ the alignment of these stack memory accesses can be inferred from the offsets
|
||||
and stack slot alignments.
|
||||
|
||||
It's also possible to obtain the address of a stack slot, which can be used
|
||||
in :ref:`unrestricted loads and stores <memory>`.
|
||||
in [unrestricted loads and stores](#memory).
|
||||
|
||||
The `stack_addr` instruction can be used to macro-expand the stack access
|
||||
instructions before instruction selection::
|
||||
instructions before instruction selection:
|
||||
|
||||
v0 = stack_load.f64 ss3, 16
|
||||
; Expands to:
|
||||
@@ -517,8 +546,7 @@ instructions before instruction selection::
|
||||
When Cranelift code is running in a sandbox, it can also be necessary to include
|
||||
stack overflow checks in the prologue.
|
||||
|
||||
Global values
|
||||
-------------
|
||||
### Global values
|
||||
|
||||
A *global value* is an object whose value is not known at compile time. The
|
||||
value is computed at runtime by `global_value`, possibly using
|
||||
@@ -579,8 +607,7 @@ GV = [colocated] symbol Name
|
||||
:arg Name: External name.
|
||||
:result GV: Global value.
|
||||
|
||||
Heaps
|
||||
-----
|
||||
### Heaps
|
||||
|
||||
Code compiled from WebAssembly or asm.js runs in a sandbox where it can't access
|
||||
all process memory. Instead, it is given a small set of memory areas to work
|
||||
@@ -588,7 +615,7 @@ in, and all accesses are bounds checked. Cranelift models this through the
|
||||
concept of *heaps*.
|
||||
|
||||
A heap is declared in the function preamble and can be accessed with the
|
||||
`heap_addr` instruction that :term:`traps` on out-of-bounds accesses or
|
||||
`heap_addr` instruction that [traps] on out-of-bounds accesses or
|
||||
returns a pointer that is guaranteed to trap. Heap addresses can be smaller than
|
||||
the native pointer size, for example unsigned `i32` offsets on a 64-bit
|
||||
architecture.
|
||||
@@ -606,27 +633,26 @@ architecture.
|
||||
|
||||
A heap appears as three consecutive ranges of address space:
|
||||
|
||||
1. The *mapped pages* are the :term:`accessible` memory range in the heap. A
|
||||
1. The *mapped pages* are the [accessible] memory range in the heap. A
|
||||
heap may have a minimum guaranteed size which means that some mapped pages
|
||||
are always present.
|
||||
2. The *unmapped pages* is a possibly empty range of address space that may be
|
||||
mapped in the future when the heap is grown. They are :term:`addressable` but
|
||||
not :term:`accessible`.
|
||||
mapped in the future when the heap is grown. They are [addressable] but
|
||||
not [accessible].
|
||||
3. The *offset-guard pages* is a range of address space that is guaranteed to
|
||||
always cause a trap when accessed. It is used to optimize bounds checking for
|
||||
heap accesses with a shared base pointer. They are :term:`addressable` but
|
||||
not :term:`accessible`.
|
||||
heap accesses with a shared base pointer. They are [addressable] but
|
||||
not [accessible].
|
||||
|
||||
The *heap bound* is the total size of the mapped and unmapped pages. This is
|
||||
the bound that `heap_addr` checks against. Memory accesses inside the
|
||||
heap bounds can trap if they hit an unmapped page (which is not
|
||||
:term:`accessible`).
|
||||
[accessible]).
|
||||
|
||||
Two styles of heaps are supported, *static* and *dynamic*. They behave
|
||||
differently when resized.
|
||||
|
||||
Static heaps
|
||||
~~~~~~~~~~~~
|
||||
#### Static heaps
|
||||
|
||||
A *static heap* starts out with all the address space it will ever need, so it
|
||||
never moves to a different address. At the base address is a number of mapped
|
||||
@@ -646,8 +672,7 @@ H = static Base, min MinBytes, bound BoundBytes, offset_guard OffsetGuardBytes
|
||||
pages.
|
||||
:arg OffsetGuardBytes: Size of the offset-guard pages in bytes.
|
||||
|
||||
Dynamic heaps
|
||||
~~~~~~~~~~~~~
|
||||
#### Dynamic heaps
|
||||
|
||||
A *dynamic heap* can be relocated to a different base address when it is
|
||||
resized, and its bound can move dynamically. The offset-guard pages move when
|
||||
@@ -662,53 +687,91 @@ H = dynamic Base, min MinBytes, bound BoundGV, offset_guard OffsetGuardBytes
|
||||
:arg BoundGV: Global value containing the current heap bound in bytes.
|
||||
:arg OffsetGuardBytes: Size of the offset-guard pages in bytes.
|
||||
|
||||
Heap examples
|
||||
~~~~~~~~~~~~~
|
||||
#### Heap examples
|
||||
|
||||
The SpiderMonkey VM prefers to use fixed heaps with a 4 GB bound and 2 GB of
|
||||
offset-guard pages when running WebAssembly code on 64-bit CPUs. The combination
|
||||
of a 4 GB fixed bound and 1-byte bounds checks means that no code needs to be
|
||||
generated for bounds checks at all:
|
||||
|
||||
.. literalinclude:: heapex-sm64.clif
|
||||
:language: clif
|
||||
:lines: 2-
|
||||
```
|
||||
test verifier
|
||||
|
||||
function %add_members(i32, i64 vmctx) -> f32 baldrdash_system_v {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0+64
|
||||
heap0 = static gv1, min 0x1000, bound 0x1_0000_0000, offset_guard 0x8000_0000
|
||||
|
||||
block0(v0: i32, v5: i64):
|
||||
v1 = heap_addr.i64 heap0, v0, 1
|
||||
v2 = load.f32 v1+16
|
||||
v3 = load.f32 v1+20
|
||||
v4 = fadd v2, v3
|
||||
return v4
|
||||
}
|
||||
```
|
||||
|
||||
A static heap can also be used for 32-bit code when the WebAssembly module
|
||||
declares a small upper bound on its memory. A 1 MB static bound with a single 4
|
||||
KB offset-guard page still has opportunities for sharing bounds checking code:
|
||||
|
||||
.. literalinclude:: heapex-sm32.clif
|
||||
:language: clif
|
||||
:lines: 2-
|
||||
```
|
||||
test verifier
|
||||
|
||||
function %add_members(i32, i32 vmctx) -> f32 baldrdash_system_v {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i32 notrap aligned gv0+64
|
||||
heap0 = static gv1, min 0x1000, bound 0x10_0000, offset_guard 0x1000
|
||||
|
||||
block0(v0: i32, v5: i32):
|
||||
v1 = heap_addr.i32 heap0, v0, 1
|
||||
v2 = load.f32 v1+16
|
||||
v3 = load.f32 v1+20
|
||||
v4 = fadd v2, v3
|
||||
return v4
|
||||
}
|
||||
```
|
||||
|
||||
If the upper bound on the heap size is too large, a dynamic heap is required
|
||||
instead.
|
||||
|
||||
Finally, a runtime environment that simply allocates a heap with
|
||||
:c:func:`malloc()` may not have any offset-guard pages at all. In that case,
|
||||
`malloc()` may not have any offset-guard pages at all. In that case,
|
||||
full bounds checking is required for each access:
|
||||
|
||||
.. literalinclude:: heapex-dyn.clif
|
||||
:language: clif
|
||||
:lines: 2-
|
||||
```
|
||||
test verifier
|
||||
|
||||
function %add_members(i32, i64 vmctx) -> f32 baldrdash_system_v {
|
||||
gv0 = vmctx
|
||||
gv1 = load.i64 notrap aligned gv0+64
|
||||
gv2 = load.i32 notrap aligned gv0+72
|
||||
heap0 = dynamic gv1, min 0x1000, bound gv2, offset_guard 0
|
||||
|
||||
Tables
|
||||
------
|
||||
block0(v0: i32, v6: i64):
|
||||
v1 = heap_addr.i64 heap0, v0, 20
|
||||
v2 = load.f32 v1+16
|
||||
v3 = heap_addr.i64 heap0, v0, 24
|
||||
v4 = load.f32 v3+20
|
||||
v5 = fadd v2, v4
|
||||
return v5
|
||||
}
|
||||
```
|
||||
|
||||
### Tables
|
||||
|
||||
Code compiled from WebAssembly often needs access to objects outside of its
|
||||
linear memory. WebAssembly uses *tables* to allow programs to refer to opaque
|
||||
values through integer indices.
|
||||
|
||||
A table is declared in the function preamble and can be accessed with the
|
||||
`table_addr` instruction that :term:`traps` on out-of-bounds accesses.
|
||||
`table_addr` instruction that [traps] on out-of-bounds accesses.
|
||||
Table addresses can be smaller than the native pointer size, for example
|
||||
unsigned `i32` offsets on a 64-bit architecture.
|
||||
|
||||
A table appears as a consecutive range of address space, conceptually
|
||||
divided into elements of fixed sizes, which are identified by their index.
|
||||
The memory is :term:`accessible`.
|
||||
The memory is [accessible].
|
||||
|
||||
The *table bound* is the number of elements currently in the table. This is
|
||||
the bound that `table_addr` checks against.
|
||||
@@ -725,15 +788,13 @@ T = dynamic Base, min MinElements, bound BoundGV, element_size ElementSize
|
||||
:arg BoundGV: Global value containing the current heap bound in elements.
|
||||
:arg ElementSize: Size of each element.
|
||||
|
||||
Constant materialization
|
||||
------------------------
|
||||
### Constant materialization
|
||||
|
||||
A few instructions have variants that take immediate operands, but in general
|
||||
an instruction is required to load a constant into an SSA value: `iconst`,
|
||||
`f32const`, `f64const` and `bconst` serve this purpose.
|
||||
|
||||
Bitwise operations
|
||||
------------------
|
||||
### Bitwise operations
|
||||
|
||||
The bitwise operations and operate on any value type: Integers, floating point
|
||||
numbers, and booleans. When operating on integer or floating point types, the
|
||||
@@ -750,20 +811,17 @@ to the number of bits in a *lane*, not the full size of the vector type.
|
||||
|
||||
The bit-counting instructions are scalar only.
|
||||
|
||||
Floating point operations
|
||||
-------------------------
|
||||
### Floating point operations
|
||||
|
||||
These operations generally follow IEEE 754-2008 semantics.
|
||||
|
||||
Sign bit manipulations
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
#### Sign bit manipulations
|
||||
|
||||
The sign manipulating instructions work as bitwise operations, so they don't
|
||||
have special behavior for signaling NaN operands. The exponent and trailing
|
||||
significand bits are always preserved.
|
||||
|
||||
Minimum and maximum
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
#### Minimum and maximum
|
||||
|
||||
These instructions return the larger or smaller of their operands. Note that
|
||||
unlike the IEEE 754-2008 `minNum` and `maxNum` operations, these instructions
|
||||
@@ -771,19 +829,12 @@ return NaN when either input is NaN.
|
||||
|
||||
When comparing zeroes, these instructions behave as if :math:`-0.0 < 0.0`.
|
||||
|
||||
Rounding
|
||||
~~~~~~~~
|
||||
#### Rounding
|
||||
|
||||
These instructions round their argument to a nearby integral value, still
|
||||
represented as a floating point number.
|
||||
|
||||
Conversion operations
|
||||
---------------------
|
||||
|
||||
.. _extload-truncstore:
|
||||
|
||||
Extending loads and truncating stores
|
||||
-------------------------------------
|
||||
### Extending loads and truncating stores
|
||||
|
||||
Most ISAs provide instructions that load an integer value smaller than a register
|
||||
and extends it to the width of the register. Similarly, store instructions that
|
||||
@@ -794,45 +845,38 @@ provides extending loads and truncation stores for 8, 16, and 32-bit memory
|
||||
accesses.
|
||||
|
||||
These instructions succeed, trap, or have undefined behavior, under the same
|
||||
conditions as :ref:`normal loads and stores <memory>`.
|
||||
conditions as [normal loads and stores](#memory).
|
||||
|
||||
ISA-specific instructions
|
||||
=========================
|
||||
## ISA-specific instructions
|
||||
|
||||
Target ISAs can define supplemental instructions that do not make sense to
|
||||
support generally.
|
||||
|
||||
x86
|
||||
-----
|
||||
### x86
|
||||
|
||||
Instructions that can only be used by the x86 target ISA.
|
||||
|
||||
Codegen implementation instructions
|
||||
===================================
|
||||
## Codegen implementation instructions
|
||||
|
||||
Frontends don't need to emit the instructions in this section themselves;
|
||||
Cranelift will generate them automatically as needed.
|
||||
|
||||
Legalization operations
|
||||
-----------------------
|
||||
### Legalization operations
|
||||
|
||||
These instructions are used as helpers when legalizing types and operations for
|
||||
the target ISA.
|
||||
|
||||
Special register operations
|
||||
---------------------------
|
||||
### Special register operations
|
||||
|
||||
The prologue and epilogue of a function needs to manipulate special registers like the stack
|
||||
pointer and the frame pointer. These instructions should not be used in regular code.
|
||||
|
||||
CPU flag operations
|
||||
-------------------
|
||||
### CPU flag operations
|
||||
|
||||
These operations are for working with the "flags" registers of some CPU
|
||||
architectures.
|
||||
|
||||
Live range splitting
|
||||
--------------------
|
||||
### Live range splitting
|
||||
|
||||
Cranelift's register allocator assigns each SSA value to a register or a spill
|
||||
slot on the stack for its entire live range. Since the live range of an SSA
|
||||
@@ -851,16 +895,14 @@ Register values can be temporarily diverted to other registers by the
|
||||
`regmove` instruction, and to and from stack slots by `regspill`
|
||||
and `regfill`.
|
||||
|
||||
Instruction groups
|
||||
==================
|
||||
## Instruction groups
|
||||
|
||||
All of the shared instructions are part of the `base` instruction
|
||||
group.
|
||||
|
||||
Target ISAs may define further instructions in their own instruction groups.
|
||||
|
||||
Implementation limits
|
||||
=====================
|
||||
## Implementation limits
|
||||
|
||||
Cranelift's intermediate representation imposes some limits on the size of
|
||||
functions and the number of entities allowed. If these limits are exceeded, the
|
||||
@@ -904,19 +946,16 @@ Size of function call arguments on the stack
|
||||
This is probably not possible to achieve given the limit on the number of
|
||||
arguments, except by requiring extremely large offsets for stack arguments.
|
||||
|
||||
Glossary
|
||||
========
|
||||
|
||||
.. glossary::
|
||||
## Glossary
|
||||
|
||||
addressable
|
||||
Memory in which loads and stores have defined behavior. They either
|
||||
succeed or :term:`trap`, depending on whether the memory is
|
||||
:term:`accessible`.
|
||||
succeed or [trap], depending on whether the memory is
|
||||
[accessible].
|
||||
|
||||
accessible
|
||||
:term:`Addressable` memory in which loads and stores always succeed
|
||||
without :term:`trapping`, except where specified otherwise (eg. with the
|
||||
[Addressable] memory in which loads and stores always succeed
|
||||
without [trapping], except where specified otherwise (eg. with the
|
||||
`aligned` flag). Heaps, globals, tables, and the stack may contain
|
||||
accessible, merely addressable, and outright unaddressable regions.
|
||||
There may also be additional regions of addressable and/or accessible
|
||||
@@ -928,7 +967,7 @@ Glossary
|
||||
the last instruction.
|
||||
|
||||
entry block
|
||||
The :term:`EBB` that is executed first in a function. Currently, a
|
||||
The [EBB] that is executed first in a function. Currently, a
|
||||
Cranelift function must have exactly one entry block which must be the
|
||||
first block in the function. The types of the entry block arguments must
|
||||
match the types of arguments in the function signature.
|
||||
@@ -936,12 +975,12 @@ Glossary
|
||||
extended basic block
|
||||
EBB
|
||||
A maximal sequence of instructions that can only be entered from the
|
||||
top, and that contains no :term:`terminator instruction`\s except for
|
||||
top, and that contains no [terminator instruction]s except for
|
||||
the last one. An EBB can contain conditional branches that can fall
|
||||
through to the following instructions in the block, but only the first
|
||||
instruction in the EBB can be a branch target.
|
||||
|
||||
The last instruction in an EBB must be a :term:`terminator instruction`,
|
||||
The last instruction in an EBB must be a [terminator instruction],
|
||||
so execution cannot flow through to the next EBB in the function. (But
|
||||
there may be a branch to the next EBB.)
|
||||
|
||||
@@ -971,7 +1010,7 @@ Glossary
|
||||
- Type and flags of each return value.
|
||||
|
||||
Not all function attributes are part of the signature. For example, a
|
||||
function that never returns could be marked as ``noreturn``, but that
|
||||
function that never returns could be marked as `noreturn`, but that
|
||||
is not necessary to know when calling it, so it is just an attribute,
|
||||
and not part of the signature.
|
||||
|
||||
@@ -996,17 +1035,17 @@ Glossary
|
||||
|
||||
stack slot
|
||||
A fixed size memory allocation in the current function's activation
|
||||
frame. These include :term:`explicit stack slot`\s and
|
||||
:term:`spill stack slot`\s.
|
||||
frame. These include [explicit stack slot]s and
|
||||
[spill stack slot]s.
|
||||
|
||||
explicit stack slot
|
||||
A fixed size memory allocation in the current function's activation
|
||||
frame. These differ from :term:`spill stack slot`\s in that they can
|
||||
frame. These differ from [spill stack slot]s in that they can
|
||||
be created by frontends and they may have their addresses taken.
|
||||
|
||||
spill stack slot
|
||||
A fixed size memory allocation in the current function's activation
|
||||
frame. These differ from :term:`explicit stack slot`\s in that they are
|
||||
frame. These differ from [explicit stack slot]s in that they are
|
||||
only created during register allocation, and they may not have their
|
||||
address taken.
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
:orphan:
|
||||
|
||||
****************
|
||||
Redirection Page
|
||||
****************
|
||||
|
||||
Cranelift's IR is documented in :doc:`ir`. Please update links to point to
|
||||
this new page.
|
||||
@@ -1,36 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
set SPHINXPROJ=cranelift
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
@@ -1,386 +0,0 @@
|
||||
*********************************
|
||||
Cranelift Meta Language Reference
|
||||
*********************************
|
||||
|
||||
.. default-domain:: py
|
||||
.. highlight:: python
|
||||
|
||||
The Cranelift meta language is used to define instructions for Cranelift. It is a
|
||||
domain specific language embedded in Rust.
|
||||
|
||||
.. todo:: Point to the Rust documentation of the meta crate here.
|
||||
|
||||
This document is very out-of-date. Instead, you can have a look at the
|
||||
work-in-progress documentation of the `meta` crate there:
|
||||
https://docs.rs/cranelift-codegen-meta/0.34.0/cranelift_codegen_meta/.
|
||||
|
||||
This document describes the Python modules that form the embedded DSL.
|
||||
|
||||
The meta language descriptions are Python modules under the
|
||||
`cranelift-codegen/meta-python` directory. The descriptions are processed in two
|
||||
steps:
|
||||
|
||||
1. The Python modules are imported. This has the effect of building static data
|
||||
structures in global values in the modules. These static data structures
|
||||
in the `base` and `isa` packages use the classes in the
|
||||
`cdsl` package to describe instruction sets and other properties.
|
||||
|
||||
2. The static data structures are processed to produce Rust source code and
|
||||
constant tables.
|
||||
|
||||
The main driver for this source code generation process is the
|
||||
`cranelift-codegen/meta-python/build.py` script which is invoked as part of the build
|
||||
process if anything in the `cranelift-codegen/meta-python` directory has changed
|
||||
since the last build.
|
||||
|
||||
Settings
|
||||
========
|
||||
|
||||
Settings are used by the environment embedding Cranelift to control the details
|
||||
of code generation. Each setting is defined in the meta language so a compact
|
||||
and consistent Rust representation can be generated. Shared settings are defined
|
||||
in the `base.settings` module. Some settings are specific to a target ISA,
|
||||
and defined in a `settings.py` module under the appropriate
|
||||
`cranelift-codegen/meta-python/isa/*` directory.
|
||||
|
||||
Settings can take boolean on/off values, small numbers, or explicitly enumerated
|
||||
symbolic values.
|
||||
|
||||
All settings must belong to a *group*, represented by a :class:`SettingGroup` object.
|
||||
|
||||
Normally, a setting group corresponds to all settings defined in a module. Such
|
||||
a module looks like this::
|
||||
|
||||
group = SettingGroup('example')
|
||||
|
||||
foo = BoolSetting('use the foo')
|
||||
bar = BoolSetting('enable bars', True)
|
||||
opt = EnumSetting('optimization level', 'Debug', 'Release')
|
||||
|
||||
group.close(globals())
|
||||
|
||||
Instruction descriptions
|
||||
========================
|
||||
|
||||
New instructions are defined as instances of the :class:`Instruction`
|
||||
class. As instruction instances are created, they are added to the currently
|
||||
open :class:`InstructionGroup`.
|
||||
|
||||
The basic Cranelift instruction set described in :doc:`ir` is defined by the
|
||||
Python module `base.instructions`. This module has a global value
|
||||
`base.instructions.GROUP` which is an :class:`InstructionGroup` instance
|
||||
containing all the base instructions.
|
||||
|
||||
An instruction is defined with a set of distinct input and output operands which
|
||||
must be instances of the :class:`Operand` class.
|
||||
|
||||
Cranelift uses two separate type systems for operand kinds and SSA values.
|
||||
|
||||
Type variables
|
||||
--------------
|
||||
|
||||
Instruction descriptions can be made polymorphic by using
|
||||
:class:`cdsl.operands.Operand` instances that refer to a *type variable*
|
||||
instead of a concrete value type. Polymorphism only works for SSA value
|
||||
operands. Other operands have a fixed operand kind.
|
||||
|
||||
If multiple operands refer to the same type variable they will be required to
|
||||
have the same concrete type. For example, this defines an integer addition
|
||||
instruction::
|
||||
|
||||
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
|
||||
a = Operand('a', Int)
|
||||
x = Operand('x', Int)
|
||||
y = Operand('y', Int)
|
||||
|
||||
iadd = Instruction('iadd', 'Integer addition', ins=(x, y), outs=a)
|
||||
|
||||
The type variable `Int` is allowed to vary over all scalar and vector integer
|
||||
value types, but in a given instance of the `iadd` instruction, the two
|
||||
operands must have the same type, and the result will be the same type as the
|
||||
inputs.
|
||||
|
||||
There are some practical restrictions on the use of type variables, see
|
||||
:ref:`restricted-polymorphism`.
|
||||
|
||||
Immediate operands
|
||||
------------------
|
||||
|
||||
Immediate instruction operands don't correspond to SSA values, but have values
|
||||
that are encoded directly in the instruction. Immediate operands don't
|
||||
have types from the :class:`cdsl.types.ValueType` type system; they often have
|
||||
enumerated values of a specific type. The type of an immediate operand is
|
||||
indicated with an instance of :class:`ImmediateKind`.
|
||||
|
||||
Entity references
|
||||
-----------------
|
||||
|
||||
Instruction operands can also refer to other entities in the same function. This
|
||||
can be extended basic blocks, or entities declared in the function preamble.
|
||||
|
||||
Value types
|
||||
-----------
|
||||
|
||||
Concrete value types are represented as instances of :class:`ValueType`. There
|
||||
are subclasses to represent scalar and vector types.
|
||||
|
||||
There are no predefined vector types, but they can be created as needed with
|
||||
the :func:`LaneType.by` function.
|
||||
|
||||
Instruction representation
|
||||
==========================
|
||||
|
||||
The Rust in-memory representation of instructions is derived from the
|
||||
instruction descriptions. Part of the representation is generated, and part is
|
||||
written as Rust code in the ``cranelift.instructions`` module. The instruction
|
||||
representation depends on the input operand kinds and whether the instruction
|
||||
can produce multiple results.
|
||||
|
||||
Since all SSA value operands are represented as a `Value` in Rust code, value
|
||||
types don't affect the representation.
|
||||
|
||||
When an instruction description is created, it is automatically assigned a
|
||||
predefined instruction format which is an instance of
|
||||
:class:`InstructionFormat`.
|
||||
|
||||
.. _restricted-polymorphism:
|
||||
|
||||
Restricted polymorphism
|
||||
-----------------------
|
||||
|
||||
The instruction format strictly controls the kinds of operands on an
|
||||
instruction, but it does not constrain value types at all. A given instruction
|
||||
description typically does constrain the allowed value types for its value
|
||||
operands. The type variables give a lot of freedom in describing the value type
|
||||
constraints, in practice more freedom than what is needed for normal instruction
|
||||
set architectures. In order to simplify the Rust representation of value type
|
||||
constraints, some restrictions are imposed on the use of type variables.
|
||||
|
||||
A polymorphic instruction has a single *controlling type variable*. For a given
|
||||
opcode, this type variable must be the type of the first result or the type of
|
||||
the input value operand designated by the `typevar_operand` argument to the
|
||||
:py:class:`InstructionFormat` constructor. By default, this is the first value
|
||||
operand, which works most of the time.
|
||||
|
||||
The value types of instruction results must be one of the following:
|
||||
|
||||
1. A concrete value type.
|
||||
2. The controlling type variable.
|
||||
3. A type variable derived from the controlling type variable.
|
||||
|
||||
This means that all result types can be computed from the controlling type
|
||||
variable.
|
||||
|
||||
Input values to the instruction are allowed a bit more freedom. Input value
|
||||
types must be one of:
|
||||
|
||||
1. A concrete value type.
|
||||
2. The controlling type variable.
|
||||
3. A type variable derived from the controlling type variable.
|
||||
4. A free type variable that is not used by any other operands.
|
||||
|
||||
This means that the type of an input operand can either be computed from the
|
||||
controlling type variable, or it can vary independently of the other operands.
|
||||
|
||||
|
||||
Encodings
|
||||
=========
|
||||
|
||||
Encodings describe how Cranelift instructions are mapped to binary machine code
|
||||
for the target architecture. After the legalization pass, all remaining
|
||||
instructions are expected to map 1-1 to native instruction encodings. Cranelift
|
||||
instructions that can't be encoded for the current architecture are called
|
||||
:term:`illegal instruction`\s.
|
||||
|
||||
Some instruction set architectures have different :term:`CPU mode`\s with
|
||||
incompatible encodings. For example, a modern ARMv8 CPU might support three
|
||||
different CPU modes: *A64* where instructions are encoded in 32 bits, *A32*
|
||||
where all instructions are 32 bits, and *T32* which has a mix of 16-bit and
|
||||
32-bit instruction encodings. These are incompatible encoding spaces, and while
|
||||
an `iadd` instruction can be encoded in 32 bits in each of them, it's
|
||||
not the same 32 bits. It's a judgement call if CPU modes should be modelled as
|
||||
separate targets, or as sub-modes of the same target. In the ARMv8 case, the
|
||||
different register banks means that it makes sense to model A64 as a separate
|
||||
target architecture, while A32 and T32 are CPU modes of the 32-bit ARM target.
|
||||
|
||||
In a given CPU mode, there may be multiple valid encodings of the same
|
||||
instruction. Both RISC-V and ARMv8's T32 mode have 32-bit encodings of all
|
||||
instructions with 16-bit encodings available for some opcodes if certain
|
||||
constraints are satisfied.
|
||||
|
||||
Encodings are guarded by :term:`sub-target predicate`\s. For example, the RISC-V
|
||||
"C" extension which specifies the compressed encodings may not be supported, and
|
||||
a predicate would be used to disable all of the 16-bit encodings in that case.
|
||||
This can also affect whether an instruction is legal. For example, x86 has a
|
||||
predicate that controls the SSE 4.1 instruction encodings. When that predicate
|
||||
is false, the SSE 4.1 instructions are not available.
|
||||
|
||||
Encodings also have a :term:`instruction predicate` which depends on the
|
||||
specific values of the instruction's immediate fields. This is used to ensure
|
||||
that immediate address offsets are within range, for example. The instructions
|
||||
in the base Cranelift instruction set can often represent a wider range of
|
||||
immediates than any specific encoding. The fixed-size RISC-style encodings tend
|
||||
to have more range limitations than CISC-style variable length encodings like
|
||||
x86.
|
||||
|
||||
The diagram below shows the relationship between the classes involved in
|
||||
specifying instruction encodings:
|
||||
|
||||
.. digraph:: encoding
|
||||
|
||||
node [shape=record]
|
||||
EncRecipe -> SubtargetPred
|
||||
EncRecipe -> InstrFormat
|
||||
EncRecipe -> InstrPred
|
||||
Encoding [label="{Encoding|Opcode+TypeVars}"]
|
||||
Encoding -> EncRecipe [label="+EncBits"]
|
||||
Encoding -> CPUMode
|
||||
Encoding -> SubtargetPred
|
||||
Encoding -> InstrPred
|
||||
Encoding -> Opcode
|
||||
Opcode -> InstrFormat
|
||||
CPUMode -> Target
|
||||
|
||||
An :py:class:`Encoding` instance specifies the encoding of a concrete
|
||||
instruction. The following properties are used to select instructions to be
|
||||
encoded:
|
||||
|
||||
- An opcode, i.e. `iadd_imm`, that must match the instruction's
|
||||
opcode.
|
||||
- Values for any type variables if the opcode represents a polymorphic
|
||||
instruction.
|
||||
- An :term:`instruction predicate` that must be satisfied by the instruction's
|
||||
immediate operands.
|
||||
- The CPU mode that must be active.
|
||||
- A :term:`sub-target predicate` that must be satisfied by the currently active
|
||||
sub-target.
|
||||
|
||||
An encoding specifies an *encoding recipe* along with some *encoding bits* that
|
||||
the recipe can use for native opcode fields etc. The encoding recipe has
|
||||
additional constraints that must be satisfied:
|
||||
|
||||
- An :py:class:`InstructionFormat` that must match the format required by the
|
||||
opcodes of any encodings that use this recipe.
|
||||
- An additional :term:`instruction predicate`.
|
||||
- An additional :term:`sub-target predicate`.
|
||||
|
||||
The additional predicates in the :py:class:`EncRecipe` are merged with the
|
||||
per-encoding predicates when generating the encoding matcher code. Often
|
||||
encodings only need the recipe predicates.
|
||||
|
||||
Register constraints
|
||||
====================
|
||||
|
||||
After an encoding recipe has been chosen for an instruction, it is the register
|
||||
allocator's job to make sure that the recipe's :term:`Register constraint`\s
|
||||
are satisfied. Most ISAs have separate integer and floating point registers,
|
||||
and instructions can usually only use registers from one of the banks. Some
|
||||
instruction encodings are even more constrained and can only use a subset of
|
||||
the registers in a bank. These constraints are expressed in terms of register
|
||||
classes.
|
||||
|
||||
Sometimes the result of an instruction is placed in a register that must be the
|
||||
same as one of the input registers. Some instructions even use a fixed register
|
||||
for inputs or results.
|
||||
|
||||
Each encoding recipe specifies separate constraints for its value operands and
|
||||
result. These constraints are separate from the instruction predicate which can
|
||||
only evaluate the instruction's immediate operands.
|
||||
|
||||
Register class constraints
|
||||
--------------------------
|
||||
|
||||
The most common type of register constraint is the register class. It specifies
|
||||
that an operand or result must be allocated one of the registers from the given
|
||||
register class::
|
||||
|
||||
IntRegs = RegBank('IntRegs', ISA, 'General purpose registers', units=16, prefix='r')
|
||||
GPR = RegClass(IntRegs)
|
||||
R = EncRecipe('R', Binary, ins=(GPR, GPR), outs=GPR)
|
||||
|
||||
This defines an encoding recipe for the ``Binary`` instruction format where
|
||||
both input operands must be allocated from the ``GPR`` register class.
|
||||
|
||||
Tied register operands
|
||||
----------------------
|
||||
|
||||
In more compact machine code encodings, it is common to require that the result
|
||||
register is the same as one of the inputs. This is represented with tied
|
||||
operands::
|
||||
|
||||
CR = EncRecipe('CR', Binary, ins=(GPR, GPR), outs=0)
|
||||
|
||||
This indicates that the result value must be allocated to the same register as
|
||||
the first input value. Tied operand constraints can only be used for result
|
||||
values, so the number always refers to one of the input values.
|
||||
|
||||
Fixed register operands
|
||||
-----------------------
|
||||
|
||||
Some instructions use hard-coded input and output registers for some value
|
||||
operands. An example is the ``pblendvb`` x86 SSE instruction which takes one
|
||||
of its three value operands in the hard-coded ``%xmm0`` register::
|
||||
|
||||
XMM0 = FPR[0]
|
||||
SSE66_XMM0 = EncRecipe('SSE66_XMM0', Ternary, ins=(FPR, FPR, XMM0), outs=0)
|
||||
|
||||
The syntax ``FPR[0]`` selects the first register from the ``FPR`` register
|
||||
class which consists of all the XMM registers.
|
||||
|
||||
Stack operands
|
||||
--------------
|
||||
|
||||
Cranelift's register allocator can assign an SSA value to a stack slot if there
|
||||
isn't enough registers. It will insert `spill` and `fill`
|
||||
instructions as needed to satisfy instruction operand constraints, but it is
|
||||
also possible to have instructions that can access stack slots directly::
|
||||
|
||||
CSS = EncRecipe('CSS', Unary, ins=GPR, outs=Stack(GPR))
|
||||
|
||||
An output stack value implies a store to the stack, an input value implies a
|
||||
load.
|
||||
|
||||
Targets
|
||||
=======
|
||||
|
||||
Cranelift can be compiled with support for multiple target instruction set
|
||||
architectures. Each ISA is represented by a :py:class:`cdsl.isa.TargetISA` instance.
|
||||
|
||||
The definitions for each supported target live in a package under
|
||||
`cranelift-codegen/meta-python/isa`.
|
||||
|
||||
Glossary
|
||||
========
|
||||
|
||||
.. glossary::
|
||||
|
||||
Illegal instruction
|
||||
An instruction is considered illegal if there is no encoding available
|
||||
for the current CPU mode. The legality of an instruction depends on the
|
||||
value of :term:`sub-target predicate`\s, so it can't always be
|
||||
determined ahead of time.
|
||||
|
||||
CPU mode
|
||||
Every target defines one or more CPU modes that determine how the CPU
|
||||
decodes binary instructions. Some CPUs can switch modes dynamically with
|
||||
a branch instruction (like ARM/Thumb), while other modes are
|
||||
process-wide (like x86 32/64-bit).
|
||||
|
||||
Sub-target predicate
|
||||
A predicate that depends on the current sub-target configuration.
|
||||
Examples are "Use SSE 4.1 instructions", "Use RISC-V compressed
|
||||
encodings". Sub-target predicates can depend on both detected CPU
|
||||
features and configuration settings.
|
||||
|
||||
Instruction predicate
|
||||
A predicate that depends on the immediate fields of an instruction. An
|
||||
example is "the load address offset must be a 10-bit signed integer".
|
||||
Instruction predicates do not depend on the registers selected for value
|
||||
operands.
|
||||
|
||||
Register constraint
|
||||
Value operands and results correspond to machine registers. Encodings may
|
||||
constrain operands to either a fixed register or a register class. There
|
||||
may also be register constraints between operands, for example some
|
||||
encodings require that the result register is one of the input
|
||||
registers.
|
||||
@@ -1,9 +1,4 @@
|
||||
********************************
|
||||
Register Allocation in Cranelift
|
||||
********************************
|
||||
|
||||
.. default-domain:: clif
|
||||
.. highlight:: clif
|
||||
# Register Allocation in Cranelift
|
||||
|
||||
Cranelift uses a *decoupled, SSA-based* register allocator. Decoupled means that
|
||||
register allocation is split into two primary phases: *spilling* and
|
||||
@@ -12,17 +7,16 @@ register allocator, and in fact is still in SSA form after register allocation.
|
||||
|
||||
Before the register allocator is run, all instructions in the function must be
|
||||
*legalized*, which means that every instruction has an entry in the
|
||||
``encodings`` table. The encoding entries also provide register class
|
||||
`encodings` table. The encoding entries also provide register class
|
||||
constraints on the instruction's operands that the register allocator must
|
||||
satisfy.
|
||||
|
||||
After the register allocator has run, the ``locations`` table provides a
|
||||
After the register allocator has run, the `locations` table provides a
|
||||
register or stack slot location for all SSA values used by the function. The
|
||||
register allocator may have inserted :inst:`spill`, :inst:`fill`, and
|
||||
:inst:`copy` instructions to make that possible.
|
||||
register allocator may have inserted `spill`, `fill`, and
|
||||
`copy` instructions to make that possible.
|
||||
|
||||
SSA-based register allocation
|
||||
=============================
|
||||
## SSA-based register allocation
|
||||
|
||||
The phases of the SSA-based register allocator are:
|
||||
|
||||
@@ -37,14 +31,14 @@ Coalescing
|
||||
Spilling
|
||||
The process of deciding which SSA values go in a stack slot and which
|
||||
values go in a register. The spilling phase can also split live ranges by
|
||||
inserting :inst:`copy` instructions, or transform the code in other ways to
|
||||
inserting `copy` instructions, or transform the code in other ways to
|
||||
reduce the number of values kept in registers.
|
||||
|
||||
After spilling, the number of live register values never exceeds the number
|
||||
of available registers.
|
||||
|
||||
Reload
|
||||
Insert :inst:`spill` and :inst:`fill` instructions as necessary such that
|
||||
Insert `spill` and `fill` instructions as necessary such that
|
||||
instructions that expect their operands in registers won't see values that
|
||||
live on the stack and vice versa.
|
||||
|
||||
@@ -62,8 +56,7 @@ The contract between the spilling and coloring phases is that the number of
|
||||
values in registers never exceeds the number of available registers. This
|
||||
sounds simple enough in theory, but in practice there are some complications.
|
||||
|
||||
Real-world complications to SSA coloring
|
||||
----------------------------------------
|
||||
### Real-world complications to SSA coloring
|
||||
|
||||
In practice, instruction set architectures don't have "K interchangeable
|
||||
registers", and register pressure can't be measured with a single number. There
|
||||
@@ -104,7 +97,7 @@ ABI boundaries
|
||||
Win64 callees only save the low 128 bits of AVX registers.
|
||||
|
||||
ABI boundaries also affect the location of arguments to the entry block and
|
||||
return values passed to the :inst:`return` instruction.
|
||||
return values passed to the `return` instruction.
|
||||
|
||||
Aliasing registers
|
||||
Different registers sometimes share the same bits in the register bank.
|
||||
@@ -121,8 +114,7 @@ Early clobbers
|
||||
assembly and in some other special cases.
|
||||
|
||||
|
||||
Liveness Analysis
|
||||
=================
|
||||
## Liveness Analysis
|
||||
|
||||
All the register allocator passes need to know exactly where SSA values are
|
||||
live. The liveness analysis computes this information.
|
||||
@@ -159,11 +151,11 @@ this can often be represented with coalesced live-in intervals covering many
|
||||
EBBs. It is important that the live range data structure doesn't have to grow
|
||||
linearly with the number of EBBs covered by a live range.
|
||||
|
||||
This representation is very similar to LLVM's ``LiveInterval`` data structure
|
||||
This representation is very similar to LLVM's `LiveInterval` data structure
|
||||
with a few important differences:
|
||||
|
||||
- The Cranelift ``LiveRange`` only covers a single SSA value, while LLVM's
|
||||
``LiveInterval`` represents the union of multiple related SSA values in a
|
||||
- The Cranelift `LiveRange` only covers a single SSA value, while LLVM's
|
||||
`LiveInterval` represents the union of multiple related SSA values in a
|
||||
virtual register. This makes Cranelift's representation smaller because
|
||||
individual segments don't have to annotated with a value number.
|
||||
- Cranelift stores the def-interval separately from a list of coalesced live-in
|
||||
@@ -176,8 +168,8 @@ with a few important differences:
|
||||
is not necessary to check for overlap between the two sets of live-in
|
||||
intervals. This makes the overlap check logarithmic in the number of live-in
|
||||
intervals instead of linear.
|
||||
- LLVM represents a program point as ``SlotIndex`` which holds a pointer to a
|
||||
32-byte ``IndexListEntry`` struct. The entries are organized in a double
|
||||
- LLVM represents a program point as `SlotIndex` which holds a pointer to a
|
||||
32-byte `IndexListEntry` struct. The entries are organized in a double
|
||||
linked list that mirrors the ordering of instructions in a basic block. This
|
||||
allows 'tombstone' program points corresponding to instructions that have
|
||||
been deleted.
|
||||
@@ -190,12 +182,12 @@ with a few important differences:
|
||||
A consequence of Cranelift's more compact representation is that two program
|
||||
points can't be compared without the context of a function layout.
|
||||
|
||||
Coalescing algorithm
|
||||
====================
|
||||
## Coalescing algorithm
|
||||
|
||||
Unconstrained SSA form is not well suited to register allocation because of the problems
|
||||
that can arise around EBB parameters and arguments. Consider this simple example::
|
||||
that can arise around EBB parameters and arguments. Consider this simple example:
|
||||
|
||||
```
|
||||
function %interference(i32, i32) -> i32 {
|
||||
ebb0(v0: i32, v1: i32):
|
||||
brz v0, ebb1(v1)
|
||||
@@ -205,15 +197,17 @@ that can arise around EBB parameters and arguments. Consider this simple example
|
||||
v3 = iadd v1, v2
|
||||
return v3
|
||||
}
|
||||
```
|
||||
|
||||
Here, the value ``v1`` is both passed as an argument to ``ebb1`` *and* it is
|
||||
live in to the EBB because it is used by the :inst:`iadd` instruction. Since
|
||||
EBB arguments on the :inst:`brz` instruction need to be in the same register as
|
||||
the corresponding EBB parameter ``v2``, there is going to be interference
|
||||
between ``v1`` and ``v2`` in the ``ebb1`` block.
|
||||
Here, the value `v1` is both passed as an argument to `ebb1` *and* it is
|
||||
live in to the EBB because it is used by the `iadd` instruction. Since
|
||||
EBB arguments on the `brz` instruction need to be in the same register as
|
||||
the corresponding EBB parameter `v2`, there is going to be interference
|
||||
between `v1` and `v2` in the `ebb1` block.
|
||||
|
||||
The interference can be resolved by isolating the SSA values passed as EBB arguments::
|
||||
The interference can be resolved by isolating the SSA values passed as EBB arguments:
|
||||
|
||||
```
|
||||
function %coalesced(i32, i32) -> i32 {
|
||||
ebb0(v0: i32, v1: i32):
|
||||
v5 = copy v1
|
||||
@@ -225,8 +219,9 @@ The interference can be resolved by isolating the SSA values passed as EBB argum
|
||||
v3 = iadd.i32 v1, v2
|
||||
return v3
|
||||
}
|
||||
```
|
||||
|
||||
Now the EBB argument is ``v5`` which is *not* itself live into ``ebb1``,
|
||||
Now the EBB argument is `v5` which is *not* itself live into `ebb1`,
|
||||
resolving the interference.
|
||||
|
||||
The coalescing pass groups the SSA values into sets called *virtual registers*
|
||||
@@ -239,7 +234,7 @@ and inserts copies such that:
|
||||
interfere, i.e. they don't overlap anywhere.
|
||||
|
||||
Most virtual registers contains only a single isolated SSA value because most
|
||||
SSA values are never passed as EBB arguments. The ``VirtRegs`` data structure
|
||||
SSA values are never passed as EBB arguments. The `VirtRegs` data structure
|
||||
doesn't store any information about these singleton virtual registers, it only
|
||||
tracks larger virtual registers and assumes that any value it doesn't know about
|
||||
is its own singleton virtual register
|
||||
@@ -254,8 +249,7 @@ Conventional SSA form and the virtual registers are maintained through all the
|
||||
register allocator passes.
|
||||
|
||||
|
||||
Spilling algorithm
|
||||
==================
|
||||
## Spilling algorithm
|
||||
|
||||
The spilling pass is responsible for lowering the register pressure enough that
|
||||
the coloring pass is guaranteed to be able to find a coloring solution. It does
|
||||
@@ -287,8 +281,7 @@ spill slots if the spilled value gets used a lot. The idea is to minimize stack
|
||||
*write* traffic with the spilling heuristic and to minimize stack *read* traffic
|
||||
with the reload pass.
|
||||
|
||||
Coloring algorithm
|
||||
==================
|
||||
## Coloring algorithm
|
||||
|
||||
The SSA coloring algorithm is based on a single observation: If two SSA values
|
||||
interfere, one of the values must be live where the other value is defined.
|
||||
@@ -1,93 +1,26 @@
|
||||
*****************
|
||||
Testing Cranelift
|
||||
*****************
|
||||
# Testing Cranelift
|
||||
|
||||
Cranelift is tested at multiple levels of abstraction and integration. When
|
||||
possible, Rust unit tests are used to verify single functions and types. When
|
||||
testing the interaction between compiler passes, file-level tests are
|
||||
appropriate.
|
||||
|
||||
The top-level shell script :file:`test-all.sh` runs all of the tests in the
|
||||
Cranelift repository.
|
||||
|
||||
Rust tests
|
||||
==========
|
||||
|
||||
.. highlight:: rust
|
||||
## Rust tests
|
||||
|
||||
Rust and Cargo have good support for testing. Cranelift uses unit tests, doc
|
||||
tests, and integration tests where appropriate.
|
||||
tests, and integration tests where appropriate. The
|
||||
[Rust By Example page on Testing] is a great illustration on how to write
|
||||
each of these forms of test.
|
||||
|
||||
Unit tests
|
||||
----------
|
||||
[Rust By Example page on Testing]: https://doc.rust-lang.org/rust-by-example/testing.html
|
||||
|
||||
Unit test live in a ``tests`` sub-module of the code they are testing::
|
||||
|
||||
pub fn add(x: u32, y: u32) -> u32 {
|
||||
x + y
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::add;
|
||||
|
||||
#[test]
|
||||
check_add() {
|
||||
assert_eq!(add(2, 2), 4);
|
||||
}
|
||||
}
|
||||
|
||||
Since sub-modules have access to non-public items in a Rust module, unit tests
|
||||
can be used to test module-internal functions and types too.
|
||||
|
||||
Doc tests
|
||||
---------
|
||||
|
||||
Documentation comments can contain code snippets which are also compiled and
|
||||
tested::
|
||||
|
||||
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
|
||||
//! create it.
|
||||
//!
|
||||
//! # Example
|
||||
//! ```
|
||||
//! use cranelift_codegen::settings::{self, Configurable};
|
||||
//!
|
||||
//! let mut b = settings::builder();
|
||||
//! b.set("opt_level", "fastest");
|
||||
//!
|
||||
//! let f = settings::Flags::new(&b);
|
||||
//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
|
||||
//! ```
|
||||
|
||||
These tests are useful for demonstrating how to use an API, and running them
|
||||
regularly makes sure that they stay up to date. Documentation tests are not
|
||||
appropriate for lots of assertions; use unit tests for that.
|
||||
|
||||
Integration tests
|
||||
-----------------
|
||||
|
||||
Integration tests are Rust source files that are compiled and linked
|
||||
individually. They are used to exercise the external API of the crates under
|
||||
test.
|
||||
|
||||
These tests are usually found in the :file:`tests` top-level directory where
|
||||
they have access to all the crates in the Cranelift repository. The
|
||||
:file:`cranelift-codegen` and :file:`cranelift-reader` crates have no external
|
||||
dependencies, which can make testing tedious. Integration tests that don't need
|
||||
to depend on other crates can be placed in :file:`cranelift-codegen/tests` and
|
||||
:file:`cranelift-reader/tests`.
|
||||
|
||||
File tests
|
||||
==========
|
||||
|
||||
.. highlight:: clif
|
||||
## File tests
|
||||
|
||||
Compilers work with large data structures representing programs, and it quickly
|
||||
gets unwieldy to generate test data programmatically. File-level tests make it
|
||||
easier to provide substantial input functions for the compiler tests.
|
||||
|
||||
File tests are :file:`*.clif` files in the :file:`filetests/` directory
|
||||
File tests are `*.clif` files in the `filetests/` directory
|
||||
hierarchy. Each file has a header describing what to test followed by a number
|
||||
of input functions in the :doc:`Cranelift textual intermediate representation
|
||||
<ir>`:
|
||||
@@ -108,8 +41,8 @@ header:
|
||||
isa_specs : { [`settings`] isa_spec }
|
||||
isa_spec : "isa" isa_name { `option` } "\n"
|
||||
|
||||
The options given on the ``isa`` line modify the ISA-specific settings defined in
|
||||
:file:`cranelift-codegen/meta-python/isa/*/settings.py`.
|
||||
The options given on the `isa` line modify the ISA-specific settings defined in
|
||||
`cranelift-codegen/meta-python/isa/*/settings.py`.
|
||||
|
||||
All types of tests allow shared Cranelift settings to be modified:
|
||||
|
||||
@@ -119,10 +52,11 @@ All types of tests allow shared Cranelift settings to be modified:
|
||||
option : flag | setting "=" value
|
||||
|
||||
The shared settings available for all target ISAs are defined in
|
||||
:file:`cranelift-codegen/meta-python/base/settings.py`.
|
||||
`cranelift-codegen/meta-python/base/settings.py`.
|
||||
|
||||
The ``set`` lines apply settings cumulatively::
|
||||
The `set` lines apply settings cumulatively:
|
||||
|
||||
```
|
||||
test legalizer
|
||||
set opt_level=best
|
||||
set is_pic=1
|
||||
@@ -131,22 +65,22 @@ The ``set`` lines apply settings cumulatively::
|
||||
isa riscv32 supports_m=false
|
||||
|
||||
function %foo() {}
|
||||
```
|
||||
|
||||
This example will run the legalizer test twice. Both runs will have
|
||||
``opt_level=best``, but they will have different ``is_pic`` settings. The 32-bit
|
||||
run will also have the RISC-V specific flag ``supports_m`` disabled.
|
||||
`opt_level=best`, but they will have different `is_pic` settings. The 32-bit
|
||||
run will also have the RISC-V specific flag `supports_m` disabled.
|
||||
|
||||
The filetests are run automatically as part of `cargo test`, and they can
|
||||
also be run manually with the `clif-util test` command.
|
||||
|
||||
Filecheck
|
||||
---------
|
||||
### Filecheck
|
||||
|
||||
Many of the test commands described below use *filecheck* to verify their
|
||||
output. Filecheck is a Rust implementation of the LLVM tool of the same name.
|
||||
See the `documentation <https://docs.rs/filecheck/>`_ for details of its syntax.
|
||||
|
||||
Comments in :file:`.clif` files are associated with the entity they follow.
|
||||
Comments in `.clif` files are associated with the entity they follow.
|
||||
This typically means an instruction or the whole function. Those tests that
|
||||
use filecheck will extract comments associated with each function (or its
|
||||
entities) and scan them for filecheck directives. The test output for each
|
||||
@@ -154,24 +88,24 @@ function is then matched against the filecheck directives for that function.
|
||||
|
||||
Comments appearing before the first function in a file apply to every function.
|
||||
This is useful for defining common regular expression variables with the
|
||||
``regex:`` directive, for example.
|
||||
`regex:` directive, for example.
|
||||
|
||||
Note that LLVM's file tests don't separate filecheck directives by their
|
||||
associated function. It verifies the concatenated output against all filecheck
|
||||
directives in the test file. LLVM's :command:`FileCheck` command has a
|
||||
``CHECK-LABEL:`` directive to help separate the output from different functions.
|
||||
`CHECK-LABEL:` directive to help separate the output from different functions.
|
||||
Cranelift's tests don't need this.
|
||||
|
||||
`test cat`
|
||||
----------
|
||||
### `test cat`
|
||||
|
||||
This is one of the simplest file tests, used for testing the conversion to and
|
||||
from textual IR. The ``test cat`` command simply parses each function and
|
||||
from textual IR. The `test cat` command simply parses each function and
|
||||
converts it back to text again. The text of each function is then matched
|
||||
against the associated filecheck directives.
|
||||
|
||||
Example::
|
||||
Example:
|
||||
|
||||
```
|
||||
function %r1() -> i32, f32 {
|
||||
ebb1:
|
||||
v10 = iconst.i32 3
|
||||
@@ -184,17 +118,18 @@ Example::
|
||||
; nextln: v20 = f32const 0.0
|
||||
; nextln: return v10, v20
|
||||
; nextln: }
|
||||
```
|
||||
|
||||
`test verifier`
|
||||
---------------
|
||||
### `test verifier`
|
||||
|
||||
Run each function through the IR verifier and check that it produces the
|
||||
expected error messages.
|
||||
|
||||
Expected error messages are indicated with an ``error:`` directive *on the
|
||||
Expected error messages are indicated with an `error:` directive *on the
|
||||
instruction that produces the verifier error*. Both the error message and
|
||||
reported location of the error is verified::
|
||||
reported location of the error is verified:
|
||||
|
||||
```
|
||||
test verifier
|
||||
|
||||
function %test(i32) {
|
||||
@@ -202,21 +137,22 @@ reported location of the error is verified::
|
||||
jump ebb1 ; error: terminator
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
This example test passes if the verifier fails with an error message containing
|
||||
the sub-string ``"terminator"`` *and* the error is reported for the ``jump``
|
||||
the sub-string `"terminator"` *and* the error is reported for the `jump`
|
||||
instruction.
|
||||
|
||||
If a function contains no ``error:`` annotations, the test passes if the
|
||||
If a function contains no `error:` annotations, the test passes if the
|
||||
function verifies correctly.
|
||||
|
||||
`test print-cfg`
|
||||
----------------
|
||||
### `test print-cfg`
|
||||
|
||||
Print the control flow graph of each function as a Graphviz graph, and run
|
||||
filecheck over the result. See also the :command:`clif-util print-cfg`
|
||||
command::
|
||||
command:
|
||||
|
||||
```
|
||||
; For testing cfg generation. This code is nonsense.
|
||||
test print-cfg
|
||||
test verifier
|
||||
@@ -238,13 +174,14 @@ command::
|
||||
v100 = f32const 0.0
|
||||
return v100
|
||||
}
|
||||
```
|
||||
|
||||
`test domtree`
|
||||
--------------
|
||||
### `test domtree`
|
||||
|
||||
Compute the dominator tree of each function and validate it against the
|
||||
``dominates:`` annotations::
|
||||
`dominates:` annotations::
|
||||
|
||||
```
|
||||
test domtree
|
||||
|
||||
function %test(i32) {
|
||||
@@ -258,24 +195,23 @@ Compute the dominator tree of each function and validate it against the
|
||||
ebb3:
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
Every reachable extended basic block except for the entry block has an
|
||||
*immediate dominator* which is a jump or branch instruction. This test passes
|
||||
if the ``dominates:`` annotations on the immediate dominator instructions are
|
||||
if the `dominates:` annotations on the immediate dominator instructions are
|
||||
both correct and complete.
|
||||
|
||||
This test also sends the computed CFG post-order through filecheck.
|
||||
|
||||
`test legalizer`
|
||||
----------------
|
||||
### `test legalizer`
|
||||
|
||||
Legalize each function for the specified target ISA and run the resulting
|
||||
function through filecheck. This test command can be used to validate the
|
||||
encodings selected for legal instructions as well as the instruction
|
||||
transformations performed by the legalizer.
|
||||
|
||||
`test regalloc`
|
||||
---------------
|
||||
### `test regalloc`
|
||||
|
||||
Test the register allocator.
|
||||
|
||||
@@ -288,16 +224,16 @@ assigning registers and stack slots to all values.
|
||||
|
||||
The resulting function is then run through filecheck.
|
||||
|
||||
`test binemit`
|
||||
--------------
|
||||
### `test binemit`
|
||||
|
||||
Test the emission of binary machine code.
|
||||
|
||||
The functions must contains instructions that are annotated with both encodings
|
||||
and value locations (registers or stack slots). For instructions that are
|
||||
annotated with a `bin:` directive, the emitted hexadecimal machine code for
|
||||
that instruction is compared to the directive::
|
||||
that instruction is compared to the directive:
|
||||
|
||||
```
|
||||
test binemit
|
||||
isa riscv
|
||||
|
||||
@@ -309,6 +245,7 @@ that instruction is compared to the directive::
|
||||
[R#200c,%x8] v11 = isub v0, v1 ; bin: 40628433
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
If any instructions are unencoded (indicated with a `[-]` encoding field), they
|
||||
will be encoded using the same mechanism as the legalizer uses. However,
|
||||
@@ -318,77 +255,70 @@ sequences. Instead the test will fail.
|
||||
Value locations must be present if they are required to compute the binary
|
||||
bits. Missing value locations will cause the test to crash.
|
||||
|
||||
`test simple-gvn`
|
||||
-----------------
|
||||
### `test simple-gvn`
|
||||
|
||||
Test the simple GVN pass.
|
||||
|
||||
The simple GVN pass is run on each function, and then results are run
|
||||
through filecheck.
|
||||
|
||||
`test licm`
|
||||
-----------------
|
||||
### `test licm`
|
||||
|
||||
Test the LICM pass.
|
||||
|
||||
The LICM pass is run on each function, and then results are run
|
||||
through filecheck.
|
||||
|
||||
`test dce`
|
||||
-----------------
|
||||
### `test dce`
|
||||
|
||||
Test the DCE pass.
|
||||
|
||||
The DCE pass is run on each function, and then results are run
|
||||
through filecheck.
|
||||
|
||||
`test shrink`
|
||||
-----------------
|
||||
### `test shrink`
|
||||
|
||||
Test the instruction shrinking pass.
|
||||
|
||||
The shrink pass is run on each function, and then results are run
|
||||
through filecheck.
|
||||
|
||||
`test preopt`
|
||||
-----------------
|
||||
### `test preopt`
|
||||
|
||||
Test the preopt pass.
|
||||
|
||||
The preopt pass is run on each function, and then results are run
|
||||
through filecheck.
|
||||
|
||||
`test postopt`
|
||||
-----------------
|
||||
### `test postopt`
|
||||
|
||||
Test the postopt pass.
|
||||
|
||||
The postopt pass is run on each function, and then results are run
|
||||
through filecheck.
|
||||
|
||||
`test compile`
|
||||
--------------
|
||||
### `test compile`
|
||||
|
||||
Test the whole code generation pipeline.
|
||||
|
||||
Each function is passed through the full ``Context::compile()`` function
|
||||
Each function is passed through the full `Context::compile()` function
|
||||
which is normally used to compile code. This type of test often depends
|
||||
on assertions or verifier errors, but it is also possible to use
|
||||
filecheck directives which will be matched against the final form of the
|
||||
Cranelift IR right before binary machine code emission.
|
||||
|
||||
`test run`
|
||||
----------
|
||||
### `test run`
|
||||
|
||||
Compile and execute a function.
|
||||
|
||||
Add a ``; run`` directive after each function that should be executed. These
|
||||
functions must have the signature ``() -> bNN`` where ``bNN`` is some sort of
|
||||
boolean, e.g. ``b1`` or ``b32``. A ``true`` value is interpreted as a successful
|
||||
test execution, whereas a ``false`` value is interpreted as a failed test.
|
||||
Add a `; run` directive after each function that should be executed. These
|
||||
functions must have the signature `() -> bNN` where `bNN` is some sort of
|
||||
boolean, e.g. `b1` or `b32`. A `true` value is interpreted as a successful
|
||||
test execution, whereas a `false` value is interpreted as a failed test.
|
||||
|
||||
Example::
|
||||
Example:
|
||||
|
||||
```
|
||||
test run
|
||||
|
||||
function %trivial_test() -> b1 {
|
||||
@@ -397,3 +327,4 @@ Example::
|
||||
return v0
|
||||
}
|
||||
; run
|
||||
```
|
||||
@@ -4,7 +4,7 @@ name = "cranelift-entity"
|
||||
version = "0.59.0"
|
||||
description = "Data structures using entity references as mapping keys"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-entity"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.59.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Emit Cranelift output to native object files with Faerie"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-faerie"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
@@ -4,7 +4,7 @@ authors = ["The Cranelift Project Developers"]
|
||||
version = "0.59.0"
|
||||
description = "Test driver and implementations of the filetest commands"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/en/latest/testing.html#file-tests"
|
||||
documentation = "https://docs.rs/cranelift-filetests"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
publish = false
|
||||
edition = "2018"
|
||||
|
||||
@@ -4,7 +4,7 @@ name = "cranelift-frontend"
|
||||
version = "0.59.0"
|
||||
description = "Cranelift IR builder helper"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-frontend"
|
||||
categories = ["no-std"]
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.59.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Support for linking functions and data with Cranelift"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-module"
|
||||
categories = ["no-std"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.59.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Emit Cranelift output to native object files with `object`"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-object"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
@@ -4,7 +4,7 @@ name = "cranelift-preopt"
|
||||
version = "0.59.0"
|
||||
description = "Support for optimizations in Cranelift"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-preopt"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -4,7 +4,7 @@ name = "cranelift-reader"
|
||||
version = "0.59.0"
|
||||
description = "Cranelift textual IR reader"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-reader"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.59.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "A simple JIT library backed by Cranelift"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift-simplejit"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
@@ -4,7 +4,7 @@ name = "cranelift"
|
||||
version = "0.59.0"
|
||||
description = "Umbrella for commonly-used cranelift crates"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
documentation = "https://docs.rs/cranelift"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -5,4 +5,4 @@ If you're looking for a complete WebAssembly implementation that uses this
|
||||
library, see [Wasmtime].
|
||||
|
||||
[Wasmtime]: https://github.com/bytecodealliance/wasmtime
|
||||
[Cranelift IR]: https://cranelift.readthedocs.io/en/latest/ir.html
|
||||
[Cranelift IR]: https://github.com/bytecodealliance/wasmtime/blob/master/cranelift/docs/ir.md
|
||||
|
||||
@@ -71,7 +71,7 @@ pub enum WasmError {
|
||||
/// Cranelift can compile very large and complicated functions, but the [implementation has
|
||||
/// limits][limits] that cause compilation to fail when they are exceeded.
|
||||
///
|
||||
/// [limits]: https://cranelift.readthedocs.io/en/latest/ir.html#implementation-limits
|
||||
/// [limits]: https://github.com/bytecodealliance/wasmtime/blob/master/cranelift/docs/ir.md#implementation-limits
|
||||
#[error("Implementation limit exceeded")]
|
||||
ImplLimitExceeded,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user