[RISCV] redundant return-only BB not eliminated

Robert Guthrie forkbombidable@gmail.com
Sun Sep 6 19:06:21 GMT 2026


On Fri, Sep 04, 2026 at 10:20:37AM -0600, Jeff Law wrote:
>
>
>On 9/3/26 7:13 PM, Robert Guthrie wrote:
>>>It's likely harder than a typical "simple hack of the week" as 
>>>those often end up being target patterns or match.pd patterns -- 
>>>so limited in how many APIs you need to understand, much less RTL 
>>>or gimple IL parsing, etc.  But there's folks here that can help.
>>>
>>
>>That is true: it has been a little harder than I expected!
>>Since I am modifying cleanup_cfg, and it is called so many times,
>>I am getting a lot of weird interactions leading to infinite loops or
>>other errors. Or getting different behavior when it is called in 
>>CFGRTL vs. CFGLAYOUT
>>mode (I spent last evening trying to grok the difference).
>>Maybe this is just something to tag onto the end of bbro rather than 
>>adding it
>>to a core function instead?
>But it fits fairly naturally in cfg cleanup and thinking more about 
>it, it should work irrespective of whether we're in cfg layout mode or 
>not if we do the cfg manipulations correctly.
>
>The whole point of splitting out the two modes is to allow earlier 
>passes to ignore the low level mechanics of dealing with fallthru 
>edges and the like.
>
>Conceptually a block ending in a return can have its return removed 
>and the cfg altered so that it has a fallthru edge to a block that has 
>a return and nothing else.   This is true before and after cfg layout 
>mode.
>

Ok, I have had a couple more evenings to dig at this.
I feel like something like the diff below is quite simple and works?
Let me explain how I got here for some context:

* First, I started unaware there was a difference between RTL and Layout mode.
   Whatever I was doing was not handling Fallthru correctly.
* Next, I tried to change how I handled Fallthrus, and it was breaking Layout mode
   (mainly because the EDGE_FALLTHRU flag means different things)
* I ignored Layout mode for a bit and tried to just get RTL mode working.
   I was doing what you originally suggested: delete the first block and redirect its successors
   to the second one. I was having a lot of trouble with Fallthrus, such as:
   - the infinite loop I had was: I was accidentally creating fwding blocks, which were just an
     unconditional jump-to-ret. Another transformation in `try_optimize_cfg` turned that back into a
     ret, which then hit my transform again...
   - in some cases, the fallthru predecessor of the first ret-only block was also jumping
     to the second ret-only, so whatever code I had ended up with duplicate edges
     (e.g, if I had BB ret-only blocks 4 and 5, and 3->4 and 3->5, then deleting 4 and redirecting 3->4 to 3->5
     created a dupe)

I suppose these things are in principle able to be handled, but rather than whack-a-mole instead I just deleted the second block,
redirecting its precessors to the first, which got rid of all the Fallthru problems (since there necessarily are not fallthrus).
Then, I think it also works in Layout mode as well, and it is ultimately pretty simple.
This bootstrapped correctly (on x86, I ordered a RISC-V dev board but haven't gotten it yet, though it solves my original problem too when I build cross).
I need to learn how to add good test cases before submitting as a formal patch, I am just dropping the diff
below:

diff --git a/gcc/cfgcleanup.cc b/gcc/cfgcleanup.cc
index 1d9ec908dab..d74bfcf10e2 100644
--- a/gcc/cfgcleanup.cc
+++ b/gcc/cfgcleanup.cc
@@ -2831,14 +2831,39 @@ try_optimize_cfg (int mode)
  		      redirect_edge_succ (single_succ_edge (b),
  					  EXIT_BLOCK_PTR_FOR_FN (cfun));
  		      single_succ_edge (b)->flags &= ~EDGE_CROSSING;
  		      changed_here = true;
  		    }
  		}
  
+	      /* If we have two consecutive return-only basic blocks,
+		 delete the second one, redirecting all of its predecessors
+		 to the first one.  */
+	      if (!(mode & CLEANUP_NO_INSN_DEL)
+		  && bb_is_just_return (b, &ret, &use)
+		  && bb_is_just_return (b->prev_bb, &ret, &use))
+		{
+		   basic_block pred = b->prev_bb;
+		   edge e;
+		   for (edge_iterator ei = ei_start (b->preds);
+			(e = ei_safe_edge (ei));)
+		     redirect_edge_and_branch_force (e, pred);
+
+		   if (dump_file)
+		     fprintf (dump_file,
+	       	       "deleted unnecessary ret-only block %d by "
+	       	       "re-targeting to %d\n",
+	       	       b->index, pred->index);
+
+		   delete_basic_block (b);
+		   changed = true;
+		   b = pred;
+		   continue;
+		}
+
  	      /* Try to change a conditional branch to a return to the
  		 respective conditional return.  */
  	      if (EDGE_COUNT (b->succs) == 2
  		  && any_condjump_p (BB_END (b))
  		  && bb_is_just_return (BRANCH_EDGE (b)->dest, &ret, &use))

One curiosity, I found a string of 3 ret's in symtab.o, which this only reduced to two, not one... I haven't debugged that one yet though.

>
>
>>
>>
>>BTW, I haven't gotten a response from gcc-bugzilla-account-request 
>>(not sure if that is typical,
>>I'm sure there is a lot of spam sadly) but I have not forgotten about it.
>They were swamped with yet another DDOS earlier this week.  They may 
>just be getting a little sleep.
>
>Jeff

Got it, no worries.

Thanks again
Robert


More information about the Gcc mailing list