[llvm] [WinEH] Emit state stores for SEH scopes (PR #116546)
Maurice Heumann via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 17 23:44:22 PST 2024
https://github.com/momo5502 updated https://github.com/llvm/llvm-project/pull/116546
>From 6ede329985d56c3a66f9ea4042c714849a00cf41 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann at gmail.com>
Date: Sun, 17 Nov 2024 15:52:01 +0100
Subject: [PATCH 1/3] [WinEH] Emit state stores before SEH scopes
---
llvm/lib/Target/X86/X86WinEHState.cpp | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp
index ef212736730114..e6aad3fa2a4fb1 100644
--- a/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -604,8 +604,18 @@ static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F,
return CommonState;
}
+static bool isSehScopeBegin(const CallBase &Call) {
+ const Function *CF = Call.getCalledFunction();
+ return CF && CF->isIntrinsic() &&
+ CF->getIntrinsicID() == Intrinsic::seh_scope_begin;
+}
+
bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality,
CallBase &Call) {
+ if (isSehScopeBegin(Call)) {
+ return true;
+ }
+
// If the function touches memory, it needs a state store.
if (isAsynchronousEHPersonality(Personality))
return !Call.doesNotAccessMemory();
>From 282680b4a789298fdcc2dfe693a2a3c47ab7fe7b Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann at gmail.com>
Date: Sun, 17 Nov 2024 17:23:50 +0100
Subject: [PATCH 2/3] [WinEH] Restore states after SEH scope end
---
llvm/lib/Target/X86/X86WinEHState.cpp | 31 +++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp
index e6aad3fa2a4fb1..d5bcbd2a08217d 100644
--- a/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -604,10 +604,17 @@ static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F,
return CommonState;
}
-static bool isSehScopeBegin(const CallBase &Call) {
+static bool isIntrinsic(const CallBase &Call, Intrinsic::ID ID) {
const Function *CF = Call.getCalledFunction();
- return CF && CF->isIntrinsic() &&
- CF->getIntrinsicID() == Intrinsic::seh_scope_begin;
+ return CF && CF->isIntrinsic() && CF->getIntrinsicID() == ID;
+}
+
+static bool isSehScopeEnd(const CallBase &Call) {
+ return isIntrinsic(Call, Intrinsic::seh_scope_end);
+}
+
+static bool isSehScopeBegin(const CallBase &Call) {
+ return isIntrinsic(Call, Intrinsic::seh_scope_begin);
}
bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality,
@@ -652,6 +659,8 @@ void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
DenseMap<BasicBlock *, int> InitialStates;
// FinalStates yields the state of the last call-site for a BasicBlock.
DenseMap<BasicBlock *, int> FinalStates;
+ // SEH scope end target blocks
+ SmallPtrSet<BasicBlock *, 4> ScopeEndBlocks;
// Worklist used to revisit BasicBlocks with indeterminate
// Initial/Final-States.
std::deque<BasicBlock *> Worklist;
@@ -663,7 +672,15 @@ void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
InitialState = FinalState = ParentBaseState;
for (Instruction &I : *BB) {
auto *Call = dyn_cast<CallBase>(&I);
- if (!Call || !isStateStoreNeeded(Personality, *Call))
+ if (!Call)
+ continue;
+
+ if (isSehScopeEnd(*Call)) {
+ auto *Invoke = cast<InvokeInst>(Call);
+ ScopeEndBlocks.insert(Invoke->getNormalDest());
+ }
+
+ if (!isStateStoreNeeded(Personality, *Call))
continue;
int State = getStateForCall(BlockColors, FuncInfo, *Call);
@@ -716,6 +733,12 @@ void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
FinalStates.insert({BB, SuccState});
}
+ // Insert state restores after SEH scope ends
+ for (BasicBlock *BB : ScopeEndBlocks) {
+ int state = getBaseStateForBB(BlockColors, FuncInfo, BB);
+ insertStateNumberStore(BB->getFirstNonPHI(), state);
+ }
+
// Finally, insert state stores before call-sites which transition us to a new
// state.
for (BasicBlock *BB : RPOT) {
>From 1f3e7d1f01c7fd5aa08d59d0420521c802d6c953 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann at gmail.com>
Date: Mon, 18 Nov 2024 08:43:52 +0100
Subject: [PATCH 3/3] [WinEH] Add test for SEH scope state stores
---
.../WinEH/wineh-scope-statenumbering.ll | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll
diff --git a/llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll b/llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll
new file mode 100644
index 00000000000000..40c59970faae12
--- /dev/null
+++ b/llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll
@@ -0,0 +1,46 @@
+; RUN: opt -mtriple=i386-pc-windows-msvc -S -x86-winehstate < %s | FileCheck %s
+
+target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.42.34433"
+
+%struct.Destructor = type { ptr }
+
+define dso_local void @"?HandleDestructorCallWithException@@YAXPA_N at Z"(ptr noundef %destructorCalled) personality ptr @__CxxFrameHandler3 {
+entry:
+ %destructorCalled.addr = alloca ptr, align 4
+ %x = alloca %struct.Destructor, align 4
+ store ptr %destructorCalled, ptr %destructorCalled.addr, align 4
+ %0 = load ptr, ptr %destructorCalled.addr, align 4
+ %call = call x86_thiscallcc noundef ptr @"??0Destructor@@QAE at PA_N@Z"(ptr noundef nonnull align 4 dereferenceable(4) %x, ptr noundef %0)
+ ; CHECK: store i32 0, ptr %9, align 4
+ ; CHECK-NEXT: invoke void @llvm.seh.scope.begin()
+ invoke void @llvm.seh.scope.begin()
+ to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:
+ store i32 1, ptr inttoptr (i32 1 to ptr), align 4
+ invoke void @llvm.seh.scope.end()
+ to label %invoke.cont1 unwind label %ehcleanup
+
+invoke.cont1:
+ ; CHECK: invoke.cont1:
+ ; CHECK-NEXT:%10 = getelementptr inbounds nuw %CXXExceptionRegistration, ptr %0, i32 0, i32 2
+ ; CHECK-NEXT: store i32 -1, ptr %10, align 4
+ call x86_thiscallcc void @"??1Destructor@@QAE at XZ"(ptr noundef nonnull align 4 dereferenceable(4) %x) #1
+ ret void
+
+ehcleanup:
+ %1 = cleanuppad within none []
+ call x86_thiscallcc void @"??1Destructor@@QAE at XZ"(ptr noundef nonnull align 4 dereferenceable(4) %x) #1 [ "funclet"(token %1) ]
+ cleanupret from %1 unwind to caller
+}
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+declare dso_local void @llvm.seh.scope.begin() #0
+declare dso_local void @llvm.seh.scope.end() #0
+
+declare dso_local x86_thiscallcc noundef ptr @"??0Destructor@@QAE at PA_N@Z"(ptr noundef nonnull returned align 4 dereferenceable(4) %this, ptr noundef %destructorCalled)
+declare dso_local x86_thiscallcc void @"??1Destructor@@QAE at XZ"(ptr noundef nonnull align 4 dereferenceable(4) %this) #1
+
+attributes #0 = { nounwind memory(none) }
+attributes #1 = { nounwind }
More information about the llvm-commits
mailing list