[docs] Remove special handling of CDSL python modules;

This commit is contained in:
Benjamin Bouvier
2019-07-10 12:39:10 +02:00
parent 55f36ce81a
commit abc3397017
4 changed files with 126 additions and 876 deletions

View File

@@ -1,385 +0,0 @@
# -*- coding: utf-8 -*-
#
# Sphinx domain for documenting compiler intermediate representations.
#
# This defines a 'clif' Sphinx domain with the following directives and roles:
#
# .. clif::type:: type
# Document an IR type.
# .. clif:inst:: v0, v1 = inst op0, op1
# Document an IR instruction.
#
from __future__ import absolute_import
import re
from docutils import nodes
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.locale import l_
from sphinx.roles import XRefRole
from sphinx.util.docfields import Field, GroupedField, TypedField
from sphinx.util.nodes import make_refnode
import sphinx.ext.autodoc
class ClifObject(ObjectDescription):
"""
Any kind of Cranelift IR object.
This is a shared base class for the different kinds of indexable objects
in the Cranelift IR reference.
"""
option_spec = {
'noindex': directives.flag,
'module': directives.unchanged,
'annotation': directives.unchanged,
}
def add_target_and_index(self, name, sig, signode):
"""
Add ``name`` to the index.
:param name: The object name returned by :func:`handle_signature`.
:param sig: The signature text.
:param signode: The output node.
"""
targetname = self.objtype + '-' + name
if targetname not in self.state.document.ids:
signode['names'].append(targetname)
signode['ids'].append(targetname)
signode['first'] = (not self.names)
self.state.document.note_explicit_target(signode)
inv = self.env.domaindata['clif']['objects']
if name in inv:
self.state_machine.reporter.warning(
'duplicate Cranelift object description of %s, ' % name +
'other instance in ' + self.env.doc2path(inv[name][0]),
line=self.lineno)
inv[name] = (self.env.docname, self.objtype)
indextext = self.get_index_text(name)
if indextext:
self.indexnode['entries'].append(('single', indextext,
targetname, '', None))
# Type variables are indicated as %T.
typevar = re.compile('(\%[A-Z])')
def parse_type(name, signode):
"""
Parse a type with embedded type vars and append to signode.
Return a string that can be compiled into a regular expression matching
the type.
"""
re_str = ''
for part in typevar.split(name):
if part == '':
continue
if len(part) == 2 and part[0] == '%':
# This is a type parameter. Don't display the %, use emphasis
# instead.
part = part[1]
signode += nodes.emphasis(part, part)
re_str += r'\w+'
else:
signode += addnodes.desc_name(part, part)
re_str += re.escape(part)
return re_str
class ClifType(ClifObject):
"""A Cranelift IR type description."""
def handle_signature(self, sig, signode):
"""
Parse type signature in ``sig`` and append description to signode.
Return a global object name for ``add_target_and_index``.
"""
name = sig.strip()
parse_type(name, signode)
return name
def get_index_text(self, name):
return name + ' (IR type)'
sep_equal = re.compile('\s*=\s*')
sep_comma = re.compile('\s*,\s*')
def parse_params(s, signode):
for i, p in enumerate(sep_comma.split(s)):
if i != 0:
signode += nodes.Text(', ')
signode += nodes.emphasis(p, p)
class ClifInst(ClifObject):
"""A Cranelift IR instruction."""
doc_field_types = [
TypedField('argument', label=l_('Arguments'),
names=('in', 'arg'),
typerolename='type', typenames=('type',)),
TypedField('result', label=l_('Results'),
names=('out', 'result'),
typerolename='type', typenames=('type',)),
GroupedField(
'typevar', names=('typevar',), label=l_('Type Variables')),
GroupedField('flag', names=('flag',), label=l_('Flags')),
Field('resulttype', label=l_('Result type'), has_arg=False,
names=('rtype',)),
]
def handle_signature(self, sig, signode):
# Look for signatures like
#
# v0, v1 = foo op0, op1
# v0 = foo
# foo op0
parts = re.split(sep_equal, sig, 1)
if len(parts) == 2:
# Outgoing parameters.
parse_params(parts[0], signode)
signode += nodes.Text(' = ')
name = parts[1]
else:
name = parts[0]
# Parse 'name arg, arg'
parts = name.split(None, 1)
name = parts[0]
signode += addnodes.desc_name(name, name)
if len(parts) == 2:
# Incoming parameters.
signode += nodes.Text(' ')
parse_params(parts[1], signode)
return name
def get_index_text(self, name):
return name
class ClifInstGroup(ClifObject):
"""A Cranelift IR instruction group."""
class CraneliftDomain(Domain):
"""Cranelift domain for IR objects."""
name = 'clif'
label = 'Cranelift'
object_types = {
'type': ObjType(l_('type'), 'type'),
'inst': ObjType(l_('instruction'), 'inst')
}
directives = {
'type': ClifType,
'inst': ClifInst,
'instgroup': ClifInstGroup,
}
roles = {
'type': XRefRole(),
'inst': XRefRole(),
'instgroup': XRefRole(),
}
initial_data = {
'objects': {}, # fullname -> docname, objtype
}
def clear_doc(self, docname):
for fullname, (fn, _l) in list(self.data['objects'].items()):
if fn == docname:
del self.data['objects'][fullname]
def merge_domaindata(self, docnames, otherdata):
for fullname, (fn, objtype) in otherdata['objects'].items():
if fn in docnames:
self.data['objects'][fullname] = (fn, objtype)
def resolve_xref(self, env, fromdocname, builder, typ, target, node,
contnode):
objects = self.data['objects']
if target not in objects:
return None
obj = objects[target]
return make_refnode(builder, fromdocname, obj[0],
obj[1] + '-' + target, contnode, target)
def resolve_any_xref(self, env, fromdocname, builder, target,
node, contnode):
objects = self.data['objects']
if target not in objects:
return []
obj = objects[target]
return [('clif:' + self.role_for_objtype(obj[1]),
make_refnode(builder, fromdocname, obj[0],
obj[1] + '-' + target, contnode, target))]
class TypeDocumenter(sphinx.ext.autodoc.Documenter):
# Invoke with .. autocliftype::
objtype = 'cliftype'
# Convert into clif:type directives
domain = 'clif'
directivetype = 'type'
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return False
def resolve_name(self, modname, parents, path, base):
return 'base.types', [base]
def add_content(self, more_content, no_docstring=False):
super(TypeDocumenter, self).add_content(more_content, no_docstring)
sourcename = self.get_sourcename()
membytes = self.object.membytes
if membytes:
self.add_line(u':bytes: {}'.format(membytes), sourcename)
else:
self.add_line(u':bytes: Can\'t be stored in memory', sourcename)
class InstDocumenter(sphinx.ext.autodoc.Documenter):
# Invoke with .. autoinst::
objtype = 'inst'
# Convert into clif:inst directives
domain = 'clif'
directivetype = 'inst'
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return False
def resolve_name(self, modname, parents, path, base):
if path:
return path.rstrip('.'), [base]
else:
return 'base.instructions', [base]
def format_signature(self):
inst = self.object
sig = inst.name
if len(inst.outs) > 0:
sig = ', '.join([op.name for op in inst.outs]) + ' = ' + sig
if len(inst.ins) > 0:
op = inst.ins[0]
sig += ' ' + op.name
# If the first input is variable-args, this is 'return'. No parens.
if op.kind.name == 'variable_args':
sig += '...'.format(op.name)
for op in inst.ins[1:]:
# This is a call or branch with args in (...).
if op.kind.name == 'variable_args':
sig += '({}...)'.format(op.name)
else:
sig += ', ' + op.name
return sig
def add_directive_header(self, sig):
"""Add the directive header and options to the generated content."""
domain = getattr(self, 'domain', 'clif')
directive = getattr(self, 'directivetype', self.objtype)
sourcename = self.get_sourcename()
self.add_line(u'.. %s:%s:: %s' % (domain, directive, sig), sourcename)
if self.options.noindex:
self.add_line(u' :noindex:', sourcename)
def add_content(self, more_content, no_docstring=False):
super(InstDocumenter, self).add_content(more_content, no_docstring)
sourcename = self.get_sourcename()
inst = self.object
# Add inputs and outputs.
for op in inst.ins:
if op.is_value():
typ = op.typevar
else:
typ = op.kind
self.add_line(u':in {} {}: {}'.format(
typ, op.name, op.get_doc()), sourcename)
for op in inst.outs:
if op.is_value():
typ = op.typevar
else:
typ = op.kind
self.add_line(u':out {} {}: {}'.format(
typ, op.name, op.get_doc()), sourcename)
# Document type inference for polymorphic instructions.
if inst.is_polymorphic:
if inst.ctrl_typevar is not None:
if inst.use_typevar_operand:
tvopnum = inst.value_opnums[inst.format.typevar_operand]
self.add_line(
u':typevar {}: inferred from {}'
.format(
inst.ctrl_typevar.name,
inst.ins[tvopnum]),
sourcename)
else:
self.add_line(
u':typevar {}: explicitly provided'
.format(inst.ctrl_typevar.name),
sourcename)
for tv in inst.other_typevars:
self.add_line(
u':typevar {}: from input operand'.format(tv.name),
sourcename)
class InstGroupDocumenter(sphinx.ext.autodoc.ModuleLevelDocumenter):
# Invoke with .. autoinstgroup::
objtype = 'instgroup'
# Convert into clif:instgroup directives
domain = 'clif'
directivetype = 'instgroup'
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return False
def format_name(self):
return "{}.{}".format(self.modname, ".".join(self.objpath))
def add_content(self, more_content, no_docstring=False):
super(InstGroupDocumenter, self).add_content(
more_content, no_docstring)
sourcename = self.get_sourcename()
indexed = self.env.domaindata['clif']['objects']
names = [inst.name for inst in self.object.instructions]
names.sort()
for name in names:
if name in indexed:
self.add_line(u':clif:inst:`{}`'.format(name), sourcename)
else:
self.add_line(u'``{}``'.format(name), sourcename)
def setup(app):
app.add_domain(CraneliftDomain)
app.add_autodocumenter(TypeDocumenter)
app.add_autodocumenter(InstDocumenter)
app.add_autodocumenter(InstGroupDocumenter)
return {'version': '0.1'}

