Skip to content

[BasicBlockUtils] Remove broken support for eh pads in SplitEdge() #137816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2025

Conversation

nikic
Copy link
Contributor

@nikic nikic commented Apr 29, 2025

d81d9e8 changed SplitEdge() to make use of ehAwareSplitEdge() for critical edges where the target is an eh pad. However, the implementation is incorrect at least for landing pads. What is currently produced for the code in the modified unit test is something like this:

continue:
  invoke void @sink()
          to label %normal unwind label %new_bb

new_bb:
  %cp = cleanuppad within %exception []
  cleanupret from %cp unwind label %exception

exception:
  %cleanup = landingpad i8 cleanup
  br label %trivial-eh-handler

This mixes different exception handling mechanisms in a nonsensical way, and is not well-formed IR. To actually "split" the landingpad edge (for a rather loose definition of "split"), I think we'd have to generate something along these lines:

  exception.split:
    %cleanup.split = landingpad i8 cleanup
    br label %exception.cont

  exception:
    %cleanup.orig = landingpad i8 cleanup
    br label %exception.cont
  
  exception.cont:
    %cleanup = phi i8 [ %cleanup.split, %exception_split ], [ %cleanup.orig, %exception ]

I didn't bother actually implementing that, seeing as how nobody noticed the existing codegen being broken in the last four years, so clearly nobody actually needs this function to work with EH edges. Just return nullptr instead.

d81d9e8 changed SplitEdge() to
make use of ehAwareSplitEdge() for critical edges where the
target is an eh pad. However, the implementation is incorrect for
landing pads, because this requires passing additional information
to the function and performing non-local updates.

What is currently produced for the code in the modified unit test
is this:

    continue:
      invoke void @sink()
              to label %normal unwind label %0

    0:
      %1 = cleanuppad within %exception []
      cleanupret from %1 unwind label %exception

    exception:
      %cleanup = landingpad i8
              cleanup
      br label %trivial-eh-handler

This is not well-formed IR. To actually "split" the landingpad
edge we would have to do something along the lines of what CoroFrame
does, where we'd generate multiple landingpads, which then go to
a common phi in the original block.

