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,48 +218,275 @@ static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa,
212
218
213
219
ZEND_API void 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 );
250
+ }
251
+ }
252
+
253
+ ZEND_WORKLIST_STACK_FREE_ALLOCA (& stack , stack_use_heap );
254
+ }
255
+ /* }}} */
256
+
257
+ #else
258
+ /* Iterative Pearce's SCC algorithm implementation */
259
+
260
+ typedef struct _zend_scc_iterator {
261
+ int state ;
262
+ int last ;
263
+ union {
264
+ int use ;
265
+ zend_ssa_phi * phi ;
266
+ };
267
+ } zend_scc_iterator ;
268
+
269
+ static int zend_scc_next (const zend_op_array * op_array , zend_ssa * ssa , int var , zend_scc_iterator * iterator ) /* {{{ */
270
+ {
271
+ zend_ssa_phi * phi ;
272
+ int use , var2 ;
273
+
274
+ switch (iterator -> state ) {
275
+ case 0 : goto state_0 ;
276
+ case 1 : use = iterator -> use ; goto state_1 ;
277
+ case 2 : use = iterator -> use ; goto state_2 ;
278
+ case 3 : use = iterator -> use ; goto state_3 ;
279
+ case 4 : use = iterator -> use ; goto state_4 ;
280
+ case 5 : use = iterator -> use ; goto state_5 ;
281
+ case 6 : use = iterator -> use ; goto state_6 ;
282
+ case 7 : use = iterator -> use ; goto state_7 ;
283
+ case 8 : use = iterator -> use ; goto state_8 ;
284
+ case 9 : phi = iterator -> phi ; goto state_9 ;
285
+ #ifdef SYM_RANGE
286
+ case 10 : phi = iterator -> phi ; goto state_10 ;
287
+ #endif
288
+ case 11 : goto state_11 ;
289
+ }
290
+
291
+ state_0 :
292
+ use = ssa -> vars [var ].use_chain ;
293
+ while (use >= 0 ) {
294
+ iterator -> use = use ;
295
+ var2 = ssa -> ops [use ].op1_def ;
296
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
297
+ iterator -> state = 1 ;
298
+ return var2 ;
299
+ }
300
+ state_1 :
301
+ var2 = ssa -> ops [use ].op2_def ;
302
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
303
+ iterator -> state = 2 ;
304
+ return var2 ;
238
305
}
306
+ state_2 :
307
+ var2 = ssa -> ops [use ].result_def ;
308
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
309
+ iterator -> state = 3 ;
310
+ return var2 ;
311
+ }
312
+ state_3 :
313
+ if (op_array -> opcodes [use ].opcode == ZEND_OP_DATA ) {
314
+ var2 = ssa -> ops [use - 1 ].op1_def ;
315
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
316
+ iterator -> state = 4 ;
317
+ return var2 ;
318
+ }
319
+ state_4 :
320
+ var2 = ssa -> ops [use - 1 ].op2_def ;
321
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
322
+ iterator -> state = 5 ;
323
+ return var2 ;
324
+ }
325
+ state_5 :
326
+ var2 = ssa -> ops [use - 1 ].result_def ;
327
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
328
+ iterator -> state = 8 ;
329
+ return var2 ;
330
+ }
331
+ } else if ((uint32_t )use + 1 < op_array -> last &&
332
+ op_array -> opcodes [use + 1 ].opcode == ZEND_OP_DATA ) {
333
+ var2 = ssa -> ops [use + 1 ].op1_def ;
334
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
335
+ iterator -> state = 6 ;
336
+ return var2 ;
337
+ }
338
+ state_6 :
339
+ var2 = ssa -> ops [use + 1 ].op2_def ;
340
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
341
+ iterator -> state = 7 ;
342
+ return var2 ;
343
+ }
344
+ state_7 :
345
+ var2 = ssa -> ops [use + 1 ].result_def ;
346
+ if (var2 >= 0 && !ssa -> vars [var2 ].no_val ) {
347
+ iterator -> state = 8 ;
348
+ return var2 ;
349
+ }
350
+ }
351
+ state_8 :
352
+ use = zend_ssa_next_use (ssa -> ops , var , use );
239
353
}
240
354
355
+ phi = ssa -> vars [var ].phi_use_chain ;
356
+ while (phi ) {
357
+ var2 = phi -> ssa_var ;
358
+ if (!ssa -> vars [var2 ].no_val ) {
359
+ iterator -> state = 9 ;
360
+ iterator -> phi = phi ;
361
+ return var2 ;
362
+ }
363
+ state_9 :
364
+ phi = zend_ssa_next_use_phi (ssa , var , phi );
365
+ }
366
+
367
+ #ifdef SYM_RANGE
368
+ /* Process symbolic control-flow constraints */
369
+ phi = ssa -> vars [var ].sym_use_chain ;
370
+ while (phi ) {
371
+ var2 = phi -> ssa_var ;
372
+ if (!ssa -> vars [var2 ].no_val ) {
373
+ iterator -> state = 10 ;
374
+ iterator -> phi = phi ;
375
+ return var2 ;
376
+ }
377
+ state_10 :
378
+ phi = phi -> sym_use_chain ;
379
+ }
380
+ #endif
381
+
382
+ iterator -> state = 11 ;
383
+ state_11 :
384
+ return -1 ;
385
+ }
386
+ /* }}} */
387
+
388
+ 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 ) /* {{{ */
389
+ {
390
+ restart :
391
+ zend_worklist_stack_push (vstack , var );
392
+ iterators [var ].state = 0 ;
393
+ iterators [var ].last = -1 ;
394
+ ssa -> vars [var ].scc_entry = 1 ;
395
+ ssa -> vars [var ].scc = * index ;
396
+ (* index )++ ;
397
+
398
+ while (vstack -> len > 0 ) {
399
+ var = zend_worklist_stack_peek (vstack );
400
+ while (1 ) {
401
+ int var2 ;
402
+
403
+ if (iterators [var ].last >= 0 ) {
404
+ /* finish edge */
405
+ var2 = iterators [var ].last ;
406
+ if (ssa -> vars [var2 ].scc < ssa -> vars [var ].scc ) {
407
+ ssa -> vars [var ].scc = ssa -> vars [var2 ].scc ;
408
+ ssa -> vars [var ].scc_entry = 0 ;
409
+ }
410
+ }
411
+ var2 = zend_scc_next (op_array , ssa , var , iterators + var );
412
+ iterators [var ].last = var2 ;
413
+ if (var2 < 0 ) break ;
414
+ /* begin edge */
415
+ if (ssa -> vars [var2 ].scc < 0 ) {
416
+ var = var2 ;
417
+ goto restart ;
418
+ }
419
+ }
420
+
421
+ /* finish visiting */
422
+ zend_worklist_stack_pop (vstack );
423
+ if (ssa -> vars [var ].scc_entry ) {
424
+ ssa -> sccs -- ;
425
+ while (stack -> len > 0 ) {
426
+ int var2 = zend_worklist_stack_peek (stack );
427
+ if (ssa -> vars [var2 ].scc < ssa -> vars [var ].scc ) {
428
+ break ;
429
+ }
430
+ zend_worklist_stack_pop (stack );
431
+ ssa -> vars [var2 ].scc = ssa -> sccs ;
432
+ (* index )-- ;
433
+ }
434
+ ssa -> vars [var ].scc = ssa -> sccs ;
435
+ (* index )-- ;
436
+ } else {
437
+ zend_worklist_stack_push (stack , var );
438
+ }
439
+ }
440
+ }
441
+ /* }}} */
442
+
443
+ ZEND_API void zend_ssa_find_sccs (const zend_op_array * op_array , zend_ssa * ssa ) /* {{{ */
444
+ {
445
+ int index = 0 ;
446
+ zend_worklist_stack stack , vstack ;
447
+ zend_scc_iterator * iterators ;
448
+ int j ;
449
+ ALLOCA_FLAG (stack_use_heap )
450
+ ALLOCA_FLAG (vstack_use_heap )
451
+ ALLOCA_FLAG (iterators_use_heap )
452
+
453
+ iterators = do_alloca (sizeof (zend_scc_iterator ) * ssa -> vars_count , iterators_use_heap );
454
+ ZEND_WORKLIST_STACK_ALLOCA (& vstack , ssa -> vars_count , vstack_use_heap );
455
+ ZEND_WORKLIST_STACK_ALLOCA (& stack , ssa -> vars_count , stack_use_heap );
456
+
457
+ /* Find SCCs using Pearce's algorithm. */
458
+ ssa -> sccs = ssa -> vars_count ;
459
+ for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
460
+ if (!ssa -> vars [j ].no_val && ssa -> vars [j ].scc < 0 ) {
461
+ zend_ssa_check_scc_var (op_array , ssa , j , & index , & stack , & vstack , iterators );
462
+ }
463
+ }
464
+
465
+ if (ssa -> sccs ) {
466
+ /* Shift SCC indexes. */
467
+ for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
468
+ if (ssa -> vars [j ].scc >= 0 ) {
469
+ ssa -> vars [j ].scc -= ssa -> sccs ;
470
+ }
471
+ }
472
+ }
473
+ ssa -> sccs = ssa -> vars_count - ssa -> sccs ;
474
+
241
475
for (j = 0 ; j < ssa -> vars_count ; j ++ ) {
242
476
if (ssa -> vars [j ].scc >= 0 ) {
243
477
int var = j ;
244
- if (root [j ] == j ) {
245
- ssa -> vars [j ].scc_entry = 1 ;
246
- }
247
478
FOR_EACH_VAR_USAGE (var , CHECK_SCC_ENTRY );
248
479
}
249
480
}
250
481
251
482
ZEND_WORKLIST_STACK_FREE_ALLOCA (& stack , stack_use_heap );
252
- free_alloca ( root , root_use_heap );
253
- free_alloca (dfs , dfs_use_heap );
483
+ ZEND_WORKLIST_STACK_FREE_ALLOCA ( & vstack , vstack_use_heap );
484
+ free_alloca (iterators , iterators_use_heap );
254
485
}
255
486
/* }}} */
256
487
488
+ #endif
489
+
257
490
ZEND_API void zend_ssa_find_false_dependencies (const zend_op_array * op_array , zend_ssa * ssa ) /* {{{ */
258
491
{
259
492
zend_ssa_var * ssa_vars = ssa -> vars ;
0 commit comments