@@ -133,6 +133,19 @@ static zend_bool zend_ssa_is_last_use(const zend_op_array *op_array, const zend_
133
133
return use < 0 || zend_ssa_is_no_val_use (op_array -> opcodes + use , ssa -> ops + use , var );
134
134
}
135
135
136
+ static zend_bool zend_ival_is_last_use (const zend_lifetime_interval * ival , int use )
137
+ {
138
+ if (ival -> flags & ZREG_LAST_USE ) {
139
+ const zend_life_range * range = & ival -> range ;
140
+
141
+ while (range -> next ) {
142
+ range = range -> next ;
143
+ }
144
+ return range -> end == use ;
145
+ }
146
+ return 0 ;
147
+ }
148
+
136
149
static zend_bool zend_is_commutative (zend_uchar opcode )
137
150
{
138
151
return
@@ -702,9 +715,7 @@ static int zend_jit_add_range(zend_lifetime_interval **intervals, int var, uint3
702
715
}
703
716
ival -> ssa_var = var ;
704
717
ival -> reg = ZREG_NONE ;
705
- ival -> split = 0 ;
706
- ival -> store = 0 ;
707
- ival -> load = 0 ;
718
+ ival -> flags = 0 ;
708
719
ival -> range .start = from ;
709
720
ival -> range .end = to ;
710
721
ival -> range .next = NULL ;
@@ -831,13 +842,12 @@ static int zend_jit_split_interval(zend_lifetime_interval *current, uint32_t pos
831
842
}
832
843
}
833
844
834
- current -> store = 1 ;
845
+ current -> flags |= ZREG_STORE ;
835
846
836
847
ival -> ssa_var = current -> ssa_var ;
837
848
ival -> reg = ZREG_NONE ;
838
- ival -> split = 1 ;
839
- ival -> store = 0 ;
840
- ival -> load = 1 ;
849
+ ival -> flags |= ZREG_SPLIT | ZREG_LOAD ;
850
+ ival -> flags &= ZREG_STORE ;
841
851
ival -> hint = NULL ;
842
852
843
853
do {
@@ -1431,7 +1441,7 @@ static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, zend_ss
1431
1441
1432
1442
/* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
1433
1443
Michael Franz, CGO'10 (2010), Figure 6. */
1434
- if (current -> split ) {
1444
+ if (current -> flags & ZREG_SPLIT ) {
1435
1445
/* for each interval it in inactive intersecting with current do */
1436
1446
/* freeUntilPos[it.reg] = next intersection of it with current */
1437
1447
it = inactive ;
@@ -1451,9 +1461,13 @@ static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, zend_ss
1451
1461
range = & current -> range ;
1452
1462
do {
1453
1463
uint32_t line = range -> start ;
1464
+ uint32_t last_use_line = (uint32_t )-1 ;
1454
1465
zend_regset regset ;
1455
1466
zend_reg reg ;
1456
1467
1468
+ if ((current -> flags & ZREG_LAST_USE ) && !range -> next ) {
1469
+ last_use_line = range -> end ;
1470
+ }
1457
1471
if (ssa -> ops [line ].op1_def == current -> ssa_var ||
1458
1472
ssa -> ops [line ].op2_def == current -> ssa_var ||
1459
1473
ssa -> ops [line ].result_def == current -> ssa_var ) {
@@ -1463,7 +1477,7 @@ static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, zend_ss
1463
1477
regset = zend_jit_get_scratch_regset (
1464
1478
op_array -> opcodes + line ,
1465
1479
ssa -> ops + line ,
1466
- op_array , ssa , current -> ssa_var );
1480
+ op_array , ssa , current -> ssa_var , line == last_use_line );
1467
1481
ZEND_REGSET_FOREACH (regset , reg ) {
1468
1482
if (line < freeUntilPos [reg ]) {
1469
1483
freeUntilPos [reg ] = line ;
@@ -1717,6 +1731,22 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1717
1731
goto failure ;
1718
1732
}
1719
1733
1734
+ if (list ) {
1735
+ /* Set ZREG_LAST_USE flags */
1736
+ ival = list ;
1737
+ while (ival ) {
1738
+ zend_life_range * range = & ival -> range ;
1739
+
1740
+ while (range -> next ) {
1741
+ range = range -> next ;
1742
+ }
1743
+ if (zend_ssa_is_last_use (op_array , ssa , ival -> ssa_var , range -> end )) {
1744
+ ival -> flags |= ZREG_LAST_USE ;
1745
+ }
1746
+ ival = ival -> list_next ;
1747
+ }
1748
+ }
1749
+
1720
1750
if (list ) {
1721
1751
if (ZCG (accel_directives ).jit_debug & ZEND_JIT_DEBUG_REG_ALLOC ) {
1722
1752
fprintf (stderr , "Live Ranges \"%s\"\n" , op_array -> function_name ? ZSTR_VAL (op_array -> function_name ) : "[main]" );
@@ -1733,10 +1763,10 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1733
1763
fprintf (stderr , ", %u-%u" , range -> start , range -> end );
1734
1764
range = range -> next ;
1735
1765
}
1736
- if (ival -> load ) {
1766
+ if (ival -> flags & ZREG_LOAD ) {
1737
1767
fprintf (stderr , " load" );
1738
1768
}
1739
- if (ival -> store ) {
1769
+ if (ival -> flags & ZREG_STORE ) {
1740
1770
fprintf (stderr , " store" );
1741
1771
}
1742
1772
if (ival -> hint ) {
@@ -1781,13 +1811,13 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1781
1811
src = phi -> sources [0 ];
1782
1812
if (intervals [i ]) {
1783
1813
if (!intervals [src ]) {
1784
- intervals [i ]-> load = 1 ;
1814
+ intervals [i ]-> flags |= ZREG_LOAD ;
1785
1815
} else if (intervals [i ]-> reg != intervals [src ]-> reg ) {
1786
- intervals [i ]-> load = 1 ;
1787
- intervals [src ]-> store = 1 ;
1816
+ intervals [i ]-> flags |= ZREG_LOAD ;
1817
+ intervals [src ]-> flags |= ZREG_STORE ;
1788
1818
}
1789
1819
} else if (intervals [src ]) {
1790
- intervals [src ]-> store = 1 ;
1820
+ intervals [src ]-> flags |= ZREG_STORE ;
1791
1821
}
1792
1822
}
1793
1823
} else {
@@ -1815,7 +1845,7 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1815
1845
}
1816
1846
if (need_move ) {
1817
1847
if (intervals [i ]) {
1818
- intervals [i ]-> load = 1 ;
1848
+ intervals [i ]-> flags |= ZREG_LOAD ;
1819
1849
}
1820
1850
for (k = 0 ; k < ssa -> cfg .blocks [phi -> block ].predecessors_count ; k ++ ) {
1821
1851
src = phi -> sources [k ];
@@ -1827,7 +1857,7 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1827
1857
src = ssa -> vars [src ].definition_phi -> sources [0 ];
1828
1858
}
1829
1859
if (intervals [src ]) {
1830
- intervals [src ]-> store = 1 ;
1860
+ intervals [src ]-> flags |= ZREG_STORE ;
1831
1861
}
1832
1862
}
1833
1863
}
@@ -1838,15 +1868,15 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1838
1868
/* Remove useless register allocation */
1839
1869
for (i = 0 ; i < ssa -> vars_count ; i ++ ) {
1840
1870
if (intervals [i ] &&
1841
- (intervals [i ]-> load ||
1842
- (intervals [i ]-> store && ssa -> vars [i ].definition >= 0 )) &&
1871
+ (( intervals [i ]-> flags & ZREG_LOAD ) ||
1872
+ (( intervals [i ]-> flags & ZREG_STORE ) && ssa -> vars [i ].definition >= 0 )) &&
1843
1873
ssa -> vars [i ].use_chain < 0 ) {
1844
1874
zend_bool may_remove = 1 ;
1845
1875
zend_ssa_phi * phi = ssa -> vars [i ].phi_use_chain ;
1846
1876
1847
1877
while (phi ) {
1848
1878
if (intervals [phi -> ssa_var ] &&
1849
- !intervals [phi -> ssa_var ]-> load ) {
1879
+ !( intervals [phi -> ssa_var ]-> flags & ZREG_LOAD ) ) {
1850
1880
may_remove = 0 ;
1851
1881
break ;
1852
1882
}
@@ -1860,16 +1890,16 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1860
1890
/* Remove intervals used once */
1861
1891
for (i = 0 ; i < ssa -> vars_count ; i ++ ) {
1862
1892
if (intervals [i ] &&
1863
- intervals [i ]-> load &&
1864
- intervals [i ]-> store &&
1893
+ ( intervals [i ]-> flags & ZREG_LOAD ) &&
1894
+ ( intervals [i ]-> flags & ZREG_STORE ) &&
1865
1895
(ssa -> vars [i ].use_chain < 0 ||
1866
1896
zend_ssa_next_use (ssa -> ops , i , ssa -> vars [i ].use_chain ) < 0 )) {
1867
1897
zend_bool may_remove = 1 ;
1868
1898
zend_ssa_phi * phi = ssa -> vars [i ].phi_use_chain ;
1869
1899
1870
1900
while (phi ) {
1871
1901
if (intervals [phi -> ssa_var ] &&
1872
- !intervals [phi -> ssa_var ]-> load ) {
1902
+ !( intervals [phi -> ssa_var ]-> flags & ZREG_LOAD ) ) {
1873
1903
may_remove = 0 ;
1874
1904
break ;
1875
1905
}
@@ -1899,10 +1929,10 @@ static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array
1899
1929
range = range -> next ;
1900
1930
}
1901
1931
fprintf (stderr , " (%s)" , zend_reg_name [ival -> reg ]);
1902
- if (ival -> load ) {
1932
+ if (ival -> flags & ZREG_LOAD ) {
1903
1933
fprintf (stderr , " load" );
1904
1934
}
1905
- if (ival -> store ) {
1935
+ if (ival -> flags & ZREG_STORE ) {
1906
1936
fprintf (stderr , " store" );
1907
1937
}
1908
1938
if (ival -> hint ) {
@@ -2131,13 +2161,13 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
2131
2161
zend_lifetime_interval * ival = ra [phi -> ssa_var ];
2132
2162
2133
2163
if (ival ) {
2134
- if (ival -> load ) {
2164
+ if (ival -> flags & ZREG_LOAD ) {
2135
2165
ZEND_ASSERT (ival -> reg != ZREG_NONE );
2136
2166
2137
2167
if (!zend_jit_load_var (& dasm_state , ssa -> var_info [phi -> ssa_var ].type , ssa -> vars [phi -> ssa_var ].var , ival -> reg )) {
2138
2168
goto jit_failure ;
2139
2169
}
2140
- } else if (ival -> store ) {
2170
+ } else if (ival -> flags & ZREG_STORE ) {
2141
2171
ZEND_ASSERT (ival -> reg != ZREG_NONE );
2142
2172
2143
2173
if (!zend_jit_store_var (& dasm_state , ssa -> var_info [phi -> ssa_var ].type , ssa -> vars [phi -> ssa_var ].var , ival -> reg )) {
0 commit comments