77
77
#define CHECK_SCC_VAR (var2 ) \
78
78
do { \
79
79
if (!ssa->vars[var2].no_val) { \
80
- if (dfs [var2] < 0) { \
81
- zend_ssa_check_scc_var(op_array, ssa, var2, index, dfs, root, stack); \
80
+ if (ssa->vars [var2].scc < 0) { \
81
+ zend_ssa_check_scc_var(op_array, ssa, var2, index, stack); \
82
82
} \
83
- if (ssa->vars[var2].scc < 0 && dfs[root[var]] >= dfs[root[var2]]) { \
84
- root[var] = root[var2]; \
83
+ if (ssa->vars[var2].scc < ssa->vars[var].scc) { \
84
+ ssa->vars[var].scc = ssa->vars[var2].scc; \
85
+ is_root = 0; \
85
86
} \
86
87
} \
87
88
} while (0)
@@ -172,15 +173,17 @@ static inline bool sub_will_overflow(zend_long a, zend_long b) {
172
173
}
173
174
#endif
174
175
175
- static void zend_ssa_check_scc_var (const zend_op_array * op_array , zend_ssa * ssa , int var , int * index , int * dfs , int * root , zend_worklist_stack * stack ) /* {{{ */
176
+ #if 0
177
+ /* Recursive Pearce's SCC algorithm implementation */
178
+ static void zend_ssa_check_scc_var (const zend_op_array * op_array , zend_ssa * ssa , int var , int * index , zend_worklist_stack * stack ) /* {{{ */
176
179
{
180
+ int is_root = 1 ;
177
181
#ifdef SYM_RANGE
178
182
zend_ssa_phi * p ;
179
183
#endif
180
184
181
- dfs [var ] = * index ;
185
+ ssa -> vars [var ]. scc = * index ;
182
186
(* index )++ ;
183
- root [var ] = var ;
184
187
185
188
FOR_EACH_VAR_USAGE (var , CHECK_SCC_VAR );
186
189
@@ -193,17 +196,20 @@ static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa,
193
196
}
194
197
#endif
195
198
196
- if (root [ var ] == var ) {
197
- ssa -> vars [ var ]. scc = ssa -> sccs ;
199
+ if (is_root ) {
200
+ ssa -> sccs -- ;
198
201
while (stack -> len > 0 ) {
199
202
int var2 = zend_worklist_stack_peek (stack );
200
- if (dfs [var2 ] <= dfs [var ]) {
203
+ if (ssa -> vars [var2 ]. scc < ssa -> vars [var ]. scc ) {
201
204
break ;
202
205
}
203
206
zend_worklist_stack_pop (stack );
204
207
ssa -> vars [var2 ].scc = ssa -> sccs ;
208
+ (* index )-- ;
205
209
}
206
- ssa -> sccs ++ ;
210
+ ssa -> vars [var ].scc = ssa -> sccs ;
211
+ ssa -> vars [var ].scc_entry = 1 ;
212
+ (* index )-- ;
207
213
} else {
208
214
zend_worklist_stack_push (stack , var );
209
215
}
@@ -212,50 +218,277 @@ static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa,
212
218
213
219
ZEND_API int zend_ssa_find_sccs (const zend_op_array * op_array , zend_ssa * ssa ) /* {{{ */
214
220
{
215
- int index = 0 , * dfs , * root ;
221
+ int index = 0 ;
216
222
zend_worklist_stack stack ;
217
223
int j ;
218
- ALLOCA_FLAG (dfs_use_heap )
219
- ALLOCA_FLAG (root_use_heap )
220
224
ALLOCA_FLAG (stack_use_heap )
221
225
222
- dfs = do_alloca (sizeof (int ) * ssa -> vars_count , dfs_use_heap );
223
- memset (dfs , -1 , sizeof (int ) * ssa -> vars_count );
224
- root = do_alloca (sizeof (int ) * ssa -> vars_count , root_use_heap );
225
226
ZEND_WORKLIST_STACK_ALLOCA (& stack , ssa -> vars_count , stack_use_heap );
226
227
227
- /* Find SCCs using Tarjan's algorithm. */
228
+ /* Find SCCs using Pearce's algorithm. */
229
+ ssa -> sccs = ssa -> vars_count ;
228
230
for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
229
- if (!ssa -> vars [j ].no_val && dfs [j ] < 0 ) {
230
- zend_ssa_check_scc_var (op_array , ssa , j , & index , dfs , root , & stack );
231
+ if (!ssa -> vars [j ].no_val && ssa -> vars [j ].scc < 0 ) {
232
+ zend_ssa_check_scc_var (op_array , ssa , j , & index , & stack );
233
+ }
234
+ }
235
+
236
+ if (ssa -> sccs ) {
237
+ /* Shift SCC indexes. */
238
+ for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
239
+ if (ssa -> vars [j ].scc >= 0 ) {
240
+ ssa -> vars [j ].scc -= ssa -> sccs ;
241
+ }
231
242
}
232
243
}
244
+ ssa -> sccs = ssa -> vars_count - ssa -> sccs ;
233
245
234
- /* Revert SCC order. This results in a topological order. */
235
246
for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
236
247
if (ssa -> vars [j ].scc >= 0 ) {
237
- ssa -> vars [j ].scc = ssa -> sccs - (ssa -> vars [j ].scc + 1 );
248
+ int var = j ;
249
+ FOR_EACH_VAR_USAGE (var , CHECK_SCC_ENTRY );
238
250
}
239
251
}
240
252
253
+ ZEND_WORKLIST_STACK_FREE_ALLOCA (& stack , stack_use_heap );
254
+ return SUCCESS ;
255
+ }
256
+ /* }}} */
257
+
258
+ #else
259
+ /* Iterative Pearce's SCC algorithm implementation */
260
+
261
+ typedef struct _zend_scc_iterator {
262
+ int state ;
263
+ int last ;
264
+ union {
265
+ int use ;
266
+ zend_ssa_phi * phi ;
267
+ };
268
+ } zend_scc_iterator ;
269
+
270
+ static int zend_scc_next (const zend_op_array * op_array , zend_ssa * ssa , int var , zend_scc_iterator * iterator ) /* {{{ */
271
+ {
272
+ zend_ssa_phi * phi ;
273
+ int use , var2 ;
274
+
275
+ switch (iterator -> state ) {
276
+ case 0 : goto state_0 ;
277
+ case 1 : use = iterator -> use ; goto state_1 ;
278
+ case 2 : use = iterator -> use ; goto state_2 ;
279
+ case 3 : use = iterator -> use ; goto state_3 ;
280
+ case 4 : use = iterator -> use ; goto state_4 ;
281
+ case 5 : use = iterator -> use ; goto state_5 ;
282
+ case 6 : use = iterator -> use ; goto state_6 ;
283
+ case 7 : use = iterator -> use ; goto state_7 ;
284
+ case 8 : use = iterator -> use ; goto state_8 ;
285
+ case 9 : phi = iterator -> phi ; goto state_9 ;
286
+ #ifdef SYM_RANGE
287
+ case 10 : phi = iterator -> phi ; goto state_10 ;
288
+ #endif
289
+ case 11 : goto state_11 ;
290
+ }
291
+
292
+ state_0 :
293
+ use = ssa -> vars [var ].use_chain ;
294
+ while (use >= 0 ) {
295
+ iterator -> use = use ;
296
+ var2 = ssa -> ops [use ].op1_def ;
297
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
298
+ iterator -> state = 1 ;
299
+ return var2 ;
300
+ }
301
+ state_1 :
302
+ var2 = ssa -> ops [use ].op2_def ;
303
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
304
+ iterator -> state = 2 ;
305
+ return var2 ;
306
+ }
307
+ state_2 :
308
+ var2 = ssa -> ops [use ].result_def ;
309
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
310
+ iterator -> state = 3 ;
311
+ return var2 ;
312
+ }
313
+ state_3 :
314
+ if (op_array -> opcodes [use ].opcode == ZEND_OP_DATA ) {
315
+ var2 = ssa -> ops [use - 1 ].op1_def ;
316
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
317
+ iterator -> state = 4 ;
318
+ return var2 ;
319
+ }
320
+ state_4 :
321
+ var2 = ssa -> ops [use - 1 ].op2_def ;
322
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
323
+ iterator -> state = 5 ;
324
+ return var2 ;
325
+ }
326
+ state_5 :
327
+ var2 = ssa -> ops [use - 1 ].result_def ;
328
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
329
+ iterator -> state = 8 ;
330
+ return var2 ;
331
+ }
332
+ } else if ((uint32_t )use + 1 < op_array -> last &&
333
+ op_array -> opcodes [use + 1 ].opcode == ZEND_OP_DATA ) {
334
+ var2 = ssa -> ops [use + 1 ].op1_def ;
335
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
336
+ iterator -> state = 6 ;
337
+ return var2 ;
338
+ }
339
+ state_6 :
340
+ var2 = ssa -> ops [use + 1 ].op2_def ;
341
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
342
+ iterator -> state = 7 ;
343
+ return var2 ;
344
+ }
345
+ state_7 :
346
+ var2 = ssa -> ops [use + 1 ].result_def ;
347
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
348
+ iterator -> state = 8 ;
349
+ return var2 ;
350
+ }
351
+ }
352
+ state_8 :
353
+ use = zend_ssa_next_use (ssa -> ops , var , use );
354
+ }
355
+
356
+ phi = ssa -> vars [var ].phi_use_chain ;
357
+ while (phi ) {
358
+ var2 = phi -> ssa_var ;
359
+ if (!ssa -> vars [var2 ].no_val ) {
360
+ iterator -> state = 9 ;
361
+ iterator -> phi = phi ;
362
+ return var2 ;
363
+ }
364
+ state_9 :
365
+ phi = zend_ssa_next_use_phi (ssa , var , phi );
366
+ }
367
+
368
+ #ifdef SYM_RANGE
369
+ /* Process symbolic control-flow constraints */
370
+ phi = ssa -> vars [var ].sym_use_chain ;
371
+ while (phi ) {
372
+ var2 = phi -> ssa_var ;
373
+ if (!ssa -> vars [var2 ].no_val ) {
374
+ iterator -> state = 10 ;
375
+ iterator -> phi = phi ;
376
+ return var2 ;
377
+ }
378
+ state_10 :
379
+ phi = phi -> sym_use_chain ;
380
+ }
381
+ #endif
382
+
383
+ iterator -> state = 11 ;
384
+ state_11 :
385
+ return -1 ;
386
+ }
387
+ /* }}} */
388
+
389
+ static void zend_ssa_check_scc_var (const zend_op_array * op_array , zend_ssa * ssa , int var , int * index , zend_worklist_stack * stack , zend_worklist_stack * vstack , zend_scc_iterator * iterators ) /* {{{ */
390
+ {
391
+ restart :
392
+ zend_worklist_stack_push (vstack , var );
393
+ iterators [var ].state = 0 ;
394
+ iterators [var ].last = -1 ;
395
+ ssa -> vars [var ].scc_entry = 1 ;
396
+ ssa -> vars [var ].scc = * index ;
397
+ (* index )++ ;
398
+
399
+ while (vstack -> len > 0 ) {
400
+ var = zend_worklist_stack_peek (vstack );
401
+ while (1 ) {
402
+ int var2 ;
403
+
404
+ if (iterators [var ].last >= 0 ) {
405
+ /* finish edge */
406
+ var2 = iterators [var ].last ;
407
+ if (ssa -> vars [var2 ].scc < ssa -> vars [var ].scc ) {
408
+ ssa -> vars [var ].scc = ssa -> vars [var2 ].scc ;
409
+ ssa -> vars [var ].scc_entry = 0 ;
410
+ }
411
+ }
412
+ var2 = zend_scc_next (op_array , ssa , var , iterators + var );
413
+ iterators [var ].last = var2 ;
414
+ if (var2 < 0 ) break ;
415
+ /* begin edge */
416
+ if (ssa -> vars [var2 ].scc < 0 ) {
417
+ var = var2 ;
418
+ goto restart ;
419
+ }
420
+ }
421
+
422
+ /* finish visiting */
423
+ zend_worklist_stack_pop (vstack );
424
+ if (ssa -> vars [var ].scc_entry ) {
425
+ ssa -> sccs -- ;
426
+ while (stack -> len > 0 ) {
427
+ int var2 = zend_worklist_stack_peek (stack );
428
+ if (ssa -> vars [var2 ].scc < ssa -> vars [var ].scc ) {
429
+ break ;
430
+ }
431
+ zend_worklist_stack_pop (stack );
432
+ ssa -> vars [var2 ].scc = ssa -> sccs ;
433
+ (* index )-- ;
434
+ }
435
+ ssa -> vars [var ].scc = ssa -> sccs ;
436
+ (* index )-- ;
437
+ } else {
438
+ zend_worklist_stack_push (stack , var );
439
+ }
440
+ }
441
+ }
442
+ /* }}} */
443
+
444
+ ZEND_API int zend_ssa_find_sccs (const zend_op_array * op_array , zend_ssa * ssa ) /* {{{ */
445
+ {
446
+ int index = 0 ;
447
+ zend_worklist_stack stack , vstack ;
448
+ zend_scc_iterator * iterators ;
449
+ int j ;
450
+ ALLOCA_FLAG (stack_use_heap )
451
+ ALLOCA_FLAG (vstack_use_heap )
452
+ ALLOCA_FLAG (iterators_use_heap )
453
+
454
+ iterators = do_alloca (sizeof (zend_scc_iterator ) * ssa -> vars_count , iterators_use_heap );
455
+ ZEND_WORKLIST_STACK_ALLOCA (& vstack , ssa -> vars_count , vstack_use_heap );
456
+ ZEND_WORKLIST_STACK_ALLOCA (& stack , ssa -> vars_count , stack_use_heap );
457
+
458
+ /* Find SCCs using Pearce's algorithm. */
459
+ ssa -> sccs = ssa -> vars_count ;
460
+ for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
461
+ if (!ssa -> vars [j ].no_val && ssa -> vars [j ].scc < 0 ) {
462
+ zend_ssa_check_scc_var (op_array , ssa , j , & index , & stack , & vstack , iterators );
463
+ }
464
+ }
465
+
466
+ if (ssa -> sccs ) {
467
+ /* Shift SCC indexes. */
468
+ for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
469
+ if (ssa -> vars [j ].scc >= 0 ) {
470
+ ssa -> vars [j ].scc -= ssa -> sccs ;
471
+ }
472
+ }
473
+ }
474
+ ssa -> sccs = ssa -> vars_count - ssa -> sccs ;
475
+
241
476
for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
242
477
if (ssa -> vars [j ].scc >= 0 ) {
243
478
int var = j ;
244
- if (root [j ] == j ) {
245
- ssa -> vars [j ].scc_entry = 1 ;
246
- }
247
479
FOR_EACH_VAR_USAGE (var , CHECK_SCC_ENTRY );
248
480
}
249
481
}
250
482
251
483
ZEND_WORKLIST_STACK_FREE_ALLOCA (& stack , stack_use_heap );
252
- free_alloca (root , root_use_heap );
253
- free_alloca (dfs , dfs_use_heap );
254
-
484
+ ZEND_WORKLIST_STACK_FREE_ALLOCA (& vstack , vstack_use_heap );
485
+ free_alloca (iterators , iterators_use_heap );
255
486
return SUCCESS ;
256
487
}
257
488
/* }}} */
258
489
490
+ #endif
491
+
259
492
ZEND_API int zend_ssa_find_false_dependencies (const zend_op_array * op_array , zend_ssa * ssa ) /* {{{ */
260
493
{
261
494
zend_ssa_var * ssa_vars = ssa -> vars ;
0 commit comments