phasm/phasm/stdlib/types.py
Johan B.W. de Vries b5f0fda133 Implements sum for Foldable types
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.
2025-05-12 18:36:37 +02:00

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]