diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-07-07 12:24:31 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-07-07 12:24:31 +0900 |
| commit | 1cd492d63328b77173d1a74ee061fa3cdd43ee44 (patch) | |
| tree | ebd417993b8c49f6081bc141ba870ab169059bb6 | |
| parent | 3d30b262fab3beeee738cc98d8862a012012c2a4 (diff) | |
| download | php-waddiwasi-1cd492d63328b77173d1a74ee061fa3cdd43ee44.tar.gz php-waddiwasi-1cd492d63328b77173d1a74ee061fa3cdd43ee44.tar.zst php-waddiwasi-1cd492d63328b77173d1a74ee061fa3cdd43ee44.zip | |
fix: f32.copysign and f64.copysign
| -rw-r--r-- | BUGS.txt | 2 | ||||
| -rw-r--r-- | src/Execution/Runtime.php | 22 |
2 files changed, 20 insertions, 4 deletions
@@ -2,8 +2,6 @@ ## Numeric -* F64BitwiseTest -* F32BitwiseTest * ConversionsTest * FloatExprsTest * FloatLiteralsTest diff --git a/src/Execution/Runtime.php b/src/Execution/Runtime.php index 10bed7c..98893d0 100644 --- a/src/Execution/Runtime.php +++ b/src/Execution/Runtime.php @@ -599,7 +599,9 @@ final class Runtime { $c2 = $this->stack->popFloat(); $c1 = $this->stack->popFloat(); - $this->stack->pushValue($c1 * ($c2 < 0 ? -1 : 1)); + $c1Sign = self::getFloatSign($c1); + $c2Sign = self::getFloatSign($c2); + $this->stack->pushValue($c1Sign === $c2Sign ? $c1 : -$c1); } private function execInstrNumericF32DemoteF64(Instrs\Numeric\F32DemoteF64 $instr): void @@ -793,7 +795,9 @@ final class Runtime { $c2 = $this->stack->popFloat(); $c1 = $this->stack->popFloat(); - $this->stack->pushValue($c1 * ($c2 < 0 ? -1 : 1)); + $c1Sign = self::getFloatSign($c1); + $c2Sign = self::getFloatSign($c2); + $this->stack->pushValue($c1Sign === $c2Sign ? $c1 : -$c1); } private function execInstrNumericF64Div(Instrs\Numeric\F64Div $instr): void @@ -2606,4 +2610,18 @@ final class Runtime } return (int)$result; } + + private static function getFloatSign(float $p): int + { + if (is_nan($p)) { + $n = BinaryConversion::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; + } + } } |
