phasm/phasm/stdlib/types.py
Johan B.W. de Vries 581a73e5df Ideas [skip-ci]
2025-04-13 13:56:04 +02:00

861 lines
18 KiB
Python

"""
stdlib: Standard types that are not wasm primitives
"""
from phasm.stdlib import alloc
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 returns 0, following the 'no undefined behaviour'
philosophy.
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) -> None:
g.i32.eq()
def u32_eq_equals(g: Generator) -> None:
g.i32.eq()
def u64_eq_equals(g: Generator) -> None:
g.i64.eq()
def i8_eq_equals(g: Generator) -> None:
g.i32.eq()
def i32_eq_equals(g: Generator) -> None:
g.i32.eq()
def i64_eq_equals(g: Generator) -> None:
g.i64.eq()
def f32_eq_equals(g: Generator) -> None:
g.f32.eq()
def f64_eq_equals(g: Generator) -> None:
g.f64.eq()
def u8_eq_not_equals(g: Generator) -> None:
g.i32.ne()
def u32_eq_not_equals(g: Generator) -> None:
g.i32.ne()
def u64_eq_not_equals(g: Generator) -> None:
g.i64.ne()
def i8_eq_not_equals(g: Generator) -> None:
g.i32.ne()
def i32_eq_not_equals(g: Generator) -> None:
g.i32.ne()
def i64_eq_not_equals(g: Generator) -> None:
g.i64.ne()
def f32_eq_not_equals(g: Generator) -> None:
g.f32.ne()
def f64_eq_not_equals(g: Generator) -> None:
g.f64.ne()
## ###
## class Ord
def u8_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_min__')
def u32_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_min__')
def u64_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u64_ord_min__')
def i8_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_min__')
def i32_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_min__')
def i64_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i64_ord_min__')
def f32_ord_min(g: Generator) -> None:
g.f32.min()
def f64_ord_min(g: Generator) -> None:
g.f64.min()
def u8_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_max__')
def u32_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_max__')
def u64_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u64_ord_max__')
def i8_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_max__')
def i32_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_max__')
def i64_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i64_ord_max__')
def f32_ord_max(g: Generator) -> None:
g.f32.max()
def f64_ord_max(g: Generator) -> None:
g.f64.max()
def u8_ord_less_than(g: Generator) -> None:
g.i32.lt_u()
def u32_ord_less_than(g: Generator) -> None:
g.i32.lt_u()
def u64_ord_less_than(g: Generator) -> None:
g.i64.lt_u()
def i8_ord_less_than(g: Generator) -> None:
g.i32.lt_s()
def i32_ord_less_than(g: Generator) -> None:
g.i32.lt_s()
def i64_ord_less_than(g: Generator) -> None:
g.i64.lt_s()
def f32_ord_less_than(g: Generator) -> None:
g.f32.lt()
def f64_ord_less_than(g: Generator) -> None:
g.f64.lt()
def u8_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_u()
def u32_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_u()
def u64_ord_less_than_or_equal(g: Generator) -> None:
g.i64.le_u()
def i8_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_s()
def i32_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_s()
def i64_ord_less_than_or_equal(g: Generator) -> None:
g.i64.le_s()
def f32_ord_less_than_or_equal(g: Generator) -> None:
g.f32.le()
def f64_ord_less_than_or_equal(g: Generator) -> None:
g.f64.le()
def u8_ord_greater_than(g: Generator) -> None:
g.i32.gt_u()
def u32_ord_greater_than(g: Generator) -> None:
g.i32.gt_u()
def u64_ord_greater_than(g: Generator) -> None:
g.i64.gt_u()
def i8_ord_greater_than(g: Generator) -> None:
g.i32.gt_s()
def i32_ord_greater_than(g: Generator) -> None:
g.i32.gt_s()
def i64_ord_greater_than(g: Generator) -> None:
g.i64.gt_s()
def f32_ord_greater_than(g: Generator) -> None:
g.f32.gt()
def f64_ord_greater_than(g: Generator) -> None:
g.f64.gt()
def u8_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_u()
def u32_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_u()
def u64_ord_greater_than_or_equal(g: Generator) -> None:
g.i64.ge_u()
def i8_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_s()
def i32_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_s()
def i64_ord_greater_than_or_equal(g: Generator) -> None:
g.i64.ge_s()
def f32_ord_greater_than_or_equal(g: Generator) -> None:
g.f32.ge()
def f64_ord_greater_than_or_equal(g: Generator) -> None:
g.f64.ge()
## ###
## class Bits
def u8_bits_logical_shift_left(g: Generator) -> None:
g.i32.shl()
g.i32.const(255)
g.i32.and_()
def u32_bits_logical_shift_left(g: Generator) -> None:
g.i32.shl()
def u64_bits_logical_shift_left(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.shl()
def u8_bits_logical_shift_right(g: Generator) -> None:
g.i32.shr_u()
def u32_bits_logical_shift_right(g: Generator) -> None:
g.i32.shr_u()
def u64_bits_logical_shift_right(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.shr_u()
def u8_bits_rotate_left(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u8_rotl__')
def u32_bits_rotate_left(g: Generator) -> None:
g.i32.rotl()
def u64_bits_rotate_left(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.rotl()
def u8_bits_rotate_right(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u8_rotr__')
def u32_bits_rotate_right(g: Generator) -> None:
g.i32.rotr()
def u64_bits_rotate_right(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.rotr()
def u8_bits_bitwise_and(g: Generator) -> None:
g.i32.and_()
def u32_bits_bitwise_and(g: Generator) -> None:
g.i32.and_()
def u64_bits_bitwise_and(g: Generator) -> None:
g.i64.and_()
def u8_bits_bitwise_or(g: Generator) -> None:
g.i32.or_()
def u32_bits_bitwise_or(g: Generator) -> None:
g.i32.or_()
def u64_bits_bitwise_or(g: Generator) -> None:
g.i64.or_()
def u8_bits_bitwise_xor(g: Generator) -> None:
g.i32.xor()
def u32_bits_bitwise_xor(g: Generator) -> None:
g.i32.xor()
def u64_bits_bitwise_xor(g: Generator) -> None:
g.i64.xor()
## ###
## class Fractional
def f32_fractional_ceil(g: Generator) -> None:
g.f32.ceil()
def f64_fractional_ceil(g: Generator) -> None:
g.f64.ceil()
def f32_fractional_floor(g: Generator) -> None:
g.f32.floor()
def f64_fractional_floor(g: Generator) -> None:
g.f64.floor()
def f32_fractional_trunc(g: Generator) -> None:
g.f32.trunc()
def f64_fractional_trunc(g: Generator) -> None:
g.f64.trunc()
def f32_fractional_nearest(g: Generator) -> None:
g.f32.nearest()
def f64_fractional_nearest(g: Generator) -> None:
g.f64.nearest()
def f32_fractional_div(g: Generator) -> None:
g.f32.div()
def f64_fractional_div(g: Generator) -> None:
g.f64.div()
## ###
## class Floating
def f32_floating_sqrt(g: Generator) -> None:
g.add_statement('f32.sqrt')
def f64_floating_sqrt(g: Generator) -> None:
g.add_statement('f64.sqrt')
## ###
## class Integral
def u32_integral_div(g: Generator) -> None:
g.add_statement('i32.div_u')
def u64_integral_div(g: Generator) -> None:
g.add_statement('i64.div_u')
def i32_integral_div(g: Generator) -> None:
g.add_statement('i32.div_s')
def i64_integral_div(g: Generator) -> None:
g.add_statement('i64.div_s')
def u32_integral_rem(g: Generator) -> None:
g.add_statement('i32.rem_u')
def u64_integral_rem(g: Generator) -> None:
g.add_statement('i64.rem_u')
def i32_integral_rem(g: Generator) -> None:
g.add_statement('i32.rem_s')
def i64_integral_rem(g: Generator) -> None:
g.add_statement('i64.rem_s')
## ###
## class NatNum
def u32_natnum_add(g: Generator) -> None:
g.add_statement('i32.add')
def u64_natnum_add(g: Generator) -> None:
g.add_statement('i64.add')
def i32_natnum_add(g: Generator) -> None:
g.add_statement('i32.add')
def i64_natnum_add(g: Generator) -> None:
g.add_statement('i64.add')
def f32_natnum_add(g: Generator) -> None:
g.add_statement('f32.add')
def f64_natnum_add(g: Generator) -> None:
g.add_statement('f64.add')
def u32_natnum_sub(g: Generator) -> None:
g.add_statement('i32.sub')
def u64_natnum_sub(g: Generator) -> None:
g.add_statement('i64.sub')
def i32_natnum_sub(g: Generator) -> None:
g.add_statement('i32.sub')
def i64_natnum_sub(g: Generator) -> None:
g.add_statement('i64.sub')
def f32_natnum_sub(g: Generator) -> None:
g.add_statement('f32.sub')
def f64_natnum_sub(g: Generator) -> None:
g.add_statement('f64.sub')
def u32_natnum_mul(g: Generator) -> None:
g.add_statement('i32.mul')
def u64_natnum_mul(g: Generator) -> None:
g.add_statement('i64.mul')
def i32_natnum_mul(g: Generator) -> None:
g.add_statement('i32.mul')
def i64_natnum_mul(g: Generator) -> None:
g.add_statement('i64.mul')
def f32_natnum_mul(g: Generator) -> None:
g.add_statement('f32.mul')
def f64_natnum_mul(g: Generator) -> None:
g.add_statement('f64.mul')
def u32_natnum_arithmic_shift_left(g: Generator) -> None:
g.i32.shl()
def u64_natnum_arithmic_shift_left(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.shl()
def i32_natnum_arithmic_shift_left(g: Generator) -> None:
g.i32.shl()
def i64_natnum_arithmic_shift_left(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.shl()
def f32_natnum_arithmic_shift_left(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_pow2__')
g.f32.convert_i32_u()
g.f32.mul()
def f64_natnum_arithmic_shift_left(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_pow2__')
g.f64.convert_i32_u()
g.f64.mul()
def u32_natnum_arithmic_shift_right(g: Generator) -> None:
g.i32.shr_u()
def u64_natnum_arithmic_shift_right(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.shr_u()
def i32_natnum_arithmic_shift_right(g: Generator) -> None:
g.i32.shr_s()
def i64_natnum_arithmic_shift_right(g: Generator) -> None:
g.i64.extend_i32_u()
g.i64.shr_s()
def f32_natnum_arithmic_shift_right(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_pow2__')
g.f32.convert_i32_u()
g.f32.div()
def f64_natnum_arithmic_shift_right(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_pow2__')
g.f64.convert_i32_u()
g.f64.div()
## ###
## class IntNum
def i32_intnum_abs(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_intnum_abs__')
def i64_intnum_abs(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i64_intnum_abs__')
def f32_intnum_abs(g: Generator) -> None:
g.f32.abs()
def f64_intnum_abs(g: Generator) -> None:
g.f64.abs()
def i32_intnum_neg(g: Generator) -> None:
g.i32.const(-1)
g.i32.mul()
def i64_intnum_neg(g: Generator) -> None:
g.i64.const(-1)
g.i64.mul()
def f32_intnum_neg(g: Generator) -> None:
g.f32.neg()
def f64_intnum_neg(g: Generator) -> None:
g.f64.neg()