Reorganize meta language reference.
Separate instruction descriptions from instruction formats which deal with the Rust representation. Add type class restrictions to type variables.
This commit is contained in:
@@ -4,65 +4,79 @@ Cretonne Meta Language Reference
|
|||||||
|
|
||||||
.. default-domain:: py
|
.. default-domain:: py
|
||||||
.. highlight:: python
|
.. highlight:: python
|
||||||
|
|
||||||
The Cretonne meta language is used to define instructions for Cretonne. It is a
|
|
||||||
domain specific language embedded in Python.
|
|
||||||
|
|
||||||
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`.
|
|
||||||
|
|
||||||
.. module:: cretonne
|
.. module:: cretonne
|
||||||
|
|
||||||
Value Types
|
The Cretonne meta language is used to define instructions for Cretonne. It is a
|
||||||
===========
|
domain specific language embedded in Python. This document describes the Python
|
||||||
|
modules that form the embedded DSL.
|
||||||
|
|
||||||
Concrete value types are represented as instances of :class:`cretonne.ValueType`. There are
|
The meta language descriptions are Python modules under the :file:`meta`
|
||||||
subclasses to represent scalar and vector types.
|
top-level directory. The descriptions are processed in two steps:
|
||||||
|
|
||||||
.. inheritance-diagram:: ValueType ScalarType VectorType IntType FloatType
|
1. The Python modules are imported. This has the effect of building static data
|
||||||
:parts: 1
|
structures in global variables in the modules. These static data structures
|
||||||
.. autoclass:: ValueType
|
use the classes in the :mod:`cretonne` module to describe instruction sets
|
||||||
.. autoclass:: ScalarType
|
and other properties.
|
||||||
:members:
|
|
||||||
.. autoclass:: VectorType
|
|
||||||
:members:
|
|
||||||
.. autoclass:: IntType
|
|
||||||
:members:
|
|
||||||
.. autoclass:: FloatType
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Predefined types
|
2. The static data structures are processed to produce Rust source code and
|
||||||
----------------
|
constant dables tables.
|
||||||
.. automodule:: cretonne.types
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. currentmodule:: cretonne
|
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.
|
||||||
|
|
||||||
Parametric polymorphism
|
Instruction descriptions
|
||||||
-----------------------
|
========================
|
||||||
|
|
||||||
Instruction operands can be defined with *type variables* instead of concrete
|
New instructions are defined as instances of the :class:`Instruction`
|
||||||
types for their operands. This makes the instructions polymorphic.
|
class. As instruction instances are created, they are added to the currently
|
||||||
|
open :class:`InstructionGroup`.
|
||||||
|
|
||||||
.. autoclass:: TypeVar
|
|
||||||
|
|
||||||
Instructions
|
|
||||||
============
|
|
||||||
|
|
||||||
New instructions are defined as instances of the :class:`cretonne.Instruction`
|
|
||||||
class.
|
|
||||||
|
|
||||||
.. autoclass:: Instruction
|
|
||||||
.. autoclass:: Operand
|
|
||||||
.. autoclass:: OperandKind
|
|
||||||
.. autoclass:: InstructionGroup
|
.. autoclass:: InstructionGroup
|
||||||
:members:
|
: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.
|
||||||
|
|
||||||
Immediates
|
.. 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
|
||||||
|
|
||||||
|
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
|
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
|
||||||
@@ -77,6 +91,59 @@ indicated with an instance of :class:`ImmediateKind`.
|
|||||||
|
|
||||||
.. currentmodule:: cretonne
|
.. 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:: ScalarType
|
||||||
|
:members:
|
||||||
|
.. autoclass:: VectorType
|
||||||
|
:members:
|
||||||
|
.. autoclass:: IntType
|
||||||
|
:members:
|
||||||
|
.. autoclass:: FloatType
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. automodule:: cretonne.types
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. currentmodule:: cretonne
|
||||||
|
|
||||||
|
There are no predefined vector types, but they can be created as needed with
|
||||||
|
the :func:`ScalarType.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 `cretonne.instructions` module. The instruction
|
||||||
|
representation depends on the input operand kinds and whether the instruction
|
||||||
|
can produce multiple results.
|
||||||
|
|
||||||
|
.. autoclass:: OperandKind
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
.. autodata:: value
|
||||||
|
.. autodata:: args
|
||||||
|
|
||||||
|
When an instruction description is created, it is automatically assigned a
|
||||||
|
predefined instruction format which is an instance of
|
||||||
|
:class:`InstructionFormat`:
|
||||||
|
|
||||||
|
.. autoclass:: InstructionFormat
|
||||||
|
|
||||||
|
|
||||||
Targets
|
Targets
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ def camel_case(s):
|
|||||||
# operands and the kind of each operand.
|
# operands and the kind of each operand.
|
||||||
class OperandKind(object):
|
class OperandKind(object):
|
||||||
"""
|
"""
|
||||||
The kind of an operand.
|
|
||||||
|
|
||||||
An instance of the `OperandKind` class corresponds to a kind of 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
|
Each operand kind has a corresponding type in the Rust representation of an
|
||||||
instruction.
|
instruction.
|
||||||
@@ -55,8 +53,8 @@ value = OperandKind(
|
|||||||
operand.
|
operand.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
#: A variable-sizes list of value operands. Use for Ebb and function call
|
#: A variable-sized list of value operands. Use for Ebb and function call
|
||||||
#: arguemnts.
|
#: arguments.
|
||||||
args = OperandKind(
|
args = OperandKind(
|
||||||
'args', """
|
'args', """
|
||||||
A variable size list of `value` operands.
|
A variable size list of `value` operands.
|
||||||
@@ -71,7 +69,7 @@ args = OperandKind(
|
|||||||
# module.
|
# module.
|
||||||
class ImmediateKind(OperandKind):
|
class ImmediateKind(OperandKind):
|
||||||
"""
|
"""
|
||||||
The type of an immediate instruction operand.
|
The kind of an immediate instruction operand.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, doc):
|
def __init__(self, name, doc):
|
||||||
@@ -215,13 +213,30 @@ class BoolType(ScalarType):
|
|||||||
|
|
||||||
class TypeVar(object):
|
class TypeVar(object):
|
||||||
"""
|
"""
|
||||||
A Type Variable.
|
|
||||||
|
|
||||||
Type variables can be used in place of concrete types when defining
|
Type variables can be used in place of concrete types when defining
|
||||||
instructions. This makes the instructions *polymorphic*.
|
instructions. This makes the instructions *polymorphic*.
|
||||||
|
|
||||||
|
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):
|
def __init__(
|
||||||
|
self, name, doc, base=None,
|
||||||
|
ints=False, floats=False, bools=False,
|
||||||
|
scalars=True, simd=False):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.__doc__ = doc
|
self.__doc__ = doc
|
||||||
|
|
||||||
@@ -238,8 +253,6 @@ class TypeVar(object):
|
|||||||
|
|
||||||
class InstructionGroup(object):
|
class InstructionGroup(object):
|
||||||
"""
|
"""
|
||||||
An instruction group.
|
|
||||||
|
|
||||||
Every instruction must belong to exactly one instruction group. A given
|
Every instruction must belong to exactly one instruction group. A given
|
||||||
target architecture can support instructions from multiple groups, and it
|
target architecture can support instructions from multiple groups, and it
|
||||||
does not necessarily support all instructions in a group.
|
does not necessarily support all instructions in a group.
|
||||||
@@ -286,8 +299,6 @@ class InstructionGroup(object):
|
|||||||
|
|
||||||
class Operand(object):
|
class Operand(object):
|
||||||
"""
|
"""
|
||||||
An instruction operand.
|
|
||||||
|
|
||||||
An instruction operand can be either an *immediate* or an *SSA value*. The
|
An instruction operand can be either an *immediate* or an *SSA value*. The
|
||||||
type of the operand is one of:
|
type of the operand is one of:
|
||||||
|
|
||||||
@@ -318,8 +329,6 @@ class Operand(object):
|
|||||||
|
|
||||||
class InstructionFormat(object):
|
class InstructionFormat(object):
|
||||||
"""
|
"""
|
||||||
An instruction format.
|
|
||||||
|
|
||||||
Every instruction opcode has a corresponding instruction format which
|
Every instruction opcode has a corresponding instruction format which
|
||||||
determines the number of operands and their kinds. Instruction formats are
|
determines the number of operands and their kinds. Instruction formats are
|
||||||
identified structurally, i.e., the format of an instruction is derived from
|
identified structurally, i.e., the format of an instruction is derived from
|
||||||
@@ -396,8 +405,6 @@ class InstructionFormat(object):
|
|||||||
|
|
||||||
class Instruction(object):
|
class Instruction(object):
|
||||||
"""
|
"""
|
||||||
An instruction description.
|
|
||||||
|
|
||||||
The operands to the instruction are specified as two tuples: ``ins`` and
|
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
|
``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`
|
allowed to specify a singleton as just the operand itself, i.e., `ins=x`
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ from immediates import imm64, ieee32, ieee64, immvector
|
|||||||
|
|
||||||
instructions = InstructionGroup("base", "Shared base instruction set")
|
instructions = InstructionGroup("base", "Shared base instruction set")
|
||||||
|
|
||||||
Int = TypeVar('Int', 'A scalar or vector integer type')
|
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
|
||||||
iB = TypeVar('iB', 'A scalar integer type')
|
iB = TypeVar('iB', 'A scalar integer type', ints=True)
|
||||||
TxN = TypeVar('%Tx%N', 'A SIMD vector type')
|
TxN = TypeVar(
|
||||||
|
'%Tx%N', 'A SIMD vector type',
|
||||||
|
ints=True, floats=True, bools=True, scalars=False, simd=True)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Materializing constants.
|
# Materializing constants.
|
||||||
@@ -217,7 +219,10 @@ isub_imm = Instruction(
|
|||||||
#
|
#
|
||||||
|
|
||||||
# TODO: Which types should permit boolean operations? Any reason to restrict?
|
# 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)
|
x = Operand('x', bits)
|
||||||
y = Operand('y', bits)
|
y = Operand('y', bits)
|
||||||
a = Operand('a', bits)
|
a = Operand('a', bits)
|
||||||
|
|||||||
Reference in New Issue
Block a user