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 return False
def resolve_name(self, modname, parents, path, base): def resolve_name(self, modname, parents, path, base):
return 'cretonne.base', [base] return 'base.instructions', [base]
def format_signature(self): def format_signature(self):
inst = self.object inst = self.object

View File

@@ -849,7 +849,7 @@ Base instruction group
All of the shared instructions are part of the :instgroup:`base` instruction All of the shared instructions are part of the :instgroup:`base` instruction
group. group.
.. autoinstgroup:: cretonne.base.instructions .. 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.

View File

@@ -71,7 +71,7 @@ a module looks like this::
Instruction descriptions Instruction descriptions
======================== ========================
.. currentmodule:: cretonne .. module:: cdsl.instructions
New instructions are defined as instances of the :class:`Instruction` 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
@@ -81,12 +81,14 @@ open :class:`InstructionGroup`.
:members: :members:
The basic Cretonne instruction set described in :doc:`langref` is defined by the The basic Cretonne instruction set described in :doc:`langref` is defined by the
Python module :mod:`cretonne.base`. This module has a global variable Python module :mod:`base.instructions`. This module has a global variable
:data:`cretonne.base.instructions` which is an :class:`InstructionGroup` :data:`base.instructions.GROUP` which is an :class:`InstructionGroup` instance
instance containing all the base instructions. containing all the base instructions.
.. autoclass:: Instruction .. 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.
@@ -201,7 +203,7 @@ represent SSA values:
.. autodata:: VALUE .. autodata:: VALUE
.. autodata:: VARIABLE_ARGS .. autodata:: VARIABLE_ARGS
.. currentmodule:: cretonne .. 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
@@ -253,6 +255,8 @@ controlling type variable, or it can vary independently of the other operands.
Encodings Encodings
========= =========
.. currentmodule:: cretonne
Encodings describe how Cretonne instructions are mapped to binary machine code Encodings describe how Cretonne 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. Cretonne 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. support.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from cdsl.operands import VARIABLE_ARGS from cdsl.operands import Operand, VARIABLE_ARGS
from cdsl.typevar import TypeVar 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.types import i8, f32, f64, b1
from base.immediates import imm64, uimm8, ieee32, ieee64, immvector from base.immediates import imm64, uimm8, ieee32, ieee64, immvector
from base.immediates import intcc, floatcc from base.immediates import intcc, floatcc
from base import entities from base import entities
import base.formats # noqa 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) Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
iB = TypeVar('iB', 'A scalar integer type', ints=True) iB = TypeVar('iB', 'A scalar integer type', ints=True)
@@ -1213,4 +1213,4 @@ iconcat_lohi = Instruction(
""", """,
ins=(lo, hi), outs=a) 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 from __future__ import absolute_import
import importlib import importlib
from cdsl import camel_case
from cdsl.predicates import And from cdsl.predicates import And
from cdsl.types import ValueType
from cdsl.typevar import TypeVar 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 # The typing module is only required by mypy, and we don't use these imports
# outside type comments. # outside type comments.
try: try:
from typing import Tuple, Union, Any, Iterable, Sequence, TYPE_CHECKING # noqa from typing import Tuple, Union, Any, Iterable, Sequence, TYPE_CHECKING # noqa
from cdsl.predicates import Predicate, FieldPredicate # noqa from cdsl.predicates import Predicate, FieldPredicate # noqa
MaybeBoundInst = Union['Instruction', 'BoundInstruction'] from cdsl.instructions import MaybeBoundInst # noqa
AnyPredicate = Union['Predicate', 'FieldPredicate'] AnyPredicate = Union['Predicate', 'FieldPredicate']
except ImportError: except ImportError:
TYPE_CHECKING = False TYPE_CHECKING = False
@@ -27,310 +23,6 @@ if TYPE_CHECKING:
from cdsl.typevar import TypeVar # noqa 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. # 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. for patern matching an rewriting of cretonne instructions.
""" """
from __future__ import absolute_import from __future__ import absolute_import
import cretonne from cdsl import instructions
try: try:
from typing import Union, Tuple # noqa from typing import Union, Tuple # noqa
@@ -20,7 +20,7 @@ class Def(object):
Example: Example:
>>> from .base import iadd_cout, iconst >>> from base.instructions import iadd_cout, iconst
>>> x = Var('x') >>> x = Var('x')
>>> y = Var('y') >>> y = Var('y')
>>> x << iconst(4) >>> x << iconst(4)
@@ -162,7 +162,7 @@ class Apply(Expr):
instructions. This applies to both bound and unbound polymorphic instructions. This applies to both bound and unbound polymorphic
instructions: instructions:
>>> from .base import jump, iadd >>> from base.instructions import jump, iadd
>>> jump('next', ()) >>> jump('next', ())
Apply(jump, ('next', ())) Apply(jump, ('next', ()))
>>> iadd.i32('x', 'y') >>> iadd.i32('x', 'y')
@@ -174,12 +174,12 @@ class Apply(Expr):
""" """
def __init__(self, inst, args): def __init__(self, inst, args):
# type: (Union[cretonne.Instruction, cretonne.BoundInstruction], Tuple[Expr, ...]) -> None # noqa # type: (instructions.MaybeBoundInst, Tuple[Expr, ...]) -> None # noqa
if isinstance(inst, cretonne.BoundInstruction): if isinstance(inst, instructions.BoundInstruction):
self.inst = inst.inst self.inst = inst.inst
self.typevars = inst.typevars self.typevars = inst.typevars
else: else:
assert isinstance(inst, cretonne.Instruction) assert isinstance(inst, instructions.Instruction)
self.inst = inst self.inst = inst
self.typevars = () self.typevars = ()
self.args = args 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. instructions that are legal.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from .base import iadd, iadd_cout, iadd_cin, iadd_carry from base.instructions import iadd, iadd_cout, iadd_cin, iadd_carry
from .base import isub, isub_bin, isub_bout, isub_borrow from base.instructions import isub, isub_bin, isub_bout, isub_borrow
from .base import band, bor, bxor, isplit_lohi, iconcat_lohi from base.instructions import band, bor, bxor, isplit_lohi, iconcat_lohi
from .base import icmp from base.instructions import icmp
from .ast import Var from .ast import Var
from .xform import Rtl, XFormGroup from .xform import Rtl, XFormGroup

View File

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

View File

@@ -1,8 +1,8 @@
from __future__ import absolute_import from __future__ import absolute_import
from unittest import TestCase from unittest import TestCase
from doctest import DocTestSuite from doctest import DocTestSuite
from base.instructions import iadd, iadd_imm, iconst
from . import xform from . import xform
from .base import iadd, iadd_imm, iconst
from .ast import Var from .ast import Var
from .xform import Rtl, XForm 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 A legalization pattern must have a source pattern containing only a single
instruction. instruction.
>>> from .base import iconst, iadd, iadd_imm >>> from base.instructions import iconst, iadd, iadd_imm
>>> a = Var('a') >>> a = Var('a')
>>> c = Var('c') >>> c = Var('c')
>>> v = Var('v') >>> v = Var('v')

View File

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

View File

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

View File

@@ -5,9 +5,9 @@ Commonly used definitions.
""" """
from __future__ import absolute_import from __future__ import absolute_import
from cretonne import TargetISA, CPUMode 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. # CPU modes for 32-bit and 64-bit operation.
RV32 = CPUMode('RV32', isa) RV32 = CPUMode('RV32', isa)

View File

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