Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ protected function getOpCodeTypeFromBinaryOp(Op\Expr\BinaryOp $expr): int {
return OpCode::TYPE_IDENTICAL;
} elseif ($expr instanceof Op\Expr\BinaryOp\NotIdentical) {
return OpCode::TYPE_NOT_IDENTICAL;
} elseif ($expr instanceof Op\Expr\BinaryOp\Spaceship) {
return OpCode::TYPE_SPACESHIP;
} elseif ($expr instanceof Op\Expr\BinaryOp\Minus) {
return OpCode::TYPE_MINUS;
} elseif ($expr instanceof Op\Expr\BinaryOp\Mul) {
Expand Down
1 change: 1 addition & 0 deletions lib/JIT.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ private function compileBlockInternal(
case OpCode::TYPE_NOT_IDENTICAL:
case OpCode::TYPE_EQUAL:
case OpCode::TYPE_NOT_EQUAL:
case OpCode::TYPE_SPACESHIP:
$this->assignOperand(
$block->getOperand($op->arg1),
$this->context->helper->binaryOp(
Expand Down
1 change: 1 addition & 0 deletions lib/JIT.pre
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ class JIT {
case OpCode::TYPE_NOT_IDENTICAL:
case OpCode::TYPE_EQUAL:
case OpCode::TYPE_NOT_EQUAL:
case OpCode::TYPE_SPACESHIP:
$this->assignOperand(
$block->getOperand($op->arg1),
$this->context->helper->binaryOp(
Expand Down
22 changes: 21 additions & 1 deletion lib/JIT/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,17 @@ public function binaryOp(OpCode $opcode, Variable $left, Variable $right): Varia
goto return_bool;
case OpCode::TYPE_NOT_IDENTICAL:
case OpCode::TYPE_NOT_EQUAL:
case OpCode::TYPE_NOT_IDENTICAL:
$result = $this->context->builder->fcmp(Builder::REAL_ONE, $leftValue, $rightValue);
goto return_bool;
case OpCode::TYPE_SPACESHIP:
$lt = $this->context->builder->fcmp(Builder::REAL_OLT, $leftValue, $rightValue);
$gt = $this->context->builder->fcmp(Builder::REAL_OGT, $leftValue, $rightValue);
$ty = $leftValue->typeOf();
$negOne = $ty->constInt(-1, true);
$one = $ty->constInt(1, true);
$zero = $ty->constInt(0, false);
$result = $this->context->builder->select($gt, $one, $this->context->builder->select($lt, $negOne, $zero));
goto return_long;
}
break;
case TYPE_PAIR_NATIVE_LONG_NATIVE_LONG:
Expand Down Expand Up @@ -434,6 +442,8 @@ public function binaryOp(OpCode $opcode, Variable $left, Variable $right): Varia








Expand All @@ -444,6 +454,16 @@ public function binaryOp(OpCode $opcode, Variable $left, Variable $right): Varia
$__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
$result = $this->context->builder->icmp(\PHPLLVM\Builder::INT_NE, $leftValue, $__right);
goto return_bool;
case OpCode::TYPE_SPACESHIP:
$__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
$lt = $this->context->builder->icmp(\PHPLLVM\Builder::INT_SLT, $leftValue, $__right);
$gt = $this->context->builder->icmp(\PHPLLVM\Builder::INT_SGT, $leftValue, $__right);
$ty = $leftValue->typeOf();
$negOne = $ty->constInt(-1, true);
$one = $ty->constInt(1, true);
$zero = $ty->constInt(0, false);
$result = $this->context->builder->select($gt, $one, $this->context->builder->select($lt, $negOne, $zero));
goto return_long;
}
break;
case TYPE_PAIR_NATIVE_LONG_NATIVE_BOOL:
Expand Down
22 changes: 22 additions & 0 deletions lib/JIT/Helper.pre
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,17 @@ restart:
case OpCode::TYPE_NOT_IDENTICAL:
$result = $this->context->builder->fcmp(Builder::REAL_ONE, $leftValue, $rightValue);
goto return_bool;
case OpCode::TYPE_SPACESHIP:
compile {
if ($leftValue < $rightValue) {
$result = -1;
} elseif ($leftValue > $rightValue) {
$result = 1;
} else {
$result = 0;
}
}
goto return_long;
}
break;
case TYPE_PAIR_NATIVE_LONG_NATIVE_LONG:
Expand Down Expand Up @@ -183,6 +194,17 @@ restart:
$result = $leftValue != $rightValue;
}
goto return_bool;
case OpCode::TYPE_SPACESHIP:
compile {
if ($leftValue < $rightValue) {
$result = -1;
} elseif ($leftValue > $rightValue) {
$result = 1;
} else {
$result = 0;
}
}
goto return_long;
}
break;
case TYPE_PAIR_NATIVE_LONG_NATIVE_BOOL:
Expand Down
1 change: 1 addition & 0 deletions lib/OpCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class OpCode {
const TYPE_POW = 58;
const TYPE_NOT_EQUAL = 59;
const TYPE_NOT_IDENTICAL = 60;
const TYPE_SPACESHIP = 61;

public int $type;
public ?int $arg1;
Expand Down
6 changes: 6 additions & 0 deletions lib/VM.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ public function run(Block $block): int {
$arg3 = $frame->scope[$op->arg3];
$arg1->compareOp($op->type, $arg2, $arg3);
break;
case OpCode::TYPE_SPACESHIP:
$arg1 = $frame->scope[$op->arg1];
$arg2 = $frame->scope[$op->arg2];
$arg3 = $frame->scope[$op->arg3];
$arg1->spaceshipOp($arg2, $arg3);
break;
case OpCode::TYPE_PLUS:
case OpCode::TYPE_MINUS:
case OpCode::TYPE_MUL:
Expand Down
51 changes: 51 additions & 0 deletions lib/VM/Variable.php
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ public function equals(Variable $other): bool {
}
return $this->looseEqual($self, $other);
}
throw new \LogicException("Equals comparison between {$self->type} and {$other->type} not implemented");
}

private function looseEqual(Variable $self, Variable $other): bool {
Expand Down Expand Up @@ -471,6 +472,56 @@ private function _compareOp(int $opCode, $left, $right): bool {
}
}

public function spaceshipOp(Variable $left, Variable $right): void {
$this->reset();
restart:
switch (type_pair($left->type, $right->type)) {
case TYPE_PAIR_INTEGER_INTEGER:
$this->int($this->_spaceship($left->integer, $right->integer));
break;
case TYPE_PAIR_INTEGER_FLOAT:
$this->int($this->_spaceship($left->integer, $right->float));
break;
case TYPE_PAIR_FLOAT_INTEGER:
$this->int($this->_spaceship($left->float, $right->integer));
break;
case TYPE_PAIR_FLOAT_FLOAT:
$this->int($this->_spaceship($left->float, $right->float));
break;
case TYPE_PAIR_STRING_STRING:
$cmp = strcmp($left->string, $right->string);
$this->int($cmp < 0 ? -1 : ($cmp > 0 ? 1 : 0));
break;
case TYPE_PAIR_BOOLEAN_BOOLEAN:
$this->int($this->_spaceship((int) $left->bool, (int) $right->bool));
break;
case TYPE_PAIR_NULL_NULL:
$this->int(0);
break;
default:
if ($left->type === self::TYPE_INDIRECT) {
$left = $left->indirect;
goto restart;
} elseif ($right->type === self::TYPE_INDIRECT) {
$right = $right->indirect;
goto restart;
} else {
$this->int($this->_spaceship($left->toNumeric(), $right->toNumeric()));
}
}
}

private function _spaceship($left, $right): int {
if ($left < $right) {
return -1;
}
if ($left > $right) {
return 1;
}

return 0;
}

public function bitwiseOp(int $opCode, Variable $left, Variable $right): void {
$this->reset();
restart:
Expand Down
10 changes: 10 additions & 0 deletions patches/php-types-binaryop-spaceship.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--- vendor/ircmaxell/php-types/lib/PHPTypes/TypeReconstructor.php
+++ vendor/ircmaxell/php-types/lib/PHPTypes/TypeReconstructor.php
@@ -205,6 +205,7 @@
case 'Expr_BinaryOp_Mod':
case 'Expr_BinaryOp_ShiftLeft':
case 'Expr_BinaryOp_ShiftRight':
+ case 'Expr_BinaryOp_Spaceship':
case 'Expr_Cast_Int':
case 'Expr_Print':
return [Type::int()];
1 change: 1 addition & 0 deletions script/apply-patches.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ apply_patch "$PATCH_DIR/php-llvm-x86-posix-fallback.patch"

if [[ -d "$ROOT/vendor/ircmaxell/php-types" ]]; then
apply_patch "$PATCH_DIR/php-types-binaryop-pow.patch"
apply_patch "$PATCH_DIR/php-types-binaryop-spaceship.patch"
apply_patch "$PATCH_DIR/php-types-str-bool-fns.patch"
apply_patch "$PATCH_DIR/php-types-dollars-brace.patch"
fi
Expand Down
9 changes: 9 additions & 0 deletions test/compliance/cases/language/spaceship_operator.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--TEST--
Spaceship operator (<=>) for numbers and strings
--FILE--
<?php
echo 1 <=> 2, 2 <=> 2, 3 <=> 2, "\n";
echo 'b' <=> 'a', 'a' <=> 'a', 'a' <=> 'b', "\n";
--EXPECT--
-101
10-1
7 changes: 7 additions & 0 deletions test/compliance/cases/language/spaceship_operator_jit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
--TEST--
Spaceship operator (<=>) under JIT for integers
--FILE--
<?php
echo 1 <=> 2, 2 <=> 2, 3 <=> 2;
--EXPECT--
-101
Loading