@@ -1538,6 +1538,75 @@ bool const_folding(insn_t *insn)
1538
1538
return false;
1539
1539
}
1540
1540
1541
+ /* Dead code detection helper */
1542
+ bool is_side_effect_free (insn_t * insn )
1543
+ {
1544
+ /* Instructions that have no side effects and can be eliminated if unused */
1545
+ switch (insn -> opcode ) {
1546
+ case OP_load_constant :
1547
+ case OP_add :
1548
+ case OP_sub :
1549
+ case OP_mul :
1550
+ case OP_div :
1551
+ case OP_mod :
1552
+ case OP_lshift :
1553
+ case OP_rshift :
1554
+ case OP_bit_and :
1555
+ case OP_bit_or :
1556
+ case OP_bit_xor :
1557
+ case OP_bit_not :
1558
+ case OP_negate :
1559
+ case OP_log_and :
1560
+ case OP_log_or :
1561
+ case OP_log_not :
1562
+ case OP_eq :
1563
+ case OP_neq :
1564
+ case OP_lt :
1565
+ case OP_leq :
1566
+ case OP_gt :
1567
+ case OP_geq :
1568
+ case OP_read :
1569
+ case OP_assign :
1570
+ case OP_load_data_address :
1571
+ return true;
1572
+ default :
1573
+ return false;
1574
+ }
1575
+ }
1576
+
1577
+ /* Check if instruction result is never used */
1578
+ bool is_result_dead (insn_t * insn )
1579
+ {
1580
+ if (!insn -> rd )
1581
+ return false;
1582
+
1583
+ /* Check if the result variable is never used after this instruction */
1584
+ var_t * var = insn -> rd ;
1585
+ insn_t * next = insn -> next ;
1586
+ bool found_use = false;
1587
+
1588
+ /* Scan forward in the basic block */
1589
+ while (next && next -> belong_to == insn -> belong_to ) {
1590
+ if ((next -> rs1 && next -> rs1 == var ) ||
1591
+ (next -> rs2 && next -> rs2 == var )) {
1592
+ found_use = true;
1593
+ break ;
1594
+ }
1595
+ /* Check if variable is redefined without being used */
1596
+ if (next -> rd && next -> rd == var ) {
1597
+ /* Variable redefined before use - original is dead */
1598
+ return true;
1599
+ }
1600
+ next = next -> next ;
1601
+ }
1602
+
1603
+ /* If not used in current block and not global, it's likely dead */
1604
+ if (!found_use && !var -> is_global )
1605
+ return true;
1606
+
1607
+ return false;
1608
+ }
1609
+
1541
1610
/* initial mark useful instruction */
1542
1611
int dce_init_mark (insn_t * insn , insn_t * work_list [], int work_list_idx )
1543
1612
{
@@ -1576,6 +1645,15 @@ int dce_init_mark(insn_t *insn, insn_t *work_list[], int work_list_idx)
1576
1645
mark_num ++ ;
1577
1646
}
1578
1647
break ;
1648
+ /* Mark branches and jumps as initially useful */
1649
+ case OP_branch :
1650
+ case OP_jump :
1651
+ /* Will be re-evaluated later for dead branch elimination */
1652
+ insn -> useful = true;
1653
+ insn -> belong_to -> useful = true;
1654
+ work_list [work_list_idx + mark_num ] = insn ;
1655
+ mark_num ++ ;
1656
+ break ;
1579
1657
default :
1580
1658
if (!insn -> rd )
1581
1659
break ;
@@ -1586,6 +1664,13 @@ int dce_init_mark(insn_t *insn, insn_t *work_list[], int work_list_idx)
1586
1664
work_list [work_list_idx + mark_num ] = insn ;
1587
1665
mark_num ++ ;
1588
1666
}
1667
+ /* Skip marking if result is provably dead */
1668
+ else if (!is_result_dead (insn ) && !is_side_effect_free (insn )) {
1669
+ insn -> useful = true;
1670
+ insn -> belong_to -> useful = true;
1671
+ work_list [work_list_idx + mark_num ] = insn ;
1672
+ mark_num ++ ;
1673
+ }
1589
1674
break ;
1590
1675
}
1591
1676
return mark_num ;
@@ -1644,13 +1729,22 @@ void dce_insn(basic_block_t *bb)
1644
1729
}
1645
1730
}
1646
1731
1732
+
1647
1733
void dce_sweep (void )
1648
1734
{
1649
1735
for (func_t * func = FUNC_LIST .head ; func ; func = func -> next ) {
1650
1736
for (basic_block_t * bb = func -> bbs ; bb ; bb = bb -> rpo_next ) {
1651
- for (insn_t * insn = bb -> insn_list .head ; insn ; insn = insn -> next ) {
1652
- if (insn -> useful )
1737
+ insn_t * insn = bb -> insn_list .head ;
1738
+ insn_t * next ;
1739
+
1740
+ while (insn ) {
1741
+ next = insn -> next ;
1742
+
1743
+ if (insn -> useful ) {
1744
+ insn = next ;
1653
1745
continue ;
1746
+ }
1747
+
1654
1748
/* If a branch instruction is useless, redirect to the
1655
1749
* reverse immediate dominator of this basic block and
1656
1750
* remove the branch instruction. Later, register allocation
@@ -1669,15 +1763,42 @@ void dce_sweep(void)
1669
1763
}
1670
1764
}
1671
1765
1766
+ /* Additional check for dead stores */
1767
+ if (insn -> opcode == OP_write && insn -> rd && !insn -> useful ) {
1768
+ /* Check if this store is immediately overwritten */
1769
+ insn_t * check = insn -> next ;
1770
+ bool is_dead_store = false;
1771
+ while (check && check -> belong_to == bb ) {
1772
+ if (check -> opcode == OP_write &&
1773
+ check -> rd == insn -> rd ) {
1774
+ /* Found overwriting store - original is dead */
1775
+ is_dead_store = true;
1776
+ break ;
1777
+ }
1778
+ /* Stop if the value is read */
1779
+ if ((check -> rs1 && check -> rs1 == insn -> rd ) ||
1780
+ (check -> rs2 && check -> rs2 == insn -> rd )) {
1781
+ break ;
1782
+ }
1783
+ check = check -> next ;
1784
+ }
1785
+ if (is_dead_store )
1786
+ insn -> useful = false;
1787
+ }
1788
+
1672
1789
/* remove useless instructions */
1673
- if (insn -> next )
1674
- insn -> next -> prev = insn -> prev ;
1675
- else
1676
- bb -> insn_list .tail = insn -> prev ;
1677
- if (insn -> prev )
1678
- insn -> prev -> next = insn -> next ;
1679
- else
1680
- bb -> insn_list .head = insn -> next ;
1790
+ if (!insn -> useful ) {
1791
+ if (insn -> next )
1792
+ insn -> next -> prev = insn -> prev ;
1793
+ else
1794
+ bb -> insn_list .tail = insn -> prev ;
1795
+ if (insn -> prev )
1796
+ insn -> prev -> next = insn -> next ;
1797
+ else
1798
+ bb -> insn_list .head = insn -> next ;
1799
+ }
1800
+
1801
+ insn = next ;
1681
1802
}
1682
1803
}
1683
1804
}
@@ -1689,8 +1810,6 @@ void build_reversed_rpo();
1689
1810
void simple_copy_propagation (basic_block_t * bb );
1690
1811
void redundant_load_elimination (basic_block_t * bb );
1691
1812
void dead_store_elimination (basic_block_t * bb );
1692
-
1693
- /* Enhanced optimization function declarations */
1694
1813
bool enhanced_const_fold (insn_t * insn );
1695
1814
1696
1815
void optimize (void )
0 commit comments