Browse Source

Reorganize meta language reference.

Separate instruction descriptions from instruction formats which deal with the
Rust representation.

Add type class restrictions to type variables.
pull/1019/head
Jakob Stoklund Olesen 9 years ago
parent
commit
639d92177a
  1. 141
      cranelift/docs/metaref.rst
  2. 41
      meta/cretonne/__init__.py
  3. 13
      meta/cretonne/base.py

141
cranelift/docs/metaref.rst

@ -4,26 +4,103 @@ Cretonne Meta Language Reference
.. default-domain:: py
.. highlight:: python
.. module:: cretonne
The Cretonne meta language is used to define instructions for Cretonne. It is a
domain specific language embedded in Python.
domain specific language embedded in Python. This document describes the Python
modules that form the embedded DSL.
An instruction set is described by a Python module under the :file:`meta`
directory that has a global variable called ``instructions``. The basic
Cretonne instruction set described in :doc:`langref` is defined by the Python
module :mod:`cretonne.base`.
The meta language descriptions are Python modules under the :file:`meta`
top-level directory. The descriptions are processed in two steps:
.. module:: cretonne
1. The Python modules are imported. This has the effect of building static data
structures in global variables in the modules. These static data structures
use the classes in the :mod:`cretonne` module to describe instruction sets
and other properties.
2. The static data structures are processed to produce Rust source code and
constant dables tables.
The main driver for this source code generation process is the
:file:`meta/build.py` script which is invoked as part of the build process if
anything in the :file:`meta` directory has changed since the last build.
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`.
.. autoclass:: InstructionGroup
:members:
The basic Cretonne instruction set described in :doc:`langref` is defined by the
Python module :mod:`cretonne.base`. This module has a global variable
:data:`cretonne.base.instructions` which is an :class:`InstructionGroup`
instance containing all the base instructions.
.. autoclass:: Instruction
An instruction is defined with a set of distinct input and output operands which
must be instances of the :class:`Operand` class.
.. autoclass:: Operand
Value Types
===========
Cretonne uses two separate type systems for immediate operands and SSA values.
Type variables
--------------
Instruction descriptions can be made polymorphic by using :class:`Operand`
instances that refer to a *type variable* instead of a concrete value type.
Polymorphism only works for SSA value operands. Immediate operands have a fixed
operand kind.
.. autoclass:: TypeVar
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.
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:`cretonne.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`.
.. autoclass:: ImmediateKind
.. automodule:: cretonne.immediates
:members:
.. currentmodule:: cretonne
Value types
-----------
Concrete value types are represented as instances of :class:`cretonne.ValueType`. There are
subclasses to represent scalar and vector types.
.. autoclass:: ValueType
.. inheritance-diagram:: ValueType ScalarType VectorType IntType FloatType
:parts: 1
.. autoclass:: ValueType
.. autoclass:: ScalarType
:members:
.. autoclass:: VectorType
@ -33,49 +110,39 @@ subclasses to represent scalar and vector types.
.. autoclass:: FloatType
:members:
Predefined types
----------------
.. automodule:: cretonne.types
:members:
.. currentmodule:: cretonne
Parametric polymorphism
-----------------------
Instruction operands can be defined with *type variables* instead of concrete
types for their operands. This makes the instructions polymorphic.
There are no predefined vector types, but they can be created as needed with
the :func:`ScalarType.by` function.
.. autoclass:: TypeVar
Instructions
============
Instruction representation
==========================
New instructions are defined as instances of the :class:`cretonne.Instruction`
class.
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 `cretonne.instructions` module. The instruction
representation depends on the input operand kinds and whether the instruction
can produce multiple results.
.. autoclass:: Instruction
.. autoclass:: Operand
.. autoclass:: OperandKind
.. autoclass:: InstructionGroup
:members:
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
represent SSA values:
Immediates
----------
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:`cretonne.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`.
.. autodata:: value
.. autodata:: args
.. autoclass:: ImmediateKind
When an instruction description is created, it is automatically assigned a
predefined instruction format which is an instance of
:class:`InstructionFormat`:
.. automodule:: cretonne.immediates
:members:
.. autoclass:: InstructionFormat
.. currentmodule:: cretonne
Targets
=======

41
meta/cretonne/__init__.py

@ -24,8 +24,6 @@ def camel_case(s):
# operands and the kind of each operand.
class OperandKind(object):
"""
The kind of an operand.
An instance of the `OperandKind` class corresponds to a kind of operand.
Each operand kind has a corresponding type in the Rust representation of an
instruction.
@ -55,8 +53,8 @@ value = OperandKind(
operand.
""")
#: A variable-sizes list of value operands. Use for Ebb and function call
#: arguemnts.
#: A variable-sized list of value operands. Use for Ebb and function call
#: arguments.
args = OperandKind(
'args', """
A variable size list of `value` operands.
@ -71,7 +69,7 @@ args = OperandKind(
# module.
class ImmediateKind(OperandKind):
"""
The type of an immediate instruction operand.
The kind of an immediate instruction operand.
"""
def __init__(self, name, doc):
@ -215,13 +213,30 @@ class BoolType(ScalarType):
class TypeVar(object):
"""
A Type Variable.
Type variables can be used in place of concrete types when defining
instructions. This makes the instructions *polymorphic*.
"""
def __init__(self, name, doc):
A type variable is restricted to vary over a subset of the value types.
This subset is specified by a set of flags that control the permitted base
types and whether the type variable can assume scalar or vector types, or
both.
:param name: Short name of type variable used in instruction descriptions.
:param doc: Documentation string.
:param base: Single base type or list of base types. Use this to specify an
exact set of base types if the general categories below are not good
enough.
:param ints: Allow all integer base types.
:param floats: Allow all floating point base types.
:param bools: Allow all boolean base types.
:param scalars: Allow type variable to assume scalar types.
:param simd: Allow type variable to assume vector types.
"""
def __init__(
self, name, doc, base=None,
ints=False, floats=False, bools=False,
scalars=True, simd=False):
self.name = name
self.__doc__ = doc
@ -238,8 +253,6 @@ class TypeVar(object):
class InstructionGroup(object):
"""
An instruction group.
Every instruction must belong to exactly one instruction group. A given
target architecture can support instructions from multiple groups, and it
does not necessarily support all instructions in a group.
@ -286,8 +299,6 @@ class InstructionGroup(object):
class Operand(object):
"""
An instruction operand.
An instruction operand can be either an *immediate* or an *SSA value*. The
type of the operand is one of:
@ -318,8 +329,6 @@ class Operand(object):
class InstructionFormat(object):
"""
An instruction format.
Every instruction opcode has a corresponding instruction format which
determines the number of operands and their kinds. Instruction formats are
identified structurally, i.e., the format of an instruction is derived from
@ -396,8 +405,6 @@ class InstructionFormat(object):
class Instruction(object):
"""
An instruction description.
The operands to the instruction are specified as two tuples: ``ins`` and
``outs``. Since the Python singleton tuple syntax is a bit awkward, it is
allowed to specify a singleton as just the operand itself, i.e., `ins=x`

13
meta/cretonne/base.py

@ -10,9 +10,11 @@ from immediates import imm64, ieee32, ieee64, immvector
instructions = InstructionGroup("base", "Shared base instruction set")
Int = TypeVar('Int', 'A scalar or vector integer type')
iB = TypeVar('iB', 'A scalar integer type')
TxN = TypeVar('%Tx%N', 'A SIMD vector type')
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
iB = TypeVar('iB', 'A scalar integer type', ints=True)
TxN = TypeVar(
'%Tx%N', 'A SIMD vector type',
ints=True, floats=True, bools=True, scalars=False, simd=True)
#
# Materializing constants.
@ -217,7 +219,10 @@ isub_imm = Instruction(
#
# TODO: Which types should permit boolean operations? Any reason to restrict?
bits = TypeVar('bits', 'Any integer, float, or boolean scalar or vector type')
bits = TypeVar(
'bits', 'Any integer, float, or boolean scalar or vector type',
ints=True, floats=True, bools=True, scalars=True, simd=True)
x = Operand('x', bits)
y = Operand('y', bits)
a = Operand('a', bits)

Loading…
Cancel
Save