Add entity references as a new operand kind.

Define known entities in the cretonne.entities module.
This commit is contained in:
Jakob Stoklund Olesen
2016-05-18 15:30:16 -07:00
parent 1dcac579fb
commit d85fda0346
7 changed files with 96 additions and 41 deletions

View File

@@ -36,11 +36,11 @@ Here is the same function compiled into Cretonne IL:
The first line of a function definition provides the function *name* and The first line of a function definition provides the function *name* and
the :term:`function signature` which declares the argument and return types. the :term:`function signature` which declares the argument and return types.
Then follows the :term:`function preample` which declares a number of entities Then follows the :term:`function preamble` which declares a number of entities
that can be referenced inside the function. In the example above, the preample that can be referenced inside the function. In the example above, the preamble
declares a single local variable, ``ss1``. declares a single local variable, ``ss1``.
After the preample follows the :term:`function body` which consists of After the preamble follows the :term:`function body` which consists of
:term:`extended basic block`\s, one of which is marked as the :term:`entry :term:`extended basic block`\s, one of which is marked as the :term:`entry
block`. Every EBB ends with a :term:`terminator instruction`, so execution can block`. Every EBB ends with a :term:`terminator instruction`, so execution can
never fall through to the next EBB without an explicit branch. never fall through to the next EBB without an explicit branch.
@@ -49,7 +49,7 @@ A ``.cton`` file consists of a sequence of independent function definitions:
.. productionlist:: .. productionlist::
function-list : { function } function-list : { function }
function : function-spec "{" preample function-body "}" function : function-spec "{" preamble function-body "}"
function-spec : "function" function-name signature function-spec : "function" function-name signature
preamble : { preamble-decl } preamble : { preamble-decl }
function-body : { extended-basic-block } function-body : { extended-basic-block }
@@ -361,12 +361,12 @@ instruction in the EBB.
blocks. Split critical edges as needed to work around this. blocks. Split critical edges as needed to work around this.
:arg iN x: Integer index into jump table. :arg iN x: Integer index into jump table.
:arg JT: Jump table which was declared in the preample. :arg JT: Jump table which was declared in the preamble.
:result: None. :result: None.
.. inst:: JT = jump_table EBB0, EBB1, ..., EBBn .. inst:: JT = jump_table EBB0, EBB1, ..., EBBn
Declare a jump table in the :term:`function preample`. Declare a jump table in the :term:`function preamble`.
This declares a jump table for use by the :inst:`br_table` indirect branch This declares a jump table for use by the :inst:`br_table` indirect branch
instruction. Entries in the table are either EBB names, or ``0`` which instruction. Entries in the table are either EBB names, or ``0`` which
@@ -433,7 +433,7 @@ dependent. They make it possible to call native functions on the target
platform. When calling other Cretonne functions, the flags are not necessary. platform. When calling other Cretonne functions, the flags are not necessary.
Functions that are called directly must be declared in the :term:`function Functions that are called directly must be declared in the :term:`function
preample`: preamble`:
.. inst:: F = function NAME signature .. inst:: F = function NAME signature
@@ -476,7 +476,7 @@ This simple example illustrates direct function calls and signatures::
return v1 return v1
} }
Indirect function calls use a signature declared in the preample. Indirect function calls use a signature declared in the preamble.
.. inst:: SIG = signature signature .. inst:: SIG = signature signature
@@ -556,12 +556,12 @@ Local variables
One set of restricted memory operations access the current function's stack One set of restricted memory operations access the current function's stack
frame. The stack frame is divided into fixed-size stack slots that are frame. The stack frame is divided into fixed-size stack slots that are
allocated in the :term:`function preample`. Stack slots are not typed, they allocated in the :term:`function preamble`. Stack slots are not typed, they
simply represent a contiguous sequence of bytes in the stack frame. simply represent a contiguous sequence of bytes in the stack frame.
.. inst:: SS = stack_slot Bytes, Flags... .. inst:: SS = stack_slot Bytes, Flags...
Allocate a stack slot in the preample. Allocate a stack slot in the preamble.
If no alignment is specified, Cretonne will pick an appropriate alignment If no alignment is specified, Cretonne will pick an appropriate alignment
for the stack slot based on its size and access patterns. for the stack slot based on its size and access patterns.
@@ -633,14 +633,14 @@ all process memory. Instead, it is given a small set of memory areas to work
in, and all accesses are bounds checked. Cretonne models this through the in, and all accesses are bounds checked. Cretonne models this through the
concept of *heaps*. concept of *heaps*.
A heap is declared in the function preample and can be accessed with restricted A heap is declared in the function preamble and can be accessed with restricted
instructions that trap on out-of-bounds accesses. Heap addresses can be smaller instructions that trap on out-of-bounds accesses. Heap addresses can be smaller
than the native pointer size, for example unsigned :type:`i32` offsets on a than the native pointer size, for example unsigned :type:`i32` offsets on a
64-bit architecture. 64-bit architecture.
.. inst:: H = heap Name .. inst:: H = heap Name
Declare a heap in the function preample. Declare a heap in the function preamble.
This doesn't allocate memory, it just retrieves a handle to a sandbox from This doesn't allocate memory, it just retrieves a handle to a sandbox from
the runtime environment. the runtime environment.
@@ -1034,9 +1034,9 @@ Glossary
is not necessary to know when calling it, so it is just an attribute, is not necessary to know when calling it, so it is just an attribute,
and not part of the signature. and not part of the signature.
function preample function preamble
A list of declarations of entities that are used by the function body. A list of declarations of entities that are used by the function body.
Some of the entities that can be declared in the preample are: Some of the entities that can be declared in the preamble are:
- Local variables. - Local variables.
- Functions that are called directly. - Functions that are called directly.
@@ -1045,7 +1045,7 @@ Glossary
function body function body
The extended basic blocks which contain all the executable code in a The extended basic blocks which contain all the executable code in a
function. The function body follows the function preample. function. The function body follows the function preamble.
basic block basic block
A maximal sequence of instructions that can only be entered from the A maximal sequence of instructions that can only be entered from the

