@@ -454,6 +454,27 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
454
454
return removed_ops ;
455
455
}
456
456
457
+ static zend_always_inline void take_successor_0 (zend_ssa * ssa , int block_num , zend_basic_block * block )
458
+ {
459
+ if (block -> successors_count == 2 ) {
460
+ if (block -> successors [1 ] != block -> successors [0 ]) {
461
+ zend_ssa_remove_predecessor (ssa , block_num , block -> successors [1 ]);
462
+ }
463
+ block -> successors_count = 1 ;
464
+ }
465
+ }
466
+
467
+ static zend_always_inline void take_successor_1 (zend_ssa * ssa , int block_num , zend_basic_block * block )
468
+ {
469
+ if (block -> successors_count == 2 ) {
470
+ if (block -> successors [1 ] != block -> successors [0 ]) {
471
+ zend_ssa_remove_predecessor (ssa , block_num , block -> successors [0 ]);
472
+ block -> successors [0 ] = block -> successors [1 ];
473
+ }
474
+ block -> successors_count = 1 ;
475
+ }
476
+ }
477
+
457
478
static int zend_dfa_optimize_jmps (zend_op_array * op_array , zend_ssa * ssa )
458
479
{
459
480
int removed_ops = 0 ;
@@ -468,62 +489,188 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
468
489
zend_basic_block * block = & ssa -> cfg .blocks [block_num ];
469
490
uint32_t op_num ;
470
491
zend_op * opline ;
471
- zend_ssa_op * op ;
492
+ zend_ssa_op * ssa_op ;
472
493
473
494
while (next_block_num < ssa -> cfg .blocks_count
474
495
&& !(ssa -> cfg .blocks [next_block_num ].flags & ZEND_BB_REACHABLE )) {
475
496
next_block_num ++ ;
476
497
}
477
498
478
499
if (block -> len ) {
479
- if (block -> successors_count == 2 ) {
480
- if (block -> successors [0 ] == block -> successors [1 ]) {
481
- op_num = block -> start + block -> len - 1 ;
482
- opline = op_array -> opcodes + op_num ;
483
- switch (opline -> opcode ) {
484
- case ZEND_JMPZ :
485
- case ZEND_JMPNZ :
486
- case ZEND_JMPZNZ :
487
- op = ssa -> ops + op_num ;
500
+ op_num = block -> start + block -> len - 1 ;
501
+ opline = op_array -> opcodes + op_num ;
502
+ ssa_op = ssa -> ops + op_num ;
503
+
504
+ switch (opline -> opcode ) {
505
+ case ZEND_JMP :
506
+ optimize_jmp :
507
+ if (block -> successors [0 ] == next_block_num ) {
508
+ MAKE_NOP (opline );
509
+ removed_ops ++ ;
510
+ }
511
+ break ;
512
+ case ZEND_JMPZ :
513
+ optimize_jmpz :
514
+ if (opline -> op1_type == IS_CONST ) {
515
+ if (zend_is_true (CT_CONSTANT_EX (op_array , opline -> op1 .constant ))) {
516
+ MAKE_NOP (opline );
517
+ removed_ops ++ ;
518
+ take_successor_1 (ssa , block_num , block );
519
+ } else {
520
+ opline -> opcode = ZEND_JMP ;
521
+ COPY_NODE (opline -> op1 , opline -> op2 );
522
+ take_successor_0 (ssa , block_num , block );
523
+ goto optimize_jmp ;
524
+ }
525
+ } else {
526
+ if (block -> successors [0 ] == next_block_num ) {
527
+ take_successor_0 (ssa , block_num , block );
528
+ if (opline -> op1_type == IS_CV || !(OP1_INFO () & (MAY_BE_STRING |MAY_BE_ARRAY |MAY_BE_OBJECT |MAY_BE_RESOURCE |MAY_BE_REF ))) {
529
+ zend_ssa_remove_instr (ssa , opline , ssa_op );
530
+ removed_ops ++ ;
531
+ } else {
532
+ opline -> opcode = ZEND_FREE ;
533
+ opline -> op2 .num = 0 ;
534
+ }
535
+ }
536
+ }
537
+ break ;
538
+ case ZEND_JMPNZ :
539
+ optimize_jmpnz :
540
+ if (opline -> op1_type == IS_CONST ) {
541
+ if (zend_is_true (CT_CONSTANT_EX (op_array , opline -> op1 .constant ))) {
542
+ opline -> opcode = ZEND_JMP ;
543
+ COPY_NODE (opline -> op1 , opline -> op2 );
544
+ take_successor_0 (ssa , block_num , block );
545
+ goto optimize_jmp ;
546
+ } else {
547
+ MAKE_NOP (opline );
548
+ removed_ops ++ ;
549
+ take_successor_1 (ssa , block_num , block );
550
+ }
551
+ } else {
552
+ ZEND_ASSERT (block -> successors_count == 2 );
553
+ if (block -> successors [0 ] == next_block_num ) {
554
+ take_successor_0 (ssa , block_num , block );
555
+ if (opline -> op1_type == IS_CV || !(OP1_INFO () & (MAY_BE_STRING |MAY_BE_ARRAY |MAY_BE_OBJECT |MAY_BE_RESOURCE |MAY_BE_REF ))) {
556
+ zend_ssa_remove_instr (ssa , opline , ssa_op );
557
+ removed_ops ++ ;
558
+ } else {
559
+ opline -> opcode = ZEND_FREE ;
560
+ opline -> op2 .num = 0 ;
561
+ }
562
+ }
563
+ }
564
+ break ;
565
+ case ZEND_JMPZNZ :
566
+ if (opline -> op1_type == IS_CONST ) {
567
+ if (zend_is_true (CT_CONSTANT_EX (op_array , opline -> op1 .constant ))) {
568
+ zend_op * target_opline = ZEND_OFFSET_TO_OPLINE (opline , opline -> extended_value );
569
+ ZEND_SET_OP_JMP_ADDR (opline , opline -> op1 , target_opline );
570
+ take_successor_1 (ssa , block_num , block );
571
+ } else {
572
+ zend_op * target_opline = ZEND_OP2_JMP_ADDR (opline );
573
+ ZEND_SET_OP_JMP_ADDR (opline , opline -> op1 , target_opline );
574
+ take_successor_0 (ssa , block_num , block );
575
+ }
576
+ opline -> op1_type = IS_UNUSED ;
577
+ opline -> extended_value = 0 ;
578
+ opline -> opcode = ZEND_JMP ;
579
+ goto optimize_jmp ;
580
+ } else {
581
+ ZEND_ASSERT (block -> successors_count == 2 );
582
+ if (block -> successors [0 ] == block -> successors [1 ]) {
583
+ take_successor_0 (ssa , block_num , block );
488
584
if (block -> successors [0 ] == next_block_num ) {
489
- if (opline -> op1_type & (IS_CV |IS_CONST )) {
490
- zend_ssa_remove_instr (ssa , opline , op );
491
- if (op -> op1_use >= 0 ) {
492
- zend_ssa_unlink_use_chain (ssa , op_num , op -> op1_use );
493
- op -> op1_use = -1 ;
494
- op -> op1_use_chain = -1 ;
495
- }
496
- MAKE_NOP (opline );
585
+ if (opline -> op1_type == IS_CV || !(OP1_INFO () & (MAY_BE_STRING |MAY_BE_ARRAY |MAY_BE_OBJECT |MAY_BE_RESOURCE |MAY_BE_REF ))) {
586
+ zend_ssa_remove_instr (ssa , opline , ssa_op );
497
587
removed_ops ++ ;
498
588
} else {
499
589
opline -> opcode = ZEND_FREE ;
500
590
opline -> op2 .num = 0 ;
501
591
}
502
- } else {
503
- if (opline -> op1_type & (IS_CV |IS_CONST )) {
504
- if (op -> op1_use >= 0 ) {
505
- zend_ssa_unlink_use_chain (ssa , op_num , op -> op1_use );
506
- op -> op1_use = -1 ;
507
- op -> op1_use_chain = -1 ;
508
- }
509
- opline -> opcode = ZEND_JMP ;
510
- opline -> op1_type = IS_UNUSED ;
511
- opline -> op1 .num = opline -> op2 .num ;
592
+ } else if (opline -> op1_type == IS_CV || !(OP1_INFO () & (MAY_BE_STRING |MAY_BE_ARRAY |MAY_BE_OBJECT |MAY_BE_RESOURCE |MAY_BE_REF ))) {
593
+ ZEND_ASSERT (ssa_op -> op1_use >= 0 );
594
+ zend_ssa_unlink_use_chain (ssa , op_num , ssa_op -> op1_use );
595
+ ssa_op -> op1_use = -1 ;
596
+ ssa_op -> op1_use_chain = -1 ;
597
+ opline -> opcode = ZEND_JMP ;
598
+ opline -> op1_type = IS_UNUSED ;
599
+ opline -> op1 .num = opline -> op2 .num ;
600
+ goto optimize_jmp ;
601
+ }
602
+ }
603
+ }
604
+ break ;
605
+ case ZEND_JMPZ_EX :
606
+ if (ssa -> vars [ssa_op -> result_def ].use_chain < 0
607
+ && ssa -> vars [ssa_op -> result_def ].phi_use_chain == NULL ) {
608
+ opline -> opcode = ZEND_JMPZ ;
609
+ opline -> result_type = IS_UNUSED ;
610
+ zend_ssa_remove_result_def (ssa , ssa_op );
611
+ goto optimize_jmpz ;
612
+ } else if (opline -> op1_type == IS_CONST ) {
613
+ if (zend_is_true (CT_CONSTANT_EX (op_array , opline -> op1 .constant ))) {
614
+ opline -> opcode = ZEND_QM_ASSIGN ;
615
+ take_successor_1 (ssa , block_num , block );
616
+ }
617
+ }
618
+ break ;
619
+ case ZEND_JMPNZ_EX :
620
+ if (ssa -> vars [ssa_op -> result_def ].use_chain < 0
621
+ && ssa -> vars [ssa_op -> result_def ].phi_use_chain == NULL ) {
622
+ opline -> opcode = ZEND_JMPNZ ;
623
+ opline -> result_type = IS_UNUSED ;
624
+ zend_ssa_remove_result_def (ssa , ssa_op );
625
+ goto optimize_jmpnz ;
626
+ } else if (opline -> op1_type == IS_CONST ) {
627
+ if (!zend_is_true (CT_CONSTANT_EX (op_array , opline -> op1 .constant ))) {
628
+ opline -> opcode = ZEND_QM_ASSIGN ;
629
+ take_successor_1 (ssa , block_num , block );
630
+ }
631
+ }
632
+ break ;
633
+ case ZEND_JMP_SET :
634
+ if (ssa -> vars [ssa_op -> result_def ].use_chain < 0
635
+ && ssa -> vars [ssa_op -> result_def ].phi_use_chain == NULL ) {
636
+ opline -> opcode = ZEND_JMPNZ ;
637
+ opline -> result_type = IS_UNUSED ;
638
+ zend_ssa_remove_result_def (ssa , ssa_op );
639
+ goto optimize_jmpnz ;
640
+ } else if (opline -> op1_type == IS_CONST ) {
641
+ if (!zend_is_true (CT_CONSTANT_EX (op_array , opline -> op1 .constant ))) {
642
+ MAKE_NOP (opline );
643
+ removed_ops ++ ;
644
+ take_successor_1 (ssa , block_num , block );
645
+ }
646
+ }
647
+ break ;
648
+ case ZEND_COALESCE :
649
+ if (opline -> op1_type == IS_CONST ) {
650
+ if (Z_TYPE_P (CT_CONSTANT_EX (op_array , opline -> op1 .constant )) == IS_NULL ) {
651
+ MAKE_NOP (opline );
652
+ removed_ops ++ ;
653
+ take_successor_1 (ssa , block_num , block );
654
+ } else {
655
+ zend_ssa_var * var = & ssa -> vars [ssa_op -> result_def ];
656
+ if (var -> use_chain < 0 && var -> phi_use_chain == NULL ) {
657
+ ssa_op -> result_def = -1 ;
658
+ if (opline -> result_type & (IS_TMP_VAR |IS_VAR )) {
659
+ zend_optimizer_remove_live_range_ex (op_array , opline -> result .var , var -> definition );
512
660
}
661
+ zend_ssa_unlink_use_chain (ssa , opline - op_array -> opcodes , ssa_op -> op1_use );
662
+ ssa_op -> op1_use = -1 ;
663
+ ssa_op -> op1_use_chain = -1 ;
664
+ opline -> opcode = ZEND_JMP ;
665
+ COPY_NODE (opline -> op1 , opline -> op2 );
666
+ take_successor_0 (ssa , block_num , block );
513
667
}
514
- break ;
515
- default :
516
- break ;
668
+ }
517
669
}
518
- }
519
- } else if (block -> successors_count == 1 && block -> successors [0 ] == next_block_num ) {
520
- op_num = block -> start + block -> len - 1 ;
521
- opline = op_array -> opcodes + op_num ;
522
- if (opline -> opcode == ZEND_JMP ) {
523
- MAKE_NOP (opline );
524
- removed_ops ++ ;
525
- }
526
- }
670
+ break ;
671
+ default :
672
+ break ;
673
+ }
527
674
}
528
675
529
676
block_num = next_block_num ;
@@ -574,6 +721,9 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
574
721
if (dce_optimize_op_array (op_array , ssa , 0 )) {
575
722
remove_nops = 1 ;
576
723
}
724
+ if (zend_dfa_optimize_jmps (op_array , ssa )) {
725
+ remove_nops = 1 ;
726
+ }
577
727
if (ctx -> debug_level & ZEND_DUMP_AFTER_PASS_14 ) {
578
728
zend_dump_op_array (op_array , ZEND_DUMP_SSA , "after dce pass" , ssa );
579
729
}
0 commit comments