Split out instruction definitions.

- cdsl.instructions defines the Instruction class.
- base.instructions defines the base instruction set.
This commit is contained in:
Jakob Stoklund Olesen
2016-11-08 12:08:14 -08:00
parent 2a15130518
commit 5fa322f797
15 changed files with 360 additions and 348 deletions

View File

@@ -269,7 +269,7 @@ class InstDocumenter(sphinx.ext.autodoc.Documenter):
return False
def resolve_name(self, modname, parents, path, base):
return 'cretonne.base', [base]
return 'base.instructions', [base]
def format_signature(self):
inst = self.object

View File

@@ -849,7 +849,7 @@ Base instruction group
All of the shared instructions are part of the :instgroup:`base` instruction
group.
.. autoinstgroup:: cretonne.base.instructions
.. autoinstgroup:: base.instructions.GROUP
Target ISAs may define further instructions in their own instruction groups.

View File

@@ -71,7 +71,7 @@ a module looks like this::
Instruction descriptions
========================
.. currentmodule:: cretonne
.. module:: cdsl.instructions
New instructions are defined as instances of the :class:`Instruction`
class. As instruction instances are created, they are added to the currently
@@ -81,12 +81,14 @@ open :class:`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.
Python module :mod:`base.instructions`. This module has a global variable
:data:`base.instructions.GROUP` which is an :class:`InstructionGroup` instance
containing all the base instructions.
.. autoclass:: Instruction
.. currentmodule:: cdsl.operands
An instruction is defined with a set of distinct input and output operands which
must be instances of the :class:`Operand` class.
@@ -201,7 +203,7 @@ represent SSA values:
.. autodata:: VALUE
.. autodata:: VARIABLE_ARGS
.. currentmodule:: cretonne
.. module:: cdsl.formats
When an instruction description is created, it is automatically assigned a
predefined instruction format which is an instance of
@@ -253,6 +255,8 @@ controlling type variable, or it can vary independently of the other operands.
Encodings
=========
.. currentmodule:: cretonne
Encodings describe how Cretonne instructions are mapped to binary machine code
for the target architecture. After the legalization pass, all remaining
instructions are expected to map 1-1 to native instruction encodings. Cretonne

View File

@@ -5,16 +5,16 @@ This module defines the basic Cretonne instruction set that all targets
support.
"""
from __future__ import absolute_import
from cdsl.operands import VARIABLE_ARGS
from cdsl.operands import Operand, VARIABLE_ARGS
from cdsl.typevar import TypeVar
from . import Operand, Instruction, InstructionGroup
from cdsl.instructions import Instruction, InstructionGroup
from base.types import i8, f32, f64, b1
from base.immediates import imm64, uimm8, ieee32, ieee64, immvector
from base.immediates import intcc, floatcc
from base import entities
import base.formats # noqa
instructions = InstructionGroup("base", "Shared base instruction set")
GROUP = InstructionGroup("base", "Shared base instruction set")
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
iB = TypeVar('iB', 'A scalar integer type', ints=True)
@@ -1213,4 +1213,4 @@ iconcat_lohi = Instruction(
""",
ins=(lo, hi), outs=a)
instructions.close()
GROUP.close()

View File

@@ -0,0 +1,316 @@
"""Classes for defining instructions."""
from __future__ import absolute_import
from . import camel_case
from .types import ValueType
from .operands import Operand
from .formats import InstructionFormat
try:
from typing import Union, Sequence
# List of operands for ins/outs:
OpList = Union[Sequence[Operand], Operand]
MaybeBoundInst = Union['Instruction', 'BoundInstruction']
from typing import Tuple, Any # noqa
except ImportError:
pass
class InstructionGroup(object):
"""
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.
New instructions are automatically added to the currently open instruction
group.
"""
# The currently open instruction group.
_current = None # type: InstructionGroup
def open(self):
# type: () -> None
"""
Open this instruction group such that future new instructions are
added to this group.
"""
assert InstructionGroup._current is None, (
"Can't open {} since {} is already open"
.format(self, InstructionGroup._current))
InstructionGroup._current = self
def close(self):
# type: () -> None
"""
Close this instruction group. This function should be called before
opening another instruction group.
"""
assert InstructionGroup._current is self, (
"Can't close {}, the open instuction group is {}"
.format(self, InstructionGroup._current))
InstructionGroup._current = None
def __init__(self, name, doc):
# type: (str, str) -> None
self.name = name
self.__doc__ = doc
self.instructions = [] # type: List[Instruction]
self.open()
@staticmethod
def append(inst):
# type: (Instruction) -> None
assert InstructionGroup._current, \
"Open an instruction group before defining instructions."
InstructionGroup._current.instructions.append(inst)
class Instruction(object):
"""
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`
and `ins=(x,)` are both allowed and mean the same thing.
:param name: Instruction mnemonic, also becomes opcode name.
:param doc: Documentation string.
:param ins: Tuple of input operands. This can be a mix of SSA value
operands and other operand kinds.
:param outs: Tuple of output operands. The output operands must be SSA
values or `variable_args`.
:param is_terminator: This is a terminator instruction.
:param is_branch: This is a branch instruction.
"""
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
# type: (str, str, OpList, OpList, **Any) -> None # noqa
self.name = name
self.camel_name = camel_case(name)
self.__doc__ = doc
self.ins = self._to_operand_tuple(ins)
self.outs = self._to_operand_tuple(outs)
self.format = InstructionFormat.lookup(self.ins, self.outs)
# Indexes into outs for value results. Others are `variable_args`.
self.value_results = tuple(
i for i, o in enumerate(self.outs) if o.is_value())
self._verify_polymorphic()
InstructionGroup.append(self)
def __str__(self):
prefix = ', '.join(o.name for o in self.outs)
if prefix:
prefix = prefix + ' = '
suffix = ', '.join(o.name for o in self.ins)
return '{}{} {}'.format(prefix, self.name, suffix)
def snake_name(self):
# type: () -> str
"""
Get the snake_case name of this instruction.
Keywords in Rust and Python are altered by appending a '_'
"""
if self.name == 'return':
return 'return_'
else:
return self.name
def blurb(self):
"""Get the first line of the doc comment"""
for line in self.__doc__.split('\n'):
line = line.strip()
if line:
return line
return ""
def _verify_polymorphic(self):
"""
Check if this instruction is polymorphic, and verify its use of type
variables.
"""
poly_ins = [
i for i in self.format.value_operands
if self.ins[i].typ.free_typevar()]
poly_outs = [
i for i, o in enumerate(self.outs)
if o.typ.free_typevar()]
self.is_polymorphic = len(poly_ins) > 0 or len(poly_outs) > 0
if not self.is_polymorphic:
return
# Prefer to use the typevar_operand to infer the controlling typevar.
self.use_typevar_operand = False
typevar_error = None
if self.format.typevar_operand is not None:
try:
tv = self.ins[self.format.typevar_operand].typ
if tv is tv.free_typevar():
self.other_typevars = self._verify_ctrl_typevar(tv)
self.ctrl_typevar = tv
self.use_typevar_operand = True
except RuntimeError as e:
typevar_error = e
if not self.use_typevar_operand:
# The typevar_operand argument doesn't work. Can we infer from the
# first result instead?
if len(self.outs) == 0:
if typevar_error:
raise typevar_error
else:
raise RuntimeError(
"typevar_operand must be a free type variable")
tv = self.outs[0].typ
if tv is not tv.free_typevar():
raise RuntimeError("first result must be a free type variable")
self.other_typevars = self._verify_ctrl_typevar(tv)
self.ctrl_typevar = tv
def _verify_ctrl_typevar(self, ctrl_typevar):
"""
Verify that the use of TypeVars is consistent with `ctrl_typevar` as
the controlling type variable.
All polymorhic inputs must either be derived from `ctrl_typevar` or be
independent free type variables only used once.
All polymorphic results must be derived from `ctrl_typevar`.
Return list of other type variables used, or raise an error.
"""
other_tvs = []
# Check value inputs.
for opidx in self.format.value_operands:
typ = self.ins[opidx].typ
tv = typ.free_typevar()
# Non-polymorphic or derived form ctrl_typevar is OK.
if tv is None or tv is ctrl_typevar:
continue
# No other derived typevars allowed.
if typ is not tv:
raise RuntimeError(
"{}: type variable {} must be derived from {}"
.format(self.ins[opidx], typ.name, ctrl_typevar))
# Other free type variables can only be used once each.
if tv in other_tvs:
raise RuntimeError(
"type variable {} can't be used more than once"
.format(tv.name))
other_tvs.append(tv)
# Check outputs.
for result in self.outs:
typ = result.typ
tv = typ.free_typevar()
# Non-polymorphic or derived from ctrl_typevar is OK.
if tv is None or tv is ctrl_typevar:
continue
raise RuntimeError(
"type variable in output not derived from ctrl_typevar")
return other_tvs
@staticmethod
def _to_operand_tuple(x):
# type: (Union[Sequence[Operand], Operand]) -> Tuple[Operand, ...]
# Allow a single Operand instance instead of the awkward singleton
# tuple syntax.
if isinstance(x, Operand):
x = (x,)
else:
x = tuple(x)
for op in x:
assert isinstance(op, Operand)
return x
def bind(self, *args):
# type: (*ValueType) -> BoundInstruction
"""
Bind a polymorphic instruction to a concrete list of type variable
values.
"""
assert self.is_polymorphic
return BoundInstruction(self, args)
def __getattr__(self, name):
# type: (str) -> BoundInstruction
"""
Bind a polymorphic instruction to a single type variable with dot
syntax:
>>> iadd.i32
"""
return self.bind(ValueType.by_name(name))
def fully_bound(self):
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
"""
Verify that all typevars have been bound, and return a
`(inst, typevars)` pair.
This version in `Instruction` itself allows non-polymorphic
instructions to duck-type as `BoundInstruction`\s.
"""
assert not self.is_polymorphic, self
return (self, ())
def __call__(self, *args):
"""
Create an `ast.Apply` AST node representing the application of this
instruction to the arguments.
"""
from cretonne.ast import Apply
return Apply(self, args)
class BoundInstruction(object):
"""
A polymorphic `Instruction` bound to concrete type variables.
"""
def __init__(self, inst, typevars):
# type: (Instruction, Tuple[ValueType, ...]) -> None
self.inst = inst
self.typevars = typevars
assert len(typevars) <= 1 + len(inst.other_typevars)
def __str__(self):
return '.'.join([self.inst.name, ] + list(map(str, self.typevars)))
def bind(self, *args):
# type: (*ValueType) -> BoundInstruction
"""
Bind additional typevars.
"""
return BoundInstruction(self.inst, self.typevars + args)
def __getattr__(self, name):
# type: (str) -> BoundInstruction
"""
Bind an additional typevar dot syntax:
>>> uext.i32.i8
"""
return self.bind(ValueType.by_name(name))
def fully_bound(self):
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
"""
Verify that all typevars have been bound, and return a
`(inst, typevars)` pair.
"""
if len(self.typevars) < 1 + len(self.inst.other_typevars):
unb = ', '.join(
str(tv) for tv in
self.inst.other_typevars[len(self.typevars) - 1:])
raise AssertionError("Unbound typevar {} in {}".format(unb, self))
assert len(self.typevars) == 1 + len(self.inst.other_typevars)
return (self.inst, self.typevars)
def __call__(self, *args):
"""
Create an `ast.Apply` AST node representing the application of this
instruction to the arguments.
"""
from cretonne.ast import Apply
return Apply(self, args)

View File

@@ -6,19 +6,15 @@ instructions.
"""
from __future__ import absolute_import
import importlib
from cdsl import camel_case
from cdsl.predicates import And
from cdsl.types import ValueType
from cdsl.typevar import TypeVar
from cdsl.operands import Operand
from cdsl.formats import InstructionFormat
# The typing module is only required by mypy, and we don't use these imports
# outside type comments.
try:
from typing import Tuple, Union, Any, Iterable, Sequence, TYPE_CHECKING # noqa
from cdsl.predicates import Predicate, FieldPredicate # noqa
MaybeBoundInst = Union['Instruction', 'BoundInstruction']
from cdsl.instructions import MaybeBoundInst # noqa
AnyPredicate = Union['Predicate', 'FieldPredicate']
except ImportError:
TYPE_CHECKING = False
@@ -27,310 +23,6 @@ if TYPE_CHECKING:
from cdsl.typevar import TypeVar # noqa
# Defining instructions.
class InstructionGroup(object):
"""
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.
New instructions are automatically added to the currently open instruction
group.
"""
# The currently open instruction group.
_current = None # type: InstructionGroup
def open(self):
# type: () -> None
"""
Open this instruction group such that future new instructions are
added to this group.
"""
assert InstructionGroup._current is None, (
"Can't open {} since {} is already open"
.format(self, InstructionGroup._current))
InstructionGroup._current = self
def close(self):
# type: () -> None
"""
Close this instruction group. This function should be called before
opening another instruction group.
"""
assert InstructionGroup._current is self, (
"Can't close {}, the open instuction group is {}"
.format(self, InstructionGroup._current))
InstructionGroup._current = None
def __init__(self, name, doc):
# type: (str, str) -> None
self.name = name
self.__doc__ = doc
self.instructions = [] # type: List[Instruction]
self.open()
@staticmethod
def append(inst):
# type: (Instruction) -> None
assert InstructionGroup._current, \
"Open an instruction group before defining instructions."
InstructionGroup._current.instructions.append(inst)
class Instruction(object):
"""
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`
and `ins=(x,)` are both allowed and mean the same thing.
:param name: Instruction mnemonic, also becomes opcode name.
:param doc: Documentation string.
:param ins: Tuple of input operands. This can be a mix of SSA value
operands and other operand kinds.
:param outs: Tuple of output operands. The output operands must be SSA
values or `variable_args`.
:param is_terminator: This is a terminator instruction.
:param is_branch: This is a branch instruction.
"""
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
# type: (str, str, Union[Sequence[Operand], Operand], Union[Sequence[Operand], Operand], **Any) -> None # noqa
self.name = name
self.camel_name = camel_case(name)
self.__doc__ = doc
self.ins = self._to_operand_tuple(ins)
self.outs = self._to_operand_tuple(outs)
self.format = InstructionFormat.lookup(self.ins, self.outs)
# Indexes into outs for value results. Others are `variable_args`.
self.value_results = tuple(
i for i, o in enumerate(self.outs) if o.is_value())
self._verify_polymorphic()
InstructionGroup.append(self)
def __str__(self):
prefix = ', '.join(o.name for o in self.outs)
if prefix:
prefix = prefix + ' = '
suffix = ', '.join(o.name for o in self.ins)
return '{}{} {}'.format(prefix, self.name, suffix)
def snake_name(self):
# type: () -> str
"""
Get the snake_case name of this instruction.
Keywords in Rust and Python are altered by appending a '_'
"""
if self.name == 'return':
return 'return_'
else:
return self.name
def blurb(self):
"""Get the first line of the doc comment"""
for line in self.__doc__.split('\n'):
line = line.strip()
if line:
return line
return ""
def _verify_polymorphic(self):
"""
Check if this instruction is polymorphic, and verify its use of type
variables.
"""
poly_ins = [
i for i in self.format.value_operands
if self.ins[i].typ.free_typevar()]
poly_outs = [
i for i, o in enumerate(self.outs)
if o.typ.free_typevar()]
self.is_polymorphic = len(poly_ins) > 0 or len(poly_outs) > 0
if not self.is_polymorphic:
return
# Prefer to use the typevar_operand to infer the controlling typevar.
self.use_typevar_operand = False
typevar_error = None
if self.format.typevar_operand is not None:
try:
tv = self.ins[self.format.typevar_operand].typ
if tv is tv.free_typevar():
self.other_typevars = self._verify_ctrl_typevar(tv)
self.ctrl_typevar = tv
self.use_typevar_operand = True
except RuntimeError as e:
typevar_error = e
if not self.use_typevar_operand:
# The typevar_operand argument doesn't work. Can we infer from the
# first result instead?
if len(self.outs) == 0:
if typevar_error:
raise typevar_error
else:
raise RuntimeError(
"typevar_operand must be a free type variable")
tv = self.outs[0].typ
if tv is not tv.free_typevar():
raise RuntimeError("first result must be a free type variable")
self.other_typevars = self._verify_ctrl_typevar(tv)
self.ctrl_typevar = tv
def _verify_ctrl_typevar(self, ctrl_typevar):
"""
Verify that the use of TypeVars is consistent with `ctrl_typevar` as
the controlling type variable.
All polymorhic inputs must either be derived from `ctrl_typevar` or be
independent free type variables only used once.
All polymorphic results must be derived from `ctrl_typevar`.
Return list of other type variables used, or raise an error.
"""
other_tvs = []
# Check value inputs.
for opidx in self.format.value_operands:
typ = self.ins[opidx].typ
tv = typ.free_typevar()
# Non-polymorphic or derived form ctrl_typevar is OK.
if tv is None or tv is ctrl_typevar:
continue
# No other derived typevars allowed.
if typ is not tv:
raise RuntimeError(
"{}: type variable {} must be derived from {}"
.format(self.ins[opidx], typ.name, ctrl_typevar))
# Other free type variables can only be used once each.
if tv in other_tvs:
raise RuntimeError(
"type variable {} can't be used more than once"
.format(tv.name))
other_tvs.append(tv)
# Check outputs.
for result in self.outs:
typ = result.typ
tv = typ.free_typevar()
# Non-polymorphic or derived from ctrl_typevar is OK.
if tv is None or tv is ctrl_typevar:
continue
raise RuntimeError(
"type variable in output not derived from ctrl_typevar")
return other_tvs
@staticmethod
def _to_operand_tuple(x):
# type: (Union[Sequence[Operand], Operand]) -> Tuple[Operand, ...]
# Allow a single Operand instance instead of the awkward singleton
# tuple syntax.
if isinstance(x, Operand):
x = (x,)
else:
x = tuple(x)
for op in x:
assert isinstance(op, Operand)
return x
def bind(self, *args):
# type: (*ValueType) -> BoundInstruction
"""
Bind a polymorphic instruction to a concrete list of type variable
values.
"""
assert self.is_polymorphic
return BoundInstruction(self, args)
def __getattr__(self, name):
# type: (str) -> BoundInstruction
"""
Bind a polymorphic instruction to a single type variable with dot
syntax:
>>> iadd.i32
"""
return self.bind(ValueType.by_name(name))
def fully_bound(self):
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
"""
Verify that all typevars have been bound, and return a
`(inst, typevars)` pair.
This version in `Instruction` itself allows non-polymorphic
instructions to duck-type as `BoundInstruction`\s.
"""
assert not self.is_polymorphic, self
return (self, ())
def __call__(self, *args):
"""
Create an `ast.Apply` AST node representing the application of this
instruction to the arguments.
"""
from .ast import Apply
return Apply(self, args)
class BoundInstruction(object):
"""
A polymorphic `Instruction` bound to concrete type variables.
"""
def __init__(self, inst, typevars):
# type: (Instruction, Tuple[ValueType, ...]) -> None
self.inst = inst
self.typevars = typevars
assert len(typevars) <= 1 + len(inst.other_typevars)
def __str__(self):
return '.'.join([self.inst.name, ] + list(map(str, self.typevars)))
def bind(self, *args):
# type: (*ValueType) -> BoundInstruction
"""
Bind additional typevars.
"""
return BoundInstruction(self.inst, self.typevars + args)
def __getattr__(self, name):
# type: (str) -> BoundInstruction
"""
Bind an additional typevar dot syntax:
>>> uext.i32.i8
"""
return self.bind(ValueType.by_name(name))
def fully_bound(self):
# type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
"""
Verify that all typevars have been bound, and return a
`(inst, typevars)` pair.
"""
if len(self.typevars) < 1 + len(self.inst.other_typevars):
unb = ', '.join(
str(tv) for tv in
self.inst.other_typevars[len(self.typevars) - 1:])
raise AssertionError("Unbound typevar {} in {}".format(unb, self))
assert len(self.typevars) == 1 + len(self.inst.other_typevars)
return (self.inst, self.typevars)
def __call__(self, *args):
"""
Create an `ast.Apply` AST node representing the application of this
instruction to the arguments.
"""
from .ast import Apply
return Apply(self, args)
# Defining target ISAs.

