[llvm-dev] LLVM Pass To Remove Dead Code In A Basic Block

Aaron via llvm-dev llvm-dev at lists.llvm.org
Fri May 25 14:24:13 PDT 2018


> I’m just wondering why not have a ‘br’ to an exit basic block instead of
‘ret’ mid-stream of instructions.
> Have you considered this approach instead?

Thanks for bringing this up.

Yes. In fact, I tried that approach/pattern first. Simply, you create
default exit block and a local return variable (to track return value) per
function, but it requires extra flags and variables to track function exit
block and return value anytime during code generation (which my approach
does not need to do these).

When generating code, every time you see a return instruction, you store
return value into that local variable (if it returns a value) and create
branch instruction to function's exit block. Then function can generate
return instruction by using local return variable or just ret void.

entry:
  <this is the entry block>
  <alloc local return variable>
  <…>
  <store return value into local return variable, if returns a value>
  br .exit

.bb0:
  <this is by definition unreachable>
  <…>
  <store return value into local return variables, if returns a value>
  br .exit

.exit:
  ret <local return value> OR ret void.


But this approach still does not resolve the issue I had. Front-end still
can create multiple "br" instruction per block. Now we hit the original
problem: we can't create multiple terminator instructions in a block.

One or the other pattern could have advantages based on language spec or
the way you implement front-end. Who knows, I may want to return back to
this approach in the future if creates better advantages. I'm constantly
considering alternatives. The simplest / cleanest design wins.

Best,

Aaron


On Fri, May 25, 2018 at 1:41 AM, Dean Michael Berris <dean.berris at gmail.com>
wrote:

>
> > On 25 May 2018, at 03:53, Aaron <acraft at gmail.com> wrote:
> >
> > Hi Dean,
> >
> > Thanks for your reply.
> >
> > That's exactly what I am doing, but I was looking for a default
> optimization or pass implementation if there was.
> >
>
> There’s a dead code elimination pass, but it works with a control flow
> graph (it removes basic blocks that are unreachable after constant
> propagation and other passes earlier on have run).
>
> > I used BasicBlock::splitBasicBlock() but it puts "br" end of original
> basic block. I tried to delete the br instruction by using
> eraseFromParent() but it didn't work.
> >
>
> This is working as intended. All LLVM BasicBlocks *must* have a terminator
> as the last instruction.
>
> > I had to rewrite my own splitBasicBlock() by modifying the original one.
> Just removed the br instruction creation lines.
> >
>
> It sounds like it would have just been easier to replace the branch
> instruction into a ret, then remove all successors of the original br
> instruction. There’s nothing special here, this is how it’s supposed to be
> done.
>
> > >> Just curious, how are you getting return instructions in the middle
> of a basic block?
> > My code generation pass allows multiple return instruction generation
> since that simplifies front-end significantly.
> >
>
> I’m just wondering why not have a ‘br’ to an exit basic block instead of
> ‘ret’ mid-stream of instructions. That way you don’t need to do any special
> post-processing while you’re emitting the LLVM IR, you end up with valid
> basic blocks all the time, and you can leverage all the other passes that
> come with LLVM already.
>
> That at least sounds simpler to me.
>
> I’m not sure whether you can have non-entry blocks with no predecessors in
> LLVM (need to look up the langref about that) but I can imagine it’s a
> fairly useful construct to support. e.g. something like (pseudo-IR):
>
> .entry:
>   <this is the entry block>
>   <…>
>   br .exit
>
> .bb0:
>   <this is by definition unreachable>
>   <…>
>   br .exit
>
> .exit:
>   ret
>
> This structure makes it easier for dead code elimination to determine that
> .bb0 is unreachable from .entry and can elide it safely. From your
> front-end, you can have a single ‘.exit’ block in a function and let the
> optimisations do the basic-block merging later on.
>
> Have you considered this approach instead?
>
> -- Dean
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180525/5d24213b/attachment.html>


More information about the llvm-dev mailing list