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
7 changes: 5 additions & 2 deletions ext/standard/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function getFunctions(): array
{
return [
$this->parseAndCompileFunction('str_repeat', __DIR__.'/str_repeat.php'),
$this->parseAndCompileFunction('decbin', __DIR__.'/decbin.php'),
new decbin(),
new abs(),
new ceil(),
new floor(),
Expand All @@ -31,6 +31,9 @@ public function getFunctions(): array
new rad2deg(),
new log(),
new exp(),
new sin(),
new cos(),
new tan(),
new is_nan(),
new is_finite(),
new is_infinite(),
Expand Down Expand Up @@ -78,7 +81,7 @@ public function jitInit(JIT\Context $context): void
$context->registerFunction('strtol', $fn);
}
$double = $context->getTypeFromString('double');
foreach (['ceil', 'floor', 'round', 'sqrt', 'log', 'exp', 'pow', 'fmod'] as $name) {
foreach (['ceil', 'floor', 'round', 'sqrt', 'log', 'exp', 'sin', 'cos', 'tan', 'pow', 'fmod'] as $name) {
try {
$context->lookupFunction($name);
} catch (\Throwable $e) {
Expand Down
63 changes: 63 additions & 0 deletions ext/standard/cos.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-Compiler, a PHP CFG Compiler for PHP code
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/**
* cos() for integer or float arguments (subset of PHP standard library).
*/
final class cos extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== count($frame->calledArgs)) {
throw new \LogicException('cos() requires exactly one argument');
}
$v = $frame->calledArgs[0]->resolveIndirect();
if (null === $frame->returnVar) {
return;
}
$frame->returnVar->float(\cos(self::toFloat($v)));
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
$this->context = $context;
if (1 !== count($args)) {
throw new \LogicException('cos() requires exactly one argument');
}
$double = $context->getTypeFromString('double');
$asFloat = pow::toJitDouble($context, $args[0], $double);
$fn = $context->lookupFunction('cos');

return $context->builder->call($fn, $asFloat);
}

private static function toFloat(Variable $v): float
{
if (Variable::TYPE_INTEGER === $v->type) {
return (float) $v->toInt();
}
if (Variable::TYPE_FLOAT === $v->type) {
return $v->toFloat();
}
throw new \LogicException('cos() only supports integers and floats in this compiler build');
}
}
73 changes: 65 additions & 8 deletions ext/standard/decbin.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,75 @@

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/**
* decbin() implemented as compiled PHP (subset: non-negative integers).
* decbin() for non-negative integers (subset of PHP standard library).
*/
function decbin(int $num): string
final class decbin extends Internal
{
if (0 === $num) {
return '0';
public function execute(Frame $frame): void
{
if (1 !== count($frame->calledArgs)) {
throw new \LogicException('decbin() requires exactly one argument');
}
$v = $frame->calledArgs[0]->resolveIndirect();
if (null === $frame->returnVar) {
return;
}
if (Variable::TYPE_INTEGER !== $v->type) {
throw new \LogicException('decbin() only supports integers in this compiler build');
}
$frame->returnVar->string(\decbin($v->toInt()));
}
$result = '';
for ($n = $num; $n > 0; $n = intval($n / 2)) {
$result = strval($n % 2) . $result;

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
$this->context = $context;
if (1 !== count($args)) {
throw new \LogicException('decbin() requires exactly one argument');
}
if (JITVariable::TYPE_NATIVE_LONG !== $args[0]->type) {
throw new \LogicException('decbin() only supports integers in this compiler build');
}

return $this->formatToString($context, $context->helper->loadValue($args[0]), '%b');
}

return $result;
private function formatToString(Context $context, Value $value, string $format): Value
{
$sizeT = $context->getTypeFromString('size_t');
$charPtr = $context->getTypeFromString('char*');
$i64 = $context->getTypeFromString('int64');
$bufSize = $sizeT->constInt(64, false);
$buf = $context->builder->call($context->lookupFunction('__mm__malloc'), $bufSize);
$bufChar = $context->builder->pointerCast($buf, $charPtr);
$fmt = $context->builder->pointerCast(
$context->constantFromString($format),
$charPtr
);
$written = $context->builder->call(
$context->lookupFunction('snprintf'),
$bufChar,
$bufSize,
$fmt,
$value
);
$len = $context->builder->zExt($written, $i64);
$str = $context->builder->call(
$context->lookupFunction('__string__init'),
$len,
$bufChar
);
$context->builder->call($context->lookupFunction('__mm__free'), $buf);

return $str;
}
}
63 changes: 63 additions & 0 deletions ext/standard/sin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-Compiler, a PHP CFG Compiler for PHP code
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/**
* sin() for integer or float arguments (subset of PHP standard library).
*/
final class sin extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== count($frame->calledArgs)) {
throw new \LogicException('sin() requires exactly one argument');
}
$v = $frame->calledArgs[0]->resolveIndirect();
if (null === $frame->returnVar) {
return;
}
$frame->returnVar->float(\sin(self::toFloat($v)));
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
$this->context = $context;
if (1 !== count($args)) {
throw new \LogicException('sin() requires exactly one argument');
}
$double = $context->getTypeFromString('double');
$asFloat = pow::toJitDouble($context, $args[0], $double);
$fn = $context->lookupFunction('sin');

return $context->builder->call($fn, $asFloat);
}

