Skip to content

Commit 077113f

Browse files
committed
Add dead code elimination for unreachable blocks
This commit implements dead code elimination that works in conjunction with SCCP to remove unreachable code after constant propagation and branch folding. These optimizations target code that becomes dead after constant propagation, such as: - Branches with constant conditions (if(1), if(0)) - Instructions that are immediately overwritten - Unreachable code blocks after branch folding
1 parent db3c389 commit 077113f

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

src/peephole.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,13 +320,129 @@ bool redundant_move_elim(ph2_ir_t *ph2_ir)
320320
return false;
321321
}
322322

323+
/* Simple dead instruction elimination within basic blocks.
324+
* Removes instructions whose results are never used (dead stores).
325+
* Works in conjunction with existing SSA-based DCE.
326+
*/
327+
bool eliminate_dead_instructions(func_t *func)
328+
{
329+
if (!func || !func->bbs)
330+
return false;
331+
332+
bool changed = false;
333+
334+
for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) {
335+
ph2_ir_t *ir = bb->ph2_ir_list.head;
336+
while (ir && ir->next) {
337+
ph2_ir_t *next = ir->next;
338+
339+
/* Check if next instruction immediately overwrites this one's
340+
* result */
341+
if (ir->op == OP_load_constant && next->op == OP_load_constant &&
342+
ir->dest == next->dest) {
343+
/* Consecutive constant loads to same register - first is dead
344+
*/
345+
ir->next = next->next;
346+
if (next == bb->ph2_ir_list.tail) {
347+
bb->ph2_ir_list.tail = ir;
348+
}
349+
changed = true;
350+
continue;
351+
}
352+
353+
/* Check for dead arithmetic results */
354+
if ((ir->op == OP_add || ir->op == OP_sub || ir->op == OP_mul) &&
355+
next->op == OP_assign && ir->dest == next->dest) {
356+
/* Arithmetic result immediately overwritten by assignment */
357+
ir->next = next->next;
358+
if (next == bb->ph2_ir_list.tail) {
359+
bb->ph2_ir_list.tail = ir;
360+
}
361+
changed = true;
362+
continue;
363+
}
364+
365+
ir = ir->next;
366+
}
367+
}
368+
369+
return changed;
370+
}
371+
372+
/* Simple constant folding for branches after SCCP.
373+
* Converts branches with obvious constant conditions to jumps.
374+
* Very conservative to maintain bootstrap stability.
375+
*/
376+
bool fold_constant_branches(func_t *func)
377+
{
378+
if (!func || !func->bbs)
379+
return false;
380+
381+
bool changed = false;
382+
383+
for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) {
384+
if (!bb->ph2_ir_list.tail)
385+
continue;
386+
387+
ph2_ir_t *last = bb->ph2_ir_list.tail;
388+
389+
/* Only handle branches */
390+
if (last->op != OP_branch || last->src0 < 0)
391+
continue;
392+
393+
/* Look for immediately preceding constant load to the same register */
394+
ph2_ir_t *prev = bb->ph2_ir_list.head;
395+
ph2_ir_t *found = NULL;
396+
397+
/* Find the most recent constant load to the branch condition register
398+
*/
399+
while (prev && prev != last) {
400+
if (prev->op == OP_load_constant && prev->dest == last->src0) {
401+
found = prev;
402+
/* Keep looking - want the most recent load */
403+
}
404+
/* Stop if we see any other write to this register */
405+
else if (prev->dest == last->src0) {
406+
found = NULL; /* Register was modified, can't fold */
407+
}
408+
prev = prev->next;
409+
}
410+
411+
if (found) {
412+
/* Found constant condition - convert branch to jump */
413+
int const_val = found->src0;
414+
415+
/* Just change the opcode, don't modify CFG edges directly */
416+
last->op = OP_jump;
417+
418+
if (const_val != 0) {
419+
/* Always take then branch */
420+
last->next_bb = bb->then_;
421+
} else {
422+
/* Always take else branch */
423+
last->next_bb = bb->else_;
424+
}
425+
426+
/* Don't modify src0 or CFG edges - let later passes handle it */
427+
changed = true;
428+
}
429+
}
430+
431+
return changed;
432+
}
433+
323434
/* Main peephole optimization driver.
324435
* It iterates through all functions, basic blocks, and IR instructions to apply
325436
* local optimizations on adjacent instruction pairs.
326437
*/
327438
void peephole(void)
328439
{
329440
for (func_t *func = FUNC_LIST.head; func; func = func->next) {
441+
/* Phase 1: Dead code elimination working with SCCP results */
442+
eliminate_dead_instructions(func);
443+
fold_constant_branches(func);
444+
445+
/* Phase 2: Local peephole optimizations */
330446
for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) {
331447
for (ph2_ir_t *ir = bb->ph2_ir_list.head; ir; ir = ir->next) {
332448
ph2_ir_t *next = ir->next;

0 commit comments

Comments
 (0)