@@ -54,6 +54,19 @@ bool check_live_out(basic_block_t *bb, var_t *var)
5454 return false;
5555}
5656
57+ void track_var_use (var_t * var , int insn_idx )
58+ {
59+ if (!var )
60+ return ;
61+
62+ var -> use_count ++ ;
63+
64+ if (var -> first_use < 0 )
65+ var -> first_use = insn_idx ;
66+
67+ var -> last_use = insn_idx ;
68+ }
69+
5770void refresh (basic_block_t * bb , insn_t * insn )
5871{
5972 for (int i = 0 ; i < REG_CNT ; i ++ ) {
@@ -93,18 +106,57 @@ ph2_ir_t *bb_add_ph2_ir(basic_block_t *bb, opcode_t op)
93106 return n ;
94107}
95108
109+ /* Calculate the cost of spilling a variable from a register.
110+ * Higher cost means the variable is more valuable to keep in a register.
111+ * The cost is computed based on multiple factors that affect performance.
112+ */
96113int calculate_spill_cost (var_t * var , basic_block_t * bb , int current_idx )
97114{
115+ int cost = 0 ;
116+
117+ /* Variables that are live-out of the basic block must be spilled anyway,
118+ * so give them a high cost to prefer spilling them over others
119+ */
98120 if (check_live_out (bb , var ))
99- return 1000 ;
121+ cost += 1000 ;
100122
123+ /* Variables that will be used soon should have higher cost.
124+ * The closer the next use, the higher the penalty for spilling
125+ */
101126 if (var -> consumed > current_idx ) {
102127 int distance = var -> consumed - current_idx ;
103128 if (distance < 10 )
104- return 100 - distance * 10 ;
129+ cost += 100 - distance * 10 ; /* Max 100 points for immediate use */
130+ }
131+
132+ /* Frequently used variables should stay in registers.
133+ * Each use adds 5 points to the cost
134+ */
135+ if (var -> use_count > 0 )
136+ cost += var -> use_count * 5 ;
137+
138+ /* Variables inside loops are accessed repeatedly, so they should have much
139+ * higher priority to stay in registers (200 points per level)
140+ */
141+ if (var -> loop_depth > 0 )
142+ cost += var -> loop_depth * 200 ;
143+
144+ /* Constants can be easily reloaded, so prefer spilling them by reducing
145+ * their cost
146+ */
147+ if (var -> is_const )
148+ cost -= 50 ;
149+
150+ /* Variables with long live ranges may benefit from spilling to free up
151+ * registers for other variables
152+ */
153+ if (var -> first_use >= 0 && var -> last_use >= 0 ) {
154+ int range_length = var -> last_use - var -> first_use ;
155+ if (range_length > 100 )
156+ cost += 20 ; /* Small penalty for very long live ranges */
105157 }
106158
107- return 0 ;
159+ return cost ;
108160}
109161
110162int find_best_spill (basic_block_t * bb ,
@@ -269,9 +321,8 @@ int prepare_dest(basic_block_t *bb, var_t *var, int operand_0, int operand_1)
269321 }
270322 }
271323
272- if (REGS [spilled ].var ) {
324+ if (REGS [spilled ].var )
273325 vreg_clear_phys (REGS [spilled ].var );
274- }
275326
276327 spill_var (bb , REGS [spilled ].var , spilled );
277328 REGS [spilled ].var = var ;
@@ -512,6 +563,7 @@ void reg_alloc(void)
512563
513564 switch (insn -> opcode ) {
514565 case OP_unwound_phi :
566+ track_var_use (insn -> rs1 , insn -> idx );
515567 src0 = prepare_operand (bb , insn -> rs1 , -1 );
516568
517569 if (!insn -> rd -> offset ) {
@@ -610,6 +662,7 @@ void reg_alloc(void)
610662 if (insn -> rd -> consumed == -1 )
611663 break ;
612664
665+ track_var_use (insn -> rs1 , insn -> idx );
613666 src0 = find_in_regs (insn -> rs1 );
614667
615668 /* If operand is loaded from stack, clear the original slot
@@ -754,6 +807,8 @@ void reg_alloc(void)
754807 case OP_bit_and :
755808 case OP_bit_or :
756809 case OP_bit_xor :
810+ track_var_use (insn -> rs1 , insn -> idx );
811+ track_var_use (insn -> rs2 , insn -> idx );
757812 src0 = prepare_operand (bb , insn -> rs1 , -1 );
758813 src1 = prepare_operand (bb , insn -> rs2 , src0 );
759814 dest = prepare_dest (bb , insn -> rd , src0 , src1 );
0 commit comments