From 639d92177ab9f0e8248143238b908ac192bba7d6 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 18 May 2016 11:31:47 -0700 Subject: [PATCH] Reorganize meta language reference. Separate instruction descriptions from instruction formats which deal with the Rust representation. Add type class restrictions to type variables. --- cranelift/docs/metaref.rst | 141 +++++++++++++++++++++++++++---------- meta/cretonne/__init__.py | 39 +++++----- meta/cretonne/base.py | 13 ++-- 3 files changed, 136 insertions(+), 57 deletions(-) diff --git a/cranelift/docs/metaref.rst b/cranelift/docs/metaref.rst index fe46e8af4a..2e47535492 100644 --- a/cranelift/docs/metaref.rst +++ b/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 ======= diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index cbad9185fc..7e6f61d6bf 100644 --- a/meta/cretonne/__init__.py +++ b/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*. + + 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.__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` diff --git a/meta/cretonne/base.py b/meta/cretonne/base.py index 412e7f3abd..3fd8554cf3 100644 --- a/meta/cretonne/base.py +++ b/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)