View File

@@ -47,14 +47,14 @@ must be instances of the :class:`Operand` class.
.. autoclass:: Operand .. autoclass:: Operand
Cretonne uses two separate type systems for immediate operands and SSA values. Cretonne uses two separate type systems for operand kinds and SSA values.
Type variables Type variables
-------------- --------------
Instruction descriptions can be made polymorphic by using :class:`Operand` Instruction descriptions can be made polymorphic by using :class:`Operand`
instances that refer to a *type variable* instead of a concrete value type. 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 Polymorphism only works for SSA value operands. Other operands have a fixed
operand kind. operand kind.
.. autoclass:: TypeVar .. autoclass:: TypeVar
@@ -95,6 +95,18 @@ indicated with an instance of :class:`ImmediateKind`.
.. currentmodule:: cretonne .. currentmodule:: cretonne
Entity references
-----------------
Instruction operands can also refer to other entties in the same function. This
can be extended basic blocks, or entities declared in the function preamble.
.. autoclass:: EntityRefKind
.. automodule:: cretonne.entities
:members:
.. currentmodule:: cretonne
Value types Value types
----------- -----------
@@ -133,13 +145,14 @@ representation depends on the input operand kinds and whether the instruction
can produce multiple results. can produce multiple results.
.. autoclass:: OperandKind .. autoclass:: OperandKind
.. inheritance-diagram:: OperandKind ImmediateKind EntityRefkind
Since all SSA value operands are represented as a `Value` in Rust code, value 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 types don't affect the representation. Two special operand kinds are used to
represent SSA values: represent SSA values:
.. autodata:: value .. autodata:: value
.. autodata:: args .. autodata:: variable_args
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

View File

