diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-04-06 02:23:01 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-04-06 02:23:01 +0900 |
| commit | fa9ad79209d85b0677b00ca1d41d070105fec09f (patch) | |
| tree | 95a81c0909e761e9cecb3cd7333201cb4ac62161 | |
| parent | a0f17ee6807f9a0605261a11a8ba46c57a9849a0 (diff) | |
| parent | de116dceae7ea654df28caab3fd2f3aefdffe188 (diff) | |
| download | php-waddiwasi-fa9ad79209d85b0677b00ca1d41d070105fec09f.tar.gz php-waddiwasi-fa9ad79209d85b0677b00ca1d41d070105fec09f.tar.zst php-waddiwasi-fa9ad79209d85b0677b00ca1d41d070105fec09f.zip | |
Merge branch 'fix/float-handling'
| -rw-r--r-- | BUGS | 7 | ||||
| -rw-r--r-- | TODO | 2 | ||||
| -rw-r--r-- | composer.json | 2 | ||||
| -rw-r--r-- | composer.lock | 514 | ||||
| -rw-r--r-- | phpunit.xml | 4 | ||||
| -rw-r--r-- | src/BitOps/BinaryConversion.php | 256 | ||||
| -rw-r--r-- | src/BitOps/FloatOps.php | 40 | ||||
| -rw-r--r-- | src/BitOps/FloatTraits.php | 50 | ||||
| -rw-r--r-- | src/BitOps/PackFloatSpecifiers.php | 11 | ||||
| -rw-r--r-- | src/BitOps/PackIntSpecifiers.php | 14 | ||||
| -rw-r--r-- | src/BitOps/Signedness.php | 24 | ||||
| -rw-r--r-- | src/BitOps/UnpackFloatSpecifiers.php | 19 | ||||
| -rw-r--r-- | src/BitOps/UnpackIntSpecifiers.php | 24 | ||||
| -rw-r--r-- | src/WebAssembly/BinaryFormat/Decoder.php | 18 | ||||
| -rw-r--r-- | src/WebAssembly/Execution/MemInst.php | 29 | ||||
| -rw-r--r-- | src/WebAssembly/Execution/NumericOps.php | 231 | ||||
| -rw-r--r-- | tests/src/SpecTestsuites/SpecTestsuiteBase.php | 24 |
17 files changed, 706 insertions, 563 deletions
@@ -1,12 +1,5 @@ # Failed spec tests -## Numeric - -* ConversionsTest -* FloatExprsTest -* FloatLiteralsTest -* FloatMemoryTest - ## Validation * ImportsTest @@ -1,8 +1,6 @@ * Support text format (.wat) * Implement validation * Fix known bugs (BUGS) - * We need to implement software-defined f32 in order to support floating-point number operations. -* Implement NaN propagation * Provide sane bindings to PHP * Write PHPDoc for public APIs * Provide high-level APIs diff --git a/composer.json b/composer.json index 4b1c171..e937c62 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "phpstan/phpstan": "^1.12.23", "phpstan/phpstan-deprecation-rules": "^1.2.1", "phpstan/phpstan-strict-rules": "^1.6.2", - "phpunit/phpunit": "^11.5.15", + "phpunit/phpunit": "^12.1.0", "reliforp/reli-prof": "0.12.x-dev", "symplify/easy-coding-standard": "^12.5.11" }, diff --git a/composer.lock b/composer.lock index 47cb3b6..bce450e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5bdf3a9814794abff1d728afd94ae1bf", + "content-hash": "476c89d52de8f0f2d5de2b5aa6f347ae", "packages": [], "packages-dev": [ { @@ -1885,16 +1885,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.9", + "version": "12.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" + "reference": "05c33d01a856f9f62488d144bafddc3d7b7a4ebb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", - "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/05c33d01a856f9f62488d144bafddc3d7b7a4ebb", + "reference": "05c33d01a856f9f62488d144bafddc3d7b7a4ebb", "shasum": "" }, "require": { @@ -1902,18 +1902,17 @@ "ext-libxml": "*", "ext-xmlwriter": "*", "nikic/php-parser": "^5.4.0", - "php": ">=8.2", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-text-template": "^4.0.1", - "sebastian/code-unit-reverse-lookup": "^4.0.1", - "sebastian/complexity": "^4.0.1", - "sebastian/environment": "^7.2.0", - "sebastian/lines-of-code": "^3.0.1", - "sebastian/version": "^5.0.2", + "php": ">=8.3", + "phpunit/php-file-iterator": "^6.0", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^11.5.2" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -1922,7 +1921,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.0.x-dev" + "dev-main": "12.1.x-dev" } }, "autoload": { @@ -1951,7 +1950,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.1.2" }, "funding": [ { @@ -1959,32 +1958,32 @@ "type": "github" } ], - "time": "2025-02-25T13:26:39+00:00" + "time": "2025-04-03T14:34:39+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "961bc913d42fe24a257bfff826a5068079ac7782" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -2012,7 +2011,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" }, "funding": [ { @@ -2020,28 +2019,28 @@ "type": "github" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2025-02-07T04:58:37+00:00" }, { "name": "phpunit/php-invoker", - "version": "5.0.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-pcntl": "*" @@ -2049,7 +2048,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -2076,7 +2075,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" }, "funding": [ { @@ -2084,32 +2083,32 @@ "type": "github" } ], - "time": "2024-07-03T05:07:44+00:00" + "time": "2025-02-07T04:58:58+00:00" }, { "name": "phpunit/php-text-template", - "version": "4.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2136,7 +2135,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" }, "funding": [ { @@ -2144,32 +2143,32 @@ "type": "github" } ], - "time": "2024-07-03T05:08:43+00:00" + "time": "2025-02-07T04:59:16+00:00" }, { "name": "phpunit/php-timer", - "version": "7.0.1", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -2196,7 +2195,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", "security": "https://github.com/sebastianbergmann/php-timer/security/policy", - "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" }, "funding": [ { @@ -2204,20 +2203,20 @@ "type": "github" } ], - "time": "2024-07-03T05:09:35+00:00" + "time": "2025-02-07T04:59:38+00:00" }, { "name": "phpunit/phpunit", - "version": "11.5.15", + "version": "12.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c" + "reference": "c433e7972440e1370a26879bb54c359f8898aa3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", - "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c433e7972440e1370a26879bb54c359f8898aa3a", + "reference": "c433e7972440e1370a26879bb54c359f8898aa3a", "shasum": "" }, "require": { @@ -2230,34 +2229,30 @@ "myclabs/deep-copy": "^1.13.0", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.9", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-invoker": "^5.0.1", - "phpunit/php-text-template": "^4.0.1", - "phpunit/php-timer": "^7.0.1", - "sebastian/cli-parser": "^3.0.2", - "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.1", - "sebastian/diff": "^6.0.2", - "sebastian/environment": "^7.2.0", - "sebastian/exporter": "^6.3.0", - "sebastian/global-state": "^7.0.2", - "sebastian/object-enumerator": "^6.0.1", - "sebastian/type": "^5.1.2", - "sebastian/version": "^5.0.2", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.1.2", + "phpunit/php-file-iterator": "^6.0.0", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.0.0", + "sebastian/comparator": "^7.0.1", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.0.0", + "sebastian/exporter": "^7.0.0", + "sebastian/global-state": "^8.0.0", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/type": "^6.0.2", + "sebastian/version": "^6.0.0", "staabm/side-effects-detector": "^1.0.5" }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files" - }, "bin": [ "phpunit" ], "type": "library", "extra": { "branch-alias": { - "dev-main": "11.5-dev" + "dev-main": "12.1-dev" } }, "autoload": { @@ -2289,7 +2284,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.0" }, "funding": [ { @@ -2305,7 +2300,7 @@ "type": "tidelift" } ], - "time": "2025-03-23T16:02:11+00:00" + "time": "2025-04-04T04:10:58+00:00" }, { "name": "psr/container", @@ -2665,28 +2660,28 @@ }, { "name": "sebastian/cli-parser", - "version": "3.0.2", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/6d584c727d9114bcdc14c86711cd1cad51778e7c", + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2710,64 +2705,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-07-03T04:41:36+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "security": "https://github.com/sebastianbergmann/code-unit/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.0.0" }, "funding": [ { @@ -2775,87 +2713,31 @@ "type": "github" } ], - "time": "2025-03-19T07:56:08+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "4.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-07-03T04:45:54+00:00" + "time": "2025-02-07T04:53:50+00:00" }, { "name": "sebastian/comparator", - "version": "6.3.1", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + "reference": "b478f34614f934e0291598d0c08cbaba9644bee5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b478f34614f934e0291598d0c08cbaba9644bee5", + "reference": "b478f34614f934e0291598d0c08cbaba9644bee5", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/diff": "^6.0", - "sebastian/exporter": "^6.0" + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^11.4" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-bcmath": "For comparing BcMath\\Number objects" @@ -2863,7 +2745,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -2903,7 +2785,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/7.0.1" }, "funding": [ { @@ -2911,33 +2793,33 @@ "type": "github" } ], - "time": "2025-03-07T06:57:01+00:00" + "time": "2025-03-07T07:00:32+00:00" }, { "name": "sebastian/complexity", - "version": "4.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", "shasum": "" }, "require": { "nikic/php-parser": "^5.0", - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2961,7 +2843,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" }, "funding": [ { @@ -2969,33 +2851,33 @@ "type": "github" } ], - "time": "2024-07-03T04:49:50+00:00" + "time": "2025-02-07T04:55:25+00:00" }, { "name": "sebastian/diff", - "version": "6.0.2", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -3028,7 +2910,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" }, "funding": [ { @@ -3036,27 +2918,27 @@ "type": "github" } ], - "time": "2024-07-03T04:53:05+00:00" + "time": "2025-02-07T04:55:46+00:00" }, { "name": "sebastian/environment", - "version": "7.2.0", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" + "reference": "8afe311eca49171bf95405cc0078be9a3821f9f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", - "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8afe311eca49171bf95405cc0078be9a3821f9f2", + "reference": "8afe311eca49171bf95405cc0078be9a3821f9f2", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-posix": "*" @@ -3064,7 +2946,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "7.2-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -3092,7 +2974,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" + "source": "https://github.com/sebastianbergmann/environment/tree/8.0.0" }, "funding": [ { @@ -3100,34 +2982,34 @@ "type": "github" } ], - "time": "2024-07-03T04:54:44+00:00" + "time": "2025-02-07T04:56:08+00:00" }, { "name": "sebastian/exporter", - "version": "6.3.0", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + "reference": "76432aafc58d50691a00d86d0632f1217a47b688" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/76432aafc58d50691a00d86d0632f1217a47b688", + "reference": "76432aafc58d50691a00d86d0632f1217a47b688", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/recursion-context": "^6.0" + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.1-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -3170,7 +3052,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.0" }, "funding": [ { @@ -3178,35 +3060,35 @@ "type": "github" } ], - "time": "2024-12-05T09:17:50+00:00" + "time": "2025-02-07T04:56:42+00:00" }, { "name": "sebastian/global-state", - "version": "7.0.2", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/570a2aeb26d40f057af686d63c4e99b075fb6cbc", + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -3232,7 +3114,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.0" }, "funding": [ { @@ -3240,33 +3122,33 @@ "type": "github" } ], - "time": "2024-07-03T04:57:36+00:00" + "time": "2025-02-07T04:56:59+00:00" }, { "name": "sebastian/lines-of-code", - "version": "3.0.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", "shasum": "" }, "require": { "nikic/php-parser": "^5.0", - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -3290,7 +3172,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" }, "funding": [ { @@ -3298,34 +3180,34 @@ "type": "github" } ], - "time": "2024-07-03T04:58:38+00:00" + "time": "2025-02-07T04:57:28+00:00" }, { "name": "sebastian/object-enumerator", - "version": "6.0.1", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -3348,7 +3230,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" }, "funding": [ { @@ -3356,32 +3238,32 @@ "type": "github" } ], - "time": "2024-07-03T05:00:13+00:00" + "time": "2025-02-07T04:57:48+00:00" }, { "name": "sebastian/object-reflector", - "version": "4.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -3404,7 +3286,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" }, "funding": [ { @@ -3412,32 +3294,32 @@ "type": "github" } ], - "time": "2024-07-03T05:01:32+00:00" + "time": "2025-02-07T04:58:17+00:00" }, { "name": "sebastian/recursion-context", - "version": "6.0.2", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/c405ae3a63e01b32eb71577f8ec1604e39858a7c", + "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -3468,7 +3350,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.0" }, "funding": [ { @@ -3476,32 +3358,32 @@ "type": "github" } ], - "time": "2024-07-03T05:10:34+00:00" + "time": "2025-02-07T05:00:01+00:00" }, { "name": "sebastian/type", - "version": "5.1.2", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/1d7cd6e514384c36d7a390347f57c385d4be6069", + "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -3525,7 +3407,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/type/issues", "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + "source": "https://github.com/sebastianbergmann/type/tree/6.0.2" }, "funding": [ { @@ -3533,29 +3415,29 @@ "type": "github" } ], - "time": "2025-03-18T13:35:50+00:00" + "time": "2025-03-18T13:37:31+00:00" }, { "name": "sebastian/version", - "version": "5.0.2", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -3579,7 +3461,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/version/issues", "security": "https://github.com/sebastianbergmann/version/security/policy", - "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" }, "funding": [ { @@ -3587,7 +3469,7 @@ "type": "github" } ], - "time": "2024-10-09T05:16:32+00:00" + "time": "2025-02-07T05:00:38+00:00" }, { "name": "sj-i/php-cast", diff --git a/phpunit.xml b/phpunit.xml index 336683b..a6c6ac1 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -28,6 +28,7 @@ <file>tests/src/SpecTestsuites/Core/CallIndirectTest.php</file> <file>tests/src/SpecTestsuites/Core/CallTest.php</file> <file>tests/src/SpecTestsuites/Core/ConstTest.php</file> + <file>tests/src/SpecTestsuites/Core/ConversionsTest.php</file> <file>tests/src/SpecTestsuites/Core/DataTest.php</file> <file>tests/src/SpecTestsuites/Core/ElemTest.php</file> <file>tests/src/SpecTestsuites/Core/EndiannessTest.php</file> @@ -39,6 +40,9 @@ <file>tests/src/SpecTestsuites/Core/F64CmpTest.php</file> <file>tests/src/SpecTestsuites/Core/F64Test.php</file> <file>tests/src/SpecTestsuites/Core/FacTest.php</file> + <file>tests/src/SpecTestsuites/Core/FloatExprsTest.php</file> + <file>tests/src/SpecTestsuites/Core/FloatLiteralsTest.php</file> + <file>tests/src/SpecTestsuites/Core/FloatMemoryTest.php</file> <file>tests/src/SpecTestsuites/Core/FloatMiscTest.php</file> <file>tests/src/SpecTestsuites/Core/ForwardTest.php</file> <file>tests/src/SpecTestsuites/Core/FuncPtrsTest.php</file> diff --git a/src/BitOps/BinaryConversion.php b/src/BitOps/BinaryConversion.php new file mode 100644 index 0000000..14b33c9 --- /dev/null +++ b/src/BitOps/BinaryConversion.php @@ -0,0 +1,256 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +use function assert; +use function is_float; +use function is_int; +use function ord; +use function pack; +use function strlen; +use function unpack; + +final readonly class BinaryConversion +{ + private function __construct() + { + } + + /** + * @return non-empty-string + */ + public static function serializeI8(int $x): string + { + return self::packInt(PackIntSpecifiers::Int8, $x); + } + + /** + * @return non-empty-string + */ + public static function serializeI16(int $x): string + { + return self::packInt(PackIntSpecifiers::Int16LittleEndian, $x); + } + + /** + * @return non-empty-string + */ + public static function serializeI32(int $x): string + { + return self::packInt(PackIntSpecifiers::Int32LittleEndian, $x); + } + + /** + * @return non-empty-string + */ + public static function serializeI64(int $x): string + { + return self::packInt(PackIntSpecifiers::Int64LittleEndian, $x); + } + + /** + * @return non-empty-string + */ + public static function serializeI64InBigEndian(int $x): string + { + return self::packInt(PackIntSpecifiers::Int64BigEndian, $x); + } + + /** + * @return non-empty-string + */ + public static function serializeF32(float $x): string + { + // PHP's pack() does not preserve NaN payload bits, so we have to + // manually check if the float is NaN and convert it to a 32-bit float. + if (is_nan($x)) { + [$sign, , $payload] = FloatOps::destructF64Bits($x); + $i = 0 + | FloatTraits::getF32SignBit(Signedness::fromSignBit($sign)) + | FloatTraits::F32_EXPONENT_NAN + | ($payload >> (FloatTraits::F64_MANTISSA_BITS - FloatTraits::F32_MANTISSA_BITS)); + return self::packInt(PackIntSpecifiers::Int32LittleEndian, $i); + } else { + return self::packFloat(PackFloatSpecifiers::Float32LittleEndian, $x); + } + } + + /** + * @return non-empty-string + */ + public static function serializeF64(float $x): string + { + return self::packFloat(PackFloatSpecifiers::Float64LittleEndian, $x); + } + + /** + * @param non-empty-string $s + */ + public static function deserializeS8(string $s): int + { + return self::unpackInt(UnpackIntSpecifiers::SignedInt8, $s); + } + + /** + * @param non-empty-string $s + */ + public static function deserializeS16(string $s): int + { + // PHP does not support unpacking signed integer in fixed endian, so we + // have to swap byte order if the machine's endianness is not little + // endian. + return self::unpackInt(UnpackIntSpecifiers::SignedInt16MachineOrder, self::byteSwapIfNeeded($s)); + } + + /** + * @param non-empty-string $s + */ + public static function deserializeS32(string $s): int + { + // PHP does not support unpacking signed integer in fixed endian, so we + // have to swap byte order if the machine's endianness is not little + // endian. + return self::unpackInt(UnpackIntSpecifiers::SignedInt32MachineOrder, self::byteSwapIfNeeded($s)); + } + + /** + * @param non-empty-string $s + */ + public static function deserializeS64(string $s): int + { + // PHP does not support unpacking signed integer in fixed endian, so we + // have to swap byte order if the machine's endianness is not little + // endian. + return self::unpackInt(UnpackIntSpecifiers::SignedInt64MachineOrder, self::byteSwapIfNeeded($s)); + } + + /** + * @param non-empty-string $s + */ + public static function deserializeF32(string $s): float + { + // PHP's unpack() does not preserve NaN payload bits, so we have to + // manually check if the float is NaN and convert it to a 32-bit float. + $i = self::unpackInt(UnpackIntSpecifiers::UnsignedInt32LittleEndian, $s); + if (($i & FloatTraits::F32_EXPONENT_MASK) === FloatTraits::F32_EXPONENT_NAN) { + $sign = $i & FloatTraits::F32_SIGN_MASK; + $payload = $i & FloatTraits::F32_MANTISSA_MASK; + $j = 0 | + FloatTraits::getF64SignBit(Signedness::fromSignBit($sign)) | + FloatTraits::F64_EXPONENT_NAN | + ($payload << (FloatTraits::F64_MANTISSA_BITS - FloatTraits::F32_MANTISSA_BITS)); + return self::unpackFloat(UnpackFloatSpecifiers::Float64LittleEndian, self::packInt(PackIntSpecifiers::Int64LittleEndian, $j)); + } else { + return self::unpackFloat(UnpackFloatSpecifiers::Float32LittleEndian, $s); + } + } + + /** + * @param non-empty-string $s + */ + public static function deserializeF64(string $s): float + { + return self::unpackFloat(UnpackFloatSpecifiers::Float64LittleEndian, $s); + } + + public static function reinterpretI32AsF32(int $x): float + { + return self::deserializeF32(self::serializeI32($x)); + } + + public static function reinterpretI64AsF32(int $x): float + { + return self::deserializeF32(self::serializeI64($x)); + } + + public static function reinterpretI32AsF64(int $x): float + { + return self::deserializeF64(self::serializeI32($x)); + } + + public static function reinterpretI64AsF64(int $x): float + { + return self::deserializeF64(self::serializeI64($x)); + } + + public static function reinterpretF32AsI32(float $x): int + { + return self::deserializeS32(self::serializeF32($x)); + } + + public static function reinterpretF64AsI32(float $x): int + { + return self::deserializeS32(self::serializeF64($x)); + } + + public static function reinterpretF32AsI64(float $x): int + { + return self::deserializeS64(self::serializeF32($x)); + } + + public static function reinterpretF64AsI64(float $x): int + { + return self::deserializeS64(self::serializeF64($x)); + } + + /** + * @return non-empty-string + */ + private static function packInt(PackIntSpecifiers $spec, int $x): string + { + $result = pack($spec->value, $x); + assert($result !== ''); + return $result; + } + + /** + * @return non-empty-string + */ + private static function packFloat(PackFloatSpecifiers $spec, float $x): string + { + $result = pack($spec->value, $x); + assert($result !== ''); + return $result; + } + + /** + * @param non-empty-string $s + */ + private static function unpackInt(UnpackIntSpecifiers $spec, string $s): int + { + assert(strlen($s) === $spec->byteCount()); + $result = unpack($spec->value, $s); + assert($result !== false && isset($result[1]) && is_int($result[1])); + return $result[1]; + } + + /** + * @param non-empty-string $s + */ + private static function unpackFloat(UnpackFloatSpecifiers $spec, string $s): float + { + assert(strlen($s) === $spec->byteCount()); + $result = unpack($spec->value, $s); + assert($result !== false && isset($result[1]) && is_float($result[1])); + return $result[1]; + } + + private static function isLittleEndian(): bool + { + return pack("s", ord("a"))[0] === "a"; + } + + /** + * @param non-empty-string $s + * @return non-empty-string + */ + private static function byteSwapIfNeeded(string $s): string + { + // note: currently phpstan cannot infer that strrev(non-empty-string) returns non-empty-string. + $ret = self::isLittleEndian() ? $s : strrev($s); + assert($ret !== ''); + return $ret; + } +} diff --git a/src/BitOps/FloatOps.php b/src/BitOps/FloatOps.php new file mode 100644 index 0000000..cb6cbc4 --- /dev/null +++ b/src/BitOps/FloatOps.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +final readonly class FloatOps +{ + private function __construct() + { + } + + /** + * @return array{int, int, int} + */ + public static function destructF64Bits(float $x): array + { + $i = BinaryConversion::deserializeS64(BinaryConversion::serializeF64($x)); + return [ + $i & FloatTraits::F64_SIGN_MASK, + $i & FloatTraits::F64_EXPONENT_MASK, + $i & FloatTraits::F64_MANTISSA_MASK, + ]; + } + + public static function constructNan(Signedness $sign, float $x): float + { + [, , $payload] = self::destructF64Bits($x); + $i = 0 | + FloatTraits::getF64SignBit($sign) | + FloatTraits::F64_EXPONENT_NAN | + $payload; + return BinaryConversion::deserializeF64(BinaryConversion::serializeI64($i)); + } + + public static function getSignedness(float $x): Signedness + { + return self::destructF64Bits($x)[0] === 0 ? Signedness::Unsigned : Signedness::Signed; + } +} diff --git a/src/BitOps/FloatTraits.php b/src/BitOps/FloatTraits.php new file mode 100644 index 0000000..dca9e18 --- /dev/null +++ b/src/BitOps/FloatTraits.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +final readonly class FloatTraits +{ + public const int F32_EXPONENT_BITS = 8; + public const int F32_MANTISSA_BITS = 23; + + public const int F32_SIGN_MASK = 0b10000000_00000000_00000000_00000000; + public const int F32_EXPONENT_MASK = 0b01111111_10000000_00000000_00000000; + public const int F32_MANTISSA_MASK = 0b00000000_01111111_11111111_11111111; + + public const int F32_SIGN_UNSIGNED = 0; + public const int F32_SIGN_SIGNED = 0b10000000_00000000_00000000_00000000; + public const int F32_EXPONENT_NAN = 0b01111111_10000000_00000000_00000000; + + public const int F64_EXPONENT_BITS = 11; + public const int F64_MANTISSA_BITS = 52; + + public const int F64_SIGN_MASK = PHP_INT_MIN; + public const int F64_EXPONENT_MASK = 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000; + public const int F64_MANTISSA_MASK = 0b00000000_00001111_11111111_11111111_11111111_11111111_11111111_11111111; + + public const int F64_SIGN_UNSIGNED = 0; + public const int F64_SIGN_SIGNED = PHP_INT_MIN; + public const int F64_EXPONENT_NAN = 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000; + + private function __construct() + { + } + + public static function getF32SignBit(Signedness $sign): int + { + return match ($sign) { + Signedness::Unsigned => self::F32_SIGN_UNSIGNED, + Signedness::Signed => self::F32_SIGN_SIGNED, + }; + } + + public static function getF64SignBit(Signedness $sign): int + { + return match ($sign) { + Signedness::Unsigned => self::F64_SIGN_UNSIGNED, + Signedness::Signed => self::F64_SIGN_SIGNED, + }; + } +} diff --git a/src/BitOps/PackFloatSpecifiers.php b/src/BitOps/PackFloatSpecifiers.php new file mode 100644 index 0000000..645cae0 --- /dev/null +++ b/src/BitOps/PackFloatSpecifiers.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +enum PackFloatSpecifiers: string +{ + case Float32LittleEndian = 'g'; + case Float64LittleEndian = 'e'; +} diff --git a/src/BitOps/PackIntSpecifiers.php b/src/BitOps/PackIntSpecifiers.php new file mode 100644 index 0000000..da10ab2 --- /dev/null +++ b/src/BitOps/PackIntSpecifiers.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +enum PackIntSpecifiers: string +{ + case Int8 = 'c'; + case Int16LittleEndian = 'v'; + case Int32LittleEndian = 'V'; + case Int64BigEndian = 'J'; + case Int64LittleEndian = 'P'; +} diff --git a/src/BitOps/Signedness.php b/src/BitOps/Signedness.php new file mode 100644 index 0000000..80cd03b --- /dev/null +++ b/src/BitOps/Signedness.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +enum Signedness +{ + case Unsigned; + case Signed; + + public static function fromSignBit(int $b): self + { + return $b === 0 ? self::Unsigned : self::Signed; + } + + public function negated(): self + { + return match ($this) { + self::Unsigned => self::Signed, + self::Signed => self::Unsigned, + }; + } +} diff --git a/src/BitOps/UnpackFloatSpecifiers.php b/src/BitOps/UnpackFloatSpecifiers.php new file mode 100644 index 0000000..5a3aa4f --- /dev/null +++ b/src/BitOps/UnpackFloatSpecifiers.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +enum UnpackFloatSpecifiers: string +{ + case Float32LittleEndian = 'g'; + case Float64LittleEndian = 'e'; + + public function byteCount(): int + { + return match ($this) { + self::Float32LittleEndian => 4, + self::Float64LittleEndian => 8, + }; + } +} diff --git a/src/BitOps/UnpackIntSpecifiers.php b/src/BitOps/UnpackIntSpecifiers.php new file mode 100644 index 0000000..be210f3 --- /dev/null +++ b/src/BitOps/UnpackIntSpecifiers.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Waddiwasi\BitOps; + +enum UnpackIntSpecifiers: string +{ + case SignedInt8 = 'c'; + case SignedInt16MachineOrder = 's'; + case SignedInt32MachineOrder = 'l'; + case UnsignedInt32LittleEndian = 'V'; + case SignedInt64MachineOrder = 'q'; + + public function byteCount(): int + { + return match ($this) { + self::SignedInt8 => 1, + self::SignedInt16MachineOrder => 2, + self::SignedInt32MachineOrder, self::UnsignedInt32LittleEndian => 4, + self::SignedInt64MachineOrder => 8, + }; + } +} diff --git a/src/WebAssembly/BinaryFormat/Decoder.php b/src/WebAssembly/BinaryFormat/Decoder.php index e64fac8..f0a5c29 100644 --- a/src/WebAssembly/BinaryFormat/Decoder.php +++ b/src/WebAssembly/BinaryFormat/Decoder.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Nsfisis\Waddiwasi\WebAssembly\BinaryFormat; +use Nsfisis\Waddiwasi\BitOps\BinaryConversion; use Nsfisis\Waddiwasi\Stream\StreamInterface; use Nsfisis\Waddiwasi\Stream\UnexpectedEofException; use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\Internal\Code; @@ -39,7 +40,6 @@ use function assert; use function count; use function get_class; use function in_array; -use function is_float; use function is_int; use function ord; use function sprintf; @@ -1090,13 +1090,7 @@ final class Decoder */ private function decodeF32(): float { - $buf = $this->stream->read(4); - $result = unpack('g', $buf); - if ($result === false) { - throw new InvalidBinaryFormatException("f32"); - } - assert(isset($result[1]) && is_float($result[1])); - return $result[1]; + return BinaryConversion::deserializeF32($this->stream->read(4)); } /** @@ -1104,13 +1098,7 @@ final class Decoder */ private function decodeF64(): float { - $buf = $this->stream->read(8); - $result = unpack('e', $buf); - if ($result === false) { - throw new InvalidBinaryFormatException("f64"); - } - assert(isset($result[1]) && is_float($result[1])); - return $result[1]; + return BinaryConversion::deserializeF64($this->stream->read(8)); } /** diff --git a/src/WebAssembly/Execution/MemInst.php b/src/WebAssembly/Execution/MemInst.php index 94d57cf..9ced0a3 100644 --- a/src/WebAssembly/Execution/MemInst.php +++ b/src/WebAssembly/Execution/MemInst.php @@ -44,11 +44,6 @@ final class MemInst private CData $dataS64_6; private CData $dataS64_7; - private CData $dataF32_0; - private CData $dataF32_1; - private CData $dataF32_2; - private CData $dataF32_3; - private CData $dataF64_0; private CData $dataF64_1; private CData $dataF64_2; @@ -155,11 +150,6 @@ final class MemInst $this->dataS64_6 = $castInt(64, true, 6); $this->dataS64_7 = $castInt(64, true, 7); - $this->dataF32_0 = $castFloat(32, 0); - $this->dataF32_1 = $castFloat(32, 1); - $this->dataF32_2 = $castFloat(32, 2); - $this->dataF32_3 = $castFloat(32, 3); - $this->dataF64_0 = $castFloat(64, 0); $this->dataF64_1 = $castFloat(64, 1); $this->dataF64_2 = $castFloat(64, 2); @@ -380,7 +370,10 @@ final class MemInst if ($this->size() < $ptr + 4) { return null; } - return $this->dataF32($ptr)[$ptr >> 2]; + // f32 cannot be loaded directly from memory because PHP handles NaN + // differently than WebAssembly spec defines. + $i = $this->dataU32($ptr)[$ptr >> 2]; + return NumericOps::f32ReinterpretI32($i); } /** @@ -517,7 +510,9 @@ final class MemInst if ($this->size() < $ptr + 4) { return false; } - $this->dataF32($ptr)[$ptr >> 2] = $c; + // f32 cannot be stored directly in memory because PHP handles NaN + // differently than WebAssembly spec defines. + $this->dataU32($ptr)[$ptr >> 2] = NumericOps::i32ReinterpretF32($c); return true; } @@ -578,16 +573,6 @@ final class MemInst }; } - private function dataF32(int $ptr): CData - { - return match ($ptr & 3) { - 0 => $this->dataF32_0, - 1 => $this->dataF32_1, - 2 => $this->dataF32_2, - 3 => $this->dataF32_3, - }; - } - private function dataF64(int $ptr): CData { return match ($ptr & 7) { diff --git a/src/WebAssembly/Execution/NumericOps.php b/src/WebAssembly/Execution/NumericOps.php index a24791f..2b48679 100644 --- a/src/WebAssembly/Execution/NumericOps.php +++ b/src/WebAssembly/Execution/NumericOps.php @@ -5,7 +5,8 @@ declare(strict_types=1); namespace Nsfisis\Waddiwasi\WebAssembly\Execution; use FFI; -use InvalidArgumentException; +use Nsfisis\Waddiwasi\BitOps\BinaryConversion; +use Nsfisis\Waddiwasi\BitOps\FloatOps; use RoundingMode; use function abs; use function assert; @@ -25,12 +26,10 @@ use function is_int; use function is_nan; use function max; use function min; -use function pack; use function round; use function sprintf; use function sqrt; use function substr; -use function unpack; use const PHP_INT_MAX; use const PHP_INT_MIN; @@ -82,14 +81,18 @@ final readonly class NumericOps public static function f32CopySign(float $x, float $y): float { - $xSign = self::getFloatSign($x); - $ySign = self::getFloatSign($y); + $xSign = FloatOps::getSignedness($x); + $ySign = FloatOps::getSignedness($y); return $xSign === $ySign ? $x : self::f32Neg($x); } public static function f32DemoteF64(float $x): float { - return self::truncateF64ToF32($x); + if (is_nan($x)) { + return NAN; + } else { + return self::truncateF64ToF32($x); + } } public static function f32Div(float $x, float $y): float @@ -170,7 +173,7 @@ final readonly class NumericOps { if (is_nan($x)) { // Negate operator does not work for NaN in PHP. - return self::constructNan(-self::getFloatSign($x), $x); + return FloatOps::constructNan(FloatOps::getSignedness($x)->negated(), $x); } else { return -$x; } @@ -178,12 +181,12 @@ final readonly class NumericOps public static function f32ReinterpretI32(int $x): float { - return self::reinterpretI32AsF32($x); + return BinaryConversion::reinterpretI32AsF32($x); } public static function f32ReinterpretI64(int $x): float { - return self::reinterpretI64AsF32($x); + return BinaryConversion::reinterpretI64AsF32($x); } public static function f32Sqrt(float $x): float @@ -250,8 +253,8 @@ final readonly class NumericOps public static function f64CopySign(float $x, float $y): float { - $xSign = self::getFloatSign($x); - $ySign = self::getFloatSign($y); + $xSign = FloatOps::getSignedness($x); + $ySign = FloatOps::getSignedness($y); return $xSign === $ySign ? $x : self::f64Neg($x); } @@ -333,7 +336,7 @@ final readonly class NumericOps { if (is_nan($x)) { // Negate operator does not work for NaN in PHP. - return self::constructNan(-self::getFloatSign($x), $x); + return FloatOps::constructNan(FloatOps::getSignedness($x)->negated(), $x); } else { return -$x; } @@ -341,17 +344,21 @@ final readonly class NumericOps public static function f64PromoteF32(float $x): float { - return $x; + if (is_nan($x)) { + return NAN; + } else { + return $x; + } } public static function f64ReinterpretI32(int $x): float { - return self::reinterpretI32AsF64($x); + return BinaryConversion::reinterpretI32AsF64($x); } public static function f64ReinterpretI64(int $x): float { - return self::reinterpretI64AsF64($x); + return BinaryConversion::reinterpretI64AsF64($x); } public static function f64Sqrt(float $x): float @@ -450,17 +457,13 @@ final readonly class NumericOps public static function i32Extend16S(int $x): int { $x = self::convertS32ToU32($x); - $result = unpack('s', pack('S', $x & 0xFFFF)); - assert($result !== false); - return $result[1]; + return BinaryConversion::deserializeS16(BinaryConversion::serializeI16($x & 0xFFFF)); } public static function i32Extend8S(int $x): int { $x = self::convertS32ToU32($x); - $result = unpack('c', pack('C', $x & 0xFF)); - assert($result !== false); - return $result[1]; + return BinaryConversion::deserializeS8(BinaryConversion::serializeI8($x & 0xFF)); } public static function i32GeS(int $x, int $y): bool @@ -542,12 +545,12 @@ final readonly class NumericOps public static function i32ReinterpretF32(float $x): int { - return self::reinterpretF32AsI32($x); + return BinaryConversion::reinterpretF32AsI32($x); } public static function i32ReinterpretF64(float $x): int { - return self::reinterpretF64AsI32($x); + return BinaryConversion::reinterpretF64AsI32($x); } public static function i32RemS(int $x, int $y): int|TrapKind @@ -831,23 +834,17 @@ final readonly class NumericOps public static function i64Extend16S(int $x): int { - $result = unpack('s', pack('S', $x & 0xFFFF)); - assert($result !== false); - return $result[1]; + return BinaryConversion::deserializeS16(BinaryConversion::serializeI16($x & 0xFFFF)); } public static function i64Extend32S(int $x): int { - $result = unpack('l', pack('L', $x & 0xFFFFFFFF)); - assert($result !== false); - return $result[1]; + return BinaryConversion::deserializeS32(BinaryConversion::serializeI32($x & 0xFFFFFFFF)); } public static function i64Extend8S(int $x): int { - $result = unpack('c', pack('C', $x & 0xFF)); - assert($result !== false); - return $result[1]; + return BinaryConversion::deserializeS8(BinaryConversion::serializeI8($x & 0xFF)); } public static function i64ExtendI32S(int $x): int @@ -868,8 +865,8 @@ final readonly class NumericOps public static function i64GeU(int $x, int $y): bool { - $yPacked = pack('J', $y); - $xPacked = pack('J', $x); + $yPacked = BinaryConversion::serializeI64InBigEndian($y); + $xPacked = BinaryConversion::serializeI64InBigEndian($x); return $xPacked >= $yPacked; } @@ -880,8 +877,8 @@ final readonly class NumericOps public static function i64GtU(int $x, int $y): bool { - $yPacked = pack('J', $y); - $xPacked = pack('J', $x); + $yPacked = BinaryConversion::serializeI64InBigEndian($y); + $xPacked = BinaryConversion::serializeI64InBigEndian($x); return $xPacked > $yPacked; } @@ -892,8 +889,8 @@ final readonly class NumericOps public static function i64LeU(int $x, int $y): bool { - $yPacked = pack('J', $y); - $xPacked = pack('J', $x); + $yPacked = BinaryConversion::serializeI64InBigEndian($y); + $xPacked = BinaryConversion::serializeI64InBigEndian($x); return $xPacked <= $yPacked; } @@ -904,8 +901,8 @@ final readonly class NumericOps public static function i64LtU(int $x, int $y): bool { - $yPacked = pack('J', $y); - $xPacked = pack('J', $x); + $yPacked = BinaryConversion::serializeI64InBigEndian($y); + $xPacked = BinaryConversion::serializeI64InBigEndian($x); return $xPacked < $yPacked; } @@ -937,12 +934,12 @@ final readonly class NumericOps public static function i64ReinterpretF32(float $x): int { - return self::reinterpretF32AsI64($x); + return BinaryConversion::reinterpretF32AsI64($x); } public static function i64ReinterpretF64(float $x): int { - return self::reinterpretF64AsI64($x); + return BinaryConversion::reinterpretF64AsI64($x); } public static function i64RemS(int $x, int $y): int|TrapKind @@ -1142,116 +1139,17 @@ final readonly class NumericOps return $x ^ $y; } - public static function reinterpretI32AsF32(int $x): float - { - return self::deserializeF32FromBytes(self::serializeI32ToBytes($x)); - } - - public static function reinterpretI64AsF32(int $x): float - { - return self::deserializeF32FromBytes(self::serializeI64ToBytes($x)); - } - - public static function reinterpretI32AsF64(int $x): float - { - return self::deserializeF64FromBytes(self::serializeI32ToBytes($x)); - } - - public static function reinterpretI64AsF64(int $x): float - { - return self::deserializeF64FromBytes(self::serializeI64ToBytes($x)); - } - - public static function reinterpretF32AsI32(float $x): int - { - return self::deserializeI32FromBytes(self::serializeF32ToBytes($x)); - } - - public static function reinterpretF64AsI32(float $x): int - { - return self::deserializeI32FromBytes(self::serializeF64ToBytes($x)); - } - - public static function reinterpretF32AsI64(float $x): int - { - return self::deserializeI64FromBytes(self::serializeF32ToBytes($x)); - } - - public static function reinterpretF64AsI64(float $x): int - { - return self::deserializeI64FromBytes(self::serializeF64ToBytes($x)); - } - public static function truncateF64ToF32(float $x): float { - return self::deserializeF32FromBytes(self::serializeF32ToBytes($x)); + return BinaryConversion::deserializeF32(BinaryConversion::serializeF32($x)); } - public static function serializeI32ToBytes(int $x): string - { - return pack('l', $x); - } - - public static function deserializeI32FromBytes(string $s): int - { - $result = unpack('l', $s); - if ($result === false) { - throw new InvalidArgumentException("Failed to unpack i32: $s"); - } - return $result[1]; - } - - public static function serializeI64ToBytes(int $x): string - { - return pack('q', $x); - } - - public static function deserializeI64FromBytes(string $s): int - { - $result = unpack('q', $s); - if ($result === false) { - throw new InvalidArgumentException("Failed to unpack i64: $s"); - } - return $result[1]; - } - - public static function serializeF32ToBytes(float $x): string - { - return pack('f', $x); - } - - public static function deserializeF32FromBytes(string $s): float - { - $result = unpack('f', $s); - if ($result === false) { - throw new InvalidArgumentException("Failed to unpack f32: $s"); - } - return $result[1]; - } - - public static function serializeF64ToBytes(float $x): string - { - return pack('d', $x); - } - - public static function deserializeF64FromBytes(string $s): float - { - $result = unpack('d', $s); - if ($result === false) { - throw new InvalidArgumentException("Failed to unpack f64: $s"); - } - return $result[1]; - } public static function convertS32ToU32(int $x): int { - // assert(-0x80000000 <= $x && $x <= 0x7FFFFFFF, "convertS32ToU32: out of range $x"); + assert(-0x80000000 <= $x && $x <= 0x7FFFFFFF); if ($x < 0) { - $buf = pack('l', $x); - $result = unpack('L', $buf); - assert($result !== false); - assert(0x00000000 <= $result[1] && $result[1] <= 0xFFFFFFFF, "convertS32ToU32: out of range $result[1]"); - return $result[1]; + return $x + 0x100000000; } else { return $x; } @@ -1261,11 +1159,7 @@ final readonly class NumericOps { assert(0x00000000 <= $x && $x <= 0xFFFFFFFF); if (($x & 0x80000000) !== 0) { - $buf = pack('L', $x); - $result = unpack('l', $buf); - assert($result !== false); - assert(-0x80000000 <= $result[1] && $result[1] <= 0x7FFFFFFF, "convertU32ToS32: out of range $result[1]"); - return $result[1]; + return $x - 0x100000000; } else { return $x; } @@ -1297,45 +1191,6 @@ final readonly class NumericOps return (int)$result; } - /** - * @return 1|-1 - */ - public static function getFloatSign(float $p): int - { - if (is_nan($p)) { - $n = self::reinterpretF64AsI64($p); - // The MSB is the sign bit. - return (($n >> 63) & 1) === 1 ? -1 : 1; - } elseif ($p !== 0.0) { - return $p < 0.0 ? -1 : 1; - } else { - // Comparison with 0 does not work for -0.0. - return fdiv(1, $p) < 0.0 ? -1 : 1; - } - } - - /** - * @param -1|1 $sign - */ - private static function constructNan(int $sign, float $x): float - { - [$_, $_, $payload] = self::destructFloat($x); - $i = ($sign === 1 ? 0 : PHP_INT_MIN) | 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000 | $payload; - return self::reinterpretI64AsF64($i); - } - - /** - * @return array{int, int, int} - */ - private static function destructFloat(float $x): array - { - $i = self::reinterpretF64AsI64($x); - return [ - $i & PHP_INT_MIN, - $i & 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000, - $i & 0b00000000_00001111_11111111_11111111_11111111_11111111_11111111_11111111, - ]; - } private static function castBitIntToCFloat(string $x): float { diff --git a/tests/src/SpecTestsuites/SpecTestsuiteBase.php b/tests/src/SpecTestsuites/SpecTestsuiteBase.php index 6d92ed8..5b3cc4d 100644 --- a/tests/src/SpecTestsuites/SpecTestsuiteBase.php +++ b/tests/src/SpecTestsuites/SpecTestsuiteBase.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Nsfisis\Waddiwasi\Tests\SpecTestsuites; +use Nsfisis\Waddiwasi\BitOps\BinaryConversion; use Nsfisis\Waddiwasi\Stream\FileStream; use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\Decoder; use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\InvalidBinaryFormatException; @@ -12,7 +13,6 @@ use Nsfisis\Waddiwasi\WebAssembly\Execution\FuncInst; use Nsfisis\Waddiwasi\WebAssembly\Execution\GlobalInst; use Nsfisis\Waddiwasi\WebAssembly\Execution\Linker; use Nsfisis\Waddiwasi\WebAssembly\Execution\MemInst; -use Nsfisis\Waddiwasi\WebAssembly\Execution\NumericOps; use Nsfisis\Waddiwasi\WebAssembly\Execution\Ref; use Nsfisis\Waddiwasi\WebAssembly\Execution\Refs\RefExtern; use Nsfisis\Waddiwasi\WebAssembly\Execution\Refs\RefFunc; @@ -254,15 +254,15 @@ abstract class SpecTestsuiteBase extends TestCase $type = $arg['type']; $value = $arg['value']; return match ($type) { - 'i32' => unpack('l', pack('V', (int)$value))[1], - 'i64' => unpack('q', self::convertInt64ToBinary($value))[1], + 'i32' => BinaryConversion::deserializeS32(BinaryConversion::serializeI32((int)$value)), + 'i64' => BinaryConversion::deserializeS64(self::convertInt64ToBinary($value)), 'f32' => match ($value) { 'nan:canonical', 'nan:arithmetic' => $value, - default => unpack('g', pack('V', (int)$value))[1], + default => BinaryConversion::deserializeF32(BinaryConversion::serializeI32((int)$value)), }, 'f64' => match ($value) { 'nan:canonical', 'nan:arithmetic' => $value, - default => unpack('e', self::convertInt64ToBinary($value))[1], + default => BinaryConversion::deserializeF64(self::convertInt64ToBinary($value)), }, 'externref' => $value === 'null' ? Ref::RefNull(ValType::ExternRef) : Ref::RefExtern((int)$value), 'funcref' => $value === 'null' ? Ref::RefNull(ValType::FuncRef) : Ref::RefFunc((int)$value), @@ -320,16 +320,16 @@ abstract class SpecTestsuiteBase extends TestCase is_nan($actualResult), "result $i is not NaN" . $message, ); - $actualBits = sprintf("%064b", NumericOps::reinterpretF64AsI64($actualResult)); + $actualBits = sprintf("%064b", BinaryConversion::reinterpretF64AsI64($actualResult)); if (str_starts_with($actualBits, '0')) { $this->assertSame( - sprintf("%064b", NumericOps::reinterpretF64AsI64(NAN)), + sprintf("%064b", BinaryConversion::reinterpretF64AsI64(NAN)), $actualBits, "result $i is not canonical NaN" . $message, ); } else { $this->assertSame( - sprintf("1%b", NumericOps::reinterpretF64AsI64(NAN)), + sprintf("1%b", BinaryConversion::reinterpretF64AsI64(NAN)), $actualBits, "result $i is not canonical NaN" . $message, ); @@ -339,7 +339,7 @@ abstract class SpecTestsuiteBase extends TestCase is_nan($actualResult), "result $i is not NaN" . $message, ); - $actualBits = sprintf("%064b", NumericOps::reinterpretF64AsI64($actualResult)); + $actualBits = sprintf("%064b", BinaryConversion::reinterpretF64AsI64($actualResult)); if (str_starts_with($actualBits, '0')) { $this->assertStringStartsWith( '0111111111111', @@ -359,8 +359,8 @@ abstract class SpecTestsuiteBase extends TestCase "result $i is not NaN" . $message, ); $this->assertSame( - sprintf("%b", NumericOps::reinterpretF64AsI64($expectedValue)), - sprintf("%b", NumericOps::reinterpretF64AsI64($actualResult)), + sprintf("%b", BinaryConversion::reinterpretF64AsI64($expectedValue)), + sprintf("%b", BinaryConversion::reinterpretF64AsI64($actualResult)), "result $i Nan payload mismatch" . $message, ); } elseif ($expectedValue instanceof RefNull) { @@ -434,6 +434,6 @@ abstract class SpecTestsuiteBase extends TestCase if (bccomp(bcsub(bcpow('2', '63'), '1'), $value) < 0) { $value = bcsub($value, bcpow('2', '64')); } - return pack('q', (int)$value); + return BinaryConversion::serializeI64((int)$value); } } |
