aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-04-03 02:42:41 +0900
committernsfisis <nsfisis@gmail.com>2025-04-03 02:44:01 +0900
commit5fd76d0bf2cf3128cc8e9f55364641f16e1aa82e (patch)
tree7eeefa8cfb4c7179d04242ffe9385a4d3275e99c
parent33f89afa91e62e8c496e02a188301cd11497f287 (diff)
downloadphp-waddiwasi-5fd76d0bf2cf3128cc8e9f55364641f16e1aa82e.tar.gz
php-waddiwasi-5fd76d0bf2cf3128cc8e9f55364641f16e1aa82e.tar.zst
php-waddiwasi-5fd76d0bf2cf3128cc8e9f55364641f16e1aa82e.zip
fix: truncate ops
-rw-r--r--BUGS1
-rw-r--r--phpstan.neon3
-rw-r--r--phpunit.xml1
-rw-r--r--src/WebAssembly/Execution/NumericOps.php77
4 files changed, 55 insertions, 27 deletions
diff --git a/BUGS b/BUGS
index c48050d..905a6e5 100644
--- a/BUGS
+++ b/BUGS
@@ -6,7 +6,6 @@
* FloatExprsTest
* FloatLiteralsTest
* FloatMemoryTest
-* FloatMiscTest
## Validation
diff --git a/phpstan.neon b/phpstan.neon
index fd3341e..94b1d70 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -9,7 +9,8 @@ parameters:
paths:
- src
- examples/hello-world
- - examples/php-on-wasm
+ # TODO
+ # - examples/php-on-wasm
typeAliases:
Byte: 'int'
U32: 'int'
diff --git a/phpunit.xml b/phpunit.xml
index a2f646e..336683b 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -39,6 +39,7 @@
<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/FloatMiscTest.php</file>
<file>tests/src/SpecTestsuites/Core/ForwardTest.php</file>
<file>tests/src/SpecTestsuites/Core/FuncPtrsTest.php</file>
<file>tests/src/SpecTestsuites/Core/FuncTest.php</file>
diff --git a/src/WebAssembly/Execution/NumericOps.php b/src/WebAssembly/Execution/NumericOps.php
index 0a8345f..ee13aad 100644
--- a/src/WebAssembly/Execution/NumericOps.php
+++ b/src/WebAssembly/Execution/NumericOps.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Nsfisis\Waddiwasi\WebAssembly\Execution;
use InvalidArgumentException;
+use RoundingMode;
use function abs;
use function assert;
use function bcadd;
@@ -25,12 +26,12 @@ 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;
-use const PHP_ROUND_HALF_EVEN;
final readonly class NumericOps
{
@@ -161,7 +162,7 @@ final readonly class NumericOps
if (is_nan($x)) {
return NAN;
}
- return round($x, mode: PHP_ROUND_HALF_EVEN);
+ return round($x, mode: RoundingMode::HalfEven);
}
public static function f32Neg(float $x): float
@@ -324,7 +325,7 @@ final readonly class NumericOps
if (is_nan($x)) {
return NAN;
}
- return round($x, mode: PHP_ROUND_HALF_EVEN);
+ return round($x, mode: RoundingMode::HalfEven);
}
public static function f64Neg(float $x): float
@@ -633,7 +634,7 @@ final readonly class NumericOps
if ($x <= -2147483649.0 || 2147483648.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
public static function i32TruncF32U(float $x): int|TrapKind
@@ -647,7 +648,7 @@ final readonly class NumericOps
if ($x <= -1.0 || 4294967296.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return self::convertU32ToS32((int) $x);
+ return self::convertU32ToS32((int)round($x, mode: RoundingMode::TowardsZero));
}
public static function i32TruncF64S(float $x): int|TrapKind
@@ -661,7 +662,7 @@ final readonly class NumericOps
if ($x <= -2147483649.0 || 2147483648.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
public static function i32TruncF64U(float $x): int|TrapKind
@@ -675,50 +676,62 @@ final readonly class NumericOps
if ($x <= -1.0 || 4294967296.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return self::convertU32ToS32((int) $x);
+ return self::convertU32ToS32((int)round($x, mode: RoundingMode::TowardsZero));
}
public static function i32TruncSatF32S(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < -2147483648.0) {
return -2147483648;
} elseif (2147483647.0 < $x) {
return 2147483647;
} else {
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
}
public static function i32TruncSatF32U(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < 0.0) {
return 0;
} elseif (4294967295.0 < $x) {
return -1;
} else {
- return self::convertU32ToS32((int) $x);
+ return self::convertU32ToS32((int)round($x, mode: RoundingMode::TowardsZero));
}
}
public static function i32TruncSatF64S(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < -2147483648.0) {
return -2147483648;
} elseif (2147483647.0 < $x) {
return 2147483647;
} else {
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
}
public static function i32TruncSatF64U(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < 0.0) {
return 0;
} elseif (4294967295.0 < $x) {
return -1;
} else {
- return self::convertU32ToS32((int) $x);
+ return self::convertU32ToS32((int)round($x, mode: RoundingMode::TowardsZero));
}
}
@@ -1018,7 +1031,7 @@ final readonly class NumericOps
if ($x < -9223372036854775808.0 || 9223372036854775808.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
public static function i64TruncF32U(float $x): int|TrapKind
@@ -1032,7 +1045,7 @@ final readonly class NumericOps
if ($x <= -1.0 || 18446744073709551616.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return (int) $x;
+ return self::bigIntToPhpInt(sprintf('%F', round($x, mode: RoundingMode::TowardsZero)));
}
public static function i64TruncF64S(float $x): int|TrapKind
@@ -1046,7 +1059,7 @@ final readonly class NumericOps
if ($x < -9223372036854775808.0 || 9223372036854775808.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
public static function i64TruncF64U(float $x): int|TrapKind
@@ -1060,52 +1073,66 @@ final readonly class NumericOps
if ($x <= -1.0 || 18446744073709551616.0 <= $x) {
return TrapKind::IntegerOverflow;
}
- return (int) $x;
+ return self::bigIntToPhpInt(sprintf('%F', round($x, mode: RoundingMode::TowardsZero)));
}
public static function i64TruncSatF32S(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < -9223372036854775808.0) {
return PHP_INT_MIN;
} elseif (9223372036854775808.0 <= $x) {
return PHP_INT_MAX;
} else {
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
}
public static function i64TruncSatF32U(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < 0.0) {
return 0;
- } elseif (9223372036854775807.0 < $x) {
- // @todo
- return (int) $x;
+ } elseif (is_infinite($x)) {
+ return self::bigIntToPhpInt('18446744073709551615');
+ } elseif (bccomp('18446744073709551615', sprintf('%.9F', $x)) < 0) {
+ return self::bigIntToPhpInt('18446744073709551615');
} else {
- return (int) $x;
+ return self::bigIntToPhpInt(sprintf('%F', round($x, mode: RoundingMode::TowardsZero)));
}
}
public static function i64TruncSatF64S(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < -9223372036854775808.0) {
return PHP_INT_MIN;
} elseif (9223372036854775808.0 <= $x) {
return PHP_INT_MAX;
} else {
- return (int) $x;
+ return (int)round($x, mode: RoundingMode::TowardsZero);
}
}
public static function i64TruncSatF64U(float $x): int
{
+ if (is_nan($x)) {
+ return 0;
+ }
if ($x < 0.0) {
return 0;
- } elseif (9223372036854775807.0 < $x) {
- // @todo
- return (int) $x;
+ } elseif (is_infinite($x)) {
+ return self::bigIntToPhpInt('18446744073709551615');
+ } elseif (bccomp('18446744073709551615', sprintf('%.9F', $x)) < 0) {
+ return self::bigIntToPhpInt('18446744073709551615');
} else {
- return (int) $x;
+ return self::bigIntToPhpInt(sprintf('%F', round($x, mode: RoundingMode::TowardsZero)));
}
}