private static function toFloat(Variable $v): float
{
if (Variable::TYPE_INTEGER === $v->type) {
return (float) $v->toInt();
}
if (Variable::TYPE_FLOAT === $v->type) {
return $v->toFloat();
}
throw new \LogicException('sin() only supports integers and floats in this compiler build');
}
}
63 changes: 63 additions & 0 deletions ext/standard/tan.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-Compiler, a PHP CFG Compiler for PHP code
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/**
* tan() for integer or float arguments (subset of PHP standard library).
*/
final class tan extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== count($frame->calledArgs)) {
throw new \LogicException('tan() requires exactly one argument');
}
$v = $frame->calledArgs[0]->resolveIndirect();
if (null === $frame->returnVar) {
return;
}
$frame->returnVar->float(\tan(self::toFloat($v)));
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
$this->context = $context;
if (1 !== count($args)) {
throw new \LogicException('tan() requires exactly one argument');
}
$double = $context->getTypeFromString('double');
$asFloat = pow::toJitDouble($context, $args[0], $double);
$fn = $context->lookupFunction('tan');

return $context->builder->call($fn, $asFloat);
}

private static function toFloat(Variable $v): float
{
if (Variable::TYPE_INTEGER === $v->type) {
return (float) $v->toInt();
}
if (Variable::TYPE_FLOAT === $v->type) {
return $v->toFloat();
}
throw new \LogicException('tan() only supports integers and floats in this compiler build');
}
}
5 changes: 5 additions & 0 deletions lib/VM.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ public function run(Block $block): int {
return self::SUCCESS;
}

protected function raise(string $message, Frame $frame): int
{
throw new \LogicException($message.' in '.$frame->block->getName());
}

protected function defineClass(ClassEntry $entry, Block $block): void {
$frame = $block->getFrame($this->context);
// TODO
Expand Down
8 changes: 8 additions & 0 deletions lib/VM/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ public function constantFetch(string $name): ?Variable {
$var = new Variable(Variable::TYPE_BOOLEAN);
$var->bool(true);
return $var;
case 'inf':
$var = new Variable(Variable::TYPE_FLOAT);
$var->float(INF);
return $var;
case 'nan':
$var = new Variable(Variable::TYPE_FLOAT);
$var->float(NAN);
return $var;
}
if (isset($this->constants[$name])) {
return $this->constants[$name];
Expand Down
20 changes: 18 additions & 2 deletions script/ci-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,21 @@
# Local CI baseline: install deps and run the full PHPUnit suite (no Docker).
set -euo pipefail
cd "$(dirname "$0")/.."
composer install --no-interaction --ignore-platform-reqs --no-plugins
php vendor/bin/phpunit "$@"
PHP_BIN="${PHP_COMPILER_PHP:-php}"
if ! command -v "$PHP_BIN" >/dev/null 2>&1; then
PHP_BIN="php8.2"
fi
export PHP_COMPILER_EXT_DIR="${PHP_COMPILER_EXT_DIR:-/usr/lib/php/20220829}"
EXT_DIR="$PHP_COMPILER_EXT_DIR"
PHP_OPTS=()
if [[ -d "$EXT_DIR" ]]; then
for ext in tokenizer mbstring dom xml xmlwriter ffi; do
if [[ -f "$EXT_DIR/${ext}.so" ]]; then
PHP_OPTS+=(-d "extension=$EXT_DIR/${ext}.so")
fi
done
fi
if command -v composer >/dev/null 2>&1; then
composer install --no-interaction --ignore-platform-reqs --no-plugins
fi
"$PHP_BIN" "${PHP_OPTS[@]}" vendor/bin/phpunit "$@"
Loading