More ideas about easy code generation

This commit is contained in:
Johan B.W. de Vries 2022-08-06 13:44:11 +02:00
parent fea817ca00
commit a5c68065d7
4 changed files with 206 additions and 1 deletions

0
phasm/stdlib/__init__.py Normal file
View File

129
phasm/stdlib/alloc.py Normal file
View File

@ -0,0 +1,129 @@
"""
stdlib: Memory allocation
"""
from phasm.wasmeasy import Generator, func_wrapper
IDENTIFIER = 0xA1C0
ADR_IDENTIFIER = 0
ADR_RESERVED0 = ADR_IDENTIFIER + 4
ADR_FREE_BLOCK_PTR = ADR_RESERVED0 + 4
ADR_UNALLOC_PTR = ADR_FREE_BLOCK_PTR + 4
@func_wrapper
def __init__(g: Generator) -> None:
"""
Initializes the memory so we can allocate it
"""
# Check if the memory is already initialized
g.i32.const(0)
g.i32.load()
g.i32.const(IDENTIFIER)
g.i32.eq()
with g.if_():
# Already initialized, return without any changes
g.return_()
# Store the first reserved i32
g.i32.const(ADR_RESERVED0)
g.i32.const(0)
g.i32.store()
# Store the pointer towards the first free block
# In this case, 0 since we haven't freed any blocks yet
g.i32.const(ADR_FREE_BLOCK_PTR)
g.i32.const(0)
g.i32.store()
# Store the pointer towards the first unallocated block
# In this case the end of the stdlib.alloc header at the start
g.i32.const(ADR_UNALLOC_PTR)
g.i32.const(0x10)
g.i32.store()
# Store that we've initialized the memory
g.i32.const(0)
g.i32.const(IDENTIFIER)
g.i32.store()
@func_wrapper
def __find_free_block__(g: Generator) -> None:
# Find out if we've freed any blocks at all so far
g.i32.const(ADR_FREE_BLOCK_PTR)
g.i32.load()
g.i32.const(0)
g.i32.eq()
with g.if_():
g.i32.const(0)
g.return_()
g.unreachable()
@func_wrapper
def __alloc__(g: Generator) -> None:
g.i32.const(ADR_IDENTIFIER)
g.i32.load()
g.i32.const(IDENTIFIER)
g.i32.ne()
with g.if_():
g.unreachable()
# def _generate_stdlib_alloc___alloc__(mod: ourlang.Module) -> wasm.Function:
# return wasm.Function(
# 'stdlib.alloc.__alloc__',
# 'stdlib.alloc.__alloc__',
# [
# ('alloc_size', type_(mod.types['i32']), ),
# ],
# [
# ('result', type_(mod.types['i32']), ),
# ],
# type_(mod.types['i32']),
# [
# i32.const(0),
# i32.load(),
# i32.const(STDLIB_ALLOC__IDENTIFIER),
# i32.ne(),
# *wasmeasy.if_(
# wasm.Statement('unreachable'),
# ),
#
# wasm.Statement('local.get', '$alloc_size'),
# wasm.Statement('call', '$stdlib.alloc.__find_free_block__'),
# wasm.Statement('local.set', '$result'),
#
# # Check if there was a free block
# wasm.Statement('local.get', '$result'),
# i32.const(0),
# i32.eq(),
# *wasmeasy.if_(
# # Use unallocated space
# i32.const(STDLIB_ALLOC__ADR_UNALLOC_PTR),
#
# i32.const(STDLIB_ALLOC__ADR_UNALLOC_PTR),
# i32.load(),
# wasm.Statement('local.tee', '$result'),
#
# # Updated unalloc pointer (address already set on stack)
# i32.const(4), # Header size
# i32.add(),
# wasm.Statement('local.get', '$alloc_size'),
# i32.add(),
# i32.store('offset=0'),
# ),
#
# # Store block size
# wasm.Statement('local.get', '$result'),
# wasm.Statement('local.get', '$alloc_size'),
# i32.store('offset=0'),
#
# # Return address of the allocated bytes
# wasm.Statement('local.get', '$result'),
# i32.const(4), # Header size
# i32.add(),
# ],
# )

View File

@ -1,7 +1,7 @@
"""
Helper functions to quickly generate WASM code
"""
from typing import List, Optional
from typing import Any, List, Optional
import functools
@ -67,3 +67,76 @@ class Block:
]
if_ = Block('if')
class Generator_i32:
def __init__(self, generator: 'Generator') -> None:
self.generator = generator
# 2.4.1. Numeric Instructions
self.eq = functools.partial(self.generator.add, 'i32.eq')
self.ne = functools.partial(self.generator.add, 'i32.ne')
# 2.4.4. Memory Instructions
self.load = functools.partial(self.generator.add, 'i32.load')
self.store = functools.partial(self.generator.add, 'i32.store')
def const(self, value: int, comment: Optional[str] = None) -> None:
self.generator.add('i32.const', f'0x{value:08x}', comment=comment)
class GeneratorBlock:
def __init__(self, generator: 'Generator', name: str) -> None:
self.generator = generator
self.name = name
def __enter__(self) -> None:
self.generator.add(self.name)
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
if not exc_type:
self.generator.add('end')
class Generator:
def __init__(self) -> None:
self.statements: List[wasm.Statement] = []
self.i32 = Generator_i32(self)
# 2.4.5 Control Instructions
self.nop = functools.partial(self.add, 'nop')
self.unreachable = functools.partial(self.add, 'unreachable')
# block
# loop
self.if_ = functools.partial(GeneratorBlock, self, 'if')
# br
# br_if
# br_table
self.return_ = functools.partial(self.add, 'return')
# call
# call_indirect
def add(self, name: str, *args: str, comment: Optional[str] = None) -> None:
self.statements.append(wasm.Statement(name, *args, comment=comment))
def func_wrapper(func: Any) -> wasm.Function:
assert func.__module__.startswith('phasm.')
assert Generator is func.__annotations__['g']
params: Any = []
locals_: Any = []
assert None is func.__annotations__['return']
return_type = wasm.WasmTypeNone()
generator = Generator()
func(g=generator)
return wasm.Function(
func.__module__[6:] + '.' + func.__name__,
func.__module__[6:] + '.' + func.__name__,
params,
locals_,
return_type,
generator.statements,
)

View File

@ -1,2 +1,5 @@
[MASTER]
disable=C0122,R0903,R0911,R0912,R0913,R0915,R1710,W0223
[stdlib]
good-names=g