[PATCH] D13274: [WinEH] Clone funclets with multiple parents

Andy Kaylor via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 6 10:24:04 PST 2015


andrew.w.kaylor added a comment.

I understood that iterating sets and maps was not deterministic and thought I had accounted for that.  There are several places in this code where the non-determinism is OK because it doesn't lead to non-deterministic output.  I just had one bug where I was looking at unwind edges that hadn't been processed yet.

In any event, reverting was the right thing to do.  I should have this ready to go back in shortly.


================
Comment at: lib/CodeGen/WinEHPrepare.cpp:856-860
@@ +855,7 @@
+//
+// If the terminator is a catchret its successor is a block in its parent
+// funclet.  If the instruction returns to a block in the parent for which the
+// cloned funclet was created, the terminator in the original block must be
+// replaced by an unreachable instruction.  Otherwise the terminator in the
+// clone block must be replaced by an unreachable instruction.
+//
----------------
andrew.w.kaylor wrote:
> JosephTremoulet wrote:
> > Do the new tests cover these cases?  I.e. where funclet A includes a branch to block Shared, and funclet B has child catch funclet C, and Shared is the target of the catchret from C back to B?
> I don't think so.  I'll add something.
This isn't working and I'm not sure how it should be handled.  Consider the following function:

```
define void @test13() personality i32 (...)* @__CxxFrameHandler3 {
entry:
  invoke void @f()
    to label %invoke.cont unwind label %left
invoke.cont:
  invoke void @f()
    to label %exit unwind label %right
left:
  %l = catchpad []
    to label %left.cont unwind label %left.end
left.cont:
  invoke void @f()
    to label %left.ret unwind label %inner
left.ret:
  catchret %l to label %invoke.cont
left.end:
  catchendpad unwind to caller
right:
  %r = catchpad []
    to label %right.catch unwind label %right.end
right.catch:
  invoke void @f()
    to label %right.ret unwind label %inner
right.ret:
  catchret %r to label %exit
right.end:
  catchendpad unwind to caller
shared:
  call void @h(i32 0)
  unreachable
inner:
  %i = catchpad []
    to label %inner.catch unwind label %inner.end
inner.catch:
  call void @h(i32 1)
  catchret %i to label %shared
inner.end:
  catchendpad unwind label %left.end
exit:
  ret void
}

```

The existing funclet coloring code will recognize that it needs a copy of %shared for both %left and %right, but because both are reached from the same catchret instruction one of the clones will be unreachable following cloneCommonBlocks().  Then when my new code gets to the point of cloning %inner it will remove the catchret in %inner.catch for whichever of the parents received the unreachable clone of %shared (because the reachable %shared belongs to the other funclet).

I could instead make yet another clone of %shared at this point, but that really just pushes the problem to the next block in cases where %shared has successors.  What I really need to do is to be able to find the unreachable clone.  Does that sound reasonable?


Repository:
  rL LLVM

http://reviews.llvm.org/D13274





More information about the llvm-commits mailing list