Skip to content

Commit d93f45b

Browse files
committed
Optimizer: Optimize IS_IDENTICAL with true/false/null to TYPE_CHECK
This optimization is already happening in the compiler for explicit `===` expressions, but not for `match()`, which also compiles to `IS_IDENTICAL`.
1 parent 7831f65 commit d93f45b

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

Zend/Optimizer/block_pass.c

+29-1
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,36 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
470470
goto optimize_bool;
471471
}
472472
break;
473+
case ZEND_IS_IDENTICAL:
474+
if (opline->op1_type == IS_CONST &&
475+
opline->op2_type == IS_CONST) {
476+
goto optimize_constant_binary_op;
477+
}
473478

479+
if (opline->op1_type == IS_CONST &&
480+
(Z_TYPE(ZEND_OP1_LITERAL(opline)) <= IS_TRUE && Z_TYPE(ZEND_OP1_LITERAL(opline)) >= IS_NULL)) {
481+
/* IS_IDENTICAL(TRUE, T) => TYPE_CHECK(T, TRUE)
482+
* IS_IDENTICAL(FALSE, T) => TYPE_CHECK(T, FALSE)
483+
* IS_IDENTICAL(NULL, T) => TYPE_CHECK(T, NULL)
484+
*/
485+
opline->opcode = ZEND_TYPE_CHECK;
486+
opline->extended_value = (1 << Z_TYPE(ZEND_OP1_LITERAL(opline)));
487+
COPY_NODE(opline->op1, opline->op2);
488+
SET_UNUSED(opline->op2);
489+
++(*opt_count);
490+
} else if (opline->op2_type == IS_CONST &&
491+
(Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_TRUE && Z_TYPE(ZEND_OP2_LITERAL(opline)) >= IS_NULL)) {
492+
/* IS_IDENTICAL(T, TRUE) => TYPE_CHECK(T, TRUE)
493+
* IS_IDENTICAL(T, FALSE) => TYPE_CHECK(T, FALSE)
494+
* IS_IDENTICAL(T, NULL) => TYPE_CHECK(T, NULL)
495+
*/
496+
opline->opcode = ZEND_TYPE_CHECK;
497+
opline->extended_value = (1 << Z_TYPE(ZEND_OP2_LITERAL(opline)));
498+
SET_UNUSED(opline->op2);
499+
++(*opt_count);
500+
}
501+
break;
502+
474503
case ZEND_BOOL:
475504
case ZEND_BOOL_NOT:
476505
optimize_bool:
@@ -803,7 +832,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
803832
case ZEND_SR:
804833
case ZEND_IS_SMALLER:
805834
case ZEND_IS_SMALLER_OR_EQUAL:
806-
case ZEND_IS_IDENTICAL:
807835
case ZEND_IS_NOT_IDENTICAL:
808836
case ZEND_BOOL_XOR:
809837
case ZEND_BW_OR:

ext/opcache/tests/match/005.phpt

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
Match expression true
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.opt_debug_level=0x20000
7+
zend_test.observer.enabled=0
8+
--EXTENSIONS--
9+
opcache
10+
--FILE--
11+
<?php
12+
13+
$text = 'Bienvenue chez nous';
14+
15+
$result = match (true) {
16+
!!preg_match('/Welcome/', $text), !!preg_match('/Hello/', $text) => 'en',
17+
!!preg_match('/Bienvenue/', $text), !!preg_match('/Bonjour/', $text) => 'fr',
18+
default => 'other',
19+
};
20+
21+
var_dump($result);
22+
23+
?>
24+
--EXPECTF--
25+
$_main:
26+
; (lines=28, args=0, vars=2, tmps=3)
27+
; (after optimizer)
28+
; %s
29+
0000 ASSIGN CV0($text) string("Bienvenue chez nous")
30+
0001 T2 = FRAMELESS_ICALL_2(preg_match) string("/Welcome/") CV0($text)
31+
0002 T3 = BOOL T2
32+
0003 T2 = TYPE_CHECK (true) T3
33+
0004 JMPNZ T2 0018
34+
0005 T4 = FRAMELESS_ICALL_2(preg_match) string("/Hello/") CV0($text)
35+
0006 T3 = BOOL T4
36+
0007 T2 = TYPE_CHECK (true) T3
37+
0008 JMPNZ T2 0018
38+
0009 T4 = FRAMELESS_ICALL_2(preg_match) string("/Bienvenue/") CV0($text)
39+
0010 T3 = BOOL T4
40+
0011 T2 = TYPE_CHECK (true) T3
41+
0012 JMPNZ T2 0020
42+
0013 T4 = FRAMELESS_ICALL_2(preg_match) string("/Bonjour/") CV0($text)
43+
0014 T3 = BOOL T4
44+
0015 T2 = TYPE_CHECK (true) T3
45+
0016 JMPNZ T2 0020
46+
0017 JMP 0022
47+
0018 T2 = QM_ASSIGN string("en")
48+
0019 JMP 0023
49+
0020 T2 = QM_ASSIGN string("fr")
50+
0021 JMP 0023
51+
0022 T2 = QM_ASSIGN string("other")
52+
0023 ASSIGN CV1($result) T2
53+
0024 INIT_FCALL 1 %d string("var_dump")
54+
0025 SEND_VAR CV1($result) 1
55+
0026 DO_ICALL
56+
0027 RETURN int(1)
57+
string(2) "fr"

0 commit comments

Comments
 (0)