@@ -242,6 +242,84 @@ bool insn_fusion(ph2_ir_t *ph2_ir)
242242 return false;
243243}
244244
245+ /* Redundant move elimination
246+ * Eliminates unnecessary move operations that are overwritten or redundant
247+ */
248+ bool redundant_move_elim (ph2_ir_t * ph2_ir )
249+ {
250+ ph2_ir_t * next = ph2_ir -> next ;
251+ if (!next )
252+ return false;
253+
254+ /* Pattern 1: Consecutive assignments to same destination
255+ * {mov rd, rs1; mov rd, rs2} → {mov rd, rs2}
256+ * The first move is completely overwritten by the second
257+ */
258+ if (ph2_ir -> op == OP_assign && next -> op == OP_assign &&
259+ ph2_ir -> dest == next -> dest ) {
260+ /* Replace first move with second, skip second */
261+ ph2_ir -> src0 = next -> src0 ;
262+ ph2_ir -> next = next -> next ;
263+ return true;
264+ }
265+
266+ /* Pattern 2: Redundant load immediately overwritten
267+ * {load rd, offset; mov rd, rs} → {mov rd, rs}
268+ * Loading a value that's immediately replaced is wasteful
269+ */
270+ if ((ph2_ir -> op == OP_load || ph2_ir -> op == OP_global_load ) &&
271+ next -> op == OP_assign && ph2_ir -> dest == next -> dest ) {
272+ /* Replace load with move */
273+ ph2_ir -> op = OP_assign ;
274+ ph2_ir -> src0 = next -> src0 ;
275+ ph2_ir -> src1 = 0 ; /* Clear unused field */
276+ ph2_ir -> next = next -> next ;
277+ return true;
278+ }
279+
280+ /* Pattern 3: Load constant immediately overwritten
281+ * {li rd, imm; mov rd, rs} → {mov rd, rs}
282+ * Loading a constant that's immediately replaced
283+ */
284+ if (ph2_ir -> op == OP_load_constant && next -> op == OP_assign &&
285+ ph2_ir -> dest == next -> dest ) {
286+ /* Replace constant load with move */
287+ ph2_ir -> op = OP_assign ;
288+ ph2_ir -> src0 = next -> src0 ;
289+ ph2_ir -> next = next -> next ;
290+ return true;
291+ }
292+
293+ /* Pattern 4: Consecutive loads to same register
294+ * {load rd, offset1; load rd, offset2} → {load rd, offset2}
295+ * First load is pointless if immediately overwritten
296+ */
297+ if ((ph2_ir -> op == OP_load || ph2_ir -> op == OP_global_load ) &&
298+ (next -> op == OP_load || next -> op == OP_global_load ) &&
299+ ph2_ir -> dest == next -> dest ) {
300+ /* Keep only the second load */
301+ ph2_ir -> op = next -> op ;
302+ ph2_ir -> src0 = next -> src0 ;
303+ ph2_ir -> src1 = next -> src1 ;
304+ ph2_ir -> next = next -> next ;
305+ return true;
306+ }
307+
308+ /* Pattern 5: Consecutive constant loads (already handled in main loop
309+ * but included here for completeness)
310+ * {li rd, imm1; li rd, imm2} → {li rd, imm2}
311+ */
312+ if (ph2_ir -> op == OP_load_constant && next -> op == OP_load_constant &&
313+ ph2_ir -> dest == next -> dest ) {
314+ /* Keep only the second constant */
315+ ph2_ir -> src0 = next -> src0 ;
316+ ph2_ir -> next = next -> next ;
317+ return true;
318+ }
319+
320+ return false;
321+ }
322+
245323/* Main peephole optimization driver.
246324 * It iterates through all functions, basic blocks, and IR instructions to apply
247325 * local optimizations on adjacent instruction pairs.
@@ -265,7 +343,13 @@ void peephole(void)
265343 continue ;
266344 }
267345
268- insn_fusion (ir );
346+ /* Try instruction fusion first */
347+ if (insn_fusion (ir ))
348+ continue ;
349+
350+ /* Apply redundant move elimination */
351+ if (redundant_move_elim (ir ))
352+ continue ;
269353 }
270354 }
271355 }
0 commit comments