-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
[SEH] Add test to track EHa register liveness verification #76921
Conversation
This test tracks bug of MachineVerifier to check live range segment for EHa. Async exception can happen at any place within seh scope, not only the call instruction. Need to teach MachineVerifier to know that.
@llvm/pr-subscribers-backend-x86 Author: None (HaohaiWen) ChangesThis test tracks bug of MachineVerifier to check live range segment for Full diff: https://github.com/llvm/llvm-project/pull/76921.diff 1 Files Affected:
diff --git a/llvm/test/CodeGen/X86/windows-seh-EHa-RegisterLiveness.ll b/llvm/test/CodeGen/X86/windows-seh-EHa-RegisterLiveness.ll
new file mode 100644
index 00000000000000..d23318c6e16a11
--- /dev/null
+++ b/llvm/test/CodeGen/X86/windows-seh-EHa-RegisterLiveness.ll
@@ -0,0 +1,69 @@
+; XFAIL: *
+; RUN: llc --verify-machineinstrs < %s | FileCheck %s
+source_filename = "test.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.12.0"
+
+$"?test@Test@@Plugin@@Host@@@Z" = comdat any
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: nounwind memory(none)
+declare dso_local void @llvm.seh.scope.begin() #1
+
+; Function Attrs: nobuiltin allocsize(0)
+declare dso_local noundef nonnull ptr @"??2@Test@Z"(i64 noundef) #1
+
+; Function Attrs: nounwind memory(none)
+declare dso_local void @llvm.seh.scope.end() #0
+
+; Function Attrs: nobuiltin nounwind
+declare dso_local void @"??3@YAXPEAX@Z"(ptr noundef) #2
+
+; Function Attrs: mustprogress uwtable
+define weak_odr dso_local noundef ptr @"?test@Test@@Plugin@@Host@@@Z"(ptr noundef nonnull align 8 dereferenceable(48) %this, ptr noundef %host) unnamed_addr #3 comdat align 2 personality ptr @__CxxFrameHandler3 {
+entry:
+ %host.addr = alloca ptr, align 8
+ %this.addr = alloca ptr, align 8
+ store ptr %host, ptr %host.addr, align 8
+ store ptr %this, ptr %this.addr, align 8
+ %this1 = load ptr, ptr %this.addr, align 8
+ %call = call noalias noundef nonnull ptr @"??2@Test@Z"(i64 noundef 152) #5
+ invoke void @llvm.seh.scope.begin()
+ to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont: ; preds = %entry
+ %call3 = invoke noundef ptr @"??Test@?A0x2749C4FD@@QEAA@Test@Test@@@Z"(ptr noundef nonnull align 8 dereferenceable(152) %call, ptr noundef %this1)
+ to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2: ; preds = %invoke.cont
+ invoke void @llvm.seh.scope.end()
+ to label %invoke.cont4 unwind label %ehcleanup
+
+invoke.cont4: ; preds = %invoke.cont2
+ ret ptr %call
+
+ehcleanup: ; preds = %invoke.cont2, %invoke.cont, %entry
+ %0 = cleanuppad within none []
+ call void @"??3@YAXPEAX@Z"(ptr noundef %call) #6 [ "funclet"(token %0) ]
+ cleanupret from %0 unwind to caller
+}
+
+; Function Attrs: uwtable
+declare hidden noundef ptr @"??Test@?A0x2749C4FD@@QEAA@Test@Test@@@Z"(ptr noundef nonnull returned align 8 dereferenceable(152), ptr noundef) unnamed_addr #4 align 2
+
+attributes #0 = { nounwind memory(none) }
+attributes #1 = { nobuiltin allocsize(0) "target-cpu"="x86-64" "target-features"="+cmov,+crc32,+cx8,+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87" "tune-cpu"="generic" }
+attributes #2 = { nobuiltin nounwind "target-cpu"="x86-64" "target-features"="+cmov,+crc32,+cx8,+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87" "tune-cpu"="generic" }
+attributes #3 = { mustprogress uwtable "target-cpu"="x86-64" "target-features"="+cmov,+crc32,+cx8,+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87" "tune-cpu"="generic" }
+attributes #4 = { uwtable "target-cpu"="x86-64" "target-features"="+cmov,+crc32,+cx8,+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87" "tune-cpu"="generic" }
+attributes #5 = { builtin allocsize(0) }
+attributes #6 = { builtin nounwind }
+
+!llvm.module.flags = !{!1, !2, !3, !4, !5}
+
+!1 = !{i32 1, !"wchar_size", i32 2}
+!2 = !{i32 2, !"eh-asynch", i32 1}
+!3 = !{i32 8, !"PIC Level", i32 2}
+!4 = !{i32 7, !"uwtable", i32 2}
+!5 = !{i32 1, !"MaxTLSAlign", i32 65536}
|
|
%1 lives before entering seh.scope.begin. It's valid. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
!llvm.module.flags = !{!1, !2, !3, !4, !5} | ||
|
||
!1 = !{i32 1, !"wchar_size", i32 2} | ||
!2 = !{i32 2, !"eh-asynch", i32 1} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can leave it only.
declare dso_local void @llvm.seh.scope.begin() #1 | ||
|
||
; Function Attrs: nobuiltin allocsize(0) | ||
declare dso_local noundef nonnull ptr @"??2@Test@Z"(i64 noundef) #1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the dso_local
, noundef
etc.
declare dso_local void @"??3@YAXPEAX@Z"(ptr noundef) #2 | ||
|
||
; Function Attrs: mustprogress uwtable | ||
define weak_odr dso_local noundef ptr @"?test@Test@@Plugin@@Host@@@Z"(ptr noundef nonnull align 8 dereferenceable(48) %this, ptr noundef %host) unnamed_addr #3 comdat align 2 personality ptr @__CxxFrameHandler3 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto.
This effectively reverts llvm@61d22f2. llvm@61d22f2 claims that when the predecessor unwinds to an EH pad, we should take the live-out values of not the predecessor's terminator but the last call. But if the call has a possibility to unwind to an EH pad, it means it was an `invoke` before and it should either be the terminating instruction of a BB or be right before a branch, which is the terminator. If a call is in a middle of a BB, that means the call was not an `invoke` before and it unwinds to the caller if it throws. This can fail in the case when there are unwinding instructions that are not calls, such as `CLEANUPRET` or other target-specific throwing instructions (e.g. Wasm's `throw`/`rethrow`/`throw_ref`). For example, as in the test case attached, ```mir bb.2 (landing-pad): ... CALL @foo %0 = CONST_I32 0 CLEANUPRET %bb.3 bb.3 (landing-pad): call @bar, %0 ... ``` When examining the live range of `bb.3`'s `%0`, we should check the live-outs at `CLEANUPRET`, and not `CALL @foo`. But because of this checking routine this PR deletes, this ends up passing `CLEANUPRET` and `%0 = CONST_I32 0` and search for `%0`'s liveout at `CALL @foo`, which is incorrect and results in a validation error. ```cpp // Predecessor of landing pad live-out on last call. if (MFI->isEHPad()) { for (const MachineInstr &MI : llvm::reverse(*Pred)) { if (MI.isCall()) { PEnd = Indexes->getInstructionIndex(MI).getBoundaryIndex(); break; } } } ``` Also I'm not sure if I understand the description about `llvm.experimental.gc.statepoint` intrinsic given in llvm@61d22f2. There doesn't seem to be any special thing about that intrinsic; if it can unwind to an EH pad, it would be at the end of a BB. If it unwinds to the caller, it shouldn't be where we take the live-outs from. Both the test case `statepoint-invoke-ra1.ll` given in that commit, and also https://github.com/llvm/llvm-project/blob/main/llvm/test/CodeGen/X86/statepoint-invoke-ra.mir that replaced it in llvm@2e1150d, seem to pass even with this PR (because it was an `invoke` and at the end of a BB anyway). --- This also deletes `windows-seh-EHa-RegisterLiveness.ll `, a test case added in llvm#76921. It looks that test case was added to track a MachineVerifier bug, which I guess may be the same thing this PR is trying to fix. After this PR, that test unexpectedly succeeds, which I think means we can delete it. (There is also another PR (llvm#76933) that tried to fix this bug in another way, which still has not landed.) --- This bug is discovered from the reproducer in llvm#126916, even though this is not the bug reported there.
This test tracks bug of MachineVerifier to check live range segment for
EHa. Async exception can happen at any place within seh scope, not only
the call instruction. Need to teach MachineVerifier to know that.