Browse Source

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.
pull/1249/head
Alex Crichton 5 years ago
committed by GitHub
parent
commit
3179dcf6f1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Cargo.toml
  2. 4
      README.md
  3. 2
      cranelift/Cargo.toml
  4. 22
      cranelift/README.md
  5. 2
      cranelift/bforest/Cargo.toml
  6. 2
      cranelift/codegen/Cargo.toml
  7. 2
      cranelift/codegen/src/result.rs
  8. 24
      cranelift/docs/Makefile
  9. 16
      cranelift/docs/callex.clif
  10. 69
      cranelift/docs/clif_lexer.py
  11. 83
      cranelift/docs/compare-llvm.md
  12. 169
      cranelift/docs/conf.py
  13. 8
      cranelift/docs/example.c
  14. 39
      cranelift/docs/example.clif
  15. 16
      cranelift/docs/heapex-dyn.clif
  16. 15
      cranelift/docs/heapex-sm32.clif
  17. 14
      cranelift/docs/heapex-sm64.clif
  18. 59
      cranelift/docs/index.md
  19. 467
      cranelift/docs/ir.md
  20. 8
      cranelift/docs/langref.rst
  21. 36
      cranelift/docs/make.bat
  22. 386
      cranelift/docs/meta.rst
  23. 71
      cranelift/docs/regalloc.md
  24. 195
      cranelift/docs/testing.md
  25. 2
      cranelift/entity/Cargo.toml
  26. 2
      cranelift/faerie/Cargo.toml
  27. 2
      cranelift/filetests/Cargo.toml
  28. 2
      cranelift/frontend/Cargo.toml
  29. 2
      cranelift/module/Cargo.toml
  30. 2
      cranelift/object/Cargo.toml
  31. 2
      cranelift/preopt/Cargo.toml
  32. 2
      cranelift/reader/Cargo.toml
  33. 2
      cranelift/simplejit/Cargo.toml
  34. 2
      cranelift/umbrella/Cargo.toml
  35. 2
      cranelift/wasm/README.md
  36. 2
      cranelift/wasm/src/environ/spec.rs

2
Cargo.toml

@ -4,7 +4,7 @@ version = "0.12.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Command-line interface for Wasmtime" description = "Command-line interface for Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://bytecodealliance.github.io/wasmtime/cli.html"
categories = ["wasm"] categories = ["wasm"]
keywords = ["webassembly", "wasm"] keywords = ["webassembly", "wasm"]
repository = "https://github.com/bytecodealliance/wasmtime" repository = "https://github.com/bytecodealliance/wasmtime"

4
README.md

@ -65,7 +65,7 @@ Hello, world!
with your needs. It fits on tiny chips as well as makes use of huge servers. 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. 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. quickly generate high-quality machine code at runtime.
* **Configurable**. Whether you need to precompile your wasm ahead of time, * **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 well. Wasmtime developers are intimately engaged with the WebAssembly
standards process all along the way too. standards process all along the way too.
[Cranelift]: https://github.com/bytecodealliance/wasmtime/blob/master/cranelift/README.md
## Documentation ## Documentation
[📚 Read the Wasmtime guide here! 📚][guide] [📚 Read the Wasmtime guide here! 📚][guide]

2
cranelift/Cargo.toml

@ -4,7 +4,7 @@ authors = ["The Cranelift Project Developers"]
version = "0.59.0" version = "0.59.0"
description = "Binaries for testing the Cranelift libraries" description = "Binaries for testing the Cranelift libraries"
license = "Apache-2.0 WITH LLVM-exception" 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" repository = "https://github.com/bytecodealliance/cranelift"
publish = false publish = false
edition = "2018" edition = "2018"

22
cranelift/README.md

