diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-06-29 01:05:21 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-06-29 01:25:47 +0900 |
| commit | 8589fd9fb5fda63579fd152c958e1678d9724a77 (patch) | |
| tree | cbd38ef73c5f7044dfe52545e1e6fd071fbb406c | |
| parent | d96c3f29fdcf0b14f74e6c08f2bc949776227d97 (diff) | |
| download | php-waddiwasi-8589fd9fb5fda63579fd152c958e1678d9724a77.tar.gz php-waddiwasi-8589fd9fb5fda63579fd152c958e1678d9724a77.tar.zst php-waddiwasi-8589fd9fb5fda63579fd152c958e1678d9724a77.zip | |
fix: i64.* ops
| -rw-r--r-- | src/Execution/Runtime.php | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/src/Execution/Runtime.php b/src/Execution/Runtime.php index d798ae5..71faddf 100644 --- a/src/Execution/Runtime.php +++ b/src/Execution/Runtime.php @@ -1346,12 +1346,12 @@ final class Runtime private function execInstrNumericI64DivU(Instrs\Numeric\I64DivU $instr): void { - $c2 = $this->stack->popInt(); - $c1 = $this->stack->popInt(); - if ($c2 === 0) { + $c2 = self::convertS64ToBigUInt($this->stack->popInt()); + $c1 = self::convertS64ToBigUInt($this->stack->popInt()); + if ($c2 === '0') { throw new TrapException("i64.div_u: divide by zero", trapKind: TrapKind::DivideByZero); } - $this->stack->pushValue(intdiv($c1, $c2)); + $this->stack->pushValue(self::bigIntToPhpInt(bcdiv($c1, $c2, 0))); } private function execInstrNumericI64Eq(Instrs\Numeric\I64Eq $instr): void @@ -1529,12 +1529,12 @@ final class Runtime private function execInstrNumericI64RemU(Instrs\Numeric\I64RemU $instr): void { - $c2 = $this->stack->popInt(); - $c1 = $this->stack->popInt(); - if ($c2 === 0) { + $c2 = self::convertS64ToBigUInt($this->stack->popInt()); + $c1 = self::convertS64ToBigUInt($this->stack->popInt()); + if ($c2 === '0') { throw new TrapException("i64.rem_u: divide by zero", trapKind: TrapKind::DivideByZero); } - $this->stack->pushValue($c1 % $c2); + $this->stack->pushValue(self::bigIntToPhpInt(bcmod($c1, $c2, 0))); } private function execInstrNumericI64RotL(Instrs\Numeric\I64RotL $instr): void @@ -1542,7 +1542,9 @@ final class Runtime $i2 = $this->stack->popInt(); $i1 = $this->stack->popInt(); $k = $i2 % 64; - $this->stack->pushValue(($i1 << $k) | ($i1 >> (64 - $k))); + $left = $i1 << $k; + $right = ($i1 >> (64 - $k)) & 0x7FFFFFFFFFFFFFFF; + $this->stack->pushValue($left | $right); } private function execInstrNumericI64RotR(Instrs\Numeric\I64RotR $instr): void @@ -1550,29 +1552,31 @@ final class Runtime $i2 = $this->stack->popInt(); $i1 = $this->stack->popInt(); $k = $i2 % 64; + $left = ($i1 >> $k) & 0x7FFFFFFFFFFFFFFF; + $right = $i1 << (64 - $k); $this->stack->pushValue(($i1 >> $k) | ($i1 << (64 - $k))); } private function execInstrNumericI64Shl(Instrs\Numeric\I64Shl $instr): void { - $c2 = $this->stack->popInt(); - $k = $c2 % 64; + $c2 = self::convertS64ToBigUInt($this->stack->popInt()); + $k = (int)bcmod($c2, '64'); $c1 = $this->stack->popInt(); $this->stack->pushValue($c1 << $k); } private function execInstrNumericI64ShrS(Instrs\Numeric\I64ShrS $instr): void { - $c2 = $this->stack->popInt(); - $k = $c2 % 64; + $c2 = self::convertS64ToBigUInt($this->stack->popInt()); + $k = (int)bcmod($c2, '64'); $c1 = $this->stack->popInt(); $this->stack->pushValue($c1 >> $k); } private function execInstrNumericI64ShrU(Instrs\Numeric\I64ShrU $instr): void { - $c2 = $this->stack->popInt(); - $k = $c2 % 64; + $c2 = self::convertS64ToBigUInt($this->stack->popInt()); + $k = (int)bcmod($c2, '64'); if ($k === 0) { return; } @@ -2541,6 +2545,15 @@ final class Runtime } } + private static function convertS64ToBigUInt(int $x): string + { + if ($x < 0) { + return bcadd((string)$x, '18446744073709551616'); + } else { + return (string)$x; + } + } + private static function bigIntToPhpInt(string $s): int { $result = bcmod($s, bcpow('2', '64')); |
