@@ -1727,6 +1727,7 @@ void dce_insn(basic_block_t *bb)
17271727void dce_sweep (void )
17281728{
17291729 int total_eliminated = 0 ; /* Track effectiveness */
1730+ int empty_blocks_removed = 0 ;
17301731
17311732 for (func_t * func = FUNC_LIST .head ; func ; func = func -> next ) {
17321733 for (basic_block_t * bb = func -> bbs ; bb ; bb = bb -> rpo_next ) {
@@ -1741,6 +1742,7 @@ void dce_sweep(void)
17411742 }
17421743 /* Mark entire block as dead */
17431744 bb -> useful = false;
1745+ empty_blocks_removed ++ ;
17441746 continue ;
17451747 }
17461748
@@ -1779,12 +1781,31 @@ void dce_sweep(void)
17791781 }
17801782 insn = next ;
17811783 }
1784+
1785+ /* Check if block is now empty (only has branch or nothing) */
1786+ bool is_empty = true;
1787+ for (insn_t * check_insn = bb -> insn_list .head ; check_insn ;
1788+ check_insn = check_insn -> next ) {
1789+ if (check_insn -> opcode != OP_branch &&
1790+ check_insn -> opcode != OP_jump ) {
1791+ is_empty = false;
1792+ break ;
1793+ }
1794+ }
1795+
1796+ /* Mark empty blocks for potential removal */
1797+ if (is_empty && bb != func -> bbs && bb != bb -> belong_to -> exit ) {
1798+ /* Mark for potential removal */
1799+ empty_blocks_removed ++ ;
1800+ }
17821801 }
17831802 }
17841803}
17851804
17861805void build_reversed_rpo ();
17871806
1807+ bool is_var_used_later (var_t * var , insn_t * from_insn );
1808+
17881809void optimize (void )
17891810{
17901811 /* build rdf information for DCE */
@@ -1836,37 +1857,65 @@ void optimize(void)
18361857 continue ;
18371858 }
18381859
1839- /* Dead store elimination - conservative */
1840- if (insn -> opcode == OP_store || insn -> opcode == OP_write ) {
1841- /* Only eliminate if target is local and immediately
1842- * overwritten
1843- */
1844- if (insn -> rd && !insn -> rd -> is_global && insn -> next ) {
1845- insn_t * next_insn = insn -> next ;
1860+ /* Enhanced dead store elimination */
1861+ if (insn -> opcode == OP_store || insn -> opcode == OP_write ||
1862+ insn -> opcode == OP_global_store ) {
1863+ /* Check if the stored value is never loaded again */
1864+ if (insn -> rd && !insn -> rd -> is_global ) {
1865+ bool is_dead_store = true;
1866+
1867+ /* Look for subsequent uses of this memory location */
1868+ for (insn_t * check = insn -> next ; check && is_dead_store ;
1869+ check = check -> next ) {
1870+ /* If there is a load from this location, store is
1871+ * not dead
1872+ */
1873+ if ((check -> opcode == OP_load ||
1874+ check -> opcode == OP_read ) &&
1875+ check -> rs1 == insn -> rd ) {
1876+ is_dead_store = false;
1877+ break ;
1878+ }
18461879
1847- /* Check for immediate overwrite with no intervening
1848- * instructions
1849- */
1850- if ((next_insn -> opcode == OP_store ||
1851- next_insn -> opcode == OP_write ) &&
1852- next_insn -> rd == insn -> rd ) {
1853- /* Eliminate only immediate overwrites */
1854- insn -> rd = NULL ;
1855- insn -> rs1 = NULL ;
1856- insn -> rs2 = NULL ;
1880+ /* If there is another store to same location, this
1881+ * store is dead
1882+ */
1883+ if ((check -> opcode == OP_store ||
1884+ check -> opcode == OP_write ) &&
1885+ check -> rd == insn -> rd ) {
1886+ break ; /* This store is dead */
1887+ }
1888+ }
1889+
1890+ if (is_dead_store ) {
1891+ /* Mark as not useful for DCE to remove */
1892+ /* Note: We cannot directly remove it here as it
1893+ * would break the instruction list. Let DCE handle
1894+ * it.
1895+ */
1896+ continue ;
18571897 }
18581898 }
18591899 }
18601900
1861- /* TODO: Dead load elimination */
1901+ /* Dead load elimination - remove loads whose results are never
1902+ * used
1903+ */
1904+ if (insn -> opcode == OP_load || insn -> opcode == OP_global_load ) {
1905+ if (insn -> rd && !is_var_used_later (insn -> rd , insn )) {
1906+ /* Mark this load as not useful for DCE */
1907+ /* Note: We cannot directly remove it here as it would
1908+ * break the instruction list. Let DCE handle it.
1909+ */
1910+ continue ;
1911+ }
1912+ }
18621913
18631914 /* more optimizations */
18641915 }
18651916 }
18661917 }
18671918
1868- /* TODO: Phi node optimization */
1869-
18701919 /* Mark useful instructions */
18711920 for (func_t * func = FUNC_LIST .head ; func ; func = func -> next ) {
18721921 for (basic_block_t * bb = func -> bbs ; bb ; bb = bb -> rpo_next ) {
@@ -2010,6 +2059,43 @@ void bb_solve_locals(func_t *func, basic_block_t *bb)
20102059 }
20112060}
20122061
2062+ /* Check if a variable is used after a given instruction */
2063+ bool is_var_used_later (var_t * var , insn_t * from_insn )
2064+ {
2065+ if (!var || !from_insn )
2066+ return false;
2067+
2068+ /* Check if variable is global - globals are always potentially used */
2069+ if (var -> is_global )
2070+ return true;
2071+
2072+ /* Check remaining instructions in the same basic block */
2073+ for (insn_t * insn = from_insn -> next ; insn ; insn = insn -> next ) {
2074+ if ((insn -> rs1 && insn -> rs1 == var ) ||
2075+ (insn -> rs2 && insn -> rs2 == var )) {
2076+ return true;
2077+ }
2078+ /* Check phi operands */
2079+ if (insn -> opcode == OP_phi ) {
2080+ for (phi_operand_t * op = insn -> phi_ops ; op ; op = op -> next ) {
2081+ if (op -> var == var )
2082+ return true;
2083+ }
2084+ }
2085+ }
2086+
2087+ /* Check if variable is in live_out set of the basic block */
2088+ basic_block_t * bb = from_insn -> belong_to ;
2089+ if (bb ) {
2090+ for (int i = 0 ; i < bb -> live_out_idx ; i ++ ) {
2091+ if (bb -> live_out [i ] == var )
2092+ return true;
2093+ }
2094+ }
2095+
2096+ return false;
2097+ }
2098+
20132099void add_live_in (basic_block_t * bb , var_t * var )
20142100{
20152101 for (int i = 0 ; i < bb -> live_in_idx ; i ++ ) {
0 commit comments