View File

@@ -5,7 +5,7 @@ This module defines classes that can be used to create abstract syntax trees
for patern matching an rewriting of cretonne instructions.
"""
from __future__ import absolute_import
import cretonne
from cdsl import instructions
try:
from typing import Union, Tuple # noqa
@@ -20,7 +20,7 @@ class Def(object):
Example:
>>> from .base import iadd_cout, iconst
>>> from base.instructions import iadd_cout, iconst
>>> x = Var('x')
>>> y = Var('y')
>>> x << iconst(4)
@@ -162,7 +162,7 @@ class Apply(Expr):
instructions. This applies to both bound and unbound polymorphic
instructions:
>>> from .base import jump, iadd
>>> from base.instructions import jump, iadd
>>> jump('next', ())
Apply(jump, ('next', ()))
>>> iadd.i32('x', 'y')
@@ -174,12 +174,12 @@ class Apply(Expr):
"""
def __init__(self, inst, args):
# type: (Union[cretonne.Instruction, cretonne.BoundInstruction], Tuple[Expr, ...]) -> None # noqa
if isinstance(inst, cretonne.BoundInstruction):
# type: (instructions.MaybeBoundInst, Tuple[Expr, ...]) -> None # noqa
if isinstance(inst, instructions.BoundInstruction):
self.inst = inst.inst
self.typevars = inst.typevars
else:
assert isinstance(inst, cretonne.Instruction)
assert isinstance(inst, instructions.Instruction)
self.inst = inst
self.typevars = ()
self.args = args

