Skip to content

JIT: implement empty($cv) fast path in function & tracing JIT - #24239

Merged
ndossche merged 2 commits into
php:masterfrom
ndossche:jit-empty-cv
Oct 15, 2026
Merged

ndossche merged 2 commits into
php:masterfrom
ndossche:jit-empty-cv

Conversation

@ndossche

Copy link
Copy Markdown
Member

We can simply defer to zend_jit_bool_jmpznz() which already generates optimized paths for many types.

Example PHP:

function f(int $i) {
    if (empty($i)) return 1;
    return 2;
}

Before (function JIT):

.L1:
	movl $0x414d88a0, %r15d          ; opline = ISSET_ISEMPTY_CV
	movabsq $0x55a80140fe00, %rax
	callq *%rax                      ; Call VM handler
	cmpl $0x414d88e0, %r15d          ; check if the handler branched
	jne .L2
	movq 0x10(%r14), %rax            ; return 1
	...
.L2:                                     ; return 2
	...

After (function JIT):

.L1:
	cmpq $0, 0x50(%r14)              ; empty($i) check
	je .L3
	movq 0x10(%r14), %rax            ; return 2
	...
.L3:                                     ; return 1
	...

We can simply defer to zend_jit_bool_jmpznz() which already generates
optimized paths for many types.

Example PHP:
```php
function f(int $i) {
    if (empty($i)) return 1;
    return 2;
}
```

Before (function JIT):
```asm
.L1:
	movl $0x414d88a0, %r15d          ; opline = ISSET_ISEMPTY_CV
	movabsq $0x55a80140fe00, %rax
	callq *%rax                      ; Call VM handler
	cmpl $0x414d88e0, %r15d          ; check if the handler branched
	jne .L2
	movq 0x10(%r14), %rax            ; return 1
	...
.L2:                                     ; return 2
	...
```

After (function JIT):
```asm
.L1:
	cmpq $0, 0x50(%r14)              ; empty($i) check
	je .L3
	movq 0x10(%r14), %rax            ; return 2
	...
.L3:                                     ; return 1
	...
```

@arnaud-lb arnaud-lb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me otherwise

Comment thread ext/opcache/jit/zend_jit_ir.c Outdated
Comment on lines +8357 to +8358
if (op1_info & MAY_BE_UNDEF) {
op1_info = (op1_info & ~MAY_BE_UNDEF) | MAY_BE_NULL;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that this could kick back later. Can we add a "isempty" argument to zend_jit_bool_jmpznz() instead? I think that we only need to change the condition before the zend_jit_type_check_undef() call?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I agree that's maybe cleaner. Although I'd call it warn_on_undef or something like that. I believe isempty leaks details.
There are 2 places where zend_jit_type_check_undef is done, so both need to be guarded by an if.

@ndossche
ndossche merged commit 57a90a3 into php:master Oct 15, 2026
16 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants