From 1cd492d63328b77173d1a74ee061fa3cdd43ee44 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 7 Jul 2024 12:24:31 +0900 Subject: fix: f32.copysign and f64.copysign --- src/Execution/Runtime.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src') 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; + } + } } -- cgit v1.2.3-70-g09d2