[llvm-bugs] [Bug 45283] New: LLVM emits extra jump instructions when invokes share an unreachable normal destination
via llvm-bugs
llvm-bugs at lists.llvm.org
Mon Mar 23 12:17:18 PDT 2020
https://bugs.llvm.org/show_bug.cgi?id=45283
Bug ID: 45283
Summary: LLVM emits extra jump instructions when invokes share
an unreachable normal destination
Product: libraries
Version: trunk
Hardware: PC
OS: All
Status: NEW
Severity: enhancement
Priority: P
Component: Common Code Generator Code
Assignee: unassignedbugs at nondot.org
Reporter: rnk at google.com
CC: aeubanks at google.com, akhuang at google.com,
hans at chromium.org, llvm-bugs at lists.llvm.org,
matze at braunis.de, nicolasweber at gmx.de,
quentin.colombet at gmail.com
Consider this example:
$ cat t.cpp
struct HasCleanup {
~HasCleanup();
};
extern "C" void mythrow1();
extern "C" void mythrow2();
extern "C" void mythrow3();
extern "C" int multi_throw(bool c1, bool c2, bool c3) {
HasCleanup obj;
if (c1) {
mythrow1();
goto unreachable;
}
if (c2) {
mythrow2();
goto unreachable;
}
if (c3) {
mythrow3();
goto unreachable;
}
return 0;
unreachable:
__builtin_unreachable();
}
Clang emits extra branches after each call to mythrowN:
$ clang -S -O1 t.cpp -o - | grep -A3 mythrow
callq mythrow1
.Ltmp5:
jmp .LBB0_7
.LBB0_4: # %if.then4
--
callq mythrow2
.Ltmp3:
jmp .LBB0_7
.LBB0_6: # %if.then8
--
callq mythrow3
.Ltmp1:
.LBB0_7: # %unreachable
.LBB0_2: # %lpad
I encountered this issue because Clang uses the same IR pattern to emit calls
to C++ throw expressions. See the code that uses `getUnreachableBlock` here:
https://github.com/llvm/llvm-project/blob/master/clang/lib/CodeGen/CGCall.cpp#L3794
C++ source & asm:
$ cat b.cpp
struct HasCleanup { ~HasCleanup(); };
extern "C" int multi_throw(bool c1, bool c2, bool c3) {
HasCleanup obj;
if (c1)
throw 1;
if (c2)
throw 2;
if (c3)
throw 3;
return 0;
}
$ clang -S -O1 b.cpp -o - | grep -A3 call.*throw
callq __cxa_throw
.Ltmp5:
jmp .LBB0_7
.LBB0_4: # %if.then4
--
callq __cxa_throw
.Ltmp3:
jmp .LBB0_7
.LBB0_6: # %if.then8
--
callq __cxa_throw
.Ltmp1:
.LBB0_7: # %unreachable
.LBB0_2: # %lpad
We could teach clang not to use this IR pattern, but the first example shows
that this is an LLVM issue too.
There are a few possible places to fix this:
- Clang: Most users probably don't write code like example 1, more like example
2, so we could change the generated IR and declare victory.
- SimplifyCFG: This pass already does a lot of unreachable handling. However,
this would increase the BB count and instruction count, so it could be
considered non-canonical. Then again, we don't canonicalize in the opposite
direction by tail merging in the IR. I did have a patch for this
(https://reviews.llvm.org/D29428), but the results were not promising.
- CodeGenPrepare: We do some CFG adjustment here already, but we'd need a new
loop over all BBs just for this. It doesn't fit into the existing transforms.
This would be limited to, duplicate unreachable BBs after invokes. We'd have to
think about dbg.values as well.
- ISel: We already have handling for switch () { default: unreachable; }, so we
could handle invoke unreachable. I tried this locally, but it seems to cause
bugs in machine CFG passes like branch folding. We end up with an MBB with one
successor, but no terminator instruction, and passes try to merge the landing
pad into the throwing block. Also, it would need to be done in SDISel and
GlobalISel. Maybe these issues are related to https://llvm.org/pr27659.
See also https://llvm.org/PR45064#c4, where this code pattern caused issues
with the win64 unwinder.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200323/9f351efa/attachment.html>
More information about the llvm-bugs
mailing list