[llvm] [WinEH] Emit state stores for SEH scopes (PR #116546)
Maurice Heumann via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 24 04:18:51 PST 2024
https://github.com/momo5502 updated https://github.com/llvm/llvm-project/pull/116546
>From e2ecad2f8a6080614479e14940c1124decba0197 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/4] [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 85485229aaf243..1cb28099b0948f 100644
--- a/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -608,8 +608,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 92fbbeb24183ef38dfa7501fc769aaf683b97317 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/4] [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 1cb28099b0948f..169355da5d9968 100644
--- a/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -608,10 +608,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,
@@ -656,6 +663,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;
@@ -667,7 +676,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);
@@ -720,6 +737,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 e4a56b8024d0036a35eb62899fb7b1a5147a121f 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/4] [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 }
>From ce214c24a74390ad883790c2ab988bbac4f3eb61 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann at gmail.com>
Date: Sun, 24 Nov 2024 13:09:33 +0100
Subject: [PATCH 4/4] Insert state restore before SEH scope end
---
llvm/lib/Target/X86/X86WinEHState.cpp | 50 +++++++------------
.../WinEH/wineh-scope-statenumbering.ll | 5 +-
2 files changed, 21 insertions(+), 34 deletions(-)
diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp
index 169355da5d9968..b3e4c70eb57f30 100644
--- a/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -517,11 +517,28 @@ int WinEHStatePass::getBaseStateForBB(
return BaseState;
}
+static bool isIntrinsic(const CallBase &Call, Intrinsic::ID ID) {
+ const Function *CF = Call.getCalledFunction();
+ 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);
+}
+
// Calculate the state a call-site is in.
int WinEHStatePass::getStateForCall(
DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,
CallBase &Call) {
if (auto *II = dyn_cast<InvokeInst>(&Call)) {
+ if (isSehScopeEnd(*II)) {
+ return getBaseStateForBB(BlockColors, FuncInfo, II->getNormalDest());
+ }
+
// Look up the state number of the EH pad this unwinds to.
assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!");
return FuncInfo.InvokeStateMap[II];
@@ -608,22 +625,9 @@ static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F,
return CommonState;
}
-static bool isIntrinsic(const CallBase &Call, Intrinsic::ID ID) {
- const Function *CF = Call.getCalledFunction();
- 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,
CallBase &Call) {
- if (isSehScopeBegin(Call)) {
+ if (isSehScopeBegin(Call) || isSehScopeEnd(Call)) {
return true;
}
@@ -663,8 +667,6 @@ 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;
@@ -676,15 +678,7 @@ void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
InitialState = FinalState = ParentBaseState;
for (Instruction &I : *BB) {
auto *Call = dyn_cast<CallBase>(&I);
- if (!Call)
- continue;
-
- if (isSehScopeEnd(*Call)) {
- auto *Invoke = cast<InvokeInst>(Call);
- ScopeEndBlocks.insert(Invoke->getNormalDest());
- }
-
- if (!isStateStoreNeeded(Personality, *Call))
+ if (!Call || !isStateStoreNeeded(Personality, *Call))
continue;
int State = getStateForCall(BlockColors, FuncInfo, *Call);
@@ -737,12 +731,6 @@ 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) {
diff --git a/llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll b/llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll
index 40c59970faae12..9cebb9a8330ab1 100644
--- a/llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll
+++ b/llvm/test/CodeGen/WinEH/wineh-scope-statenumbering.ll
@@ -19,13 +19,12 @@ entry:
invoke.cont:
store i32 1, ptr inttoptr (i32 1 to ptr), align 4
+ ; CHECK: store i32 -1, ptr %10, align 4
+ ; CHECK-NEXT: invoke void @llvm.seh.scope.end()
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
More information about the llvm-commits
mailing list