diff --git a/phasm/compiler.py b/phasm/compiler.py index cc7aa1e..79beba3 100644 --- a/phasm/compiler.py +++ b/phasm/compiler.py @@ -208,6 +208,12 @@ def expression(wgn: WasmGenerator, mod: ourlang.Module, inp: ourlang.Expression) wgn.i32.const(inp.value) return + if inp.type3 in (prelude.i16, prelude.u16, ): + # No native u16 type - treat as i32, with caution + assert isinstance(inp.value, int) + wgn.i32.const(inp.value) + return + if inp.type3 in (prelude.i32, prelude.u32, ): assert isinstance(inp.value, int) wgn.i32.const(inp.value) @@ -476,6 +482,12 @@ def module_data_u8(inp: int) -> bytes: """ return struct.pack(' bytes: + """ + Compile: module data, u16 value + """ + return struct.pack(' bytes: """ Compile: module data, u32 value @@ -494,6 +506,12 @@ def module_data_i8(inp: int) -> bytes: """ return struct.pack(' bytes: + """ + Compile: module data, i16 value + """ + return struct.pack(' bytes: """ Compile: module data, i32 value @@ -549,6 +567,12 @@ def module_data(inp: ourlang.ModuleData) -> bytes: data_list.append(module_data_u8(constant.value)) continue + if constant.type3 == prelude.u16: + assert isinstance(constant, ourlang.ConstantPrimitive) + assert isinstance(constant.value, int) + data_list.append(module_data_u16(constant.value)) + continue + if constant.type3 == prelude.u32: assert isinstance(constant, ourlang.ConstantPrimitive) assert isinstance(constant.value, int) @@ -567,6 +591,12 @@ def module_data(inp: ourlang.ModuleData) -> bytes: data_list.append(module_data_i8(constant.value)) continue + if constant.type3 == prelude.i16: + assert isinstance(constant, ourlang.ConstantPrimitive) + assert isinstance(constant.value, int) + data_list.append(module_data_i16(constant.value)) + continue + if constant.type3 == prelude.i32: assert isinstance(constant, ourlang.ConstantPrimitive) assert isinstance(constant.value, int) @@ -653,6 +683,8 @@ def module(inp: ourlang.Module) -> wasm.Module: stdlib_types.__u32_pow2__, stdlib_types.__u8_rotl__, stdlib_types.__u8_rotr__, + stdlib_types.__u16_rotl__, + stdlib_types.__u16_rotr__, ] + [ function(inp, x) for x in inp.functions.values() diff --git a/phasm/prelude/__init__.py b/phasm/prelude/__init__.py index 461a201..f651ff9 100644 --- a/phasm/prelude/__init__.py +++ b/phasm/prelude/__init__.py @@ -110,6 +110,13 @@ The unsigned 8-bit integer type. Operations on variables employ modular arithmetic, with modulus 2^8. """ +u16 = Type3('u16', TypeApplication_Nullary(None, None)) +""" +The unsigned 16-bit integer type. + +Operations on variables employ modular arithmetic, with modulus 2^16. +""" + u32 = Type3('u32', TypeApplication_Nullary(None, None)) """ The unsigned 32-bit integer type. @@ -132,6 +139,14 @@ Operations on variables employ modular arithmetic, with modulus 2^8, but with the middel point being 0. """ +i16 = Type3('i16', TypeApplication_Nullary(None, None)) +""" +The signed 16-bit integer type. + +Operations on variables employ modular arithmetic, with modulus 2^16, but +with the middel point being 0. +""" + i32 = Type3('i32', TypeApplication_Nullary(None, None)) """ The unsigned 32-bit integer type. @@ -210,6 +225,10 @@ instance_type_class(Eq, u8, operators={ '==': stdtypes.u8_eq_equals, '!=': stdtypes.u8_eq_not_equals, }) +instance_type_class(Eq, u16, operators={ + '==': stdtypes.u16_eq_equals, + '!=': stdtypes.u16_eq_not_equals, +}) instance_type_class(Eq, u32, operators={ '==': stdtypes.u32_eq_equals, '!=': stdtypes.u32_eq_not_equals, @@ -222,6 +241,10 @@ instance_type_class(Eq, i8, operators={ '==': stdtypes.i8_eq_equals, '!=': stdtypes.i8_eq_not_equals, }) +instance_type_class(Eq, i16, operators={ + '==': stdtypes.i16_eq_equals, + '!=': stdtypes.i16_eq_not_equals, +}) instance_type_class(Eq, i32, operators={ '==': stdtypes.i32_eq_equals, '!=': stdtypes.i32_eq_not_equals, @@ -258,6 +281,15 @@ instance_type_class(Ord, u8, methods={ '>': stdtypes.u8_ord_greater_than, '>=': stdtypes.u8_ord_greater_than_or_equal, }) +instance_type_class(Ord, u16, methods={ + 'min': stdtypes.u16_ord_min, + 'max': stdtypes.u16_ord_max, +}, operators={ + '<': stdtypes.u16_ord_less_than, + '<=': stdtypes.u16_ord_less_than_or_equal, + '>': stdtypes.u16_ord_greater_than, + '>=': stdtypes.u16_ord_greater_than_or_equal, +}) instance_type_class(Ord, u32, methods={ 'min': stdtypes.u32_ord_min, 'max': stdtypes.u32_ord_max, @@ -285,6 +317,15 @@ instance_type_class(Ord, i8, methods={ '>': stdtypes.i8_ord_greater_than, '>=': stdtypes.i8_ord_greater_than_or_equal, }) +instance_type_class(Ord, i16, methods={ + 'min': stdtypes.i16_ord_min, + 'max': stdtypes.i16_ord_max, +}, operators={ + '<': stdtypes.i16_ord_less_than, + '<=': stdtypes.i16_ord_less_than_or_equal, + '>': stdtypes.i16_ord_greater_than, + '>=': stdtypes.i16_ord_greater_than_or_equal, +}) instance_type_class(Ord, i32, methods={ 'min': stdtypes.i32_ord_min, 'max': stdtypes.i32_ord_max, @@ -344,6 +385,16 @@ instance_type_class(Bits, u8, methods={ '|': stdtypes.u8_bits_bitwise_or, '^': stdtypes.u8_bits_bitwise_xor, }) +instance_type_class(Bits, u16, methods={ + 'shl': stdtypes.u16_bits_logical_shift_left, + 'shr': stdtypes.u16_bits_logical_shift_right, + 'rotl': stdtypes.u16_bits_rotate_left, + 'rotr': stdtypes.u16_bits_rotate_right, +}, operators={ + '&': stdtypes.u16_bits_bitwise_and, + '|': stdtypes.u16_bits_bitwise_or, + '^': stdtypes.u16_bits_bitwise_xor, +}) instance_type_class(Bits, u32, methods={ 'shl': stdtypes.u32_bits_logical_shift_left, 'shr': stdtypes.u32_bits_logical_shift_right, @@ -516,6 +567,10 @@ Extendable = Type3Class('Extendable', (a, b, ), methods={ 'wrap': [b, a], }, operators={}) +instance_type_class(Extendable, u8, u16, methods={ + 'extend': stdtypes.u8_u16_extend, + 'wrap': stdtypes.u8_u16_wrap, +}) instance_type_class(Extendable, u8, u32, methods={ 'extend': stdtypes.u8_u32_extend, 'wrap': stdtypes.u8_u32_wrap, @@ -524,10 +579,22 @@ instance_type_class(Extendable, u8, u64, methods={ 'extend': stdtypes.u8_u64_extend, 'wrap': stdtypes.u8_u64_wrap, }) +instance_type_class(Extendable, u16, u32, methods={ + 'extend': stdtypes.u16_u32_extend, + 'wrap': stdtypes.u16_u32_wrap, +}) +instance_type_class(Extendable, u16, u64, methods={ + 'extend': stdtypes.u16_u64_extend, + 'wrap': stdtypes.u16_u64_wrap, +}) instance_type_class(Extendable, u32, u64, methods={ 'extend': stdtypes.u32_u64_extend, 'wrap': stdtypes.u32_u64_wrap, }) +instance_type_class(Extendable, i8, i16, methods={ + 'extend': stdtypes.i8_i16_extend, + 'wrap': stdtypes.i8_i16_wrap, +}) instance_type_class(Extendable, i8, i32, methods={ 'extend': stdtypes.i8_i32_extend, 'wrap': stdtypes.i8_i32_wrap, @@ -536,6 +603,14 @@ instance_type_class(Extendable, i8, i64, methods={ 'extend': stdtypes.i8_i64_extend, 'wrap': stdtypes.i8_i64_wrap, }) +instance_type_class(Extendable, i16, i32, methods={ + 'extend': stdtypes.i16_i32_extend, + 'wrap': stdtypes.i16_i32_wrap, +}) +instance_type_class(Extendable, i16, i64, methods={ + 'extend': stdtypes.i16_i64_extend, + 'wrap': stdtypes.i16_i64_wrap, +}) instance_type_class(Extendable, i32, i64, methods={ 'extend': stdtypes.i32_i64_extend, 'wrap': stdtypes.i32_i64_wrap, @@ -644,9 +719,11 @@ PRELUDE_TYPES: dict[str, Type3] = { 'none': none, 'bool': bool_, 'u8': u8, + 'u16': u16, 'u32': u32, 'u64': u64, 'i8': i8, + 'i16': i16, 'i32': i32, 'i64': i64, 'f32': f32, diff --git a/phasm/stdlib/types.py b/phasm/stdlib/types.py index 1294fe4..f8961d1 100644 --- a/phasm/stdlib/types.py +++ b/phasm/stdlib/types.py @@ -40,6 +40,8 @@ TYPE_INFO_MAP: Mapping[str, TypeInfo] = { 'u8': TypeInfo('u8', WasmTypeInt32, 'i32.load8_u', 'i32.store8', 1), 'i8': TypeInfo('i8', WasmTypeInt32, 'i32.load8_s', 'i32.store8', 1), + 'u16': TypeInfo('u16', WasmTypeInt32, 'i32.load16_u', 'i32.store16', 2), + 'i16': TypeInfo('i16', WasmTypeInt32, 'i32.load16_s', 'i32.store16', 2), 'u32': TypeInfo('u32', WasmTypeInt32, 'i32.load', 'i32.store', 4), 'u64': TypeInfo('u64', WasmTypeInt64, 'i64.load', 'i64.store', 8), @@ -434,6 +436,86 @@ def __u8_rotr__(g: Generator, x: i32, r: i32) -> i32: return i32('return') # To satisfy mypy +@func_wrapper() +def __u16_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) + # 0x0000B2C3 + g.local.get(r) + # 0x0000B2C3, 3 + g.i32.shl() + # 0x00059618 + g.local.tee(s) + # 0x00059618 + g.i32.const(0xFFFF) + # 0x00059618, 0x0000FFFF + g.i32.and_() + # 0x00009618 + g.local.get(s) + # 0x00009618, 0x00059618 + g.i32.const(0xFFFF0000) + # 0x00009618, 0x00059618, 0xFFFF0000 + g.i32.and_() + # 0x00009618, 0x00050000 + g.i32.const(16) + # 0x00009618, 0x00050000, 16 + g.i32.shr_u() + # 0x00009618, 0x00000005, 16 + g.i32.or_() + # 0x0000961D + g.return_() + + return i32('return') # To satisfy mypy + +@func_wrapper() +def __u16_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 16 bits + g.local.get(r) + g.i32.const(16) + g.i32.rem_u() + g.local.set(r) + + # Now do the rotation + + g.local.get(x) + # 0x0000B2C3 + g.local.get(r) + # 0x0000B2C3, 3 + g.i32.rotr() + # 0x60001658 + g.local.tee(s) + # 0x60001658 + g.i32.const(0xFFFF) + # 0x60001658, 0x0000FFFF + g.i32.and_() + # 0x00001658 + g.local.get(s) + # 0x00001658, 0x60001658 + g.i32.const(0xFFFF0000) + # 0x00001658, 0x60001658, 0xFFFF0000 + g.i32.and_() + # 0x00001658, 0x60000000 + g.i32.const(16) + # 0x00001658, 0x60000000, 16 + g.i32.shr_u() + # 0x00001658, 0x00006000 + g.i32.or_() + # 0x00007658 + g.return_() + + return i32('return') # To satisfy mypy + ## ### ## class Eq @@ -441,6 +523,10 @@ def u8_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.eq() +def u16_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() @@ -453,6 +539,10 @@ def i8_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.eq() +def i16_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() @@ -473,6 +563,10 @@ def u8_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.ne() +def u16_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() @@ -485,6 +579,10 @@ def i8_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.ne() +def i16_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() @@ -508,6 +606,10 @@ def u8_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.add_statement('call $stdlib.types.__u32_ord_min__') +def u16_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__') @@ -520,6 +622,10 @@ def i8_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.add_statement('call $stdlib.types.__i32_ord_min__') +def i16_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__') @@ -540,6 +646,10 @@ def u8_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.add_statement('call $stdlib.types.__u32_ord_max__') +def u16_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__') @@ -552,6 +662,10 @@ def i8_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.add_statement('call $stdlib.types.__i32_ord_max__') +def i16_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__') @@ -573,6 +687,10 @@ def u8_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.lt_u() +def u16_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() @@ -585,6 +703,10 @@ def i8_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.lt_s() +def i16_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() @@ -605,6 +727,10 @@ def u8_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.le_u() +def u16_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() @@ -617,6 +743,10 @@ def i8_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.le_s() +def i16_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() @@ -637,6 +767,10 @@ def u8_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.gt_u() +def u16_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() @@ -649,6 +783,10 @@ def i8_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.gt_s() +def i16_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() @@ -669,6 +807,10 @@ def u8_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> No del tv_map g.i32.ge_u() +def u16_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() @@ -681,6 +823,10 @@ def i8_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> No del tv_map g.i32.ge_s() +def i16_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() @@ -703,7 +849,13 @@ def f64_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> N def u8_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.shl() - g.i32.const(255) + g.i32.const(0xFF) + g.i32.and_() + +def u16_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.i32.shl() + g.i32.const(0xFFFF) g.i32.and_() def u32_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None: @@ -719,6 +871,10 @@ def u8_bits_logical_shift_right(g: Generator, tv_map: TypeVariableLookup) -> Non del tv_map g.i32.shr_u() +def u16_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() @@ -732,6 +888,10 @@ def u8_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.add_statement('call $stdlib.types.__u8_rotl__') +def u16_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.add_statement('call $stdlib.types.__u16_rotl__') + def u32_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.rotl() @@ -745,6 +905,10 @@ def u8_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.add_statement('call $stdlib.types.__u8_rotr__') +def u16_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.add_statement('call $stdlib.types.__u16_rotr__') + def u32_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.rotr() @@ -758,6 +922,10 @@ def u8_bits_bitwise_and(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.and_() +def u16_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_() @@ -770,6 +938,10 @@ def u8_bits_bitwise_or(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.or_() +def u16_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_() @@ -782,6 +954,10 @@ def u8_bits_bitwise_xor(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.xor() +def u16_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() @@ -1074,6 +1250,12 @@ def static_array_sized_len(g: Generator, tvl: TypeVariableLookup) -> None: ## ### ## Extendable +def u8_u16_extend(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + # No-op + # u8 and u16 are both stored as u32 + pass + def u8_u32_extend(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map # No-op @@ -1084,10 +1266,26 @@ def u8_u64_extend(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i64.extend_i32_u() +def u16_u32_extend(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + # No-op + # u16 is already stored as u32 + pass + +def u16_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_i16_extend(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + # No-op + # i8 is already stored as i32 + pass + def i8_i32_extend(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map # No-op @@ -1098,10 +1296,25 @@ def i8_i64_extend(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i64.extend_i32_s() +def i16_i32_extend(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + # No-op + # i16 is already stored as i32 + pass + +def i16_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_u16_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.i32.const(0xFF) + g.i32.and_() + def u8_u32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.const(0xFF) @@ -1113,10 +1326,26 @@ def u8_u64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: g.i32.const(0xFF) g.i32.and_() +def u16_u32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.i32.const(0xFFFF) + g.i32.and_() + +def u16_u64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.i32.wrap_i64() + g.i32.const(0xFFFF) + g.i32.and_() + def u32_u64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.wrap_i64() +def i8_i16_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.i32.const(0xFF) + g.i32.and_() + def i8_i32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.const(0xFF) @@ -1125,6 +1354,19 @@ def i8_i32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: def i8_i64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map g.i32.wrap_i64() + g.i32.const(0xFF) + g.i32.and_() + +def i16_i32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.i32.const(0xFFFF) + g.i32.and_() + +def i16_i64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: + del tv_map + g.i32.wrap_i64() + g.i32.const(0xFFFF) + g.i32.and_() def i32_i64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None: del tv_map diff --git a/phasm/type3/constraints.py b/phasm/type3/constraints.py index 3ed8ccf..cd1175c 100644 --- a/phasm/type3/constraints.py +++ b/phasm/type3/constraints.py @@ -538,9 +538,11 @@ class LiteralFitsConstraint(ConstraintBase): def check(self) -> CheckResult: int_table: Dict[str, Tuple[int, bool]] = { 'u8': (1, False), + 'u16': (2, False), 'u32': (4, False), 'u64': (8, False), 'i8': (1, True), + 'i16': (2, True), 'i32': (4, True), 'i64': (8, True), } diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 5ddcf8f..907aa1c 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -124,12 +124,12 @@ class Suite: runner.interpreter_dump_memory(sys.stderr) for arg, arg_typ in zip(args, func_args, strict=True): - if arg_typ in (prelude.u8, prelude.u32, prelude.u64, ): + if arg_typ in (prelude.u8, prelude.u16, prelude.u32, prelude.u64, ): assert isinstance(arg, int) wasm_args.append(arg) continue - if arg_typ in (prelude.i8, prelude.i32, prelude.i64, ): + if arg_typ in (prelude.i8, prelude.i16, prelude.i32, prelude.i64, ): assert isinstance(arg, int) wasm_args.append(arg) continue @@ -169,9 +169,11 @@ def write_header(textio: TextIO, msg: str) -> None: WRITE_LOOKUP_MAP = { 'u8': compiler.module_data_u8, + 'u16': compiler.module_data_u16, 'u32': compiler.module_data_u32, 'u64': compiler.module_data_u64, 'i8': compiler.module_data_i8, + 'i16': compiler.module_data_i16, 'i32': compiler.module_data_i32, 'i64': compiler.module_data_i64, 'f32': compiler.module_data_f32, @@ -302,7 +304,7 @@ def _load_memory_stored_returned_value( assert isinstance(wasm_value, int), wasm_value return 0 != wasm_value - if ret_type3 in (prelude.i8, prelude.i32, prelude.i64): + if ret_type3 in (prelude.i8, prelude.i16, prelude.i32, prelude.i64): assert isinstance(wasm_value, int), wasm_value if ret_type3 is prelude.i8: @@ -311,9 +313,15 @@ def _load_memory_stored_returned_value( data = struct.pack(' An if typ is prelude.u8: return struct.unpack(' An if typ is prelude.i8: return struct.unpack(' {ext_to}: @pytest.mark.integration_test @pytest.mark.parametrize('ext_from,in_put,ext_to,exp_out', [ + ('u8', 241, 'u16', 241), ('u8', 241, 'u32', 241), - ('u32', 4059165169, 'u64', 4059165169), ('u8', 241, 'u64', 241), + ('u16', 7681, 'u32', 7681), + ('u16', 7681, 'u64', 7681), + ('u32', 4059165169, 'u64', 4059165169), + ('i8', 113, 'i16', 113), ('i8', 113, 'i32', 113), - ('i32', 1911681521, 'i64', 1911681521), ('i8', 113, 'i64', 113), + ('i8', 3585, 'i32', 3585), + ('i8', 3585, 'i64', 3585), + ('i32', 1911681521, 'i64', 1911681521), + ('i8', -15, 'i16', -15), ('i8', -15, 'i32', -15), - ('i32', -15, 'i64', -15), ('i8', -15, 'i64', -15), + ('i16', -15, 'i32', -15), + ('i16', -15, 'i64', -15), + ('i32', -15, 'i64', -15), ]) def test_extend_results(ext_from, ext_to, in_put, exp_out): @@ -89,14 +104,23 @@ def testEntry() -> {ext_from}: @pytest.mark.integration_test @pytest.mark.parametrize('ext_to,in_put,ext_from,exp_out', [ + ('u16', 0xF1F1, 'u8', 0xF1), + ('u32', 0xF1F1F1F1, 'u16', 0xF1F1), ('u32', 0xF1F1F1F1, 'u8', 0xF1), ('u64', 0xF1F1F1F1F1F1F1F1, 'u32', 0xF1F1F1F1), + ('u64', 0xF1F1F1F1F1F1F1F1, 'u16', 0xF1F1), ('u64', 0xF1F1F1F1F1F1F1F1, 'u8', 0xF1), + ('i16', 0xF171, 'i8', 113), + ('i16', 0xF1F1, 'i8', -15), + ('i32', 0xF1F171F1, 'i16', 29169), + ('i32', 0xF1F1F1F1, 'i16', -3599), ('i32', 0xF1F1F171, 'i8', 113), ('i32', 0xF1F1F1F1, 'i8', -15), - ('i64', 0x71F1F1F171F1F1F1, 'i32', 1911681521), - ('i64', 0x71F1F1F1F1F1F1F1, 'i32', -235802127), + ('i64', 0xF1F1F1F171F1F1F1, 'i32', 1911681521), + ('i64', 0xF1F1F1F1F1F1F1F1, 'i32', -235802127), + ('i64', 0xF1F1F1F1F1F171F1, 'i16', 29169), + ('i64', 0xF1F1F1F1F1F1F1F1, 'i16', -3599), ('i64', 0xF1F1F1F1F1F1F171, 'i8', 113), ('i64', 0xF1F1F1F1F1F1F1F1, 'i8', -15), ]) diff --git a/tests/integration/test_typeclasses/test_ord.py b/tests/integration/test_typeclasses/test_ord.py index 5e743d4..4d2aab0 100644 --- a/tests/integration/test_typeclasses/test_ord.py +++ b/tests/integration/test_typeclasses/test_ord.py @@ -5,16 +5,18 @@ import pytest from ..helpers import Suite TYPE_LIST = [ - 'u8', 'u32', 'u64', - 'i8', 'i32', 'i64', + 'u8', 'u16', 'u32', 'u64', + 'i8', 'i16', 'i32', 'i64', 'f32', 'f64', ] BOUND_MAP = { 'u8': struct.unpack('