View File

@@ -7,10 +7,10 @@ patterns that describe how base instructions can be transformed to other base
instructions that are legal.
"""
from __future__ import absolute_import
from .base import iadd, iadd_cout, iadd_cin, iadd_carry
from .base import isub, isub_bin, isub_bout, isub_borrow
from .base import band, bor, bxor, isplit_lohi, iconcat_lohi
from .base import icmp
from base.instructions import iadd, iadd_cout, iadd_cin, iadd_carry
from base.instructions import isub, isub_bin, isub_bout, isub_borrow
from base.instructions import band, bor, bxor, isplit_lohi, iconcat_lohi
from base.instructions import icmp
from .ast import Var
from .xform import Rtl, XFormGroup

View File

@@ -2,7 +2,7 @@ from __future__ import absolute_import
from unittest import TestCase
from doctest import DocTestSuite
from . import ast
from .base import jump, iadd
from base.instructions import jump, iadd
def load_tests(loader, tests, ignore):

View File

@@ -1,8 +1,8 @@
from __future__ import absolute_import
from unittest import TestCase
from doctest import DocTestSuite
from base.instructions import iadd, iadd_imm, iconst
from . import xform
from .base import iadd, iadd_imm, iconst
from .ast import Var
from .xform import Rtl, XForm

View File

@@ -54,7 +54,7 @@ class XForm(object):
A legalization pattern must have a source pattern containing only a single
instruction.
>>> from .base import iconst, iadd, iadd_imm
>>> from base.instructions import iconst, iadd, iadd_imm
>>> a = Var('a')
>>> c = Var('c')
>>> v = Var('v')

View File

@@ -7,7 +7,7 @@ import constant_hash
from unique_table import UniqueTable, UniqueSeqTable
import cdsl.types
import cdsl.operands
import cretonne
from cdsl.formats import InstructionFormat
def gen_formats(fmt):
@@ -21,7 +21,7 @@ def gen_formats(fmt):
fmt.doc_comment('and the `InstructionData` enums.')
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
with fmt.indented('pub enum InstructionFormat {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
fmt.doc_comment(str(f))
fmt.line(f.name + ',')
fmt.line()
@@ -34,7 +34,7 @@ def gen_formats(fmt):
"fn from(inst: &'a InstructionData) -> InstructionFormat {",
'}'):
with fmt.indented('match *inst {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
fmt.line(('InstructionData::{} {{ .. }} => ' +
'InstructionFormat::{},')
.format(f.name, f.name))
@@ -55,7 +55,7 @@ def gen_arguments_method(fmt, is_mut):
'pub fn {f}(&{m}self) -> [&{m}[Value]; 2] {{'
.format(f=method, m=mut), '}'):
with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
n = 'InstructionData::' + f.name
has_varargs = cdsl.operands.VARIABLE_ARGS in f.kinds
# Formats with both fixed and variable arguments delegate to
@@ -118,7 +118,7 @@ def gen_instruction_data_impl(fmt):
fmt.doc_comment('Get the opcode of this instruction.')
with fmt.indented('pub fn opcode(&self) -> Opcode {', '}'):
with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
fmt.line(
'InstructionData::{} {{ opcode, .. }} => opcode,'
.format(f.name))
@@ -126,7 +126,7 @@ def gen_instruction_data_impl(fmt):
fmt.doc_comment('Type of the first result, or `VOID`.')
with fmt.indented('pub fn first_type(&self) -> Type {', '}'):
with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
fmt.line(
'InstructionData::{} {{ ty, .. }} => ty,'
.format(f.name))
@@ -135,7 +135,7 @@ def gen_instruction_data_impl(fmt):
with fmt.indented(
'pub fn first_type_mut(&mut self) -> &mut Type {', '}'):
with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
fmt.line(
'InstructionData::{} {{ ref mut ty, .. }} => ty,'
.format(f.name))
@@ -147,7 +147,7 @@ def gen_instruction_data_impl(fmt):
with fmt.indented(
'pub fn second_result(&self) -> Option<Value> {', '}'):
with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
if f.multiple_results:
fmt.line(
'InstructionData::' + f.name +
@@ -164,7 +164,7 @@ def gen_instruction_data_impl(fmt):
"pub fn second_result_mut<'a>(&'a mut self)" +
" -> Option<&'a mut Value> {", '}'):
with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
if f.multiple_results:
fmt.line(
'InstructionData::' + f.name +
@@ -180,7 +180,7 @@ def gen_instruction_data_impl(fmt):
with fmt.indented(
'pub fn typevar_operand(&self) -> Option<Value> {', '}'):
with fmt.indented('match *self {', '}'):
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
n = 'InstructionData::' + f.name
if f.typevar_operand is None:
fmt.line(n + ' { .. } => None,')
@@ -612,7 +612,7 @@ def gen_builder(insts, fmt):
"pub trait InstBuilder<'f>: InstBuilderBase<'f> {", '}'):
for inst in insts:
gen_inst_builder(inst, fmt)
for f in cretonne.InstructionFormat.all_formats:
for f in InstructionFormat.all_formats:
gen_format_constructor(f, fmt)

View File

@@ -5,8 +5,8 @@ from __future__ import absolute_import
import srcgen
from unique_table import UniqueSeqTable
import constant_hash
from cdsl import camel_case
from cdsl.settings import BoolSetting, NumSetting, EnumSetting
from cretonne import camel_case
from base import settings

View File

@@ -5,9 +5,9 @@ Commonly used definitions.
"""
from __future__ import absolute_import
from cretonne import TargetISA, CPUMode
import cretonne.base
import base.instructions
isa = TargetISA('riscv', [cretonne.base.instructions])
isa = TargetISA('riscv', [base.instructions.GROUP])
# CPU modes for 32-bit and 64-bit operation.
RV32 = CPUMode('RV32', isa)

View File

@@ -2,7 +2,7 @@
RISC-V Encodings.
"""
from __future__ import absolute_import
from cretonne import base
from base import instructions as base
from .defs import RV32, RV64
from .recipes import OPIMM, OPIMM32, OP, OP32, R, Rshamt, I
from .settings import use_m