Skip to content

Commit 784d394

Browse files
committed
Implement optimization to cast values instead of verifying the type
1 parent 844f7e4 commit 784d394

File tree

4 files changed

+61
-12
lines changed

4 files changed

+61
-12
lines changed

Zend/Optimizer/dfa_pass.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,53 @@ static inline bool can_elide_return_type_check(
318318
return false;
319319
}
320320

321+
static inline bool can_return_value_safely_be_coerced(
322+
const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_op *ssa_op, zend_op *opline
323+
) {
324+
const uint32_t return_type_mask = ZEND_TYPE_FULL_MASK(op_array->arg_info[-1].type);
325+
const zend_ssa_var_info *use_info = &ssa->var_info[ssa_op->op1_use];
326+
327+
/* Type preference order: int -> float -> string -> bool */
328+
/* Can always safely cast booleans to inter */
329+
if (return_type_mask & MAY_BE_LONG) {
330+
if (use_info->type & MAY_BE_BOOL) {
331+
opline->opcode = ZEND_CAST;
332+
opline->extended_value = IS_LONG;
333+
return true;
334+
}
335+
return false;
336+
}
337+
if (return_type_mask & MAY_BE_DOUBLE) {
338+
/* Can always safely cast booleans, and integers to float */
339+
if (use_info->type & (MAY_BE_LONG|MAY_BE_BOOL)) {
340+
opline->opcode = ZEND_CAST;
341+
opline->extended_value = IS_DOUBLE;
342+
return true;
343+
}
344+
return false;
345+
}
346+
/* Can always safely cast booleans, and integers to string,
347+
* float value must not be NAN */
348+
if (return_type_mask & MAY_BE_STRING) {
349+
if (use_info->type & (MAY_BE_LONG|MAY_BE_BOOL)) {
350+
opline->opcode = ZEND_CAST;
351+
opline->extended_value = IS_STRING;
352+
return true;
353+
}
354+
return false;
355+
}
356+
return false;
357+
if ((return_type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
358+
/* Can always safely cast integers and strings to bool,
359+
* float value must not be NAN */
360+
if (use_info->type & (MAY_BE_LONG|MAY_BE_STRING)) {
361+
opline->opcode = ZEND_BOOL;
362+
return true;
363+
}
364+
return false;
365+
}
366+
}
367+
321368
static bool opline_supports_assign_contraction(
322369
zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, int src_var, uint32_t cv_var) {
323370
if (opline->opcode == ZEND_NEW) {
@@ -1289,6 +1336,8 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
12891336

12901337
MAKE_NOP(opline);
12911338
remove_nops = 1;
1339+
} else if (can_return_value_safely_be_coerced(op_array, ssa, &ssa->ops[op_1], opline)) {
1340+
continue;
12921341
}
12931342
}
12941343
}

ext/opcache/tests/opt/type_inference_class_consts1.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Test1::getStaticFoo:
7373
; (after optimizer)
7474
; %s
7575
0000 T0 = FETCH_CLASS_CONSTANT (static) (exception) string("FOO")
76-
0001 VERIFY_RETURN_TYPE T0
76+
0001 CAST (long) T0
7777
0002 RETURN T0
7878
LIVE RANGES:
7979
0: 0001 - 0002 (tmp/var)

ext/opcache/tests/opt/type_inference_class_consts4.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Test4::getSelfA:
5757
; (after optimizer)
5858
; %s
5959
0000 T0 = FETCH_CLASS_CONSTANT (self) (exception) string("A")
60-
0001 VERIFY_RETURN_TYPE T0
60+
0001 CAST (long) T0
6161
0002 RETURN T0
6262
LIVE RANGES:
6363
0: 0001 - 0002 (tmp/var)
@@ -67,7 +67,7 @@ Test4::getSelfB:
6767
; (after optimizer)
6868
; %s
6969
0000 T0 = FETCH_CLASS_CONSTANT (self) (exception) string("B")
70-
0001 VERIFY_RETURN_TYPE T0
70+
0001 CAST (long) T0
7171
0002 RETURN T0
7272
LIVE RANGES:
7373
0: 0001 - 0002 (tmp/var)
@@ -77,7 +77,7 @@ Test4::getStaticA:
7777
; (after optimizer)
7878
; %s
7979
0000 T0 = FETCH_CLASS_CONSTANT (static) (exception) string("A")
80-
0001 VERIFY_RETURN_TYPE T0
80+
0001 CAST (long) T0
8181
0002 RETURN T0
8282
LIVE RANGES:
8383
0: 0001 - 0002 (tmp/var)
@@ -87,7 +87,7 @@ Test4::getStaticB:
8787
; (after optimizer)
8888
; %s
8989
0000 T0 = FETCH_CLASS_CONSTANT (static) (exception) string("B")
90-
0001 VERIFY_RETURN_TYPE T0
90+
0001 CAST (long) T0
9191
0002 RETURN T0
9292
LIVE RANGES:
9393
0: 0001 - 0002 (tmp/var)

ext/opcache/tests/opt/verify_return_type_to_cast.phpt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ boolToInt:
118118
; (after optimizer)
119119
; %s:19-21
120120
0000 CV0($v) = RECV 1
121-
0001 VERIFY_RETURN_TYPE CV0($v)
121+
0001 CAST (long) CV0($v)
122122
0002 RETURN CV0($v)
123123

124124
strToFloat:
@@ -134,15 +134,15 @@ intToFloat:
134134
; (after optimizer)
135135
; %s:26-28
136136
0000 CV0($v) = RECV 1
137-
0001 VERIFY_RETURN_TYPE CV0($v)
137+
0001 CAST (double) CV0($v)
138138
0002 RETURN CV0($v)
139139

140140
boolToFloat:
141141
; (lines=3, args=1, vars=1, tmps=0)
142142
; (after optimizer)
143143
; %s:29-31
144144
0000 CV0($v) = RECV 1
145-
0001 VERIFY_RETURN_TYPE CV0($v)
145+
0001 CAST (double) CV0($v)
146146
0002 RETURN CV0($v)
147147

148148
floatToString:
@@ -158,15 +158,15 @@ intToString:
158158
; (after optimizer)
159159
; %s:36-38
160160
0000 CV0($v) = RECV 1
161-
0001 VERIFY_RETURN_TYPE CV0($v)
161+
0001 CAST (string) CV0($v)
162162
0002 RETURN CV0($v)
163163

164164
boolToString:
165165
; (lines=3, args=1, vars=1, tmps=0)
166166
; (after optimizer)
167167
; %s:39-41
168168
0000 CV0($v) = RECV 1
169-
0001 VERIFY_RETURN_TYPE CV0($v)
169+
0001 CAST (string) CV0($v)
170170
0002 RETURN CV0($v)
171171

172172
floatToUnion:
@@ -182,15 +182,15 @@ intToUnion:
182182
; (after optimizer)
183183
; %s:46-48
184184
0000 CV0($v) = RECV 1
185-
0001 VERIFY_RETURN_TYPE CV0($v)
185+
0001 CAST (double) CV0($v)
186186
0002 RETURN CV0($v)
187187

188188
boolToUnion:
189189
; (lines=3, args=1, vars=1, tmps=0)
190190
; (after optimizer)
191191
; %s:49-51
192192
0000 CV0($v) = RECV 1
193-
0001 VERIFY_RETURN_TYPE CV0($v)
193+
0001 CAST (long) CV0($v)
194194
0002 RETURN CV0($v)
195195

196196
stringToUnion:

0 commit comments

Comments
 (0)