From 85840fd3f968086cca0196ed24f489c6d3bc6ff9 Mon Sep 17 00:00:00 2001 From: PurHur Date: Tue, 19 May 2026 06:47:22 +0000 Subject: [PATCH] Fix AOT linking in Docker and improve LLVM CFG branch placement. Bundle libjansson for the LLVM 9 linker, detect empty bind-mounts in docker-ci-local.sh, branch from the current insert block after inline builtins, and add a HelloWorld AOT PHPT fixture. Co-authored-by: Cursor --- Docker/dev/ubuntu-22.04/Dockerfile | 2 +- lib/JIT.php | 18 ++++++++++++------ lib/JIT.pre | 18 ++++++++++++------ script/docker-ci-local.sh | 4 ++-- script/install-llvm9.sh | 12 ++++++++++++ .../aot/cases/hello_world_example.phpt | 7 +++++++ 6 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 test/fixtures/aot/cases/hello_world_example.phpt diff --git a/Docker/dev/ubuntu-22.04/Dockerfile b/Docker/dev/ubuntu-22.04/Dockerfile index cdc0a129..fb4f9397 100644 --- a/Docker/dev/ubuntu-22.04/Dockerfile +++ b/Docker/dev/ubuntu-22.04/Dockerfile @@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ git curl unzip ca-certificates \ php8.2-cli php8.2-mbstring php8.2-xml php8.2-ffi php8.2-posix php8.2-phar \ php8.2-tokenizer php8.2-dom php8.2-xmlwriter \ - build-essential clang llvm-14-dev \ + build-essential clang llvm-14-dev libjansson4 \ && rm -rf /var/lib/apt/lists/* \ && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer diff --git a/lib/JIT.php b/lib/JIT.php index f37d1097..1d193f24 100644 --- a/lib/JIT.php +++ b/lib/JIT.php @@ -461,25 +461,29 @@ private function compileBlockInternal( // case OpCode::TYPE_CASE: case OpCode::TYPE_JUMP: $newBlock = $this->compileBlockInternal($func, $op->block1, ...$args); - $builder->positionAtEnd($basicBlock); - $this->context->freeDeadVariables($func, $basicBlock, $block); + $branchBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($branchBlock); + $this->context->freeDeadVariables($func, $branchBlock, $block); $builder->branch($newBlock); return $origBasicBlock; case OpCode::TYPE_JUMPIF: $if = $this->compileBlockInternal($func, $op->block1, ...$args); $else = $this->compileBlockInternal($func, $op->block2, ...$args); - $builder->positionAtEnd($basicBlock); + $branchBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($branchBlock); $condition = $this->context->castToBool( $this->context->helper->loadValue($this->context->getVariableFromOp($block->getOperand($op->arg1))) ); - $this->context->freeDeadVariables($func, $basicBlock, $block); + $this->context->freeDeadVariables($func, $branchBlock, $block); $builder->branchIf($condition, $if, $else); return $origBasicBlock; case OpCode::TYPE_RETURN_VOID: - $this->context->freeDeadVariables($func, $basicBlock, $block); + $returnBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($returnBlock); + $this->context->freeDeadVariables($func, $returnBlock, $block); $this->context->builder->returnVoid(); return $origBasicBlock; @@ -487,7 +491,9 @@ private function compileBlockInternal( $return = $this->context->getVariableFromOp($block->getOperand($op->arg1)); $return->addref(); $retval = $this->context->helper->loadValue($return); - $this->context->freeDeadVariables($func, $basicBlock, $block); + $returnBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($returnBlock); + $this->context->freeDeadVariables($func, $returnBlock, $block); $this->context->builder->returnValue($retval); return $origBasicBlock; diff --git a/lib/JIT.pre b/lib/JIT.pre index 00f43c6b..f4a77819 100755 --- a/lib/JIT.pre +++ b/lib/JIT.pre @@ -366,32 +366,38 @@ class JIT { // case OpCode::TYPE_CASE: case OpCode::TYPE_JUMP: $newBlock = $this->compileBlockInternal($func, $op->block1, ...$args); - $builder->positionAtEnd($basicBlock); - $this->context->freeDeadVariables($func, $basicBlock, $block); + $branchBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($branchBlock); + $this->context->freeDeadVariables($func, $branchBlock, $block); $builder->branch($newBlock); return $origBasicBlock; case OpCode::TYPE_JUMPIF: $if = $this->compileBlockInternal($func, $op->block1, ...$args); $else = $this->compileBlockInternal($func, $op->block2, ...$args); - $builder->positionAtEnd($basicBlock); + $branchBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($branchBlock); $condition = $this->context->castToBool( $this->context->helper->loadValue($this->context->getVariableFromOp($block->getOperand($op->arg1))) ); - $this->context->freeDeadVariables($func, $basicBlock, $block); + $this->context->freeDeadVariables($func, $branchBlock, $block); $builder->branchIf($condition, $if, $else); return $origBasicBlock; case OpCode::TYPE_RETURN_VOID: - $this->context->freeDeadVariables($func, $basicBlock, $block); + $returnBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($returnBlock); + $this->context->freeDeadVariables($func, $returnBlock, $block); compile { return; } return $origBasicBlock; case OpCode::TYPE_RETURN: $return = $this->context->getVariableFromOp($block->getOperand($op->arg1)); $return->addref(); $retval = $this->context->helper->loadValue($return); - $this->context->freeDeadVariables($func, $basicBlock, $block); + $returnBlock = $builder->getInsertBlock(); + $builder->positionAtEnd($returnBlock); + $this->context->freeDeadVariables($func, $returnBlock, $block); compile { return $retval; } return $origBasicBlock; case OpCode::TYPE_FUNCDEF: diff --git a/script/docker-ci-local.sh b/script/docker-ci-local.sh index dee15cc7..87f9b585 100755 --- a/script/docker-ci-local.sh +++ b/script/docker-ci-local.sh @@ -10,8 +10,8 @@ if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then make docker-build-22 fi -if [[ -f vendor/bin/phpunit ]]; then - exec docker run --rm -v "$(pwd):/compiler" -w /compiler "$IMAGE" ./script/ci-local.sh "$@" +if [[ -f vendor/bin/phpunit ]] && docker run --rm -v "$(pwd):/compiler" -w /compiler "$IMAGE" test -f script/ci-local.sh 2>/dev/null; then + exec docker run --rm -v "$(pwd):/compiler" -w /compiler "$IMAGE" bash script/ci-local.sh "$@" fi echo "Bind-mount has no vendor/; copying repo into container via tar..." diff --git a/script/install-llvm9.sh b/script/install-llvm9.sh index b107b0d2..07f5bb07 100755 --- a/script/install-llvm9.sh +++ b/script/install-llvm9.sh @@ -20,6 +20,7 @@ need=0 [[ -f "$LLVM_DIR/gcc/9/crtbegin.o" ]] || need=1 [[ -f "$LLVM_DIR/libedit.so.2" ]] || need=1 [[ -f "$LLVM_DIR/libz3.so.4" ]] || need=1 +[[ -f "$LLVM_DIR/libjansson.so.4" ]] || need=1 need_headers=0 [[ -f "$LLVM_DIR/sysroot/usr/include/stdio.h" ]] || need_headers=1 if [[ "$need" -eq 0 && "$need_headers" -eq 0 ]]; then @@ -121,4 +122,15 @@ if [[ ! -f "$LLVM_DIR/libz3.so.4" ]]; then install -m 644 "$dir/usr/lib/x86_64-linux-gnu/libz3.so.4" "$LLVM_DIR/libz3.so.4" fi +# Bundled ld (binutils 2.40) needs libjansson at runtime on minimal images. +if [[ ! -f "$LLVM_DIR/libjansson.so.4" ]]; then + dir="$(fetch_deb "http://deb.debian.org/debian/pool/main/j/jansson/libjansson4_2.14-2_amd64.deb" libjansson4.deb)" + shopt -s nullglob + for lib in "$dir"/usr/lib/x86_64-linux-gnu/libjansson.so.4.*; do + install -m 644 "$lib" "$LLVM_DIR/$(basename "$lib")" + ln -sf "$(basename "$lib")" "$LLVM_DIR/libjansson.so.4" + done + shopt -u nullglob +fi + echo "LLVM 9 toolchain installed under $LLVM_DIR" diff --git a/test/fixtures/aot/cases/hello_world_example.phpt b/test/fixtures/aot/cases/hello_world_example.phpt new file mode 100644 index 00000000..43b96d33 --- /dev/null +++ b/test/fixtures/aot/cases/hello_world_example.phpt @@ -0,0 +1,7 @@ +--TEST-- +AOT: examples/000-HelloWorld (echo string literal) +--FILE-- +