@@ -242,6 +242,84 @@ bool insn_fusion(ph2_ir_t *ph2_ir)
242
242
return false;
243
243
}
244
244
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
+
245
323
/* Main peephole optimization driver.
246
324
* It iterates through all functions, basic blocks, and IR instructions to apply
247
325
* local optimizations on adjacent instruction pairs.
@@ -265,7 +343,13 @@ void peephole(void)
265
343
continue ;
266
344
}
267
345
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 ;
269
353
}
270
354
}
271
355
}
0 commit comments