Foldable take a TypeConstructor. The first argument must be a NatNum. The FunctionSignatureRouter wasn't completely on point, instead this commit adds an TypeClassArgsRouter lookup router. This makes sense since the only available arguments we have to find a router is the list of type class arguments.
1188 lines
29 KiB
Python
1188 lines
29 KiB
Python
"""
|
|
stdlib: Standard types that are not wasm primitives
|
|
"""
|
|
from phasm.stdlib import alloc
|
|
from phasm.type3.routers import TypeVariableLookup
|
|
from phasm.type3.types import IntType3, Type3
|
|
from phasm.wasmgenerator import Generator, func_wrapper
|
|
from phasm.wasmgenerator import VarType_i32 as i32
|
|
from phasm.wasmgenerator import VarType_i64 as i64
|
|
|
|
|
|
@func_wrapper()
|
|
def __alloc_bytes__(g: Generator, length: i32) -> i32:
|
|
"""
|
|
Allocates room for a bytes instance, but does not write
|
|
anything to the allocated memory
|
|
"""
|
|
result = i32('result')
|
|
|
|
# Allocate the length of the byte string, as well
|
|
# as 4 bytes for a length header
|
|
g.local.get(length)
|
|
g.i32.const(4)
|
|
g.i32.add()
|
|
g.call(alloc.__alloc__)
|
|
|
|
# Store the address in a variable so we can use it up
|
|
# for writing the length header
|
|
g.local.tee(result)
|
|
g.local.get(length)
|
|
g.i32.store()
|
|
|
|
# Get the address back from the variable as return
|
|
g.local.get(result)
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __subscript_bytes__(g: Generator, adr: i32, ofs: i32) -> i32:
|
|
"""
|
|
Returns an index from a bytes value
|
|
|
|
If ofs is more than the length of the bytes, this
|
|
function stop as unreachable.
|
|
|
|
adr i32 The pointer for the allocated bytes
|
|
ofs i32 The offset within the allocated bytes
|
|
"""
|
|
g.local.get(ofs)
|
|
g.local.get(adr)
|
|
g.i32.load()
|
|
g.i32.ge_u()
|
|
|
|
with g.if_():
|
|
# The offset is outside the allocated bytes
|
|
g.unreachable(comment='Out of bounds')
|
|
|
|
# The offset is less than the length
|
|
|
|
g.local.get(adr)
|
|
g.i32.const(4) # Bytes header
|
|
g.i32.add()
|
|
g.local.get(ofs)
|
|
g.i32.add()
|
|
g.i32.load8_u()
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __u32_ord_min__(g: Generator, x: i32, y: i32) -> i32:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i32.lt_u()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __u64_ord_min__(g: Generator, x: i64, y: i64) -> i64:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i64.lt_u()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i64('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __i32_ord_min__(g: Generator, x: i32, y: i32) -> i32:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i32.lt_s()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __i64_ord_min__(g: Generator, x: i64, y: i64) -> i64:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i64.lt_s()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i64('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __u32_ord_max__(g: Generator, x: i32, y: i32) -> i32:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i32.gt_u()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __u64_ord_max__(g: Generator, x: i64, y: i64) -> i64:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i64.gt_u()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i64('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __i32_ord_max__(g: Generator, x: i32, y: i32) -> i32:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i32.gt_s()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __i64_ord_max__(g: Generator, x: i64, y: i64) -> i64:
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i64.gt_s()
|
|
|
|
with g.if_():
|
|
g.local.get(x)
|
|
g.return_()
|
|
|
|
g.local.get(y)
|
|
g.return_()
|
|
|
|
return i64('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __i32_intnum_abs__(g: Generator, x: i32) -> i32:
|
|
# https://stackoverflow.com/a/14194764
|
|
y = i32('y')
|
|
# z = i32('z')
|
|
|
|
# y = x >> 31
|
|
g.local.get(x)
|
|
g.i32.const(31)
|
|
g.i32.shr_s() # Must be arithmetic shift
|
|
g.local.set(y)
|
|
|
|
# abs(x) = (x XOR y) - y
|
|
|
|
# (x XOR y)
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i32.xor()
|
|
|
|
# - y
|
|
g.local.get(y)
|
|
g.i32.sub()
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __i64_intnum_abs__(g: Generator, x: i64) -> i64:
|
|
# https://stackoverflow.com/a/14194764
|
|
y = i64('y')
|
|
# z = i64('z')
|
|
|
|
# y = x >> 31
|
|
g.local.get(x)
|
|
g.i64.const(31)
|
|
g.i64.shr_s() # Must be arithmetic shift
|
|
g.local.set(y)
|
|
|
|
# abs(x) = (x XOR y) - y
|
|
|
|
# (x XOR y)
|
|
g.local.get(x)
|
|
g.local.get(y)
|
|
g.i64.xor()
|
|
|
|
# - y
|
|
g.local.get(y)
|
|
g.i64.sub()
|
|
g.return_()
|
|
|
|
return i64('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __u32_pow2__(g: Generator, x: i32) -> i32:
|
|
# 2^0 == 1
|
|
g.local.get(x)
|
|
g.i32.eqz()
|
|
with g.if_():
|
|
g.i32.const(1)
|
|
g.return_()
|
|
|
|
# 2 ^ x == 2 << (x - 1)
|
|
# (when x > 1)
|
|
g.i32.const(2)
|
|
g.local.get(x)
|
|
g.i32.const(1)
|
|
g.i32.sub()
|
|
g.i32.shl()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __u8_rotl__(g: Generator, x: i32, r: i32) -> i32:
|
|
s = i32('s') # The shifted part we need to overlay
|
|
|
|
# Handle cases where we need to shift more than 8 bits
|
|
g.local.get(r)
|
|
g.i32.const(8)
|
|
g.i32.rem_u()
|
|
g.local.set(r)
|
|
|
|
# Now do the rotation
|
|
|
|
g.local.get(x)
|
|
|
|
# 0000 0000 1100 0011
|
|
|
|
g.local.get(r)
|
|
|
|
# 0000 0000 1100 0011, 3
|
|
|
|
g.i32.shl()
|
|
|
|
# 0000 0110 0001 1000
|
|
|
|
g.local.tee(s)
|
|
|
|
# 0000 0110 0001 1000
|
|
|
|
g.i32.const(255)
|
|
|
|
# 0000 0110 0001 1000, 0000 0000 1111 1111
|
|
|
|
g.i32.and_()
|
|
|
|
# 0000 0000 0001 1000
|
|
|
|
g.local.get(s)
|
|
|
|
# 0000 0000 0001 1000, 0000 0110 0001 1000
|
|
|
|
g.i32.const(65280)
|
|
|
|
# 0000 0000 0001 1000, 0000 0110 0001 1000, 1111 1111 0000 0000
|
|
|
|
g.i32.and_()
|
|
|
|
# 0000 0000 0001 1000, 0000 0110 0000 0000
|
|
|
|
g.i32.const(8)
|
|
|
|
# 0000 0000 0001 1000, 0000 0110 0000 0000, 8
|
|
|
|
g.i32.shr_u()
|
|
|
|
# 0000 0000 0001 1000, 0000 0000 0000 0110
|
|
|
|
g.i32.or_()
|
|
|
|
# 0000 0000 0001 110
|
|
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __u8_rotr__(g: Generator, x: i32, r: i32) -> i32:
|
|
s = i32('s') # The shifted part we need to overlay
|
|
|
|
# Handle cases where we need to shift more than 8 bits
|
|
g.local.get(r)
|
|
g.i32.const(8)
|
|
g.i32.rem_u()
|
|
g.local.set(r)
|
|
|
|
# Now do the rotation
|
|
|
|
g.local.get(x)
|
|
|
|
# 0000 0000 1100 0011
|
|
|
|
g.local.get(r)
|
|
|
|
# 0000 0000 1100 0011, 3
|
|
|
|
g.i32.rotr()
|
|
|
|
# 0110 0000 0000 0000 0000 0000 0001 1000
|
|
|
|
g.local.tee(s)
|
|
|
|
# 0110 0000 0000 0000 0000 0000 0001 1000
|
|
|
|
g.i32.const(255)
|
|
|
|
# 0110 0000 0000 0000 0000 0000 0001 1000, 0000 0000 1111 1111
|
|
|
|
g.i32.and_()
|
|
|
|
# 0000 0000 0000 0000 0000 0000 0001 1000
|
|
|
|
g.local.get(s)
|
|
|
|
# 0000 0000 0000 0000 0000 0000 0001 1000, 0110 0000 0000 0000 0000 0000 0001 1000
|
|
|
|
g.i32.const(4278190080)
|
|
|
|
# 0000 0000 0000 0000 0000 0000 0001 1000, 0110 0000 0000 0000 0000 0000 0001 1000, 1111 1111 0000 0000 0000 0000 0000 0000
|
|
|
|
g.i32.and_()
|
|
|
|
# 0000 0000 0000 0000 0000 0000 0001 1000, 0110 0000 0000 0000 0000 0000 0000 0000
|
|
|
|
g.i32.const(24)
|
|
|
|
# 0000 0000 0000 0000 0000 0000 0001 1000, 0110 0000 0000 0000 0000 0000 0000 0000, 24
|
|
|
|
g.i32.shr_u()
|
|
|
|
# 0000 0000 0000 0000 0000 0000 0001 1000, 0000 0000 0000 0000 0000 0000 0110 0000
|
|
|
|
g.i32.or_()
|
|
|
|
# 0000 0000 0000 0000 0000 0000 0111 1000
|
|
|
|
g.return_()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
## ###
|
|
## class Eq
|
|
|
|
def u8_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.eq()
|
|
|
|
def u32_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.eq()
|
|
|
|
def u64_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.eq()
|
|
|
|
def i8_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.eq()
|
|
|
|
def i32_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.eq()
|
|
|
|
def i64_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.eq()
|
|
|
|
def f32_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.eq()
|
|
|
|
def f64_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.eq()
|
|
|
|
def u8_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ne()
|
|
|
|
def u32_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ne()
|
|
|
|
def u64_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.ne()
|
|
|
|
def i8_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ne()
|
|
|
|
def i32_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ne()
|
|
|
|
def i64_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.ne()
|
|
|
|
def f32_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.ne()
|
|
|
|
def f64_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.ne()
|
|
|
|
## ###
|
|
## class Ord
|
|
|
|
def u8_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_ord_min__')
|
|
|
|
def u32_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_ord_min__')
|
|
|
|
def u64_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u64_ord_min__')
|
|
|
|
def i8_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i32_ord_min__')
|
|
|
|
def i32_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i32_ord_min__')
|
|
|
|
def i64_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i64_ord_min__')
|
|
|
|
def f32_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.min()
|
|
|
|
def f64_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.min()
|
|
|
|
def u8_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_ord_max__')
|
|
|
|
def u32_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_ord_max__')
|
|
|
|
def u64_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u64_ord_max__')
|
|
|
|
def i8_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i32_ord_max__')
|
|
|
|
def i32_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i32_ord_max__')
|
|
|
|
def i64_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i64_ord_max__')
|
|
|
|
def f32_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.max()
|
|
|
|
def f64_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.max()
|
|
|
|
|
|
def u8_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.lt_u()
|
|
|
|
def u32_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.lt_u()
|
|
|
|
def u64_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.lt_u()
|
|
|
|
def i8_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.lt_s()
|
|
|
|
def i32_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.lt_s()
|
|
|
|
def i64_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.lt_s()
|
|
|
|
def f32_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.lt()
|
|
|
|
def f64_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.lt()
|
|
|
|
def u8_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.le_u()
|
|
|
|
def u32_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.le_u()
|
|
|
|
def u64_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.le_u()
|
|
|
|
def i8_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.le_s()
|
|
|
|
def i32_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.le_s()
|
|
|
|
def i64_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.le_s()
|
|
|
|
def f32_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.le()
|
|
|
|
def f64_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.le()
|
|
|
|
def u8_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.gt_u()
|
|
|
|
def u32_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.gt_u()
|
|
|
|
def u64_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.gt_u()
|
|
|
|
def i8_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.gt_s()
|
|
|
|
def i32_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.gt_s()
|
|
|
|
def i64_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.gt_s()
|
|
|
|
def f32_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.gt()
|
|
|
|
def f64_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.gt()
|
|
|
|
def u8_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ge_u()
|
|
|
|
def u32_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ge_u()
|
|
|
|
def u64_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.ge_u()
|
|
|
|
def i8_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ge_s()
|
|
|
|
def i32_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.ge_s()
|
|
|
|
def i64_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.ge_s()
|
|
|
|
def f32_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.ge()
|
|
|
|
def f64_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.ge()
|
|
|
|
## ###
|
|
## class Bits
|
|
|
|
def u8_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shl()
|
|
g.i32.const(255)
|
|
g.i32.and_()
|
|
|
|
def u32_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shl()
|
|
|
|
def u64_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.shl()
|
|
|
|
def u8_bits_logical_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shr_u()
|
|
|
|
def u32_bits_logical_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shr_u()
|
|
|
|
def u64_bits_logical_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.shr_u()
|
|
|
|
def u8_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u8_rotl__')
|
|
|
|
def u32_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.rotl()
|
|
|
|
def u64_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.rotl()
|
|
|
|
def u8_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u8_rotr__')
|
|
|
|
def u32_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.rotr()
|
|
|
|
def u64_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.rotr()
|
|
|
|
def u8_bits_bitwise_and(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.and_()
|
|
|
|
def u32_bits_bitwise_and(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.and_()
|
|
|
|
def u64_bits_bitwise_and(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.and_()
|
|
|
|
def u8_bits_bitwise_or(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.or_()
|
|
|
|
def u32_bits_bitwise_or(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.or_()
|
|
|
|
def u64_bits_bitwise_or(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.or_()
|
|
|
|
def u8_bits_bitwise_xor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.xor()
|
|
|
|
def u32_bits_bitwise_xor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.xor()
|
|
|
|
def u64_bits_bitwise_xor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.xor()
|
|
|
|
## ###
|
|
## class Fractional
|
|
|
|
def f32_fractional_ceil(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.ceil()
|
|
|
|
def f64_fractional_ceil(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.ceil()
|
|
|
|
def f32_fractional_floor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.floor()
|
|
|
|
def f64_fractional_floor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.floor()
|
|
|
|
def f32_fractional_trunc(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.trunc()
|
|
|
|
def f64_fractional_trunc(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.trunc()
|
|
|
|
def f32_fractional_nearest(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.nearest()
|
|
|
|
def f64_fractional_nearest(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.nearest()
|
|
|
|
def f32_fractional_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.div()
|
|
|
|
def f64_fractional_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.div()
|
|
|
|
## ###
|
|
## class Floating
|
|
|
|
def f32_floating_sqrt(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f32.sqrt')
|
|
|
|
def f64_floating_sqrt(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f64.sqrt')
|
|
|
|
## ###
|
|
## class Integral
|
|
|
|
def u32_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.div_u')
|
|
|
|
def u64_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.div_u')
|
|
|
|
def i32_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.div_s')
|
|
|
|
def i64_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.div_s')
|
|
|
|
def u32_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.rem_u')
|
|
|
|
def u64_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.rem_u')
|
|
|
|
def i32_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.rem_s')
|
|
|
|
def i64_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.rem_s')
|
|
|
|
## ###
|
|
## class NatNum
|
|
|
|
def u32_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.add')
|
|
|
|
def u64_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.add')
|
|
|
|
def i32_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.add')
|
|
|
|
def i64_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.add')
|
|
|
|
def f32_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f32.add')
|
|
|
|
def f64_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f64.add')
|
|
|
|
def u32_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.sub')
|
|
|
|
def u64_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.sub')
|
|
|
|
def i32_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.sub')
|
|
|
|
def i64_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.sub')
|
|
|
|
def f32_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f32.sub')
|
|
|
|
def f64_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f64.sub')
|
|
|
|
def u32_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.mul')
|
|
|
|
def u64_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.mul')
|
|
|
|
def i32_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i32.mul')
|
|
|
|
def i64_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('i64.mul')
|
|
|
|
def f32_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f32.mul')
|
|
|
|
def f64_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('f64.mul')
|
|
|
|
def u32_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shl()
|
|
|
|
def u64_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.shl()
|
|
|
|
def i32_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shl()
|
|
|
|
def i64_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.shl()
|
|
|
|
def f32_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
|
g.f32.convert_i32_u()
|
|
g.f32.mul()
|
|
|
|
def f64_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
|
g.f64.convert_i32_u()
|
|
g.f64.mul()
|
|
|
|
def u32_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shr_u()
|
|
|
|
def u64_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.shr_u()
|
|
|
|
def i32_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.shr_s()
|
|
|
|
def i64_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
g.i64.shr_s()
|
|
|
|
def f32_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
|
g.f32.convert_i32_u()
|
|
g.f32.div()
|
|
|
|
def f64_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
|
g.f64.convert_i32_u()
|
|
g.f64.div()
|
|
|
|
## ###
|
|
## class IntNum
|
|
|
|
def i32_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i32_intnum_abs__')
|
|
|
|
def i64_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.add_statement('call $stdlib.types.__i64_intnum_abs__')
|
|
|
|
def f32_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.abs()
|
|
|
|
def f64_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.abs()
|
|
|
|
def i32_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.const(-1)
|
|
g.i32.mul()
|
|
|
|
def i64_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.const(-1)
|
|
g.i64.mul()
|
|
|
|
def f32_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.neg()
|
|
|
|
def f64_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.neg()
|
|
|
|
## ###
|
|
## Class Sized
|
|
|
|
def bytes_sized_len(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
# The length is stored in the first 4 bytes
|
|
g.i32.load()
|
|
|
|
## ###
|
|
## Extendable
|
|
|
|
def u8_u32_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
# No-op
|
|
# u8 is already stored as u32
|
|
pass
|
|
|
|
def u8_u64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
|
|
def u32_u64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_u()
|
|
|
|
def i8_i32_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
# No-op
|
|
# i8 is already stored as i32
|
|
pass
|
|
|
|
def i8_i64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_s()
|
|
|
|
def i32_i64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i64.extend_i32_s()
|
|
|
|
def u8_u32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.const(0xFF)
|
|
g.i32.and_()
|
|
|
|
def u8_u64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.wrap_i64()
|
|
g.i32.const(0xFF)
|
|
g.i32.and_()
|
|
|
|
def u32_u64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.wrap_i64()
|
|
|
|
def i8_i32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.const(0xFF)
|
|
g.i32.and_()
|
|
|
|
def i8_i64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.wrap_i64()
|
|
|
|
def i32_i64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.i32.wrap_i64()
|
|
|
|
## ###
|
|
## Promotable
|
|
|
|
def f32_f64_promote(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f64.promote_f32()
|
|
|
|
def f32_f64_demote(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
del tv_map
|
|
g.f32.demote_f64()
|
|
|
|
def static_array_sum(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|
assert len(tv_map) == 1
|
|
sa_type, sa_len = next(iter(tv_map.values()))
|
|
assert isinstance(sa_type, Type3)
|
|
assert isinstance(sa_len, IntType3)
|
|
|
|
if sa_len.value < 1:
|
|
raise NotImplementedError('Default value in case sum is empty')
|
|
|
|
# FIXME: We should probably use LOAD_STORE_TYPE_MAP for this?
|
|
mtyp_map = {
|
|
'u32': 'i32',
|
|
'u64': 'i64',
|
|
'i32': 'i32',
|
|
'i64': 'i64',
|
|
'f32': 'f32',
|
|
'f64': 'f64',
|
|
}
|
|
|
|
# FIXME: We should probably use calc_alloc_size for this?
|
|
type_var_size_map = {
|
|
'u32': 4,
|
|
'u64': 8,
|
|
'i32': 4,
|
|
'i64': 8,
|
|
'f32': 4,
|
|
'f64': 8,
|
|
}
|
|
|
|
type_var_add_generator = {
|
|
'u32': u32_natnum_add,
|
|
'u64': u64_natnum_add,
|
|
'i32': i32_natnum_add,
|
|
'i64': i64_natnum_add,
|
|
'f32': f32_natnum_add,
|
|
'f64': f64_natnum_add,
|
|
}
|
|
|
|
# By default, constructed types are passed as pointers
|
|
# FIXME: We don't know what add function to call
|
|
sa_type_mtyp = mtyp_map.get(sa_type.name, 'i32')
|
|
sa_type_alloc_size = type_var_size_map.get(sa_type.name, 4)
|
|
sa_type_add_gen = type_var_add_generator[sa_type.name]
|
|
|
|
# Definitions
|
|
sum_adr = g.temp_var(i32('sum_adr'))
|
|
sum_stop = g.temp_var(i32('sum_stop'))
|
|
|
|
# Stack before: [adr]
|
|
# Stack after: [sum]
|
|
|
|
# adr = {address of what's currently on stack}
|
|
# Stack: [adr] -> []
|
|
g.nop(comment=f'Start sum for {sa_type.name}[{sa_len.value}]')
|
|
g.local.set(sum_adr)
|
|
|
|
# stop = adr + ar_len * sa_type_alloc_size
|
|
# Stack: []
|
|
g.nop(comment='Calculate address at which to stop looping')
|
|
g.local.get(sum_adr)
|
|
g.i32.const(sa_len.value * sa_type_alloc_size)
|
|
g.i32.add()
|
|
g.local.set(sum_stop)
|
|
|
|
# sum = *adr
|
|
# Stack: [] -> [sum]
|
|
g.nop(comment='Get the first array value as starting point')
|
|
g.local.get(sum_adr)
|
|
g.add_statement(f'{sa_type_mtyp}.load')
|
|
|
|
# Since we did the first one, increase adr
|
|
# adr = adr + sa_type_alloc_size
|
|
# Stack: [sum] -> [sum]
|
|
g.local.get(sum_adr)
|
|
g.i32.const(sa_type_alloc_size)
|
|
g.i32.add()
|
|
g.local.set(sum_adr)
|
|
|
|
if sa_len.value > 1:
|
|
with g.loop(params=[sa_type_mtyp], result=sa_type_mtyp):
|
|
# sum = sum + *adr
|
|
# Stack: [sum] -> [sum + *adr]
|
|
g.nop(comment='Add array value')
|
|
g.local.get(sum_adr)
|
|
g.add_statement(f'{sa_type_mtyp}.load')
|
|
sa_type_add_gen(g, {})
|
|
|
|
# adr = adr + sa_type_alloc_size
|
|
# Stack: [sum] -> [sum]
|
|
g.nop(comment='Calculate address of the next value')
|
|
g.local.get(sum_adr)
|
|
g.i32.const(sa_type_alloc_size)
|
|
g.i32.add()
|
|
g.local.tee(sum_adr)
|
|
|
|
# loop if adr < stop
|
|
g.nop(comment='Check if address exceeds array bounds')
|
|
g.local.get(sum_stop)
|
|
g.i32.lt_u()
|
|
g.br_if(0)
|
|
# else: sum x[1] === x => so we don't need to loop
|
|
|
|
g.nop(comment=f'Completed sum for {sa_type.name}[{sa_len.value}]')
|
|
# End result: [sum]
|