aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-04-06 02:23:01 +0900
committernsfisis <nsfisis@gmail.com>2025-04-06 02:23:01 +0900
commitfa9ad79209d85b0677b00ca1d41d070105fec09f (patch)
tree95a81c0909e761e9cecb3cd7333201cb4ac62161
parenta0f17ee6807f9a0605261a11a8ba46c57a9849a0 (diff)
parentde116dceae7ea654df28caab3fd2f3aefdffe188 (diff)
downloadphp-waddiwasi-fa9ad79209d85b0677b00ca1d41d070105fec09f.tar.gz
php-waddiwasi-fa9ad79209d85b0677b00ca1d41d070105fec09f.tar.zst
php-waddiwasi-fa9ad79209d85b0677b00ca1d41d070105fec09f.zip
Merge branch 'fix/float-handling'
-rw-r--r--BUGS7
-rw-r--r--TODO2
-rw-r--r--composer.json2
-rw-r--r--composer.lock514
-rw-r--r--phpunit.xml4
-rw-r--r--src/BitOps/BinaryConversion.php256
-rw-r--r--src/BitOps/FloatOps.php40
-rw-r--r--src/BitOps/FloatTraits.php50
-rw-r--r--src/BitOps/PackFloatSpecifiers.php11
-rw-r--r--src/BitOps/PackIntSpecifiers.php14
-rw-r--r--src/BitOps/Signedness.php24
-rw-r--r--src/BitOps/UnpackFloatSpecifiers.php19
-rw-r--r--src/BitOps/UnpackIntSpecifiers.php24
-rw-r--r--src/WebAssembly/BinaryFormat/Decoder.php18
-rw-r--r--src/WebAssembly/Execution/MemInst.php29
-rw-r--r--src/WebAssembly/Execution/NumericOps.php231
-rw-r--r--tests/src/SpecTestsuites/SpecTestsuiteBase.php24
17 files changed, 706 insertions, 563 deletions
diff --git a/BUGS b/BUGS
index 905a6e5..3e88d14 100644
--- a/BUGS
+++ b/BUGS
@@ -1,12 +1,5 @@
# Failed spec tests
-## Numeric
-
-* ConversionsTest
-* FloatExprsTest
-* FloatLiteralsTest
-* FloatMemoryTest
-
## Validation
* ImportsTest
diff --git a/TODO b/TODO
index 80e15c0..171eb28 100644
--- a/TODO
+++ b/TODO
@@ -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);
}
}