View File

@@ -21,10 +21,6 @@ import os
import sys import sys
sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('.'))
# Also add the meta-python directory to sys.path so autodoc can find the Cranelift meta
# language definitions.
sys.path.insert(0, os.path.abspath('../cranelift-codegen/meta-python'))
# -- General configuration ------------------------------------------------ # -- General configuration ------------------------------------------------
# We don't support Sphinx versions before 1.4 since the format of index # We don't support Sphinx versions before 1.4 since the format of index
@@ -41,7 +37,6 @@ extensions = [
'sphinx.ext.ifconfig', 'sphinx.ext.ifconfig',
'sphinx.ext.graphviz', 'sphinx.ext.graphviz',
'sphinx.ext.inheritance_diagram', 'sphinx.ext.inheritance_diagram',
'clif_domain',
'clif_lexer', 'clif_lexer',
] ]

View File

@@ -86,10 +86,9 @@ containing multiple assignments to the same variables into SSA form for
Cranelift :term:`IR`. Cranelift :term:`IR`.
Such variables can also be presented to Cranelift as :term:`stack slot`\s. Such variables can also be presented to Cranelift as :term:`stack slot`\s.
Stack slots are accessed with the :inst:`stack_store` and :inst:`stack_load` Stack slots are accessed with the `stack_store` and `stack_load` instructions,
instructions, and can have their address taken with :inst:`stack_addr`, which and can have their address taken with `stack_addr`, which supports C-like
supports C-like programming languages where local variables can have their programming languages where local variables can have their address taken.
address taken.
.. _value-types: .. _value-types:
@@ -105,20 +104,20 @@ Boolean types
Boolean values are either true or false. Boolean values are either true or false.
The :type:`b1` type represents an abstract boolean value. It can only exist as The `b1` type represents an abstract boolean value. It can only exist as
an SSA value, and can't be directly stored in memory. It can, however, be an SSA value, and can't be directly stored in memory. It can, however, be
converted into an integer with value 0 or 1 by the :inst:`bint` instruction (and converted into an integer with value 0 or 1 by the `bint` instruction (and
converted back with :inst:`icmp_imm` with 0). converted back with `icmp_imm` with 0).
Several larger boolean types are also defined, primarily to be used as SIMD Several larger boolean types are also defined, primarily to be used as SIMD
element types. They can be stored in memory, and are represented as either all element types. They can be stored in memory, and are represented as either all
zero bits or all one bits. zero bits or all one bits.
.. autocliftype:: b1 - b1
.. autocliftype:: b8 - b8
.. autocliftype:: b16 - b16
.. autocliftype:: b32 - b32
.. autocliftype:: b64 - b64
Integer types Integer types
------------- -------------
@@ -129,10 +128,10 @@ number, others don't care.
The support for i8 and i16 arithmetic is incomplete and use could lead to bugs. The support for i8 and i16 arithmetic is incomplete and use could lead to bugs.
.. autocliftype:: i8 - i8
.. autocliftype:: i16 - i16
.. autocliftype:: i32 - i32
.. autocliftype:: i64 - i64
Floating point types Floating point types
-------------------- --------------------
@@ -160,8 +159,8 @@ instructions are encoded as follows:
and all bits of the trailing significand other than the MSB set to and all bits of the trailing significand other than the MSB set to
nondeterministic values. nondeterministic values.
.. autocliftype:: f32 - f32
.. autocliftype:: f64 - f64
CPU flags types CPU flags types
--------------- ---------------
@@ -172,15 +171,15 @@ compared.
Since some ISAs don't have CPU flags, these value types should not be used Since some ISAs don't have CPU flags, these value types should not be used
until the legalization phase of compilation where the code is adapted to fit until the legalization phase of compilation where the code is adapted to fit
the target ISA. Use instructions like :inst:`icmp` instead. the target ISA. Use instructions like `icmp` instead.
The CPU flags types are also restricted such that two flags values can not be The CPU flags types are also restricted such that two flags values can not be
live at the same time. After legalization, some instruction encodings will live at the same time. After legalization, some instruction encodings will
clobber the flags, and flags values are not allowed to be live across such clobber the flags, and flags values are not allowed to be live across such
instructions either. The verifier enforces these rules. instructions either. The verifier enforces these rules.
.. autocliftype:: iflags - iflags
.. autocliftype:: fflags - fflags
SIMD vector types SIMD vector types
----------------- -----------------
@@ -189,42 +188,38 @@ 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
called a *lane*. The number of lanes must be a power of two in the range 2-256. called a *lane*. The number of lanes must be a power of two in the range 2-256.
.. type:: i%Bx%N i%Bx%N
A SIMD vector of integers. The lane type `iB` is one of the integer
types `i8` ... `i64`.
A SIMD vector of integers. The lane type :type:`iB` is one of the integer Some concrete integer vector types are `i32x4`, `i64x8`, and
types :type:`i8` ... :type:`i64`. `i16x4`.
Some concrete integer vector types are :type:`i32x4`, :type:`i64x8`, and
:type:`i16x4`.
The size of a SIMD integer vector in memory is :math:`N B\over 8` bytes. The size of a SIMD integer vector in memory is :math:`N B\over 8` bytes.
.. type:: f32x%N f32x%N
A SIMD vector of single precision floating point numbers. A SIMD vector of single precision floating point numbers.
Some concrete :type:`f32` vector types are: :type:`f32x2`, :type:`f32x4`, Some concrete `f32` vector types are: `f32x2`, `f32x4`,
and :type:`f32x8`. and `f32x8`.
The size of a :type:`f32` vector in memory is :math:`4N` bytes. The size of a `f32` vector in memory is :math:`4N` bytes.
.. type:: f64x%N
f64x%N
A SIMD vector of double precision floating point numbers. A SIMD vector of double precision floating point numbers.
Some concrete :type:`f64` vector types are: :type:`f64x2`, :type:`f64x4`, Some concrete `f64` vector types are: `f64x2`, `f64x4`,
and :type:`f64x8`. and `f64x8`.
The size of a :type:`f64` vector in memory is :math:`8N` bytes. The size of a `f64` vector in memory is :math:`8N` bytes.
.. type:: b1x%N
b1x%N
A boolean SIMD vector. A boolean SIMD vector.
Boolean vectors are used when comparing SIMD vectors. For example, Boolean vectors are used when comparing SIMD vectors. For example,
comparing two :type:`i32x4` values would produce a :type:`b1x4` result. comparing two `i32x4` values would produce a `b1x4` result.
Like the :type:`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
----------------------------- -----------------------------
@@ -232,40 +227,32 @@ 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.
.. type:: iAddr iAddr
A Pointer-sized integer representing an address. A Pointer-sized integer representing an address.
This is either :type:`i32`, or :type:`i64`, depending on whether the target This is either `i32`, or `i64`, depending on whether the target
platform has 32-bit or 64-bit pointers. platform has 32-bit or 64-bit pointers.
.. type:: iB iB
Any of the scalar integer types `i8` -- `i64`.
Any of the scalar integer types :type:`i8` -- :type:`i64`. Int
Any scalar *or vector* integer type: `iB` or `iBxN`.
.. type:: Int fB
Either of the floating point scalar types: `f32` or `f64`.
Any scalar *or vector* integer type: :type:`iB` or :type:`iBxN`. Float
Any scalar *or vector* floating point type: `fB` or `fBxN`.
.. type:: fB
Either of the floating point scalar types: :type:`f32` or :type:`f64`.
.. type:: Float
Any scalar *or vector* floating point type: :type:`fB` or :type:`fBxN`.
.. type:: %Tx%N
%Tx%N
Any SIMD vector type. Any SIMD vector type.
.. type:: Mem Mem
Any type that can be stored in memory: `Int` or `Float`.
Any type that can be stored in memory: :type:`Int` or :type:`Float`. Testable
Either `b1` or `iN`.
.. type:: Testable
Either :type:`b1` or :type:`iN`.
Immediate operand types Immediate operand types
----------------------- -----------------------
@@ -273,48 +260,41 @@ 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.
.. type:: imm64 imm64
A 64-bit immediate integer. The value of this operand is interpreted as a A 64-bit immediate integer. The value of this operand is interpreted as a
signed two's complement integer. Instruction encodings may limit the valid signed two's complement integer. Instruction encodings may limit the valid
range. range.
In the textual format, :type:`imm64` immediates appear as decimal or In the textual format, `imm64` immediates appear as decimal or
hexadecimal literals using the same syntax as C. hexadecimal literals using the same syntax as C.
.. type:: offset32 offset32
A signed 32-bit immediate address offset. A signed 32-bit immediate address offset.
In the textual format, :type:`offset32` immediates always have an explicit In the textual format, `offset32` immediates always have an explicit
sign, and a 0 offset may be omitted. sign, and a 0 offset may be omitted.
.. type:: ieee32 ieee32
A 32-bit immediate floating point number in the IEEE 754-2008 binary32 A 32-bit immediate floating point number in the IEEE 754-2008 binary32
interchange format. All bit patterns are allowed. interchange format. All bit patterns are allowed.
.. type:: ieee64 ieee64
A 64-bit immediate floating point number in the IEEE 754-2008 binary64 A 64-bit immediate floating point number in the IEEE 754-2008 binary64
interchange format. All bit patterns are allowed. interchange format. All bit patterns are allowed.
.. type:: bool bool
A boolean immediate value, either false or true. A boolean immediate value, either false or true.
In the textual format, :type:`bool` immediates appear as 'false' In the textual format, `bool` immediates appear as 'false'
and 'true'. and 'true'.
.. type:: intcc intcc
An integer condition code. See the `icmp` instruction for details.
An integer condition code. See the :inst:`icmp` instruction for details. floatcc
A floating point condition code. See the `fcmp` instruction for details.
.. type:: floatcc The two IEEE floating point immediate types `ieee32` and `ieee64`
A floating point condition code. See the :inst:`fcmp` instruction for details.
The two IEEE floating point immediate types :type:`ieee32` and :type:`ieee64`
are displayed as hexadecimal floating point literals in the textual :term:`IR` are displayed as hexadecimal floating point literals in the textual :term:`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
@@ -324,9 +304,9 @@ 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. :type:`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 :type:`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
@@ -358,17 +338,10 @@ arguments, if it has any. Conditional branches only take the branch if their
condition is satisfied, otherwise execution continues at the following condition is satisfied, otherwise execution continues at the following
instruction in the EBB. instruction in the EBB.
.. autoinst:: jump JT = jump_table [EBB0, EBB1, ..., EBBn]
.. autoinst:: brz
.. autoinst:: brnz
.. autoinst:: br_icmp
.. autoinst:: br_table
.. inst:: JT = jump_table [EBB0, EBB1, ..., EBBn]
Declare a jump table in the :term:`function preamble`. Declare a jump table in the :term:`function preamble`.
This declares a jump table for use by the :inst:`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.
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
@@ -382,13 +355,9 @@ instruction in the EBB.
Traps stop the program because something went wrong. The exact behavior depends Traps stop the program because something went wrong. The exact behavior depends
on the target instruction set architecture and operating system. There are on the target instruction set architecture and operating system. There are
explicit trap instructions defined below, but some instructions may also cause explicit trap instructions defined below, but some instructions may also cause
traps for certain input value. For example, :inst:`udiv` traps when the divisor traps for certain input value. For example, `udiv` traps when the divisor
is zero. is zero.
.. autoinst:: trap
.. autoinst:: trapz
.. autoinst:: trapnz
Function calls Function calls
============== ==============
@@ -448,8 +417,7 @@ compilers.
Functions that are called directly must be declared in the :term:`function Functions that are called directly must be declared in the :term:`function
preamble`: preamble`:
.. inst:: 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.
If the colocated keyword is present, the symbol's definition will be If the colocated keyword is present, the symbol's definition will be
@@ -458,11 +426,7 @@ preamble`:
:arg NAME: Name of the function, passed to the linker for resolution. :arg NAME: Name of the function, passed to the linker for resolution.
:arg signature: Function signature. See below. :arg signature: Function signature. See below.
:result FN: A function identifier that can be used with :inst:`call`. :result FN: A function identifier that can be used with `call`.
.. autoinst:: call
.. autoinst:: x_return
.. autoinst:: fallthrough_return
This simple example illustrates direct function calls and signatures: This simple example illustrates direct function calls and signatures:
@@ -472,46 +436,39 @@ This simple example illustrates direct function calls and signatures:
Indirect function calls use a signature declared in the preamble. Indirect function calls use a signature declared in the preamble.
.. autoinst:: call_indirect
.. autoinst:: func_addr
.. _memory: .. _memory:
Memory Memory
====== ======
Cranelift provides fully general :inst:`load` and :inst:`store` instructions for Cranelift provides fully general `load` and `store` instructions for accessing
accessing memory, as well as :ref:`extending loads and truncating stores memory, as well as :ref:`extending loads and truncating stores
<extload-truncstore>`. <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 :term:`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`. :term:`accessible`, they :term:`trap`.
.. autoinst:: load
.. autoinst:: store
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.
.. autoinst:: load_complex
.. autoinst:: store_complex
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 :term:`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 :term:`accessible`.
@@ -530,8 +487,7 @@ allocated in the :term:`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 :term:`accessible` bytes in the stack
frame. frame.
.. inst:: SS = explicit_slot Bytes, Flags... SS = explicit_slot Bytes, Flags...
Allocate a stack slot in the preamble. Allocate a stack slot in the preamble.
If no alignment is specified, Cranelift will pick an appropriate alignment If no alignment is specified, Cranelift will pick an appropriate alignment
@@ -541,9 +497,6 @@ frame.
:flag align(N): Request at least N bytes alignment. :flag align(N): Request at least N bytes alignment.
:result SS: Stack slot index. :result SS: Stack slot index.
.. autoinst:: stack_load
.. autoinst:: stack_store
The dedicated stack access instructions are easy for the compiler to reason The dedicated stack access instructions are easy for the compiler to reason
about because stack slots and offsets are fixed at compile time. For example, about because stack slots and offsets are fixed at compile time. For example,
the alignment of these stack memory accesses can be inferred from the offsets the alignment of these stack memory accesses can be inferred from the offsets
@@ -552,9 +505,7 @@ 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 :ref:`unrestricted loads and stores <memory>`.
.. autoinst:: stack_addr The `stack_addr` instruction can be used to macro-expand the stack access
The :inst:`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
@@ -569,7 +520,7 @@ 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 :inst:`global_value`, possibly using value is computed at runtime by `global_value`, possibly using
information provided by the linker via relocations. There are multiple information provided by the linker via relocations. There are multiple
kinds of global values using different methods for determining their value. kinds of global values using different methods for determining their value.
Cranelift does not track the type of a global value, for they are just Cranelift does not track the type of a global value, for they are just
@@ -584,8 +535,7 @@ Cranelift functions.
Chains of global value expressions are possible, but cycles are not allowed. Chains of global value expressions are possible, but cycles are not allowed.
They will be caught by the IR verifier. They will be caught by the IR verifier.
.. inst:: GV = vmctx GV = vmctx
Declare a global value of the address of the VM context struct. Declare a global value of the address of the VM context struct.
This declares a global value which is the VM context pointer which may This declares a global value which is the VM context pointer which may
@@ -599,8 +549,7 @@ A global value can also be derived by treating another global variable as a
struct pointer and loading from one of its fields. This makes it possible to struct pointer and loading from one of its fields. This makes it possible to
chase pointers into VM runtime data structures. chase pointers into VM runtime data structures.
.. inst:: GV = load.Type BaseGV [Offset] GV = load.Type BaseGV [Offset]
Declare a global value pointed to by BaseGV plus Offset, with type Type. Declare a global value pointed to by BaseGV plus Offset, with type Type.
It is assumed the BaseGV plus Offset resides in accessible memory with the It is assumed the BaseGV plus Offset resides in accessible memory with the
@@ -610,15 +559,13 @@ chase pointers into VM runtime data structures.
:arg Offset: Offset added to the base before loading. :arg Offset: Offset added to the base before loading.
:result GV: Global value. :result GV: Global value.
.. inst:: GV = iadd_imm BaseGV, Offset GV = iadd_imm BaseGV, Offset
Declare a global value which has the value of BaseGV offset by Offset. Declare a global value which has the value of BaseGV offset by Offset.
:arg BaseGV: Global value providing the base value. :arg BaseGV: Global value providing the base value.
:arg Offset: Offset added to the base value. :arg Offset: Offset added to the base value.
.. inst:: GV = [colocated] symbol Name GV = [colocated] symbol Name
Declare a symbolic address global value. Declare a symbolic address global value.
The value of GV is symbolic and will be assigned a relocation, so that The value of GV is symbolic and will be assigned a relocation, so that
@@ -631,10 +578,6 @@ chase pointers into VM runtime data structures.
:arg Name: External name. :arg Name: External name.
:result GV: Global value. :result GV: Global value.
.. autoinst:: global_value
.. autoinst:: symbol_value
Heaps Heaps
----- -----
@@ -644,9 +587,9 @@ 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
:inst:`heap_addr` instruction that :term:`traps` on out-of-bounds accesses or `heap_addr` instruction that :term:`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 :type:`i32` offsets on a 64-bit the native pointer size, for example unsigned `i32` offsets on a 64-bit
architecture. architecture.
.. digraph:: static .. digraph:: static
@@ -674,12 +617,10 @@ A heap appears as three consecutive ranges of address space:
not :term:`accessible`. not :term:`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 :inst:`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`). :term:`accessible`).
.. autoinst:: heap_addr
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.
@@ -693,8 +634,7 @@ unmapped pages where the heap can grow up to its maximum size. After the
unmapped pages follow the offset-guard pages which are also guaranteed to unmapped pages follow the offset-guard pages which are also guaranteed to
generate a trap when accessed. generate a trap when accessed.
.. inst:: H = static Base, min MinBytes, bound BoundBytes, offset_guard OffsetGuardBytes H = static Base, min MinBytes, bound BoundBytes, offset_guard OffsetGuardBytes
Declare a static heap in the preamble. Declare a static heap in the preamble.
:arg Base: Global value holding the heap's base address. :arg Base: Global value holding the heap's base address.
@@ -712,8 +652,7 @@ 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
the heap is resized. The bound of a dynamic heap is stored in a global value. the heap is resized. The bound of a dynamic heap is stored in a global value.
.. inst:: H = dynamic Base, min MinBytes, bound BoundGV, offset_guard OffsetGuardBytes H = dynamic Base, min MinBytes, bound BoundGV, offset_guard OffsetGuardBytes
Declare a dynamic heap in the preamble. Declare a dynamic heap in the preamble.
:arg Base: Global value holding the heap's base address. :arg Base: Global value holding the heap's base address.
@@ -762,25 +701,22 @@ 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
:inst:`table_addr` instruction that :term:`traps` on out-of-bounds accesses. `table_addr` instruction that :term:`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 :type:`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 :term:`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 :inst:`table_addr` checks against. the bound that `table_addr` checks against.
.. autoinst:: table_addr
A table can be relocated to a different base address when it is resized, and A table can be relocated to a different base address when it is resized, and
its bound can move dynamically. The bound of a table is stored in a global its bound can move dynamically. The bound of a table is stored in a global
value. value.
.. inst:: T = dynamic Base, min MinElements, bound BoundGV, element_size ElementSize T = dynamic Base, min MinElements, bound BoundGV, element_size ElementSize
Declare a table in the preamble. Declare a table in the preamble.
:arg Base: Global value holding the table's base address. :arg Base: Global value holding the table's base address.
@@ -788,85 +724,12 @@ value.
: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.
Operations
==========
.. autoinst:: select
.. autoinst:: selectif
Constant materialization Constant materialization
------------------------ ------------------------
A few instructions have variants that take immediate operands (e.g., A few instructions have variants that take immediate operands, but in general
:inst:`band` / :inst:`band_imm`), but in general an instruction is required to an instruction is required to load a constant into an SSA value: `iconst`,
load a constant into an SSA value. `f32const`, `f64const` and `bconst` serve this purpose.
.. autoinst:: iconst
.. autoinst:: f32const
.. autoinst:: f64const
.. autoinst:: bconst
Vector operations
-----------------
.. autoinst:: vsplit
.. autoinst:: vconcat
.. autoinst:: vselect
.. autoinst:: splat
.. autoinst:: insertlane
.. autoinst:: extractlane
Integer operations
------------------
.. autoinst:: icmp
.. autoinst:: icmp_imm
.. autoinst:: iadd
.. autoinst:: iadd_imm
.. autoinst:: iadd_cin
.. autoinst:: iadd_cout
.. autoinst:: iadd_carry
.. autoinst:: isub
.. autoinst:: irsub_imm
.. autoinst:: isub_bin
.. autoinst:: isub_bout
.. autoinst:: isub_borrow
.. todo:: Add and subtract with signed overflow.
For example, see
`llvm.sadd.with.overflow.*` and `llvm.ssub.with.overflow.*` in
`LLVM <https://llvm.org/docs/LangRef.html#arithmetic-with-overflow-intrinsics>`_.
.. autoinst:: imul
.. autoinst:: imul_imm
.. todo:: Larger multiplication results.
For example, ``smulx`` which multiplies :type:`i32` operands to produce a
:type:`i64` result. Alternatively, ``smulhi`` and ``smullo`` pairs.
.. autoinst:: udiv
.. autoinst:: udiv_imm
.. autoinst:: sdiv
.. autoinst:: sdiv_imm
.. autoinst:: urem
.. autoinst:: urem_imm
.. autoinst:: srem
.. autoinst:: srem_imm
.. todo:: Integer minimum / maximum.
NEON has ``smin``, ``smax``, ``umin``, and ``umax`` instructions. We should
replicate those for both scalar and vector integer types. Even if the
target ISA doesn't have scalar operations, these are good pattern matching
targets.
.. todo:: Saturating arithmetic.
Mostly for SIMD use, but again these are good patterns for contraction.
Something like ``usatadd``, ``usatsub``, ``ssatadd``, and ``ssatsub`` is a
good start.
Bitwise operations Bitwise operations
------------------ ------------------
@@ -876,17 +739,6 @@ numbers, and booleans. When operating on integer or floating point types, the
bitwise operations are working on the binary representation of the values. When bitwise operations are working on the binary representation of the values. When
operating on boolean values, the bitwise operations work as logical operators. operating on boolean values, the bitwise operations work as logical operators.
.. autoinst:: band
.. autoinst:: band_imm
.. autoinst:: bor
.. autoinst:: bor_imm
.. autoinst:: bxor
.. autoinst:: bxor_imm
.. autoinst:: bnot
.. autoinst:: band_not
.. autoinst:: bor_not
.. autoinst:: bxor_not
The shift and rotate operations only work on integer types (scalar and vector). The shift and rotate operations only work on integer types (scalar and vector).
The shift amount does not have to be the same type as the value being shifted. The shift amount does not have to be the same type as the value being shifted.
Only the low `B` bits of the shift amount is significant. Only the low `B` bits of the shift amount is significant.
@@ -895,37 +747,13 @@ When operating on an integer vector type, the shift amount is still a scalar
type, and all the lanes are shifted the same amount. The shift amount is masked type, and all the lanes are shifted the same amount. The shift amount is masked
to the number of bits in a *lane*, not the full size of the vector type. to the number of bits in a *lane*, not the full size of the vector type.
.. autoinst:: rotl The bit-counting instructions are scalar only.
.. autoinst:: rotl_imm
.. autoinst:: rotr
.. autoinst:: rotr_imm
.. autoinst:: ishl
.. autoinst:: ishl_imm
.. autoinst:: ushr
.. autoinst:: ushr_imm
.. autoinst:: sshr
.. autoinst:: sshr_imm
The bit-counting instructions below are scalar only.
.. autoinst:: clz
.. autoinst:: cls
.. autoinst:: ctz
.. autoinst:: popcnt
Floating point operations Floating point operations
------------------------- -------------------------
These operations generally follow IEEE 754-2008 semantics. These operations generally follow IEEE 754-2008 semantics.
.. autoinst:: fcmp
.. autoinst:: fadd
.. autoinst:: fsub
.. autoinst:: fmul
.. autoinst:: fdiv
.. autoinst:: sqrt
.. autoinst:: fma
Sign bit manipulations Sign bit manipulations
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
@@ -933,10 +761,6 @@ 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.
.. autoinst:: fneg
.. autoinst:: fabs
.. autoinst:: fcopysign
Minimum and maximum Minimum and maximum
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
@@ -946,40 +770,15 @@ 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`.
.. autoinst:: fmin
.. autoinst:: fmax
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.
.. autoinst:: ceil
.. autoinst:: floor
.. autoinst:: trunc
.. autoinst:: nearest
Conversion operations Conversion operations
--------------------- ---------------------
.. autoinst:: bitcast
.. autoinst:: breduce
.. autoinst:: bextend
.. autoinst:: bint
.. autoinst:: bmask
.. autoinst:: ireduce
.. autoinst:: uextend
.. autoinst:: sextend
.. autoinst:: fpromote
.. autoinst:: fdemote
.. autoinst:: fcvt_to_uint
.. autoinst:: fcvt_to_sint
.. autoinst:: fcvt_to_uint_sat
.. autoinst:: fcvt_to_sint_sat
.. autoinst:: fcvt_from_uint
.. autoinst:: fcvt_from_sint
.. _extload-truncstore: .. _extload-truncstore:
Extending loads and truncating stores Extending loads and truncating stores
@@ -989,23 +788,13 @@ Most ISAs provide instructions that load an integer value smaller than a registe
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
only write the low bits of an integer register are common. only write the low bits of an integer register are common.
In addition to the normal :inst:`load` and :inst:`store` instructions, Cranelift In addition to the normal `load` and `store` instructions, Cranelift
provides extending loads and truncation stores for 8, 16, and 32-bit memory 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 :ref:`normal loads and stores <memory>`.
.. autoinst:: uload8
.. autoinst:: sload8
.. autoinst:: istore8
.. autoinst:: uload16
.. autoinst:: sload16
.. autoinst:: istore16
.. autoinst:: uload32
.. autoinst:: sload32
.. autoinst:: istore32
ISA-specific instructions ISA-specific instructions
========================= =========================
@@ -1017,16 +806,6 @@ x86
Instructions that can only be used by the x86 target ISA. Instructions that can only be used by the x86 target ISA.
.. autoinst:: isa.x86.instructions.sdivmodx
.. autoinst:: isa.x86.instructions.udivmodx
.. autoinst:: isa.x86.instructions.cvtt2si
.. autoinst:: isa.x86.instructions.fmin
.. autoinst:: isa.x86.instructions.fmax
.. autoinst:: isa.x86.instructions.bsf
.. autoinst:: isa.x86.instructions.bsr
.. autoinst:: isa.x86.instructions.push
.. autoinst:: isa.x86.instructions.pop
Codegen implementation instructions Codegen implementation instructions
=================================== ===================================
@@ -1039,42 +818,18 @@ 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.
.. autoinst:: isplit
.. autoinst:: iconcat
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.
.. autoinst:: adjust_sp_down
.. autoinst:: adjust_sp_up_imm
.. autoinst:: adjust_sp_down_imm
.. autoinst:: ifcmp_sp
.. autoinst:: copy_special
Low-level control flow operations
---------------------------------
.. autoinst:: fallthrough
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.
.. autoinst:: ifcmp
.. autoinst:: ifcmp_imm
.. autoinst:: ffcmp
.. autoinst:: trueif
.. autoinst:: trueff
.. autoinst:: trapif
.. autoinst:: trapff
.. autoinst:: brif
.. autoinst:: brff
Live range splitting Live range splitting
-------------------- --------------------
@@ -1084,37 +839,24 @@ value can be quite large, it is sometimes beneficial to split the live range
into smaller parts. into smaller parts.
A live range is split by creating new SSA values that are copies or the A live range is split by creating new SSA values that are copies or the
original value or each other. The copies are created by inserting :inst:`copy`, original value or each other. The copies are created by inserting `copy`,
:inst:`spill`, or :inst:`fill` instructions, depending on whether the values `spill`, or `fill` instructions, depending on whether the values
are assigned to registers or stack slots. are assigned to registers or stack slots.
This approach permits SSA form to be preserved throughout the register This approach permits SSA form to be preserved throughout the register
allocation pass and beyond. allocation pass and beyond.
.. autoinst:: copy
.. autoinst:: spill
.. autoinst:: fill
Register values can be temporarily diverted to other registers by the Register values can be temporarily diverted to other registers by the
:inst:`regmove` instruction, and to and from stack slots by :inst:`regspill` `regmove` instruction, and to and from stack slots by `regspill`
and :inst:`regfill`. and `regfill`.
.. autoinst:: regmove
.. autoinst:: regspill
.. autoinst:: regfill
Instruction groups Instruction groups
================== ==================
All of the shared instructions are part of the :instgroup:`base` instruction All of the shared instructions are part of the `base` instruction
group. group.
.. autoinstgroup:: base.instructions.GROUP Target ISAs may define further instructions in their own instruction groups.
Target ISAs may define further instructions in their own instruction groups:
.. autoinstgroup:: isa.x86.instructions.GROUP
Implementation limits Implementation limits
===================== =====================
@@ -1272,8 +1014,8 @@ Glossary
execution somewhere else. Execution never continues at the instruction execution somewhere else. Execution never continues at the instruction
following a terminator instruction. following a terminator instruction.
The basic terminator instructions are :inst:`br`, :inst:`return`, and The basic terminator instructions are `br`, `return`, and
:inst:`trap`. Conditional branches and instructions that trap `trap`. Conditional branches and instructions that trap
conditionally are not terminator instructions. conditionally are not terminator instructions.
trap trap

View File

@@ -4,7 +4,6 @@ Cranelift Meta Language Reference
.. default-domain:: py .. default-domain:: py
.. highlight:: python .. highlight:: python
.. module:: cdsl
The Cranelift meta language is used to define instructions for Cranelift. It is a The Cranelift meta language is used to define instructions for Cranelift. It is a
domain specific language embedded in Rust. domain specific language embedded in Rust.
@@ -18,50 +17,36 @@ domain specific language embedded in Rust.
This document describes the Python modules that form the embedded DSL. This document describes the Python modules that form the embedded DSL.
The meta language descriptions are Python modules under the The meta language descriptions are Python modules under the
:file:`cranelift-codegen/meta-python` directory. The descriptions are processed in two `cranelift-codegen/meta-python` directory. The descriptions are processed in two
steps: steps:
1. The Python modules are imported. This has the effect of building static data 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 structures in global values in the modules. These static data structures
in the :mod:`base` and :mod:`isa` packages use the classes in the in the `base` and `isa` packages use the classes in the
:mod:`cdsl` package to describe instruction sets and other properties. `cdsl` package to describe instruction sets and other properties.
2. The static data structures are processed to produce Rust source code and 2. The static data structures are processed to produce Rust source code and
constant tables. constant tables.
The main driver for this source code generation process is the The main driver for this source code generation process is the
:file:`cranelift-codegen/meta-python/build.py` script which is invoked as part of the build `cranelift-codegen/meta-python/build.py` script which is invoked as part of the build
process if anything in the :file:`cranelift-codegen/meta-python` directory has changed process if anything in the `cranelift-codegen/meta-python` directory has changed
since the last build. since the last build.
.. module:: cdsl.settings
Settings Settings
======== ========
Settings are used by the environment embedding Cranelift to control the details 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 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 and consistent Rust representation can be generated. Shared settings are defined
in the :mod:`base.settings` module. Some settings are specific to a target ISA, in the `base.settings` module. Some settings are specific to a target ISA,
and defined in a :file:`settings.py` module under the appropriate and defined in a `settings.py` module under the appropriate
:file:`cranelift-codegen/meta-python/isa/*` directory. `cranelift-codegen/meta-python/isa/*` directory.
Settings can take boolean on/off values, small numbers, or explicitly enumerated Settings can take boolean on/off values, small numbers, or explicitly enumerated
symbolic values. Each type is represented by a sub-class of :class:`Setting`: symbolic values.
.. inheritance-diagram:: Setting BoolSetting NumSetting EnumSetting All settings must belong to a *group*, represented by a :class:`SettingGroup` object.
:parts: 1
.. autoclass:: Setting
.. autoclass:: BoolSetting
.. autoclass:: NumSetting
.. autoclass:: EnumSetting
All settings must belong to a *group*, represented by a :class:`SettingGroup`
object.
.. autoclass:: SettingGroup
Normally, a setting group corresponds to all settings defined in a module. Such Normally, a setting group corresponds to all settings defined in a module. Such
a module looks like this:: a module looks like this::
@@ -74,9 +59,6 @@ a module looks like this::
group.close(globals()) group.close(globals())
.. module:: cdsl.instructions
Instruction descriptions Instruction descriptions
======================== ========================
@@ -84,27 +66,16 @@ New instructions are defined as instances of the :class:`Instruction`
class. As instruction instances are created, they are added to the currently class. As instruction instances are created, they are added to the currently
open :class:`InstructionGroup`. open :class:`InstructionGroup`.
.. autoclass:: InstructionGroup
:members:
The basic Cranelift instruction set described in :doc:`ir` is defined by the The basic Cranelift instruction set described in :doc:`ir` is defined by the
Python module :mod:`base.instructions`. This module has a global value Python module `base.instructions`. This module has a global value
:data:`base.instructions.GROUP` which is an :class:`InstructionGroup` instance `base.instructions.GROUP` which is an :class:`InstructionGroup` instance
containing all the base instructions. containing all the base instructions.
.. autoclass:: Instruction
.. currentmodule:: cdsl.operands
An instruction is defined with a set of distinct input and output operands which An instruction is defined with a set of distinct input and output operands which
must be instances of the :class:`Operand` class. must be instances of the :class:`Operand` class.
.. autoclass:: Operand
Cranelift uses two separate type systems for operand kinds and SSA values. Cranelift uses two separate type systems for operand kinds and SSA values.
.. module:: cdsl.typevar
Type variables Type variables
-------------- --------------
@@ -113,9 +84,6 @@ Instruction descriptions can be made polymorphic by using
instead of a concrete value type. Polymorphism only works for SSA value instead of a concrete value type. Polymorphism only works for SSA value
operands. Other operands have a fixed operand kind. operands. Other operands have a fixed operand kind.
.. autoclass:: TypeVar
:members:
If multiple operands refer to the same type variable they will be required to 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 have the same concrete type. For example, this defines an integer addition
instruction:: instruction::
@@ -138,61 +106,27 @@ There are some practical restrictions on the use of type variables, see
Immediate operands Immediate operands
------------------ ------------------
.. currentmodule:: cdsl.operands
Immediate instruction operands don't correspond to SSA values, but have values Immediate instruction operands don't correspond to SSA values, but have values
that are encoded directly in the instruction. Immediate operands don't that are encoded directly in the instruction. Immediate operands don't
have types from the :class:`cdsl.types.ValueType` type system; they often have 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 enumerated values of a specific type. The type of an immediate operand is
indicated with an instance of :class:`ImmediateKind`. indicated with an instance of :class:`ImmediateKind`.
.. autoclass:: ImmediateKind
.. automodule:: base.immediates
:members:
Entity references Entity references
----------------- -----------------
.. currentmodule:: cdsl.operands
Instruction operands can also refer to other entities in the same function. This 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. can be extended basic blocks, or entities declared in the function preamble.
.. autoclass:: EntityRefKind
.. automodule:: base.entities
:members:
Value types Value types
----------- -----------
.. currentmodule:: cdsl.types
Concrete value types are represented as instances of :class:`ValueType`. There Concrete value types are represented as instances of :class:`ValueType`. There
are subclasses to represent scalar and vector types. are subclasses to represent scalar and vector types.
.. autoclass:: ValueType
.. inheritance-diagram:: ValueType LaneType VectorType IntType FloatType BoolType SpecialType FlagsType
:parts: 1
.. autoclass:: LaneType
:members:
.. autoclass:: VectorType
.. autoclass:: SpecialType
.. autoclass:: IntType
.. autoclass:: FloatType
.. autoclass:: BoolType
.. autoclass:: FlagsType
.. automodule:: base.types
:members:
There are no predefined vector types, but they can be created as needed with There are no predefined vector types, but they can be created as needed with
the :func:`LaneType.by` function. the :func:`LaneType.by` function.
.. module:: cdsl.operands
Instruction representation Instruction representation
========================== ==========================
@@ -202,24 +136,12 @@ written as Rust code in the ``cranelift.instructions`` module. The instruction
representation depends on the input operand kinds and whether the instruction representation depends on the input operand kinds and whether the instruction
can produce multiple results. can produce multiple results.
.. autoclass:: OperandKind
.. inheritance-diagram:: OperandKind ImmediateKind EntityRefKind
Since all SSA value operands are represented as a `Value` in Rust code, value Since all SSA value operands are represented as a `Value` in Rust code, value
types don't affect the representation. Two special operand kinds are used to types don't affect the representation.
represent SSA values:
.. autodata:: VALUE
.. autodata:: VARIABLE_ARGS
.. module:: cdsl.formats
When an instruction description is created, it is automatically assigned a When an instruction description is created, it is automatically assigned a
predefined instruction format which is an instance of predefined instruction format which is an instance of
:class:`InstructionFormat`: :class:`InstructionFormat`.
.. autoclass:: InstructionFormat
.. _restricted-polymorphism: .. _restricted-polymorphism:
@@ -264,8 +186,6 @@ controlling type variable, or it can vary independently of the other operands.
Encodings Encodings
========= =========
.. currentmodule:: cdsl.isa
Encodings describe how Cranelift instructions are mapped to binary machine code Encodings describe how Cranelift instructions are mapped to binary machine code
for the target architecture. After the legalization pass, all remaining for the target architecture. After the legalization pass, all remaining
instructions are expected to map 1-1 to native instruction encodings. Cranelift instructions are expected to map 1-1 to native instruction encodings. Cranelift
@@ -277,7 +197,7 @@ incompatible encodings. For example, a modern ARMv8 CPU might support three
different CPU modes: *A64* where instructions are encoded in 32 bits, *A32* 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 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 32-bit instruction encodings. These are incompatible encoding spaces, and while
an :clif:inst:`iadd` instruction can be encoded in 32 bits in each of them, it's 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 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 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 different register banks means that it makes sense to model A64 as a separate
@@ -288,8 +208,6 @@ 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 instructions with 16-bit encodings available for some opcodes if certain
constraints are satisfied. constraints are satisfied.
.. autoclass:: CPUMode
Encodings are guarded by :term:`sub-target predicate`\s. For example, the RISC-V 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 "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. a predicate would be used to disable all of the 16-bit encodings in that case.
@@ -327,7 +245,7 @@ An :py:class:`Encoding` instance specifies the encoding of a concrete
instruction. The following properties are used to select instructions to be instruction. The following properties are used to select instructions to be
encoded: encoded:
- An opcode, i.e. :clif:inst:`iadd_imm`, that must match the instruction's - An opcode, i.e. `iadd_imm`, that must match the instruction's
opcode. opcode.
- Values for any type variables if the opcode represents a polymorphic - Values for any type variables if the opcode represents a polymorphic
instruction. instruction.
@@ -350,8 +268,6 @@ The additional predicates in the :py:class:`EncRecipe` are merged with the
per-encoding predicates when generating the encoding matcher code. Often per-encoding predicates when generating the encoding matcher code. Often
encodings only need the recipe predicates. encodings only need the recipe predicates.
.. autoclass:: EncRecipe
Register constraints Register constraints
==================== ====================
@@ -371,9 +287,6 @@ Each encoding recipe specifies separate constraints for its value operands and
result. These constraints are separate from the instruction predicate which can result. These constraints are separate from the instruction predicate which can
only evaluate the instruction's immediate operands. only evaluate the instruction's immediate operands.
.. module:: cdsl.registers
.. autoclass:: RegBank
Register class constraints Register class constraints
-------------------------- --------------------------
@@ -388,8 +301,6 @@ register class::
This defines an encoding recipe for the ``Binary`` instruction format where This defines an encoding recipe for the ``Binary`` instruction format where
both input operands must be allocated from the ``GPR`` register class. both input operands must be allocated from the ``GPR`` register class.
.. autoclass:: RegClass
Tied register operands Tied register operands
---------------------- ----------------------
@@ -420,7 +331,7 @@ Stack operands
-------------- --------------
Cranelift's register allocator can assign an SSA value to a stack slot if there Cranelift's register allocator can assign an SSA value to a stack slot if there
isn't enough registers. It will insert :clif:inst:`spill` and :clif:inst:`fill` isn't enough registers. It will insert `spill` and `fill`
instructions as needed to satisfy instruction operand constraints, but it is instructions as needed to satisfy instruction operand constraints, but it is
also possible to have instructions that can access stack slots directly:: also possible to have instructions that can access stack slots directly::
@@ -429,27 +340,14 @@ also possible to have instructions that can access stack slots directly::
An output stack value implies a store to the stack, an input value implies a An output stack value implies a store to the stack, an input value implies a
load. load.
.. module:: cdsl.isa
Targets Targets
======= =======
Cranelift can be compiled with support for multiple target instruction set Cranelift can be compiled with support for multiple target instruction set
architectures. Each ISA is represented by a :py:class:`cdsl.isa.TargetISA` instance. architectures. Each ISA is represented by a :py:class:`cdsl.isa.TargetISA` instance.
.. autoclass:: TargetISA
The definitions for each supported target live in a package under The definitions for each supported target live in a package under
:file:`cranelift-codegen/meta-python/isa`. `cranelift-codegen/meta-python/isa`.
.. automodule:: isa
:members:
.. automodule:: isa.riscv
.. automodule:: isa.x86
.. automodule:: isa.arm32
.. automodule:: isa.arm64
Glossary Glossary
======== ========