@@ -1910,6 +1910,73 @@ static int ir_try_swap_operands(ir_ctx *ctx, ir_ref i, ir_insn *insn)
19101910 return 0 ;
19111911}
19121912
1913+ /* Reuse a bound COPY's storage when it covers the source's optimized lifetime. */
1914+ static void ir_share_copy_spill_slots (ir_ctx * ctx )
1915+ {
1916+ ir_ref ref ;
1917+
1918+ if (!ctx -> binding ) {
1919+ return ;
1920+ }
1921+ for (ref = 1 ; ref < ctx -> insns_count ; ref += ir_insn_len (& ctx -> ir_base [ref ])) {
1922+ ir_insn * insn = & ctx -> ir_base [ref ];
1923+ ir_ref source , binding ;
1924+ ir_live_interval * source_interval , * copy_interval ;
1925+ ir_use_list * uses ;
1926+ ir_ref i ;
1927+ ir_live_range range , * source_range ;
1928+
1929+ if (insn -> op != IR_COPY || insn -> op2 != IR_COPY_HARD ) {
1930+ continue ;
1931+ }
1932+ source = insn -> op1 ;
1933+ if (source <= 0 || source != ref - 1 || ctx -> ir_base [source ].op >= IR_PHI
1934+ || ctx -> ir_base [source ].type != insn -> type
1935+ || ctx -> cfg_map [source ] != ctx -> cfg_map [ref ]
1936+ || !ctx -> vregs [source ] || !ctx -> vregs [ref ]
1937+ || ir_binding_find (ctx , source )) {
1938+ continue ;
1939+ }
1940+ binding = ir_binding_find (ctx , ref );
1941+ if (!binding ) {
1942+ continue ;
1943+ }
1944+ source_interval = ctx -> live_intervals [ctx -> vregs [source ]];
1945+ copy_interval = ctx -> live_intervals [ctx -> vregs [ref ]];
1946+ /* Do not borrow storage from a coalesced value or across a loop entry. */
1947+ if (((source_interval -> flags | copy_interval -> flags ) & IR_LIVE_INTERVAL_COALESCED )
1948+ || source_interval -> range .start < IR_START_LIVE_POS_FROM_REF (source )
1949+ || source_interval -> range .start >= IR_END_LIVE_POS_FROM_REF (source )
1950+ || copy_interval -> range .start < IR_START_LIVE_POS_FROM_REF (ref )
1951+ || copy_interval -> range .start >= IR_END_LIVE_POS_FROM_REF (ref )) {
1952+ continue ;
1953+ }
1954+ /* Ignore only the adjacent source definition before the COPY. Every
1955+ * remaining source range, including holes and backedges, must be covered. */
1956+ range = source_interval -> range ;
1957+ range .start = copy_interval -> range .start ;
1958+ source_range = range .end > range .start ? & range : range .next ;
1959+ if (source_range && !ir_ivals_inside (& copy_interval -> range , source_range )) {
1960+ continue ;
1961+ }
1962+ /* A source snapshot may require a different location from the bound COPY. */
1963+ uses = & ctx -> use_lists [source ];
1964+ for (i = 0 ; i < uses -> count ; i ++ ) {
1965+ if (ctx -> ir_base [ctx -> use_edges [uses -> refs + i ]].op == IR_SNAPSHOT ) {
1966+ break ;
1967+ }
1968+ }
1969+ if (i != uses -> count ) {
1970+ continue ;
1971+ }
1972+ /* Adjacent definitions have no intervening memory access or exit. The COPY's
1973+ * live ranges cover every later use of the identically typed source.
1974+ * Keep both identities and the allocator's binding compatibility checks. */
1975+ IR_ASSERT (binding < 0 );
1976+ ir_bind (ctx , binding , source );
1977+ }
1978+ }
1979+
19131980int ir_coalesce (ir_ctx * ctx )
19141981{
19151982 uint32_t b , n , succ , pred_b , count = 0 ;
@@ -2110,6 +2177,8 @@ int ir_coalesce(ir_ctx *ctx)
21102177 ir_mem_free (xlat );
21112178 }
21122179
2180+ ir_share_copy_spill_slots (ctx );
2181+
21132182 return 1 ;
21142183}
21152184
0 commit comments