Add heaps to the Cretonne IL.

Add preamble syntax for declaring static and dynamic heaps, and update
the langref section on heaps. Add IR support for heap references.

Remove the heap_load and heap_store as discussed in #144. We will use
heap_addr along with native load and store instructions in their place.

Add the heap_addr instruction and document its bounds checking
semantics.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-18 12:51:54 -07:00
parent a9238eda7a
commit 3b71a27632
17 changed files with 405 additions and 83 deletions

View File

@@ -30,3 +30,6 @@ func_ref = EntityRefKind('func_ref', 'An external function.')
#: A reference to a jump table declared in the function preamble.
jump_table = EntityRefKind(
'jump_table', 'A jump table.', default_member='table')
#: A reference to a heap declared in the function preamble.
heap = EntityRefKind('heap', 'A heap.')

View File

@@ -8,10 +8,11 @@ in this module.
from __future__ import absolute_import
from cdsl.formats import InstructionFormat
from cdsl.operands import VALUE, VARIABLE_ARGS
from .immediates import imm64, uimm8, ieee32, ieee64, offset32, uoffset32
from .immediates import imm64, uimm8, uimm32, ieee32, ieee64
from .immediates import offset32, uoffset32
from .immediates import boolean, intcc, floatcc, memflags, regunit
from . import entities
from .entities import ebb, sig_ref, func_ref, stack_slot
from .entities import ebb, sig_ref, func_ref, stack_slot, heap
Nullary = InstructionFormat()
@@ -59,6 +60,7 @@ StackStore = InstructionFormat(VALUE, stack_slot, offset32)
# TODO: Add a reference to a `heap` declared in the preamble.
HeapLoad = InstructionFormat(VALUE, uoffset32)
HeapStore = InstructionFormat(VALUE, VALUE, uoffset32)
HeapAddr = InstructionFormat(heap, VALUE, uimm32)
RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit))

View File

@@ -9,7 +9,7 @@ from cdsl.operands import Operand, VARIABLE_ARGS
from cdsl.typevar import TypeVar
from cdsl.instructions import Instruction, InstructionGroup
from base.types import f32, f64, b1
from base.immediates import imm64, uimm8, ieee32, ieee64, offset32, uoffset32
from base.immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32
from base.immediates import boolean, intcc, floatcc, memflags, regunit
from base import entities
from cdsl.ti import WiderOrEq
@@ -360,40 +360,26 @@ global_addr = Instruction(
#
# WebAssembly bounds-checked heap accesses.
#
# TODO: Add a `heap` operand that selects between multiple heaps.
# TODO: Should the immediate offset be a `u32`?
# TODO: Distinguish between `iAddr` for a heap and for a target address? i.e.,
# 32-bit WebAssembly on a 64-bit target has two different types.
Offset = Operand('Offset', uoffset32, 'Unsigned offset to effective address')
HeapOffset = TypeVar('HeapOffset', 'An unsigned heap offset', ints=(32, 64))
heap_load = Instruction(
'heap_load', r"""
Load a value at the address :math:`p + Offset` in the heap H.
Trap if the heap access would be out of bounds.
""",
ins=(p, Offset), outs=a, can_load=True)
heap_store = Instruction(
'heap_store', r"""
Store a value at the address :math:`p + Offset` in the heap H.
Trap if the heap access would be out of bounds.
""",
ins=(x, p, Offset), can_store=True)
H = Operand('H', entities.heap)
p = Operand('p', HeapOffset)
Size = Operand('Size', uimm32, 'Size in bytes')
heap_addr = Instruction(
'heap_addr', r"""
Bounds check and compute absolute address of heap memory.
Verify that the address range ``p .. p + Size - 1`` is valid in the
heap H, and trap if not.
Verify that the offset range ``p .. p + Size - 1`` is in bounds for the
heap H, and generate an absolute address that is safe to dereference.
Convert the heap-relative address in ``p`` to a real absolute address
and return it.
1. If ``p + Size`` is not greater than the heap bound, return an
absolute address corresponding to a byte offset of ``p`` from the
heap's base address.
2. If ``p + Size`` is greater than the heap bound, generate a trap.
""",
ins=(p, Offset), outs=addr)
ins=(H, p, Size), outs=addr)
#
# Materializing constants.