@@ -1701,40 +1701,43 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
1701
1701
return tssa ;
1702
1702
}
1703
1703
1704
- static void zend_jit_close_var (zend_jit_trace_stack * stack , uint32_t n , const zend_ssa * ssa , const zend_op * * ssa_opcodes , const zend_op_array * op_array , const zend_ssa * op_array_ssa , int * start , int * end , uint8_t * flags , int idx )
1704
+ static void zend_jit_close_var (zend_jit_trace_stack * stack , uint32_t n , int * start , int * end , uint8_t * flags , int line )
1705
1705
{
1706
1706
int32_t var = STACK_VAR (stack , n );
1707
- int32_t use ;
1708
-
1709
- if (var >= 0 && start [var ] >= 0 && end [var ] >= 0 ) {
1710
- if (end [var ] >= 0 && op_array_ssa -> vars ) {
1711
- use = ssa_opcodes [end [var ]] - op_array -> opcodes ;
1712
- if (ssa -> ops [end [var ]].op1_use == var ) {
1713
- if (zend_ssa_is_last_use (op_array , op_array_ssa , op_array_ssa -> ops [use ].op1_use , use )) {
1714
- flags [var ] |= ZREG_LAST_USE ;
1715
- return ;
1716
- }
1717
- } else if (ssa -> ops [end [var ]].op2_use == var ) {
1718
- if (zend_ssa_is_last_use (op_array , op_array_ssa , op_array_ssa -> ops [use ].op2_use , use )) {
1719
- flags [var ] |= ZREG_LAST_USE ;
1720
- return ;
1721
- }
1722
- } else if (ssa -> ops [end [var ]].result_use == var ) {
1723
- if (zend_ssa_is_last_use (op_array , op_array_ssa , op_array_ssa -> ops [use ].result_use , use )) {
1724
- flags [var ] |= ZREG_LAST_USE ;
1725
- return ;
1726
- }
1707
+
1708
+ if (var >= 0 && start [var ] >= 0 && !(flags [var ] & ZREG_LAST_USE )) {
1709
+ // TODO: shrink interval to last side exit ????
1710
+ end [var ] = line ;
1711
+ }
1712
+ }
1713
+
1714
+ static void zend_jit_trace_use_var (int line , int var , int def , int use_chain , int * start , int * end , uint8_t * flags , const zend_ssa * ssa , const zend_op * * ssa_opcodes , const zend_op_array * op_array , const zend_ssa * op_array_ssa )
1715
+ {
1716
+ ZEND_ASSERT (start [var ] >= 0 );
1717
+ ZEND_ASSERT (!(flags [var ] & ZREG_LAST_USE ));
1718
+ end [var ] = line ;
1719
+ if (def >= 0 ) {
1720
+ flags [var ] |= ZREG_LAST_USE ;
1721
+ } else if (use_chain < 0 && (flags [var ] & (ZREG_LOAD |ZREG_STORE ))) {
1722
+ flags [var ] |= ZREG_LAST_USE ;
1723
+ } else if (use_chain >= 0 && !zend_ssa_is_no_val_use (ssa_opcodes [use_chain ], ssa -> ops + use_chain , var )) {
1724
+ /* pass */
1725
+ } else if (op_array_ssa -> vars ) {
1726
+ uint32_t use = ssa_opcodes [line ] - op_array -> opcodes ;
1727
+
1728
+ if (ssa -> ops [line ].op1_use == var ) {
1729
+ if (zend_ssa_is_last_use (op_array , op_array_ssa , op_array_ssa -> ops [use ].op1_use , use )) {
1730
+ flags [var ] |= ZREG_LAST_USE ;
1731
+ }
1732
+ } else if (ssa -> ops [line ].op2_use == var ) {
1733
+ if (zend_ssa_is_last_use (op_array , op_array_ssa , op_array_ssa -> ops [use ].op2_use , use )) {
1734
+ flags [var ] |= ZREG_LAST_USE ;
1735
+ }
1736
+ } else if (ssa -> ops [line ].result_use == var ) {
1737
+ if (zend_ssa_is_last_use (op_array , op_array_ssa , op_array_ssa -> ops [use ].result_use , use )) {
1738
+ flags [var ] |= ZREG_LAST_USE ;
1727
1739
}
1728
1740
}
1729
- #if 0
1730
- // TODO: try this optimization later ???
1731
- if (flags [var ] & (ZREG_LOAD |ZREG_STORE )) {
1732
- /* we don't have to extend live range if it's already in memory */
1733
- return ;
1734
- }
1735
- #endif
1736
- // TODO: shrink interval to last side exit ????
1737
- end [var ] = idx ;
1738
1741
}
1739
1742
}
1740
1743
@@ -1844,29 +1847,32 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
1844
1847
&& start [ssa_op -> op1_use ] >= 0
1845
1848
&& !zend_ssa_is_no_val_use (opline , ssa_op , ssa_op -> op1_use )) {
1846
1849
if (support_opline ) {
1847
- end [ ssa_op -> op1_use ] = idx ;
1850
+ zend_jit_trace_use_var ( idx , ssa_op -> op1_use , ssa_op -> op1_def , ssa_op -> op1_use_chain , start , end , flags , ssa , ssa_opcodes , op_array , op_array_ssa ) ;
1848
1851
} else {
1849
1852
start [ssa_op -> op1_use ] = -1 ;
1850
1853
end [ssa_op -> op1_use ] = -1 ;
1851
1854
count -- ;
1852
1855
}
1853
1856
}
1854
1857
if (ssa_op -> op2_use >= 0
1858
+ && ssa_op -> op2_use != ssa_op -> op1_use
1855
1859
&& start [ssa_op -> op2_use ] >= 0
1856
1860
&& !zend_ssa_is_no_val_use (opline , ssa_op , ssa_op -> op2_use )) {
1857
1861
if (support_opline ) {
1858
- end [ ssa_op -> op2_use ] = idx ;
1862
+ zend_jit_trace_use_var ( idx , ssa_op -> op2_use , ssa_op -> op2_def , ssa_op -> op2_use_chain , start , end , flags , ssa , ssa_opcodes , op_array , op_array_ssa ) ;
1859
1863
} else {
1860
1864
start [ssa_op -> op2_use ] = -1 ;
1861
1865
end [ssa_op -> op2_use ] = -1 ;
1862
1866
count -- ;
1863
1867
}
1864
1868
}
1865
1869
if (ssa_op -> result_use >= 0
1870
+ && ssa_op -> result_use != ssa_op -> op1_use
1871
+ && ssa_op -> result_use != ssa_op -> op2_use
1866
1872
&& start [ssa_op -> result_use ] >= 0
1867
1873
&& !zend_ssa_is_no_val_use (opline , ssa_op , ssa_op -> result_use )) {
1868
1874
if (support_opline ) {
1869
- end [ ssa_op -> result_use ] = idx ;
1875
+ zend_jit_trace_use_var ( idx , ssa_op -> result_use , ssa_op -> result_def , ssa_op -> res_use_chain , start , end , flags , ssa , ssa_opcodes , op_array , op_array_ssa ) ;
1870
1876
} else {
1871
1877
start [ssa_op -> result_use ] = -1 ;
1872
1878
end [ssa_op -> result_use ] = -1 ;
@@ -1875,15 +1881,15 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
1875
1881
}
1876
1882
1877
1883
if (ssa_op -> op1_def >= 0 ) {
1878
- zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx );
1884
+ zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op1 .var ), start , end , flags , idx );
1879
1885
SET_STACK_VAR (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ssa_op -> op1_def );
1880
1886
}
1881
1887
if (ssa_op -> op2_def >= 0 ) {
1882
- zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op2 .var ), ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx );
1888
+ zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op2 .var ), start , end , flags , idx );
1883
1889
SET_STACK_VAR (stack , EX_VAR_TO_NUM (opline -> op2 .var ), ssa_op -> op2_def );
1884
1890
}
1885
1891
if (ssa_op -> result_def >= 0 ) {
1886
- zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> result .var ), ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx );
1892
+ zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> result .var ), start , end , flags , idx );
1887
1893
SET_STACK_VAR (stack , EX_VAR_TO_NUM (opline -> result .var ), ssa_op -> result_def );
1888
1894
}
1889
1895
@@ -1931,15 +1937,15 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
1931
1937
&& start [ssa_op -> op1_use ] >= 0
1932
1938
&& !zend_ssa_is_no_val_use (opline , ssa_op , ssa_op -> op1_use )) {
1933
1939
if (support_opline ) {
1934
- end [ ssa_op -> op1_use ] = idx ;
1940
+ zend_jit_trace_use_var ( idx , ssa_op -> op1_use , ssa_op -> op1_def , ssa_op -> op1_use_chain , start , end , flags , ssa , ssa_opcodes , op_array , op_array_ssa ) ;
1935
1941
} else {
1936
1942
start [ssa_op -> op1_use ] = -1 ;
1937
1943
end [ssa_op -> op1_use ] = -1 ;
1938
1944
count -- ;
1939
1945
}
1940
1946
}
1941
1947
if (ssa_op -> op1_def >= 0 ) {
1942
- zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx );
1948
+ zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op1 .var ), start , end , flags , idx );
1943
1949
SET_STACK_VAR (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ssa_op -> op1_def );
1944
1950
if (support_opline
1945
1951
&& (ssa -> vars [ssa_op -> op1_def ].use_chain >= 0
@@ -1961,7 +1967,7 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
1961
1967
while (opline -> opcode == ZEND_RECV_INIT ) {
1962
1968
/* RECV_INIT doesn't support registers */
1963
1969
if (ssa_op -> result_def >= 0 ) {
1964
- zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> result .var ), ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx );
1970
+ zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> result .var ), start , end , flags , idx );
1965
1971
SET_STACK_VAR (stack , EX_VAR_TO_NUM (opline -> result .var ), ssa_op -> result_def );
1966
1972
}
1967
1973
ssa_op ++ ;
@@ -1976,7 +1982,7 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
1976
1982
while (opline -> opcode == ZEND_BIND_GLOBAL ) {
1977
1983
/* BIND_GLOBAL doesn't support registers */
1978
1984
if (ssa_op -> op1_def >= 0 ) {
1979
- zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx );
1985
+ zend_jit_close_var (stack , EX_VAR_TO_NUM (opline -> op1 .var ), start , end , flags , idx );
1980
1986
SET_STACK_VAR (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ssa_op -> op1_def );
1981
1987
}
1982
1988
ssa_op ++ ;
@@ -2016,7 +2022,7 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2016
2022
} else if (p -> op == ZEND_JIT_TRACE_BACK ) {
2017
2023
/* Close exiting call frames */
2018
2024
for (i = 0 ; i < op_array -> last_var ; i ++ ) {
2019
- zend_jit_close_var (stack , i , ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx - 1 );
2025
+ zend_jit_close_var (stack , i , start , end , flags , idx - 1 );
2020
2026
}
2021
2027
op_array = p -> op_array ;
2022
2028
jit_extension =
@@ -2050,20 +2056,23 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2050
2056
zend_ssa_phi * phi = ssa -> blocks [1 ].phis ;
2051
2057
2052
2058
while (phi ) {
2053
- if (start [phi -> sources [1 ]] >= 0 ) {
2054
- end [phi -> sources [1 ]] = idx ;
2059
+ i = phi -> sources [1 ];
2060
+ if (start [i ] >= 0 ) {
2061
+ end [i ] = idx ;
2062
+ flags [i ] &= ~ZREG_LAST_USE ;
2055
2063
}
2056
2064
phi = phi -> next ;
2057
2065
}
2058
2066
2059
2067
for (i = 0 ; i < op_array -> last_var ; i ++ ) {
2060
2068
if (start [i ] >= 0 && !ssa -> vars [i ].phi_use_chain ) {
2061
2069
end [i ] = idx ;
2070
+ flags [i ] &= ~ZREG_LAST_USE ;
2062
2071
}
2063
2072
}
2064
2073
} else {
2065
2074
for (i = 0 ; i < op_array -> last_var ; i ++ ) {
2066
- zend_jit_close_var (stack , i , ssa , ssa_opcodes , op_array , op_array_ssa , start , end , flags , idx );
2075
+ zend_jit_close_var (stack , i , start , end , flags , idx );
2067
2076
}
2068
2077
}
2069
2078
@@ -2333,6 +2342,27 @@ static int zend_jit_trace_stack_needs_deoptimization(zend_jit_trace_stack *stack
2333
2342
return 0 ;
2334
2343
}
2335
2344
2345
+ static void zend_jit_trace_clenup_stack (zend_jit_trace_stack * stack , const zend_op * opline , const zend_ssa_op * ssa_op , const zend_ssa * ssa , zend_lifetime_interval * * ra )
2346
+ {
2347
+ uint32_t line = ssa_op - ssa -> ops ;
2348
+
2349
+ if (ssa_op -> op1_use >= 0
2350
+ && ra [ssa_op -> op1_use ]
2351
+ && ra [ssa_op -> op1_use ]-> range .end == line ) {
2352
+ SET_STACK_REG (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ZREG_NONE );
2353
+ }
2354
+ if (ssa_op -> op2_use >= 0
2355
+ && ra [ssa_op -> op2_use ]
2356
+ && ra [ssa_op -> op2_use ]-> range .end == line ) {
2357
+ SET_STACK_REG (stack , EX_VAR_TO_NUM (opline -> op2 .var ), ZREG_NONE );
2358
+ }
2359
+ if (ssa_op -> result_use >= 0
2360
+ && ra [ssa_op -> result_use ]
2361
+ && ra [ssa_op -> result_use ]-> range .end == line ) {
2362
+ SET_STACK_REG (stack , EX_VAR_TO_NUM (opline -> result .var ), ZREG_NONE );
2363
+ }
2364
+ }
2365
+
2336
2366
static const void * zend_jit_trace (zend_jit_trace_rec * trace_buffer , uint32_t parent_trace , uint32_t exit_num )
2337
2367
{
2338
2368
const void * handler = NULL ;
@@ -3057,8 +3087,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3057
3087
if ((opline -> result_type & (IS_SMART_BRANCH_JMPZ |IS_SMART_BRANCH_JMPNZ )) != 0 ) {
3058
3088
zend_bool exit_if_true = 0 ;
3059
3089
const zend_op * exit_opline = zend_jit_trace_get_exit_opline (p + 1 , opline + 1 , & exit_if_true );
3060
- uint32_t exit_point = zend_jit_trace_get_exit_point ( opline , exit_opline , p + 1 ) ;
3090
+ uint32_t exit_point ;
3061
3091
3092
+ if (ra ) {
3093
+ zend_jit_trace_clenup_stack (stack , opline , ssa_op , ssa , ra );
3094
+ }
3095
+ exit_point = zend_jit_trace_get_exit_point (opline , exit_opline , p + 1 );
3062
3096
exit_addr = zend_jit_trace_get_exit_addr (exit_point );
3063
3097
if (!exit_addr ) {
3064
3098
goto jit_failure ;
@@ -3086,8 +3120,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3086
3120
if ((opline -> result_type & (IS_SMART_BRANCH_JMPZ |IS_SMART_BRANCH_JMPNZ )) != 0 ) {
3087
3121
zend_bool exit_if_true = 0 ;
3088
3122
const zend_op * exit_opline = zend_jit_trace_get_exit_opline (p + 1 , opline + 1 , & exit_if_true );
3089
- uint32_t exit_point = zend_jit_trace_get_exit_point ( opline , exit_opline , p + 1 ) ;
3123
+ uint32_t exit_point ;
3090
3124
3125
+ if (ra ) {
3126
+ zend_jit_trace_clenup_stack (stack , opline , ssa_op , ssa , ra );
3127
+ }
3128
+ exit_point = zend_jit_trace_get_exit_point (opline , exit_opline , p + 1 );
3091
3129
exit_addr = zend_jit_trace_get_exit_addr (exit_point );
3092
3130
if (!exit_addr ) {
3093
3131
goto jit_failure ;
@@ -3138,8 +3176,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3138
3176
if ((opline -> result_type & (IS_SMART_BRANCH_JMPZ |IS_SMART_BRANCH_JMPNZ )) != 0 ) {
3139
3177
zend_bool exit_if_true = 0 ;
3140
3178
const zend_op * exit_opline = zend_jit_trace_get_exit_opline (p + 1 , opline + 1 , & exit_if_true );
3141
- uint32_t exit_point = zend_jit_trace_get_exit_point ( opline , exit_opline , p + 1 ) ;
3179
+ uint32_t exit_point ;
3142
3180
3181
+ if (ra ) {
3182
+ zend_jit_trace_clenup_stack (stack , opline , ssa_op , ssa , ra );
3183
+ }
3184
+ exit_point = zend_jit_trace_get_exit_point (opline , exit_opline , p + 1 );
3143
3185
exit_addr = zend_jit_trace_get_exit_addr (exit_point );
3144
3186
if (!exit_addr ) {
3145
3187
goto jit_failure ;
@@ -3256,6 +3298,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3256
3298
} else {
3257
3299
ZEND_ASSERT (0 );
3258
3300
}
3301
+ if (ra ) {
3302
+ zend_jit_trace_clenup_stack (stack , opline , ssa_op , ssa , ra );
3303
+ }
3259
3304
exit_point = zend_jit_trace_get_exit_point (opline , exit_opline , p + 1 );
3260
3305
exit_addr = zend_jit_trace_get_exit_addr (exit_point );
3261
3306
if (!exit_addr ) {
@@ -3307,8 +3352,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3307
3352
if ((opline -> result_type & (IS_SMART_BRANCH_JMPZ |IS_SMART_BRANCH_JMPNZ )) != 0 ) {
3308
3353
zend_bool exit_if_true = 0 ;
3309
3354
const zend_op * exit_opline = zend_jit_trace_get_exit_opline (p + 1 , opline + 1 , & exit_if_true );
3310
- uint32_t exit_point = zend_jit_trace_get_exit_point ( opline , exit_opline , p + 1 ) ;
3355
+ uint32_t exit_point ;
3311
3356
3357
+ if (ra ) {
3358
+ zend_jit_trace_clenup_stack (stack , opline , ssa_op , ssa , ra );
3359
+ }
3360
+ exit_point = zend_jit_trace_get_exit_point (opline , exit_opline , p + 1 );
3312
3361
exit_addr = zend_jit_trace_get_exit_addr (exit_point );
3313
3362
if (!exit_addr ) {
3314
3363
goto jit_failure ;
@@ -3513,6 +3562,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3513
3562
}
3514
3563
#endif
3515
3564
3565
+ if (ra ) {
3566
+ zend_jit_trace_clenup_stack (stack , opline , ssa_op , ssa , ra );
3567
+ }
3568
+
3516
3569
/* Keep information about known types on abstract stack */
3517
3570
if (ssa_op -> result_def >= 0 ) {
3518
3571
zend_uchar type = IS_UNKNOWN ;
0 commit comments