@ -4,19 +4,16 @@ Cranelift Code Generator
**A [Bytecode Alliance][BA] project** **A [Bytecode Alliance][BA] project**
Cranelift is a low-level retargetable code generator. It translates a Cranelift is a low-level retargetable code generator. It translates a
[target-independent intermediate [target-independent intermediate representation](docs/ir.md)
representation](https://cranelift.readthedocs.io/en/latest/ir.html)
into executable machine code. into executable machine code.
[BA]: https://bytecodealliance.org/ [BA]: https://bytecodealliance.org/
[![Documentation Status](https://readthedocs.org/projects/cranelift/badge/?version=latest)](https://cranelift.readthedocs.io/en/latest/?badge=latest)
[![Build Status](https://github.com/bytecodealliance/cranelift/workflows/CI/badge.svg)](https://github.com/bytecodealliance/cranelift/actions) [![Build Status](https://github.com/bytecodealliance/cranelift/workflows/CI/badge.svg)](https://github.com/bytecodealliance/cranelift/actions)
[![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=bytecodealliance)](https://app.fuzzit.dev/orgs/bytecodealliance/dashboard) [![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=bytecodealliance)](https://app.fuzzit.dev/orgs/bytecodealliance/dashboard)
[![Chat](https://img.shields.io/badge/chat-zulip-brightgreen.svg)](https://bytecodealliance.zulipchat.com/#narrow/stream/217117-cranelift/topic/general) [![Chat](https://img.shields.io/badge/chat-zulip-brightgreen.svg)](https://bytecodealliance.zulipchat.com/#narrow/stream/217117-cranelift/topic/general)
![Minimum rustc 1.37](https://img.shields.io/badge/rustc-1.37+-green.svg) ![Minimum rustc 1.37](https://img.shields.io/badge/rustc-1.37+-green.svg)
For more information, see [the For more information, see [the documentation](docs/index.md).
documentation](https://cranelift.readthedocs.io/en/latest/?badge=latest).
For an example of how to use the JIT, see the [SimpleJIT Demo], which For an example of how to use the JIT, see the [SimpleJIT Demo], which
implements a toy language. implements a toy language.
@ -160,21 +157,6 @@ features = ["release_max_level_warn"]
``` ```
</details> </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 Editor Support
-------------- --------------

2
cranelift/bforest/Cargo.toml

@ -4,7 +4,7 @@ name = "cranelift-bforest"
version = "0.59.0" version = "0.59.0"
description = "A forest of B+-trees" description = "A forest of B+-trees"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-bforest"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
categories = ["no-std"] categories = ["no-std"]
readme = "README.md" readme = "README.md"

2
cranelift/codegen/Cargo.toml

@ -4,7 +4,7 @@ name = "cranelift-codegen"
version = "0.59.0" version = "0.59.0"
description = "Low-level code generator library" description = "Low-level code generator library"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-codegen"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
categories = ["no-std"] categories = ["no-std"]
readme = "README.md" readme = "README.md"

2
cranelift/codegen/src/result.rs

@ -20,7 +20,7 @@ pub enum CodegenError {
/// Cranelift can compile very large and complicated functions, but the [implementation has /// Cranelift can compile very large and complicated functions, but the [implementation has
/// limits][limits] that cause compilation to fail when they are exceeded. /// 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")] #[error("Implementation limit exceeded")]
ImplLimitExceeded, ImplLimitExceeded,

24
cranelift/docs/Makefile

@ -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)

16
cranelift/docs/callex.clif

@ -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
}

69
cranelift/docs/clif_lexer.py

@ -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'}

83
cranelift/docs/compare-llvm.rst → cranelift/docs/compare-llvm.md

@ -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 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 compilers like [Clang](https://clang.llvm.org), and it is deservedly very
popular. `Chris Lattner's chapter about LLVM popular. [Chris Lattner's chapter about LLVM]
<https://www.aosabook.org/en/llvm.html>`_ in the `Architecture of Open Source (https://www.aosabook.org/en/llvm.html) in the [Architecture of Open Source
Applications <https://aosabook.org/en/index.html>`_ book gives an excellent Applications](https://aosabook.org/en/index.html>) book gives an excellent
overview of the architecture and design of LLVM. overview of the architecture and design of LLVM.
Cranelift and LLVM are superficially similar projects, so it is worth Cranelift and LLVM are superficially similar projects, so it is worth
highlighting some of the differences and similarities. Both projects: 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. differences between target instruction set architectures.
- Depend extensively on SSA form. - Depend extensively on SSA form.
- Have both textual and in-memory forms of their primary intermediate - 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. 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 LLVM uses multiple intermediate representations as it translates a program to
binary machine code: 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 This is the primary intermediate representation which has textual, binary, and
in-memory forms. It serves two main purposes: in-memory forms. It serves two main purposes:
@ -38,7 +35,7 @@ binary machine code:
- Intermediate representation for common mid-level optimizations. A large - Intermediate representation for common mid-level optimizations. A large
library of code analysis and transformation passes operate on LLVM IR. 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 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 the instruction selector. It has both ISA-agnostic and ISA-specific
opcodes. These main passes are run on the SelectionDAG representation: opcodes. These main passes are run on the SelectionDAG representation:
@ -54,7 +51,7 @@ binary machine code:
The SelectionDAG representation automatically eliminates common The SelectionDAG representation automatically eliminates common
subexpressions and dead code. 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 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 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 allocation. Many low-level optimizations run on MI code. The most important
@ -63,7 +60,7 @@ binary machine code:
- Scheduling. - Scheduling.
- Register allocation. - 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 MC serves as the output abstraction layer and is the basis for LLVM's
integrated assembler. It is used for: 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 translate simple code directly to MachineInstrs, bypassing SelectionDAG when
possible. 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 these levels of abstraction. This is possible in part because of Cranelift's
smaller scope. smaller scope.
@ -109,22 +106,21 @@ low-level optimizations are sufficient.
And, it removes some constraints in the mid-level optimize IR design space, And, it removes some constraints in the mid-level optimize IR design space,
making it more feasible to consider ideas such as using a 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 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 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. global variables that may contain references to external symbols too.
In `Cranelift's IR <https://cranelift.readthedocs.io/en/latest/ir.html>`_, In [Cranelift's IR](ir.md)
used by the `cranelift-codegen <https://docs.rs/cranelift-codegen/>`_ crate, used by the [cranelift-codegen](https://docs.rs/cranelift-codegen/) crate,
functions are self-contained, allowing them to be compiled independently. At functions are self-contained, allowing them to be compiled independently. At
this level, there is no explicit module that contains the functions. this level, there is no explicit module that contains the functions.
Module functionality in Cranelift is provided as an optional library layer, in 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 facilities for working with modules, which can contain multiple functions as
well as data objects, and it links them together. 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 condition is false. The Cranelift representation is closer to how machine code
works; LLVM's representation is more abstract. works; LLVM's representation is more abstract.
LLVM uses `phi instructions LLVM uses [phi instructions]
<https://llvm.org/docs/LangRef.html#phi-instruction>`_ in its SSA (https://llvm.org/docs/LangRef.html#phi-instruction) in its SSA
representation. Cranelift passes arguments to EBBs instead. The two representation. Cranelift passes arguments to EBBs instead. The two
representations are equivalent, but the EBB arguments are better suited to representations are equivalent, but the EBB arguments are better suited to
handle EBBs that may contain multiple branches to the same destination block 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 arguments to a function call, and the register allocator treats them very
similarly. Arguments are assigned to registers or stack locations. 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 system. It is less abstract and closer to the types that common ISA registers
can hold. can hold.
- Integer types are limited to powers of two from :clif:type:`i8` to - Integer types are limited to powers of two from `i8` to
:clif:type:`i64`. LLVM can represent integer types of arbitrary bit width. `i64`. LLVM can represent integer types of arbitrary bit width.
- Floating point types are limited to :clif:type:`f32` and :clif:type:`f64` - Floating point types are limited to `f32` and `f64`
which is what WebAssembly provides. It is possible that 16-bit and 128-bit which is what WebAssembly provides. It is possible that 16-bit and 128-bit
types will be added in the future. types will be added in the future.
- Addresses are represented as integers---There are no Cranelift pointer types. - Addresses are represented as integers---There are no Cranelift pointer types.
@ -167,14 +162,13 @@ can hold.
well as array types. well as array types.
Cranelift has multiple boolean types, whereas LLVM simply uses `i1`. The sized 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. where each lane is either all 0 or all 1 bits.
Cranelift instructions and function calls can return multiple result values. LLVM Cranelift instructions and function calls can return multiple result values. LLVM
instead models this by returning a single value of an aggregate type. 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 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 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 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 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 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 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 with only shared instructions, while x86 needs a number of specific
instructions to model addressing modes. 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.

169
cranelift/docs/conf.py

@ -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')

8
cranelift/docs/example.c

@ -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;
}

39
cranelift/docs/example.clif

@ -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
}

16
cranelift/docs/heapex-dyn.clif

@ -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
}

15
cranelift/docs/heapex-sm32.clif

@ -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
}

14
cranelift/docs/heapex-sm64.clif

@ -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
}

59
cranelift/docs/index.rst → cranelift/docs/index.md

@ -1,73 +1,62 @@
Cranelift Code Generator # Cranelift Documentation
========================
Contents: ## Miscellaneous documentation pages:
.. toctree:: - [Cranelift IR](ir.md)
:maxdepth: 1 Cranelift IR is the data structure that most of the compiler operates on.
ir - [Testing Cranelift](testing.md)
meta This page documents Cranelift's testing frameworks.
testing
regalloc
compare-llvm
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, This is an umbrella crate that re-exports the codegen and frontend crates,
to make them easier to use. 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 This is the core code generator crate. It takes Cranelift IR as input
and emits encoded machine instructions, along with symbolic relocations, and emits encoded machine instructions, along with symbolic relocations,
as output. 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 This crate contains the meta-language utilities and descriptions used by the
code generator. code generator.
`cranelift-wasm <https://docs.rs/cranelift-wasm/>`_ - [cranelift-wasm](https://docs.rs/cranelift-wasm)
This crate translates WebAssembly code into Cranelift IR. 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. 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 This crate performs auto-detection of the host, allowing Cranelift to
generate code optimized for the machine it's running on. 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 This crate translates from Cranelift IR's text format into Cranelift IR
in in-memory data structures. 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 This crate manages compiling multiple functions and data objects
together. 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 This crate provides a object-based backend for `cranelift-module`, which
emits native object files using the emits native object files using the
`object <https://github.com/gimli-rs/object>`_ library. `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 This crate provides a faerie-based backend for `cranelift-module`, which
emits native object files using the emits native object files using the
`faerie <https://github.com/m4b/faerie>`_ library. `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 This crate provides a simple JIT backend for `cranelift-module`, which
emits code and data into memory. emits code and data into memory.
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Todo list
=========
.. todolist::

467
cranelift/docs/ir.rst → cranelift/docs/ir.md

@ -1,57 +1,99 @@
********************** # Cranelift IR Reference
Cranelift IR Reference
**********************
.. default-domain:: clif ## Forward
.. highlight:: clif
.. todo:: Update the IR reference 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].
This document is likely to be outdated and missing some important [the `InstBuilder` documentation]: https://docs.rs/cranelift-codegen/latest/cranelift_codegen/ir/trait.InstBuilder.html
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
The Cranelift intermediate representation (:term:`IR`) has two primary forms: ## Intro
The Cranelift intermediate representation ([IR]) has two primary forms:
an *in-memory data structure* that the code generator library is using, and a 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. *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 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. 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 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 handles at the same time, but the functions don't share any data or reference
each other directly. each other directly.
This is a simple C function that computes the average of an array of floats: This is a simple C function that computes the average of an array of floats:
.. literalinclude:: example.c ```c
:language: 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: Here is the same function compiled into Cranelift IR:
.. literalinclude:: example.clif ```
:language: clif test verifier
:lines: 2-
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 first line of a function definition provides the function *name* and
the :term:`function signature` which declares the parameter and return types. the [function signature] which declares the parameter and return types.
Then follows the :term:`function preamble` which declares a number of entities Then follows the [function preamble] which declares a number of entities
that can be referenced inside the function. In the example above, the preamble 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 After the preamble follows the [function body] which consists of
:term:`extended basic block`\s (EBBs), the first of which is the [extended basic block]s (EBBs), the first of which is the
:term:`entry block`. Every EBB ends with a :term:`terminator instruction`, so [entry block]. Every EBB ends with a [terminator instruction], so
execution can never fall through to the next EBB without an explicit branch. 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:: .. productionlist::
function_list : { function } function_list : { function }
@ -59,14 +101,13 @@ A ``.clif`` file consists of a sequence of independent function definitions:
preamble : { preamble_decl } preamble : { preamble_decl }
function_body : { extended_basic_block } 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 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 means that every value is defined exactly once, and every use of a value must be
dominated by the definition. 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 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. is transferred to the EBB, argument values for the parameters must be provided.
When entering a function, the incoming function parameters are passed as 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 Instructions define zero, one, or more result values. All SSA values are either
EBB parameters or instruction results. EBB parameters or instruction results.
In the example above, the loop induction variable ``i`` is represented as three 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 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 `ebb2`, the EBB parameter `v5` represents the value of the induction
variable during each iteration. Finally, ``v12`` is computed as the induction variable during each iteration. Finally, `v12` is computed as the induction
variable value for the next iteration. variable value for the next iteration.
The `cranelift_frontend` crate contains utilities for translating from programs The `cranelift_frontend` crate contains utilities for translating from programs
containing multiple assignments to the same variables into SSA form for 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, 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 and can have their address taken with `stack_addr`, which supports C-like
programming languages where local variables can have their address taken. 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 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 vectors) of the value. Many instructions are polymorphic -- they can operate on
different types. different types.
Boolean types ### Boolean types
-------------
Boolean values are either true or false. Boolean values are either true or false.
@ -119,8 +156,7 @@ zero bits or all one bits.
- b32 - b32
- b64 - b64
Integer types ### Integer types
-------------
Integer values have a fixed size and can be interpreted as either signed or 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 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 - i32
- i64 - i64
Floating point types ### Floating point types
--------------------
The floating point types have the IEEE 754 semantics that are supported by most The floating point types have the IEEE 754 semantics that are supported by most
hardware, except that non-default rounding modes, unmasked exceptions, and hardware, except that non-default rounding modes, unmasked exceptions, and
@ -162,8 +197,7 @@ instructions are encoded as follows:
- f32 - f32
- f64 - f64
CPU flags types ### CPU flags types
---------------
Some target ISAs use CPU flags to represent the result of a comparison. These 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 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 - iflags
- fflags - fflags
SIMD vector types ### SIMD vector types
-----------------
A SIMD vector type represents a vector of values from one of the scalar 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 (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. 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 These are not concrete types, but convenient names used to refer to real types
in this reference. in this reference.
@ -254,8 +286,7 @@ Mem
Testable Testable
Either `b1` or `iN`. 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 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. 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. A floating point condition code. See the `fcmp` instruction for details.
The two IEEE floating point immediate types `ieee32` and `ieee64` 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 format. Decimal floating point literals are not allowed because some computer
systems can round differently when converting to binary. The hexadecimal 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 floating point format is mostly the same as the one used by C99, but extended
to represent all NaN bit patterns: to represent all NaN bit patterns:
Normal numbers Normal numbers
Compatible with C99: ``-0x1.Tpe`` where ``T`` are the trailing Compatible with C99: `-0x1.Tpe` where `T` are the trailing
significand bits encoded as hexadecimal, and ``e`` is the unbiased exponent significand bits encoded as hexadecimal, and `e` is the unbiased exponent
as a decimal number. `ieee32` has 23 trailing significand bits. They 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 are padded with an extra LSB to produce 6 hexadecimal digits. This is not
necessary for `ieee64` which has 52 trailing significand bits necessary for `ieee64` which has 52 trailing significand bits
forming 13 hexadecimal digits with no padding. forming 13 hexadecimal digits with no padding.
Zeros 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 Subnormal numbers
Compatible with C99: ``-0x0.Tpemin`` where ``T`` are the trailing Compatible with C99: `-0x0.Tpemin` where `T` are the trailing
significand bits encoded as hexadecimal, and ``emin`` is the minimum exponent significand bits encoded as hexadecimal, and `emin` is the minimum exponent
as a decimal number. as a decimal number.
Infinities Infinities
Either ``-Inf`` or ``Inf``. Either `-Inf` or `Inf`.
Quiet NaNs Quiet NaNs
Quiet NaNs have the MSB of the trailing significand set. If the remaining 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 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. significand bits encoded as hexadecimal.
Signaling NaNs 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 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 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. instruction in the EBB.
JT = jump_table [EBB0, EBB1, ..., EBBn] 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 This declares a jump table for use by the `br_table` indirect branch
instruction. Entries in the table are EBB names. 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 The EBBs listed must belong to the current function, and they can't have
any arguments. any arguments.
:arg EBB0: Target EBB when ``x = 0``. :arg EBB0: Target EBB when `x = 0`.
:arg EBB1: Target EBB when ``x = 1``. :arg EBB1: Target EBB when `x = 1`.
:arg EBBn: Target EBB when ``x = n``. :arg EBBn: Target EBB when `x = n`.
:result: A jump table identifier. (Not an SSA value). :result: A jump table identifier. (Not an SSA value).
Traps stop the program because something went wrong. The exact behavior depends 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. 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 target function may be determined dynamically at runtime, but the signature must
be known when the function call is compiled. The function signature describes be known when the function call is compiled. The function signature describes
how to call the function, including parameters, return values, and the calling 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 system, a function's calling convention is only fully determined by a
`(TargetIsa, CallConv)` tuple. `(TargetIsa, CallConv)` tuple.
=========== =========================================== | Name | Description |
Name Description | ----------| ---------- |
=========== =========================================== | sret | pointer to a return value in memory |
sret pointer to a return value in memory | link | return address |
link return address | fp | the initial value of the frame pointer |
fp the initial value of the frame pointer | csr | callee-saved register |
csr callee-saved register | vmctx | VM context pointer, which may contain pointers to heaps etc. |
vmctx VM context pointer, which may contain pointers to heaps etc. | sigid | signature id, for checking caller/callee signature compatibility |
sigid signature id, for checking caller/callee signature compatibility | stack_limit | limit value for the size of the stack |
stack_limit limit value for the size of the stack
=========== =========================================== | Name | Description |
| --------- | ----------- |
========== =========================================== | fast | not-ABI-stable convention for best performance |
Name Description | cold | not-ABI-stable convention for infrequently executed code |
========== =========================================== | system_v | System V-style convention used on many platforms |
fast not-ABI-stable convention for best performance | fastcall | Windows "fastcall" convention, also used for x64 and ARM |
cold not-ABI-stable convention for infrequently executed code | baldrdash_system_v | SpiderMonkey WebAssembly convention on platforms natively using SystemV. |
system_v System V-style convention used on many platforms | baldrdash_windows | SpiderMonkey WebAssembly convention on platforms natively using Windows. |
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 The "not-ABI-stable" conventions do not follow an external specification and
may change between versions of Cranelift. 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 dependent. These flags support interfacing with code produced by other
compilers. compilers.
Functions that are called directly must be declared in the :term:`function Functions that are called directly must be declared in the [function preamble]:
preamble`:
FN = [colocated] NAME signature FN = [colocated] NAME signature
Declare a function so it can be called directly. 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: This simple example illustrates direct function calls and signatures:
.. literalinclude:: callex.clif ```
:language: clif test verifier
:lines: 3-
Indirect function calls use a signature declared in the preamble. function %gcd(i32 uext, i32 uext) -> i32 uext system_v {
fn0 = %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext
.. _memory: 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
======
Cranelift provides fully general `load` and `store` instructions for accessing Cranelift provides fully general `load` and `store` instructions for accessing
memory, as well as :ref:`extending loads and truncating stores memory, as well as [extending loads and truncating stores](#extending-loads-and-truncating-stores).
<extload-truncstore>`.
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 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 There are also more restricted operations for accessing specific types of memory
objects. objects.
Additionally, instructions are provided for handling multi-register addressing. 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 Loads and stores can have flags that loosen their semantics in order to enable
optimizations. optimizations.
======== =========================================== | Flag | Description |
Flag Description | -------- | ----------- |
======== =========================================== | notrap | Memory is assumed to be [accessible]. |
notrap Memory is assumed to be :term:`accessible`. | aligned | Trapping allowed for misaligned accesses. |
aligned Trapping allowed for misaligned accesses. | readonly | The data at the specified address will not modified between when this function is called and exited. |
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 When the `accessible` flag is set, the behavior is undefined if the memory
is not :term:`accessible`. is not [accessible].
Loads and stores are *misaligned* if the resultant address is not a multiple of 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, 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 but when the `aligned` flag is set, a misaligned memory access is allowed to
:term:`trap`. [trap].
Explicit Stack Slots ### Explicit Stack Slots
--------------------
One set of restricted memory operations access the current function's stack 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 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 allocated in the [function preamble]. Stack slots are not typed, they
simply represent a contiguous sequence of :term:`accessible` bytes in the stack simply represent a contiguous sequence of [accessible] bytes in the stack
frame. frame.
SS = explicit_slot Bytes, Flags... 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. and stack slot alignments.
It's also possible to obtain the address of a stack slot, which can be used 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 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 v0 = stack_load.f64 ss3, 16
; Expands to: ; 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 When Cranelift code is running in a sandbox, it can also be necessary to include
stack overflow checks in the prologue. 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 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 value is computed at runtime by `global_value`, possibly using
@ -579,8 +607,7 @@ GV = [colocated] symbol Name
:arg Name: External name. :arg Name: External name.
:result GV: Global value. :result GV: Global value.
Heaps ### Heaps
-----
Code compiled from WebAssembly or asm.js runs in a sandbox where it can't access 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 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*. concept of *heaps*.
A heap is declared in the function preamble and can be accessed with the 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 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 the native pointer size, for example unsigned `i32` offsets on a 64-bit
architecture. architecture.
@ -606,27 +633,26 @@ architecture.
A heap appears as three consecutive ranges of address space: 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 heap may have a minimum guaranteed size which means that some mapped pages
are always present. are always present.
2. The *unmapped pages* is a possibly empty range of address space that may be 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 mapped in the future when the heap is grown. They are [addressable] but
not :term:`accessible`. not [accessible].
3. The *offset-guard pages* is a range of address space that is guaranteed to 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 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 heap accesses with a shared base pointer. They are [addressable] but
not :term:`accessible`. not [accessible].
The *heap bound* is the total size of the mapped and unmapped pages. This is 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 the bound that `heap_addr` checks against. Memory accesses inside the
heap bounds can trap if they hit an unmapped page (which is not 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 Two styles of heaps are supported, *static* and *dynamic*. They behave
differently when resized. differently when resized.
Static heaps #### Static heaps
~~~~~~~~~~~~
A *static heap* starts out with all the address space it will ever need, so it 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 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. pages.
:arg OffsetGuardBytes: Size of the offset-guard pages in bytes. :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 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 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 BoundGV: Global value containing the current heap bound in bytes.
:arg OffsetGuardBytes: Size of the offset-guard pages 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 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 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 of a 4 GB fixed bound and 1-byte bounds checks means that no code needs to be
generated for bounds checks at all: generated for bounds checks at all:
.. literalinclude:: heapex-sm64.clif ```
:language: clif test verifier
:lines: 2-
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 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 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: KB offset-guard page still has opportunities for sharing bounds checking code:
.. literalinclude:: heapex-sm32.clif ```
:language: clif test verifier
:lines: 2-
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 If the upper bound on the heap size is too large, a dynamic heap is required
instead. instead.
Finally, a runtime environment that simply allocates a heap with 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: full bounds checking is required for each access:
.. literalinclude:: heapex-dyn.clif ```
:language: clif test verifier
:lines: 2-
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 Code compiled from WebAssembly often needs access to objects outside of its
linear memory. WebAssembly uses *tables* to allow programs to refer to opaque linear memory. WebAssembly uses *tables* to allow programs to refer to opaque
values through integer indices. values through integer indices.
A table is declared in the function preamble and can be accessed with the 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 Table addresses can be smaller than the native pointer size, for example
unsigned `i32` offsets on a 64-bit architecture. unsigned `i32` offsets on a 64-bit architecture.
A table appears as a consecutive range of address space, conceptually A table appears as a consecutive range of address space, conceptually
divided into elements of fixed sizes, which are identified by their index. 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 *table bound* is the number of elements currently in the table. This is
the bound that `table_addr` checks against. 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 BoundGV: Global value containing the current heap bound in elements.
:arg ElementSize: Size of each element. :arg ElementSize: Size of each element.
Constant materialization ### Constant materialization
------------------------
A few instructions have variants that take immediate operands, but in general 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`, an instruction is required to load a constant into an SSA value: `iconst`,
`f32const`, `f64const` and `bconst` serve this purpose. `f32const`, `f64const` and `bconst` serve this purpose.
Bitwise operations ### Bitwise operations
------------------
The bitwise operations and operate on any value type: Integers, floating point The bitwise operations and operate on any value type: Integers, floating point
numbers, and booleans. When operating on integer or floating point types, the 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. The bit-counting instructions are scalar only.
Floating point operations ### Floating point operations
-------------------------
These operations generally follow IEEE 754-2008 semantics. 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 The sign manipulating instructions work as bitwise operations, so they don't
have special behavior for signaling NaN operands. The exponent and trailing have special behavior for signaling NaN operands. The exponent and trailing
significand bits are always preserved. significand bits are always preserved.
Minimum and maximum #### Minimum and maximum
~~~~~~~~~~~~~~~~~~~
These instructions return the larger or smaller of their operands. Note that These instructions return the larger or smaller of their operands. Note that
unlike the IEEE 754-2008 `minNum` and `maxNum` operations, these instructions 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`. 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 These instructions round their argument to a nearby integral value, still
represented as a floating point number. represented as a floating point number.
Conversion operations ### Extending loads and truncating stores
---------------------
.. _extload-truncstore:
Extending loads and truncating stores
-------------------------------------
Most ISAs provide instructions that load an integer value smaller than a register 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 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. accesses.
These instructions succeed, trap, or have undefined behavior, under the same 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 Target ISAs can define supplemental instructions that do not make sense to
support generally. support generally.
x86 ### x86
-----
Instructions that can only be used by the x86 target ISA. 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; Frontends don't need to emit the instructions in this section themselves;
Cranelift will generate them automatically as needed. Cranelift will generate them automatically as needed.
Legalization operations ### Legalization operations
-----------------------
These instructions are used as helpers when legalizing types and operations for These instructions are used as helpers when legalizing types and operations for
the target ISA. the target ISA.
Special register operations ### Special register operations
---------------------------
The prologue and epilogue of a function needs to manipulate special registers like the stack 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. 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 These operations are for working with the "flags" registers of some CPU
architectures. architectures.
Live range splitting ### Live range splitting
--------------------
Cranelift's register allocator assigns each SSA value to a register or a spill 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 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` `regmove` instruction, and to and from stack slots by `regspill`
and `regfill`. and `regfill`.
Instruction groups ## Instruction groups
==================
All of the shared instructions are part of the `base` instruction All of the shared instructions are part of the `base` instruction
group. group.
Target ISAs may define further instructions in their own instruction groups. 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 Cranelift's intermediate representation imposes some limits on the size of
functions and the number of entities allowed. If these limits are exceeded, the 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 This is probably not possible to achieve given the limit on the number of
arguments, except by requiring extremely large offsets for stack arguments. arguments, except by requiring extremely large offsets for stack arguments.
Glossary ## Glossary
========
.. glossary::
addressable addressable
Memory in which loads and stores have defined behavior. They either Memory in which loads and stores have defined behavior. They either
succeed or :term:`trap`, depending on whether the memory is succeed or [trap], depending on whether the memory is
:term:`accessible`. [accessible].
accessible accessible
:term:`Addressable` memory in which loads and stores always succeed [Addressable] memory in which loads and stores always succeed
without :term:`trapping`, except where specified otherwise (eg. with the without [trapping], except where specified otherwise (eg. with the
`aligned` flag). Heaps, globals, tables, and the stack may contain `aligned` flag). Heaps, globals, tables, and the stack may contain
accessible, merely addressable, and outright unaddressable regions. accessible, merely addressable, and outright unaddressable regions.
There may also be additional regions of addressable and/or accessible There may also be additional regions of addressable and/or accessible
@ -928,7 +967,7 @@ Glossary
the last instruction. the last instruction.
entry block 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 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 first block in the function. The types of the entry block arguments must
match the types of arguments in the function signature. match the types of arguments in the function signature.
@ -936,12 +975,12 @@ Glossary
extended basic block extended basic block
EBB EBB
A maximal sequence of instructions that can only be entered from the 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 the last one. An EBB can contain conditional branches that can fall
through to the following instructions in the block, but only the first through to the following instructions in the block, but only the first
instruction in the EBB can be a branch target. 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 so execution cannot flow through to the next EBB in the function. (But
there may be a branch to the next EBB.) there may be a branch to the next EBB.)
@ -971,7 +1010,7 @@ Glossary
- Type and flags of each return value. - Type and flags of each return value.
Not all function attributes are part of the signature. For example, a 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, is not necessary to know when calling it, so it is just an attribute,
and not part of the signature. and not part of the signature.
@ -996,17 +1035,17 @@ Glossary
stack slot stack slot
A fixed size memory allocation in the current function's activation A fixed size memory allocation in the current function's activation
frame. These include :term:`explicit stack slot`\s and frame. These include [explicit stack slot]s and
:term:`spill stack slot`\s. [spill stack slot]s.
explicit stack slot explicit stack slot
A fixed size memory allocation in the current function's activation 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. be created by frontends and they may have their addresses taken.
spill stack slot spill stack slot
A fixed size memory allocation in the current function's activation 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 only created during register allocation, and they may not have their
address taken. address taken.

8
cranelift/docs/langref.rst

@ -1,8 +0,0 @@
:orphan:
****************
Redirection Page
****************
Cranelift's IR is documented in :doc:`ir`. Please update links to point to
this new page.

36
cranelift/docs/make.bat

@ -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

386
cranelift/docs/meta.rst

@ -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.

71
cranelift/docs/regalloc.rst → cranelift/docs/regalloc.md

@ -1,9 +1,4 @@
******************************** # Register Allocation in Cranelift
Register Allocation in Cranelift
********************************
.. default-domain:: clif
.. highlight:: clif
Cranelift uses a *decoupled, SSA-based* register allocator. Decoupled means that Cranelift uses a *decoupled, SSA-based* register allocator. Decoupled means that
register allocation is split into two primary phases: *spilling* and 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 Before the register allocator is run, all instructions in the function must be
*legalized*, which means that every instruction has an entry in the *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 constraints on the instruction's operands that the register allocator must
satisfy. 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 or stack slot location for all SSA values used by the function. The
register allocator may have inserted :inst:`spill`, :inst:`fill`, and register allocator may have inserted `spill`, `fill`, and
:inst:`copy` instructions to make that possible. `copy` instructions to make that possible.
SSA-based register allocation ## SSA-based register allocation
=============================
The phases of the SSA-based register allocator are: The phases of the SSA-based register allocator are:
@ -37,14 +31,14 @@ Coalescing
Spilling Spilling
The process of deciding which SSA values go in a stack slot and which 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 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. reduce the number of values kept in registers.
After spilling, the number of live register values never exceeds the number After spilling, the number of live register values never exceeds the number
of available registers. of available registers.
Reload 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 instructions that expect their operands in registers won't see values that
live on the stack and vice versa. 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 values in registers never exceeds the number of available registers. This
sounds simple enough in theory, but in practice there are some complications. 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 In practice, instruction set architectures don't have "K interchangeable
registers", and register pressure can't be measured with a single number. There 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. Win64 callees only save the low 128 bits of AVX registers.
ABI boundaries also affect the location of arguments to the entry block and 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 Aliasing registers
Different registers sometimes share the same bits in the register bank. Different registers sometimes share the same bits in the register bank.
@ -121,8 +114,7 @@ Early clobbers
assembly and in some other special cases. assembly and in some other special cases.
Liveness Analysis ## Liveness Analysis
=================
All the register allocator passes need to know exactly where SSA values are All the register allocator passes need to know exactly where SSA values are
live. The liveness analysis computes this information. 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 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. 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: with a few important differences:
- The Cranelift ``LiveRange`` only covers a single SSA value, while LLVM's - The Cranelift `LiveRange` only covers a single SSA value, while LLVM's
``LiveInterval`` represents the union of multiple related SSA values in a `LiveInterval` represents the union of multiple related SSA values in a
virtual register. This makes Cranelift's representation smaller because virtual register. This makes Cranelift's representation smaller because
individual segments don't have to annotated with a value number. individual segments don't have to annotated with a value number.
- Cranelift stores the def-interval separately from a list of coalesced live-in - 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 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. This makes the overlap check logarithmic in the number of live-in
intervals instead of linear. intervals instead of linear.
- LLVM represents a program point as ``SlotIndex`` which holds a pointer to a - LLVM represents a program point as `SlotIndex` which holds a pointer to a
32-byte ``IndexListEntry`` struct. The entries are organized in a double 32-byte `IndexListEntry` struct. The entries are organized in a double
linked list that mirrors the ordering of instructions in a basic block. This linked list that mirrors the ordering of instructions in a basic block. This
allows 'tombstone' program points corresponding to instructions that have allows 'tombstone' program points corresponding to instructions that have
been deleted. been deleted.
@ -190,12 +182,12 @@ with a few important differences:
A consequence of Cranelift's more compact representation is that two program A consequence of Cranelift's more compact representation is that two program
points can't be compared without the context of a function layout. 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 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 { function %interference(i32, i32) -> i32 {
ebb0(v0: i32, v1: i32): ebb0(v0: i32, v1: i32):
brz v0, ebb1(v1) brz v0, ebb1(v1)
@ -205,15 +197,17 @@ that can arise around EBB parameters and arguments. Consider this simple example
v3 = iadd v1, v2 v3 = iadd v1, v2
return v3 return v3
} }
```
Here, the value ``v1`` is both passed as an argument to ``ebb1`` *and* it is 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 live in to the EBB because it is used by the `iadd` instruction. Since
EBB arguments on the :inst:`brz` instruction need to be in the same register as 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 the corresponding EBB parameter `v2`, there is going to be interference
between ``v1`` and ``v2`` in the ``ebb1`` block. 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 { function %coalesced(i32, i32) -> i32 {
ebb0(v0: i32, v1: i32): ebb0(v0: i32, v1: i32):
v5 = copy v1 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 v3 = iadd.i32 v1, v2
return v3 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. resolving the interference.
The coalescing pass groups the SSA values into sets called *virtual registers* 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. interfere, i.e. they don't overlap anywhere.
Most virtual registers contains only a single isolated SSA value because most 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 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 tracks larger virtual registers and assumes that any value it doesn't know about
is its own singleton virtual register 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. register allocator passes.
Spilling algorithm ## Spilling algorithm
==================
The spilling pass is responsible for lowering the register pressure enough that 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 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 *write* traffic with the spilling heuristic and to minimize stack *read* traffic
with the reload pass. with the reload pass.
Coloring algorithm ## Coloring algorithm
==================
The SSA coloring algorithm is based on a single observation: If two SSA values 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. interfere, one of the values must be live where the other value is defined.

195
cranelift/docs/testing.rst → cranelift/docs/testing.md

@ -1,93 +1,26 @@
***************** # Testing Cranelift
Testing Cranelift
*****************
Cranelift is tested at multiple levels of abstraction and integration. When Cranelift is tested at multiple levels of abstraction and integration. When
possible, Rust unit tests are used to verify single functions and types. When possible, Rust unit tests are used to verify single functions and types. When
testing the interaction between compiler passes, file-level tests are testing the interaction between compiler passes, file-level tests are
appropriate. appropriate.
The top-level shell script :file:`test-all.sh` runs all of the tests in the ## Rust tests
Cranelift repository.
Rust tests
==========
.. highlight:: rust
Rust and Cargo have good support for testing. Cranelift uses unit tests, doc 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
Unit tests each of these forms of test.
----------
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 [Rust By Example page on Testing]: https://doc.rust-lang.org/rust-by-example/testing.html
==========
.. highlight:: clif ## File tests
Compilers work with large data structures representing programs, and it quickly Compilers work with large data structures representing programs, and it quickly
gets unwieldy to generate test data programmatically. File-level tests make it gets unwieldy to generate test data programmatically. File-level tests make it
easier to provide substantial input functions for the compiler tests. 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 hierarchy. Each file has a header describing what to test followed by a number
of input functions in the :doc:`Cranelift textual intermediate representation of input functions in the :doc:`Cranelift textual intermediate representation
<ir>`: <ir>`:
@ -108,8 +41,8 @@ header:
isa_specs : { [`settings`] isa_spec } isa_specs : { [`settings`] isa_spec }
isa_spec : "isa" isa_name { `option` } "\n" isa_spec : "isa" isa_name { `option` } "\n"
The options given on the ``isa`` line modify the ISA-specific settings defined in The options given on the `isa` line modify the ISA-specific settings defined in
:file:`cranelift-codegen/meta-python/isa/*/settings.py`. `cranelift-codegen/meta-python/isa/*/settings.py`.
All types of tests allow shared Cranelift settings to be modified: 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 option : flag | setting "=" value
The shared settings available for all target ISAs are defined in 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 test legalizer
set opt_level=best set opt_level=best
set is_pic=1 set is_pic=1
@ -131,22 +65,22 @@ The ``set`` lines apply settings cumulatively::
isa riscv32 supports_m=false isa riscv32 supports_m=false
function %foo() {} function %foo() {}
```
This example will run the legalizer test twice. Both runs will have 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 `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. 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 The filetests are run automatically as part of `cargo test`, and they can
also be run manually with the `clif-util test` command. also be run manually with the `clif-util test` command.
Filecheck ### Filecheck
---------
Many of the test commands described below use *filecheck* to verify their 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. 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. 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 This typically means an instruction or the whole function. Those tests that
use filecheck will extract comments associated with each function (or its use filecheck will extract comments associated with each function (or its
entities) and scan them for filecheck directives. The test output for each 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. Comments appearing before the first function in a file apply to every function.
This is useful for defining common regular expression variables with the 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 Note that LLVM's file tests don't separate filecheck directives by their
associated function. It verifies the concatenated output against all filecheck associated function. It verifies the concatenated output against all filecheck
directives in the test file. LLVM's :command:`FileCheck` command has a 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. 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 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 converts it back to text again. The text of each function is then matched
against the associated filecheck directives. against the associated filecheck directives.
Example:: Example:
```
function %r1() -> i32, f32 { function %r1() -> i32, f32 {
ebb1: ebb1:
v10 = iconst.i32 3 v10 = iconst.i32 3
@ -184,17 +118,18 @@ Example::
; nextln: v20 = f32const 0.0 ; nextln: v20 = f32const 0.0
; nextln: return v10, v20 ; nextln: return v10, v20
; nextln: } ; nextln: }
```
`test verifier` ### `test verifier`
---------------
Run each function through the IR verifier and check that it produces the Run each function through the IR verifier and check that it produces the
expected error messages. 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 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 test verifier
function %test(i32) { function %test(i32) {
@ -202,21 +137,22 @@ reported location of the error is verified::
jump ebb1 ; error: terminator jump ebb1 ; error: terminator
return return
} }
```
This example test passes if the verifier fails with an error message containing 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. 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. function verifies correctly.
`test print-cfg` ### `test print-cfg`
----------------
Print the control flow graph of each function as a Graphviz graph, and run 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` filecheck over the result. See also the :command:`clif-util print-cfg`
command:: command:
```
; For testing cfg generation. This code is nonsense. ; For testing cfg generation. This code is nonsense.
test print-cfg test print-cfg
test verifier test verifier
@ -238,13 +174,14 @@ command::
v100 = f32const 0.0 v100 = f32const 0.0
return v100 return v100
} }
```
`test domtree` ### `test domtree`
--------------
Compute the dominator tree of each function and validate it against the Compute the dominator tree of each function and validate it against the
``dominates:`` annotations:: `dominates:` annotations::
```
test domtree test domtree
function %test(i32) { function %test(i32) {
@ -258,24 +195,23 @@ Compute the dominator tree of each function and validate it against the
ebb3: ebb3:
return return
} }
```
Every reachable extended basic block except for the entry block has an Every reachable extended basic block except for the entry block has an
*immediate dominator* which is a jump or branch instruction. This test passes *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. both correct and complete.
This test also sends the computed CFG post-order through filecheck. 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 Legalize each function for the specified target ISA and run the resulting
function through filecheck. This test command can be used to validate the function through filecheck. This test command can be used to validate the
encodings selected for legal instructions as well as the instruction encodings selected for legal instructions as well as the instruction
transformations performed by the legalizer. transformations performed by the legalizer.
`test regalloc` ### `test regalloc`
---------------
Test the register allocator. Test the register allocator.
@ -288,16 +224,16 @@ assigning registers and stack slots to all values.
The resulting function is then run through filecheck. The resulting function is then run through filecheck.
`test binemit` ### `test binemit`
--------------
Test the emission of binary machine code. Test the emission of binary machine code.
The functions must contains instructions that are annotated with both encodings The functions must contains instructions that are annotated with both encodings
and value locations (registers or stack slots). For instructions that are and value locations (registers or stack slots). For instructions that are
annotated with a `bin:` directive, the emitted hexadecimal machine code for 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 test binemit
isa riscv isa riscv
@ -309,6 +245,7 @@ that instruction is compared to the directive::
[R#200c,%x8] v11 = isub v0, v1 ; bin: 40628433 [R#200c,%x8] v11 = isub v0, v1 ; bin: 40628433
return return
} }
```
If any instructions are unencoded (indicated with a `[-]` encoding field), they If any instructions are unencoded (indicated with a `[-]` encoding field), they
will be encoded using the same mechanism as the legalizer uses. However, 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 Value locations must be present if they are required to compute the binary
bits. Missing value locations will cause the test to crash. bits. Missing value locations will cause the test to crash.
`test simple-gvn` ### `test simple-gvn`
-----------------
Test the simple GVN pass. Test the simple GVN pass.
The simple GVN pass is run on each function, and then results are run The simple GVN pass is run on each function, and then results are run
through filecheck. through filecheck.
`test licm` ### `test licm`
-----------------
Test the LICM pass. Test the LICM pass.
The LICM pass is run on each function, and then results are run The LICM pass is run on each function, and then results are run
through filecheck. through filecheck.
`test dce` ### `test dce`
-----------------
Test the DCE pass. Test the DCE pass.
The DCE pass is run on each function, and then results are run The DCE pass is run on each function, and then results are run
through filecheck. through filecheck.
`test shrink` ### `test shrink`
-----------------
Test the instruction shrinking pass. Test the instruction shrinking pass.
The shrink pass is run on each function, and then results are run The shrink pass is run on each function, and then results are run
through filecheck. through filecheck.
`test preopt` ### `test preopt`
-----------------
Test the preopt pass. Test the preopt pass.
The preopt pass is run on each function, and then results are run The preopt pass is run on each function, and then results are run
through filecheck. through filecheck.
`test postopt` ### `test postopt`
-----------------
Test the postopt pass. Test the postopt pass.
The postopt pass is run on each function, and then results are run The postopt pass is run on each function, and then results are run
through filecheck. through filecheck.
`test compile` ### `test compile`
--------------
Test the whole code generation pipeline. 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 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 on assertions or verifier errors, but it is also possible to use
filecheck directives which will be matched against the final form of the filecheck directives which will be matched against the final form of the
Cranelift IR right before binary machine code emission. Cranelift IR right before binary machine code emission.
`test run` ### `test run`
----------
Compile and execute a function. Compile and execute a function.
Add a ``; run`` directive after each function that should be executed. These Add a `; run` directive after each function that should be executed. These
functions must have the signature ``() -> bNN`` where ``bNN`` is some sort of 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 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. test execution, whereas a `false` value is interpreted as a failed test.
Example:: Example:
```
test run test run
function %trivial_test() -> b1 { function %trivial_test() -> b1 {
@ -397,3 +327,4 @@ Example::
return v0 return v0
} }
; run ; run
```

2
cranelift/entity/Cargo.toml

@ -4,7 +4,7 @@ name = "cranelift-entity"
version = "0.59.0" version = "0.59.0"
description = "Data structures using entity references as mapping keys" description = "Data structures using entity references as mapping keys"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-entity"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
categories = ["no-std"] categories = ["no-std"]
readme = "README.md" readme = "README.md"

2
cranelift/faerie/Cargo.toml

@ -4,7 +4,7 @@ version = "0.59.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
description = "Emit Cranelift output to native object files with Faerie" description = "Emit Cranelift output to native object files with Faerie"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-faerie"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"

2
cranelift/filetests/Cargo.toml

@ -4,7 +4,7 @@ authors = ["The Cranelift Project Developers"]
version = "0.59.0" version = "0.59.0"
description = "Test driver and implementations of the filetest commands" description = "Test driver and implementations of the filetest commands"
license = "Apache-2.0 WITH LLVM-exception" 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" repository = "https://github.com/bytecodealliance/cranelift"
publish = false publish = false
edition = "2018" edition = "2018"

2
cranelift/frontend/Cargo.toml

@ -4,7 +4,7 @@ name = "cranelift-frontend"
version = "0.59.0" version = "0.59.0"
description = "Cranelift IR builder helper" description = "Cranelift IR builder helper"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-frontend"
categories = ["no-std"] categories = ["no-std"]
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
readme = "README.md" readme = "README.md"

2
cranelift/module/Cargo.toml

@ -4,7 +4,7 @@ version = "0.59.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
description = "Support for linking functions and data with Cranelift" description = "Support for linking functions and data with Cranelift"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-module"
categories = ["no-std"] categories = ["no-std"]
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
readme = "README.md" readme = "README.md"

2
cranelift/object/Cargo.toml

@ -4,7 +4,7 @@ version = "0.59.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
description = "Emit Cranelift output to native object files with `object`" description = "Emit Cranelift output to native object files with `object`"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-object"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"

2
cranelift/preopt/Cargo.toml

@ -4,7 +4,7 @@ name = "cranelift-preopt"
version = "0.59.0" version = "0.59.0"
description = "Support for optimizations in Cranelift" description = "Support for optimizations in Cranelift"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-preopt"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
categories = ["no-std"] categories = ["no-std"]
readme = "README.md" readme = "README.md"

2
cranelift/reader/Cargo.toml

@ -4,7 +4,7 @@ name = "cranelift-reader"
version = "0.59.0" version = "0.59.0"
description = "Cranelift textual IR reader" description = "Cranelift textual IR reader"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift-reader"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"

2
cranelift/simplejit/Cargo.toml

@ -4,7 +4,7 @@ version = "0.59.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
description = "A simple JIT library backed by Cranelift" description = "A simple JIT library backed by Cranelift"
repository = "https://github.com/bytecodealliance/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" license = "Apache-2.0 WITH LLVM-exception"
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"

2
cranelift/umbrella/Cargo.toml

@ -4,7 +4,7 @@ name = "cranelift"
version = "0.59.0" version = "0.59.0"
description = "Umbrella for commonly-used cranelift crates" description = "Umbrella for commonly-used cranelift crates"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://docs.rs/cranelift"
repository = "https://github.com/bytecodealliance/cranelift" repository = "https://github.com/bytecodealliance/cranelift"
categories = ["no-std"] categories = ["no-std"]
readme = "README.md" readme = "README.md"

2
cranelift/wasm/README.md

@ -5,4 +5,4 @@ If you're looking for a complete WebAssembly implementation that uses this
library, see [Wasmtime]. library, see [Wasmtime].
[Wasmtime]: https://github.com/bytecodealliance/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

2
cranelift/wasm/src/environ/spec.rs

@ -71,7 +71,7 @@ pub enum WasmError {
/// Cranelift can compile very large and complicated functions, but the [implementation has /// Cranelift can compile very large and complicated functions, but the [implementation has
/// limits][limits] that cause compilation to fail when they are exceeded. /// 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")] #[error("Implementation limit exceeded")]
ImplLimitExceeded, ImplLimitExceeded,

Loading…
Cancel
Save