I could try to implement this here, but I find it rather dubious
(we'd still have a landingpad at the start of the "split" edge so
it's not *really* "split") and clearly nobody actually uses
SplitEdge() on eh edges, because then somebody would have noticed
that it generates broken code.
@llvmbot
Copy link
Member

llvmbot commented Apr 29, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Nikita Popov (nikic)

Changes

d81d9e8 changed SplitEdge() to make use of ehAwareSplitEdge() for critical edges where the target is an eh pad. However, the implementation is incorrect at least for landing pads. What is currently produced for the code in the modified unit test is something like this:

continue:
  invoke void @<!-- -->sink()
          to label %normal unwind label %new_bb

new_bb:
  %cp = cleanuppad within %exception []
  cleanupret from %cp unwind label %exception

exception:
  %cleanup = landingpad i8 cleanup
  br label %trivial-eh-handler

This mixes different exception handling mechanisms in a nonsensical way, and is not well-formed IR. To actually "split" the landingpad edge (for a rather loose definition of "split"), I think we'd have to generate something along these lines:

  exception.split:
    %cleanup.split = landingpad i8 cleanup
    br label %exception.cont

  exception:
    %cleanup.orig = landingpad i8 cleanup
    br label %exception.cont
  
  exception.cont:
    %cleanup = phi i8 [ %cleanup.split, %exception_split ], [ %cleanup.orig, %exception ]

I didn't bother actually implementing that, seeing as how nobody noticed the existing codegen being broken in the last four years, so clearly nobody actually needs this function to work with EH edges. Just return nullptr instead.


Full diff: https://github.com/llvm/llvm-project/pull/137816.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Utils/BasicBlockUtils.cpp (-5)
  • (modified) llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp (+2-16)
diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index 429037ab9da47..dce10c0ecd56c 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -768,11 +768,6 @@ BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT,
       CriticalEdgeSplittingOptions(DT, LI, MSSAU).setPreserveLCSSA();
 
   if ((isCriticalEdge(LatchTerm, SuccNum, Options.MergeIdenticalEdges))) {
-    // If it is a critical edge, and the succesor is an exception block, handle
-    // the split edge logic in this specific function
-    if (Succ->isEHPad())
-      return ehAwareSplitEdge(BB, Succ, nullptr, nullptr, Options, BBName);
-
     // If this is a critical edge, let SplitKnownCriticalEdge do it.
     return SplitKnownCriticalEdge(LatchTerm, SuccNum, Options, BBName);
   }
diff --git a/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp b/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp
index c9a6a32851775..e58daed887855 100644
--- a/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp
+++ b/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp
@@ -285,22 +285,8 @@ declare void @sink_alt() cold
   EXPECT_TRUE(Ehpad);
 
   BasicBlock *NewBB = SplitEdge(SrcBlock, DestBlock, &DT, &LI, &MSSAU, "");
-
-  MSSA.verifyMemorySSA();
-  EXPECT_TRUE(DT.verify());
-  EXPECT_NE(NewBB, nullptr);
-  EXPECT_EQ(NewBB->getSinglePredecessor(), SrcBlock);
-  EXPECT_EQ(NewBB, SrcBlock->getTerminator()->getSuccessor(SuccNum));
-  EXPECT_EQ(NewBB->getParent(), F);
-
-  bool BBFlag = false;
-  for (BasicBlock &BB : *F) {
-    if (BB.getName() == NewBB->getName()) {
-      BBFlag = true;
-      break;
-    }
-  }
-  EXPECT_TRUE(BBFlag);
+  // SplitEdge cannot split an eh pad edge.
+  EXPECT_EQ(NewBB, nullptr);
 }
 
 TEST(BasicBlockUtils, splitBasicBlockBefore_ex1) {

Copy link
Collaborator

@efriedma-quic efriedma-quic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nikic nikic merged commit c96f019 into llvm:main Apr 30, 2025
13 checks passed
@nikic nikic deleted the no-eh-edge-split branch April 30, 2025 07:07
nikic added a commit to nikic/llvm-project that referenced this pull request Apr 30, 2025
After llvm#137799 and
llvm#137816, instruction uses
of BasicBlocks are always terminators, so assert that instead of
checking it.
nikic added a commit that referenced this pull request Apr 30, 2025
After #137799 and
#137816, instruction uses of
BasicBlocks are always terminators, so assert that instead of checking
it.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#137816)

d81d9e8 changed SplitEdge() to make use
of ehAwareSplitEdge() for critical edges where the target is an eh pad.
However, the implementation is incorrect at least for landing pads. What
is currently produced for the code in the modified unit test is
something like this:

    continue:
      invoke void @sink()
              to label %normal unwind label %new_bb

    new_bb:
      %cp = cleanuppad within %exception []
      cleanupret from %cp unwind label %exception

    exception:
      %cleanup = landingpad i8 cleanup
      br label %trivial-eh-handler

This mixes different exception handling mechanisms in a nonsensical way,
and is not well-formed IR. To actually "split" the landingpad edge (for
a rather loose definition of "split"), I think we'd have to generate
something along these lines:

      exception.split:
        %cleanup.split = landingpad i8 cleanup
        br label %exception.cont

      exception:
        %cleanup.orig = landingpad i8 cleanup
        br label %exception.cont
      
      exception.cont:
%cleanup = phi i8 [ %cleanup.split, %exception_split ], [ %cleanup.orig,
%exception ]

I didn't bother actually implementing that, seeing as how nobody noticed
the existing codegen being broken in the last four years, so clearly
nobody actually needs this function to work with EH edges. Just return
nullptr instead.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
After llvm#137799 and
llvm#137816, instruction uses of
BasicBlocks are always terminators, so assert that instead of checking
it.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#137816)

d81d9e8 changed SplitEdge() to make use
of ehAwareSplitEdge() for critical edges where the target is an eh pad.
However, the implementation is incorrect at least for landing pads. What
is currently produced for the code in the modified unit test is
something like this:

    continue:
      invoke void @sink()
              to label %normal unwind label %new_bb

    new_bb:
      %cp = cleanuppad within %exception []
      cleanupret from %cp unwind label %exception

    exception:
      %cleanup = landingpad i8 cleanup
      br label %trivial-eh-handler

This mixes different exception handling mechanisms in a nonsensical way,
and is not well-formed IR. To actually "split" the landingpad edge (for
a rather loose definition of "split"), I think we'd have to generate
something along these lines:

      exception.split:
        %cleanup.split = landingpad i8 cleanup
        br label %exception.cont

      exception:
        %cleanup.orig = landingpad i8 cleanup
        br label %exception.cont
      
      exception.cont:
%cleanup = phi i8 [ %cleanup.split, %exception_split ], [ %cleanup.orig,
%exception ]

I didn't bother actually implementing that, seeing as how nobody noticed
the existing codegen being broken in the last four years, so clearly
nobody actually needs this function to work with EH edges. Just return
nullptr instead.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
After llvm#137799 and
llvm#137816, instruction uses of
BasicBlocks are always terminators, so assert that instead of checking
it.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#137816)

d81d9e8 changed SplitEdge() to make use
of ehAwareSplitEdge() for critical edges where the target is an eh pad.
However, the implementation is incorrect at least for landing pads. What
is currently produced for the code in the modified unit test is
something like this:

    continue:
      invoke void @sink()
              to label %normal unwind label %new_bb

    new_bb:
      %cp = cleanuppad within %exception []
      cleanupret from %cp unwind label %exception

    exception:
      %cleanup = landingpad i8 cleanup
      br label %trivial-eh-handler

This mixes different exception handling mechanisms in a nonsensical way,
and is not well-formed IR. To actually "split" the landingpad edge (for
a rather loose definition of "split"), I think we'd have to generate
something along these lines:

      exception.split:
        %cleanup.split = landingpad i8 cleanup
        br label %exception.cont

      exception:
        %cleanup.orig = landingpad i8 cleanup
        br label %exception.cont
      
      exception.cont:
%cleanup = phi i8 [ %cleanup.split, %exception_split ], [ %cleanup.orig,
%exception ]

I didn't bother actually implementing that, seeing as how nobody noticed
the existing codegen being broken in the last four years, so clearly
nobody actually needs this function to work with EH edges. Just return
nullptr instead.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
After llvm#137799 and
llvm#137816, instruction uses of
BasicBlocks are always terminators, so assert that instead of checking
it.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 6, 2025
…7931)

