Search code examples
returnllvmcode-generation

How to force LLVM to generate a single 'ret'?


Consider the following LLVM IR:

@yyy = external dso_local global i32
@zzz = external dso_local global i64

define void @exec_xxx() {
entry:
  %0 = load i32, i32* @yyy, align 4
  %1 = icmp eq i32 %0, 0
  br i1 %1, label %bb_true, label %bb_false
bb_true:
  store i64 0, i64* @zzz, align 8
  br label %bb_false
bb_false:
  ret void
}

Here we see that it has a single ret. However, the generated code has multiple ret:

exec_xxx:                               # @exec_xxx
        cmp     dword ptr [rip + yyy], 0
        je      .LBB0_1
        ret
.LBB0_1:                                # %bb_true
        mov     qword ptr [rip + zzz], 0
        ret

By some reason one need a single ret in the generated code.

Question: how to force LLVM to generate a single ret?


Solution

  • The LLVMish answer to that is to write a pass. Passes is how LLVM modifies code.

    In this case that'll be really simple, you'll need a class declaration that inherits PassInfoMixin<> and reimplements run(Function &, FunctionAnalysisManager &). Your reimplementation should be 15-20 lines of code, I think.

    I'll outline it in case you haven't written a pass before. It needs to iterate over the basic blocks and see whether the terminator of each isa<ReturnInst>(), and add the ones that are to a list. After iterating you return early if there are fewer than two returns in the list.

    Otherwise you make a new basic block. If the return type isn't void you need to create a phi node and populate it with incoming values from the returns, then create a return that returns the phi node. If it's void you make a new void return. Finally you replace all the old returns with branches to your new block. Done.