@@ -42,6 +42,12 @@ class OperandKind(object):
def __repr__(self): def __repr__(self):
return 'OperandKind({})'.format(self.name) return 'OperandKind({})'.format(self.name)
def operand_kind(self):
"""
An `OperandKind` instance can be used directly as the type of an
`Operand` when defining an instruction.
"""
return self
#: An SSA value operand. This is a value defined by another instruction. #: An SSA value operand. This is a value defined by another instruction.
value = OperandKind( value = OperandKind(
@@ -55,8 +61,8 @@ value = OperandKind(
#: A variable-sized list of value operands. Use for Ebb and function call #: A variable-sized list of value operands. Use for Ebb and function call
#: arguments. #: arguments.
args = OperandKind( variable_args = OperandKind(
'args', """ 'variable_args', """
A variable size list of `value` operands. A variable size list of `value` operands.
Use this to represent arguemtns passed to a function call, arguments Use this to represent arguemtns passed to a function call, arguments
@@ -65,8 +71,8 @@ args = OperandKind(
""") """)
# Instances of immediate operand types are provided in the cretonne.immediates # Instances of immediate operand types are provided in the
# module. # `cretonne.immediates` module.
class ImmediateKind(OperandKind): class ImmediateKind(OperandKind):
""" """
The kind of an immediate instruction operand. The kind of an immediate instruction operand.
@@ -79,12 +85,20 @@ class ImmediateKind(OperandKind):
def __repr__(self): def __repr__(self):
return 'ImmediateKind({})'.format(self.name) return 'ImmediateKind({})'.format(self.name)
def operand_kind(self):
""" # Instances of entity reference operand types are provided in the
An `ImmediateKind` instance can be used directly as the type of an # `cretonne.entities` module.
`Operand` when defining an instruction. class EntityRefKind(OperandKind):
""" """
return self The kind of an entity reference instruction operand.
"""
def __init__(self, name, doc):
self.name = name
self.__doc__ = doc
def __repr__(self):
return 'EntityRefKind({})'.format(self.name)
# ValueType instances (i8, i32, ...) are provided in the cretonne.types module. # ValueType instances (i8, i32, ...) are provided in the cretonne.types module.
@@ -315,8 +329,8 @@ class InstructionGroup(object):
class Operand(object): class Operand(object):
""" """
An instruction operand can be either an *immediate* or an *SSA value*. The An instruction operand can be an *immediate*, an *SSA value*, or an *entity
type of the operand is one of: reference*. The type of the operand is one of:
1. A :py:class:`ValueType` instance indicates an SSA value operand with a 1. A :py:class:`ValueType` instance indicates an SSA value operand with a
concrete type. concrete type.
@@ -329,6 +343,10 @@ class Operand(object):
whose value is encoded in the instruction itself rather than being whose value is encoded in the instruction itself rather than being
passed as an SSA value. passed as an SSA value.
4. An :py:class:`EntityRefKind` instance indicates an operand that
references another entity in the function, typically something declared
in the function preamble.
""" """
def __init__(self, name, typ, doc=''): def __init__(self, name, typ, doc=''):
self.name = name self.name = name
@@ -429,9 +447,9 @@ class Instruction(object):
:param name: Instruction mnemonic, also becomes opcode name. :param name: Instruction mnemonic, also becomes opcode name.
:param doc: Documentation string. :param doc: Documentation string.
:param ins: Tuple of input operands. This can be a mix of SSA value :param ins: Tuple of input operands. This can be a mix of SSA value
operands and immediate operands. operands and other operand kinds.
:param outs: Tuple of output operands. The output operands can't be :param outs: Tuple of output operands. The output operands must be SSA
immediates. values.
""" """
def __init__(self, name, doc, ins=(), outs=(), **kwargs): def __init__(self, name, doc, ins=(), outs=(), **kwargs):

23
meta/cretonne/entities.py Normal file
View File

@@ -0,0 +1,23 @@
"""
The `cretonne.entities` module predefines all the Cretonne entity reference
operand types. Thee are corresponding definitions in the `cretonne.entities`
Rust module.
"""
from . import EntityRefKind
#: A reference to an extended basic block in the same function.
#: This is primarliy used in control flow instructions.
ebb = EntityRefKind('ebb', 'An extended basic block in the same function.')
#: A reference to a stack slot declared in the function preamble.
stack_slot = EntityRefKind('stack_slot', 'A stack slot.')
#: A reference to a function sugnature declared in the function preamble.
#: Tbis is used to provide the call signature in an indirect call instruction.
signature = EntityRefKind('signature', 'A function signature.')
#: A reference to an external function declared in the function preamble.
#: This is used to provide the callee and signature in a call instruction.
function = EntityRefKind('function', 'An external function.')

View File

@@ -7,8 +7,9 @@ in this module.
""" """
from . import InstructionFormat, value, args from . import InstructionFormat, value, variable_args
from immediates import imm64, ieee32, ieee64, immvector from immediates import imm64, ieee32, ieee64, immvector
from entities import function
Nullary = InstructionFormat() Nullary = InstructionFormat()
@@ -22,7 +23,7 @@ Binary = InstructionFormat(value, value)
BinaryImm = InstructionFormat(value, imm64) BinaryImm = InstructionFormat(value, imm64)
BinaryImmRev = InstructionFormat(imm64, value) BinaryImmRev = InstructionFormat(imm64, value)
Call = InstructionFormat(args, multiple_results=True) Call = InstructionFormat(function, variable_args, multiple_results=True)
# Finally extract the names of global variables in this module. # Finally extract the names of global variables in this module.
InstructionFormat.extract_names(globals()) InstructionFormat.extract_names(globals())

View File

@@ -1,5 +1,5 @@
""" """
The cretonne.immediates module predefines all the Cretonne immediate operand The `cretonne.immediates` module predefines all the Cretonne immediate operand
types. types.
""" """

View File

@@ -300,19 +300,19 @@ impl<'a> Parser<'a> {
// Parse a whole function definition. // Parse a whole function definition.
// //
// function ::= * function-spec "{" preample function-body "}" // function ::= * function-spec "{" preamble function-body "}"
// //
fn parse_function(&mut self) -> Result<Function> { fn parse_function(&mut self) -> Result<Function> {
let (name, sig) = try!(self.parse_function_spec()); let (name, sig) = try!(self.parse_function_spec());
let mut ctx = Context::new(Function::with_name_signature(name, sig)); let mut ctx = Context::new(Function::with_name_signature(name, sig));
// function ::= function-spec * "{" preample function-body "}" // function ::= function-spec * "{" preamble function-body "}"
try!(self.match_token(Token::LBrace, "expected '{' before function body")); try!(self.match_token(Token::LBrace, "expected '{' before function body"));
// function ::= function-spec "{" * preample function-body "}" // function ::= function-spec "{" * preamble function-body "}"
try!(self.parse_preamble(&mut ctx)); try!(self.parse_preamble(&mut ctx));
// function ::= function-spec "{" preample * function-body "}" // function ::= function-spec "{" preamble * function-body "}"
try!(self.parse_function_body(&mut ctx)); try!(self.parse_function_body(&mut ctx));
// function ::= function-spec "{" preample function-body * "}" // function ::= function-spec "{" preamble function-body * "}"
try!(self.match_token(Token::RBrace, "expected '}' after function body")); try!(self.match_token(Token::RBrace, "expected '}' after function body"));
Ok(ctx.function) Ok(ctx.function)