After llvm/llvm-project#137799 and
llvm/llvm-project#137816, instruction uses of
BasicBlocks are always terminators, so assert that instead of checking
it.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
…lvm#137816)

d81d9e8 changed SplitEdge() to make use
of ehAwareSplitEdge() for critical edges where the target is an eh pad.
However, the implementation is incorrect at least for landing pads. What
is currently produced for the code in the modified unit test is
something like this:

    continue:
      invoke void @sink()
              to label %normal unwind label %new_bb

    new_bb:
      %cp = cleanuppad within %exception []
      cleanupret from %cp unwind label %exception

    exception:
      %cleanup = landingpad i8 cleanup
      br label %trivial-eh-handler

This mixes different exception handling mechanisms in a nonsensical way,
and is not well-formed IR. To actually "split" the landingpad edge (for
a rather loose definition of "split"), I think we'd have to generate
something along these lines:

      exception.split:
        %cleanup.split = landingpad i8 cleanup
        br label %exception.cont

      exception:
        %cleanup.orig = landingpad i8 cleanup
        br label %exception.cont
      
      exception.cont:
%cleanup = phi i8 [ %cleanup.split, %exception_split ], [ %cleanup.orig,
%exception ]

I didn't bother actually implementing that, seeing as how nobody noticed
the existing codegen being broken in the last four years, so clearly
nobody actually needs this function to work with EH edges. Just return
nullptr instead.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
After llvm#137799 and
llvm#137816, instruction uses of
BasicBlocks are always terminators, so assert that instead of checking
it.
Ankur-0429 pushed a commit to Ankur-0429/llvm-project that referenced this pull request May 9, 2025
…lvm#137816)

d81d9e8 changed SplitEdge() to make use
of ehAwareSplitEdge() for critical edges where the target is an eh pad.
However, the implementation is incorrect at least for landing pads. What
is currently produced for the code in the modified unit test is
something like this:

    continue:
      invoke void @sink()
              to label %normal unwind label %new_bb

    new_bb:
      %cp = cleanuppad within %exception []
      cleanupret from %cp unwind label %exception

    exception:
      %cleanup = landingpad i8 cleanup
      br label %trivial-eh-handler

This mixes different exception handling mechanisms in a nonsensical way,
and is not well-formed IR. To actually "split" the landingpad edge (for
a rather loose definition of "split"), I think we'd have to generate
something along these lines:

      exception.split:
        %cleanup.split = landingpad i8 cleanup
        br label %exception.cont

      exception:
        %cleanup.orig = landingpad i8 cleanup
        br label %exception.cont
      
      exception.cont:
%cleanup = phi i8 [ %cleanup.split, %exception_split ], [ %cleanup.orig,
%exception ]

I didn't bother actually implementing that, seeing as how nobody noticed
the existing codegen being broken in the last four years, so clearly
nobody actually needs this function to work with EH edges. Just return
nullptr instead.
Ankur-0429 pushed a commit to Ankur-0429/llvm-project that referenced this pull request May 9, 2025
After llvm#137799 and
llvm#137816, instruction uses of
BasicBlocks are always terminators, so assert that instead of checking
it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants