From 11c96408b45fab45f4af8724c2137f797a4fe334 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Mon, 19 Feb 2024 07:54:57 +1300 Subject: [PATCH] Add BE and LE versions of IEEE float packing --- exec/cnex/exclude.txt | 1 + exec/pynex/pynex.py | 18 ++++-- lib/struct.cpp | 94 +++++++++++++++++++++++++--- lib/struct.neon | 138 ++++++++++++++++++++++++++++++------------ t/struct-test.neon | 2 +- 5 files changed, 200 insertions(+), 53 deletions(-) diff --git a/exec/cnex/exclude.txt b/exec/cnex/exclude.txt index 63e20f08ca..5cb0778feb 100644 --- a/exec/cnex/exclude.txt +++ b/exec/cnex/exclude.txt @@ -7,6 +7,7 @@ gc2.neon # Object Count gc3.neon # Object Count gc-two-pointers.neon # garbage collection math-test.neon # math.powmod() +struct-test.neon # iEEE big endian packing extsample-test.neon # cell_set_pointer http-test.neon # string$split diff --git a/exec/pynex/pynex.py b/exec/pynex/pynex.py index 0261c3f41c..f1bb3cc1da 100644 --- a/exec/pynex/pynex.py +++ b/exec/pynex/pynex.py @@ -2346,14 +2346,24 @@ def neon_builtin_string__toString(self): s = self.stack.pop() self.stack.append(s) -def neon_struct_packIEEE64(self): +def neon_struct_packIEEE64BE(self): n = self.stack.pop() - r = struct.pack("d", n) + r = struct.pack(">d", n) self.stack.append(r) -def neon_struct_unpackIEEE64(self): +def neon_struct_packIEEE64LE(self): + n = self.stack.pop() + r = struct.pack("d", b)[0]) + self.stack.append(r) + +def neon_struct_unpackIEEE64LE(self): b = self.stack.pop() - r = decimal.Decimal(struct.unpack("d", b)[0]) + r = decimal.Decimal(struct.unpack(" packIEEE32(Number n) +std::vector packIEEE32BE(Number n) { float x = number_to_float(n); + uint32_t i = *(uint32_t *)&x; std::vector r(sizeof(x)); - memcpy(r.data(), &x, sizeof(x)); + r[0] = (i >> 24) & 0xff; + r[1] = (i >> 16) & 0xff; + r[2] = (i >> 8) & 0xff; + r[3] = (i ) & 0xff; return r; } -std::vector packIEEE64(Number n) +std::vector packIEEE32LE(Number n) +{ + float x = number_to_float(n); + uint32_t i = *(uint32_t *)&x; + std::vector r(sizeof(x)); + r[3] = (i >> 24) & 0xff; + r[2] = (i >> 16) & 0xff; + r[1] = (i >> 8) & 0xff; + r[0] = (i ) & 0xff; + return r; +} + +std::vector packIEEE64BE(Number n) +{ + double x = number_to_double(n); + uint64_t i = *(uint64_t *)&x; + std::vector r(sizeof(x)); + r[0] = (i >> 56) & 0xff; + r[1] = (i >> 48) & 0xff; + r[2] = (i >> 40) & 0xff; + r[3] = (i >> 32) & 0xff; + r[4] = (i >> 24) & 0xff; + r[5] = (i >> 16) & 0xff; + r[6] = (i >> 8) & 0xff; + r[7] = (i ) & 0xff; + return r; +} + +std::vector packIEEE64LE(Number n) { double x = number_to_double(n); + uint64_t i = *(uint64_t *)&x; std::vector r(sizeof(x)); - memcpy(r.data(), &x, sizeof(x)); + r[7] = (i >> 56) & 0xff; + r[6] = (i >> 48) & 0xff; + r[5] = (i >> 40) & 0xff; + r[4] = (i >> 32) & 0xff; + r[3] = (i >> 24) & 0xff; + r[2] = (i >> 16) & 0xff; + r[1] = (i >> 8) & 0xff; + r[0] = (i ) & 0xff; return r; } -Number unpackIEEE32(const std::vector &b) +Number unpackIEEE32BE(const std::vector &b) +{ + uint32_t i = (b[0] << 24) | + (b[1] << 16) | + (b[2] << 8) | + (b[3] ); + float x = *(float *)&i; + return number_from_float(x); +} + +Number unpackIEEE32LE(const std::vector &b) { - float x; - memcpy(&x, b.data(), sizeof(x)); + uint32_t i = (b[3] << 24) | + (b[2] << 16) | + (b[1] << 8) | + (b[0] ); + float x = *(float *)&i; return number_from_float(x); } -Number unpackIEEE64(const std::vector &b) +Number unpackIEEE64BE(const std::vector &b) +{ + uint64_t i = (static_cast(b[0]) << 56) | + (static_cast(b[1]) << 48) | + (static_cast(b[2]) << 40) | + (static_cast(b[3]) << 32) | + (static_cast(b[4]) << 24) | + (static_cast(b[5]) << 16) | + (static_cast(b[6]) << 8) | + (static_cast(b[7]) ); + double x = *(double *)&i; + return number_from_double(x); +} + +Number unpackIEEE64LE(const std::vector &b) { - double x; - memcpy(&x, b.data(), sizeof(x)); + uint64_t i = (static_cast(b[7]) << 56) | + (static_cast(b[6]) << 48) | + (static_cast(b[5]) << 40) | + (static_cast(b[4]) << 32) | + (static_cast(b[3]) << 24) | + (static_cast(b[2]) << 16) | + (static_cast(b[1]) << 8) | + (static_cast(b[0]) ); + double x = *(double *)&i; return number_from_double(x); } diff --git a/lib/struct.neon b/lib/struct.neon index 3cf92b463b..6611ed25ae 100644 --- a/lib/struct.neon +++ b/lib/struct.neon @@ -11,8 +11,10 @@ EXPORT Type EXPORT make EXPORT field EXPORT packBool -EXPORT packIEEE32 -EXPORT packIEEE64 +EXPORT packIEEE32BE +EXPORT packIEEE32LE +EXPORT packIEEE64BE +EXPORT packIEEE64LE EXPORT packInt8 EXPORT packInt16BE EXPORT packInt16LE @@ -28,8 +30,10 @@ EXPORT packUInt32LE EXPORT packUInt64BE EXPORT packUInt64LE EXPORT unpackBool -EXPORT unpackIEEE32 -EXPORT unpackIEEE64 +EXPORT unpackIEEE32BE +EXPORT unpackIEEE32LE +EXPORT unpackIEEE64BE +EXPORT unpackIEEE64LE EXPORT unpackInt8 EXPORT unpackInt16BE EXPORT unpackInt16LE @@ -53,8 +57,10 @@ IMPORT binary * * Values: * bool - boolean - * ieee32 - IEEE 754 32 bit binary floating point - * ieee64 - IEEE 754 64 bit binary floating point + * ieee32BE - IEEE 754 32 bit binary floating point, big endian + * ieee32LE - IEEE 754 32 bit binary floating point, little endian + * ieee64BE - IEEE 754 64 bit binary floating point, big endian + * ieee64LE - IEEE 754 64 bit binary floating point, little endian * int8 - signed 8 bit integer * int16BE - signed 16 bit integer, big endian * int16LE - signed 16 bit integer, little endian @@ -74,8 +80,10 @@ IMPORT binary */ TYPE Type IS ENUM bool - ieee32 - ieee64 + ieee32BE + ieee32LE + ieee64BE + ieee64LE int8 int16BE int16LE @@ -129,9 +137,13 @@ FUNCTION field(name: String, type: Type, width: Number DEFAULT 0): Field CASE type WHEN Type.bool DO w := 1 - WHEN Type.ieee32 DO + WHEN Type.ieee32BE DO w := 4 - WHEN Type.ieee64 DO + WHEN Type.ieee32LE DO + w := 4 + WHEN Type.ieee64BE DO + w := 8 + WHEN Type.ieee64LE DO w := 8 WHEN Type.int8 DO w := 1 @@ -175,17 +187,29 @@ FUNCTION packBool(b: Boolean): Bytes RETURN (IF b THEN HEXBYTES "01" ELSE HEXBYTES "00") END FUNCTION -/* Function: packIEEE32 +/* Function: packIEEE32BE + * + * Pack a value into a in IEEE 754 binary32 floating point format. + */ +DECLARE NATIVE FUNCTION packIEEE32BE(n: Number): Bytes + +/* Function: packIEEE32LE * * Pack a value into a in IEEE 754 binary32 floating point format. */ -DECLARE NATIVE FUNCTION packIEEE32(n: Number): Bytes +DECLARE NATIVE FUNCTION packIEEE32LE(n: Number): Bytes -/* Function: packIEEE64 +/* Function: packIEEE64BE * * Pack a value into a in IEEE 754 binary64 floating point format. */ -DECLARE NATIVE FUNCTION packIEEE64(n: Number): Bytes +DECLARE NATIVE FUNCTION packIEEE64BE(n: Number): Bytes + +/* Function: packIEEE64LE + * + * Pack a value into a in IEEE 754 binary64 floating point format. + */ +DECLARE NATIVE FUNCTION packIEEE64LE(n: Number): Bytes /* Function: packInt8 * @@ -389,17 +413,29 @@ FUNCTION unpackBool(b: Bytes): Boolean RETURN a[0] <> 0 END FUNCTION -/* Function: unpackIEEE32 +/* Function: unpackIEEE32BE + * + * Unpack a from a in IEEE 754 binary32 floating point format. + */ +DECLARE NATIVE FUNCTION unpackIEEE32BE(b: Bytes): Number + +/* Function: unpackIEEE32LE * * Unpack a from a in IEEE 754 binary32 floating point format. */ -DECLARE NATIVE FUNCTION unpackIEEE32(b: Bytes): Number +DECLARE NATIVE FUNCTION unpackIEEE32LE(b: Bytes): Number + +/* Function: unpackIEEE64BE + * + * Unpack a from a in IEEE 754 binary64 floating point format. + */ +DECLARE NATIVE FUNCTION unpackIEEE64BE(b: Bytes): Number -/* Function: unpackIEEE64 +/* Function: unpackIEEE64LE * * Unpack a from a in IEEE 754 binary64 floating point format. */ -DECLARE NATIVE FUNCTION unpackIEEE64(b: Bytes): Number +DECLARE NATIVE FUNCTION unpackIEEE64LE(b: Bytes): Number /* Function: unpackInt8 * @@ -610,10 +646,14 @@ FUNCTION Struct.pack(self: Struct, values: Dictionary): Bytes CASE self.fields[f].type WHEN Type.bool DO buf.extend(packBool(v).toArray()) - WHEN Type.ieee32 DO - buf.extend(packIEEE32(v).toArray()) - WHEN Type.ieee64 DO - buf.extend(packIEEE64(v).toArray()) + WHEN Type.ieee32BE DO + buf.extend(packIEEE32BE(v).toArray()) + WHEN Type.ieee32LE DO + buf.extend(packIEEE32LE(v).toArray()) + WHEN Type.ieee64BE DO + buf.extend(packIEEE64BE(v).toArray()) + WHEN Type.ieee64LE DO + buf.extend(packIEEE64LE(v).toArray()) WHEN Type.int8 DO buf.extend(packInt8(v).toArray()) WHEN Type.int16BE DO @@ -687,11 +727,17 @@ FUNCTION Struct.unpack(self: Struct, data: Bytes): Dictionary WHEN Type.bool DO v := unpackBool(data[i TO i]) INC i - WHEN Type.ieee32 DO - v := unpackIEEE32(data[i TO i+3]) + WHEN Type.ieee32BE DO + v := unpackIEEE32BE(data[i TO i+3]) i := i + 4 - WHEN Type.ieee64 DO - v := unpackIEEE64(data[i TO i+7]) + WHEN Type.ieee32LE DO + v := unpackIEEE32LE(data[i TO i+3]) + i := i + 4 + WHEN Type.ieee64BE DO + v := unpackIEEE64BE(data[i TO i+7]) + i := i + 8 + WHEN Type.ieee64LE DO + v := unpackIEEE64LE(data[i TO i+7]) i := i + 8 WHEN Type.int8 DO v := unpackInt8(data[i TO i]) @@ -758,13 +804,21 @@ BEGIN MAIN TESTCASE packBool(FALSE) = HEXBYTES "00" TESTCASE packBool(TRUE) = HEXBYTES "01" - TESTCASE packIEEE32(0) = HEXBYTES "00 00 00 00" - TESTCASE packIEEE32(1) = HEXBYTES "00 00 80 3f" - TESTCASE packIEEE32(1e10) = HEXBYTES "f9 02 15 50" + TESTCASE packIEEE32BE(0) = HEXBYTES "00 00 00 00" + TESTCASE packIEEE32BE(1) = HEXBYTES "3f 80 00 00" + TESTCASE packIEEE32BE(1e10) = HEXBYTES "50 15 02 f9" + + TESTCASE packIEEE32LE(0) = HEXBYTES "00 00 00 00" + TESTCASE packIEEE32LE(1) = HEXBYTES "00 00 80 3f" + TESTCASE packIEEE32LE(1e10) = HEXBYTES "f9 02 15 50" - TESTCASE packIEEE64(0) = HEXBYTES "00 00 00 00 00 00 00 00" - TESTCASE packIEEE64(1) = HEXBYTES "00 00 00 00 00 00 f0 3f" - TESTCASE packIEEE64(1e100) = HEXBYTES "7d c3 94 25 ad 49 b2 54" + TESTCASE packIEEE64BE(0) = HEXBYTES "00 00 00 00 00 00 00 00" + TESTCASE packIEEE64BE(1) = HEXBYTES "3f f0 00 00 00 00 00 00" + TESTCASE packIEEE64BE(1e100) = HEXBYTES "54 b2 49 ad 25 94 c3 7d" + + TESTCASE packIEEE64LE(0) = HEXBYTES "00 00 00 00 00 00 00 00" + TESTCASE packIEEE64LE(1) = HEXBYTES "00 00 00 00 00 00 f0 3f" + TESTCASE packIEEE64LE(1e100) = HEXBYTES "7d c3 94 25 ad 49 b2 54" TESTCASE packInt8(-128) = HEXBYTES "80" TESTCASE packInt8(-1) = HEXBYTES "FF" @@ -846,13 +900,21 @@ BEGIN MAIN TESTCASE unpackBool(HEXBYTES "00") = FALSE TESTCASE unpackBool(HEXBYTES "01") = TRUE - TESTCASE unpackIEEE32(HEXBYTES "00 00 00 00") = 0 - TESTCASE unpackIEEE32(HEXBYTES "00 00 80 3f") = 1 - TESTCASE unpackIEEE32(HEXBYTES "f9 02 15 50") = 1e10 + TESTCASE unpackIEEE32BE(HEXBYTES "00 00 00 00") = 0 + TESTCASE unpackIEEE32BE(HEXBYTES "3f 80 00 00") = 1 + TESTCASE unpackIEEE32BE(HEXBYTES "50 15 02 f9") = 1e10 + + TESTCASE unpackIEEE32LE(HEXBYTES "00 00 00 00") = 0 + TESTCASE unpackIEEE32LE(HEXBYTES "00 00 80 3f") = 1 + TESTCASE unpackIEEE32LE(HEXBYTES "f9 02 15 50") = 1e10 + + TESTCASE unpackIEEE64BE(HEXBYTES "00 00 00 00 00 00 00 00") = 0 + TESTCASE unpackIEEE64BE(HEXBYTES "3f f0 00 00 00 00 00 00") = 1 + TESTCASE unpackIEEE64BE(HEXBYTES "54 b2 49 ad 25 94 c3 7d") = 1.000000000000000015902891109759918e100 - TESTCASE unpackIEEE64(HEXBYTES "00 00 00 00 00 00 00 00") = 0 - TESTCASE unpackIEEE64(HEXBYTES "00 00 00 00 00 00 f0 3f") = 1 - TESTCASE unpackIEEE64(HEXBYTES "7d c3 94 25 ad 49 b2 54") = 1.000000000000000015902891109759918e100 + TESTCASE unpackIEEE64LE(HEXBYTES "00 00 00 00 00 00 00 00") = 0 + TESTCASE unpackIEEE64LE(HEXBYTES "00 00 00 00 00 00 f0 3f") = 1 + TESTCASE unpackIEEE64LE(HEXBYTES "7d c3 94 25 ad 49 b2 54") = 1.000000000000000015902891109759918e100 TESTCASE unpackInt8(HEXBYTES "80") = -128 TESTCASE unpackInt8(HEXBYTES "FF") = -1 diff --git a/t/struct-test.neon b/t/struct-test.neon index 7a3484e42a..7e1863a2de 100644 --- a/t/struct-test.neon +++ b/t/struct-test.neon @@ -2,7 +2,7 @@ IMPORT struct VAR s: struct.Struct := struct.make([ struct.field("field1", struct.Type.int32BE), struct.field("field2", struct.Type.string, 20), - struct.field("field3", struct.Type.ieee64), + struct.field("field3", struct.Type.ieee64LE), ]) print("\(s.sizeof())")