Load, store, local variables.

This commit is contained in:
Jakob Stoklund Olesen
2016-01-22 15:20:10 -08:00
parent 43b4f7f4e7
commit 095190b1a7
3 changed files with 128 additions and 3 deletions

View File

@@ -19,7 +19,7 @@ from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.locale import l_, _
from sphinx.roles import XRefRole
from sphinx.util.docfields import Field, TypedField
from sphinx.util.docfields import Field, GroupedField, TypedField
from sphinx.util.nodes import make_refnode
class CtonObject(ObjectDescription):
@@ -120,6 +120,7 @@ class CtonInst(CtonObject):
TypedField('result', label=l_('Results'),
names=('out', 'result'),
typerolename='type', typenames=('type',)),
GroupedField('flag', names=('flag',), label=l_('Flags')),
Field('resulttype', label=l_('Result type'), has_arg=False,
names=('rtype',)),
]

View File

@@ -28,7 +28,7 @@ class CretonneLexer(RegexLexer):
# Reserved words.
(keywords('function', 'entry'), Keyword),
# Known attributes.
(keywords('align', 'uext', 'sext', 'inreg'), Name.Attribute),
(keywords('align', 'aligntrap', 'uext', 'sext', 'inreg'), Name.Attribute),
# Well known value types.
(r'\b(bool|i\d+|f32|f64)(x\d+)?\b', Keyword.Type),
# v<nn> = value
@@ -38,7 +38,7 @@ class CretonneLexer(RegexLexer):
(r'(ebb)\d+', Name.Label),
# Match instruction names in context.
(r'(=)( *)([a-z]\w*)', bygroups(Operator, Whitespace, Name.Function)),
(r'^( +)([a-z]\w*\b)(?! *[,=])', bygroups(Whitespace, Name.Function)),
(r'^( *)([a-z]\w*\b)(?! *[,=])', bygroups(Whitespace, Name.Function)),
# Other names: results and arguments
(r'[a-z]\w*', Name),
(r'->|=|:', Operator),

View File

@@ -390,6 +390,130 @@ Indirect function calls use a signature declared in the preample.
:inst:`br_table`.
Memory
======
Cretonne provides fully general :inst:`load` and :inst:`store` instructions for
accessing memory. However, it can be very complicated to verify the safety of
general loads and stores when compiling code for a sandboxed environment, so
Cretonne also provides more restricted memory operations that are always safe.
.. inst:: a = load p, Offset, Flags...
Load from memory at ``p + Offset``.
This is a polymorphic instruction that can load any value type which has a
memory representation (i.e., everything except :type:`bool` and boolean
vectors).
:arg iPtr p: Base address.
:arg Offset: Immediate signed offset.
:flag align(N): Expected alignment of ``p + Offset``. Power of two.
:flag aligntrap: Always trap if the memory access is misaligned.
:result T a: Loaded value.
.. inst:: store x, p, Offset, Flags...
Store ``x`` to memory at ``p + Offset``.
This is a polymorphic instruction that can store any value type with a
memory representation.
:arg T x: Value to store.
:arg iPtr p: Base address.
:arg Offset: Immediate signed offset.
:flag align(N): Expected alignment of ``p + Offset``. Power of two.
:flag aligntrap: Always trap if the memory access is misaligned.
Loads and stores are *misaligned* if the resultant address is not a multiple of
the expected alignment. Depending on the target architecture, misaligned memory
accesses may trap, or they may work. Sometimes, operating systems catch
alignment traps and emulate the misaligned memory access.
On target architectures like x86 that don't check alignment, Cretonne expands
the aligntrap flag into a conditional trap instruction::
v5 = load.i32 v1, 4, align(4), aligntrap
; Becomes:
v10 = and_imm v1, 3
trapnz v10
v5 = load.i32 v1, 4
Local variables
---------------
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
allocated in the :term:`function preample`. Stack slots are not typed, they
simply represent a contiguous sequence of bytes in the stack frame.
.. inst:: SS = stack_slot Bytes, Flags...
Allocate a stack slot in the preample.
If no alignment is specified, Cretonne will pick an appropriate alignment
for the stack slot based on its size and access patterns.
:arg Bytes: Stack slot size on bytes.
:flag align(N): Request at least N bytes alignment.
:result SS: Stack slot index.
.. inst:: a = stack_load SS, Offset
Load a value from a stack slot at the constant offset.
This is a polymorphic instruction that can load any value type which has a
memory representation.
The offset is an immediate constant, not an SSA value. The memory access
cannot go out of bounds, i.e. ``sizeof(a) + Offset <= sizeof(SS)``.
:arg SS: Stack slot declared with :inst:`stack_slot`.
:arg Offset: Immediate non-negative offset.
:result T a: Value loaded.
.. inst:: stack_store x, SS, Offset
Store a value to a stack slot at a constant offset.
This is a polymorphic instruction that can store any value type with a
memory representation.
The offset is an immediate constant, not an SSA value. The memory access
cannot go out of bounds, i.e. ``sizeof(a) + Offset <= sizeof(SS)``.
:arg T x: Value to be stored.
:arg SS: Stack slot declared with :inst:`stack_slot`.
:arg Offset: Immediate non-negative offset.
The dedicated stack access instructions are easy ofr the compiler to reason
about because stack slots and offsets are fixed at compile time. For example,
the alignment of these stack memory accesses can be inferred from the offsets
and stack slot alignments.
It can be necessary to escape from the safety of the restricted instructions by
taking the address of a stack slot.
.. inst:: a = stack_addr SS, Offset
Get the address of a stack slot.
Compute the absolute address of a byte in a stack slot. The offset must
refer to a byte inside the stack slot: ``0 <= Offset < sizeof(SS)``.
:arg SS: Stack slot declared with :inst:`stack_slot`.
:arg Offset: Immediate non-negative offset.
:result iPtr a: Address.
The :inst:`stack_addr` instruction can be used to macro-expand the stack access
instructions before instruction selection::
v1 = stack_load.f64 ss3, 16
; Expands to:
v9 = stack_addr ss3, 16
v1 = load.f64 v9
Operations
==========