Skip to content

Commit 6e1a7ac

Browse files
authored
[llvm][x64] Mark win x64 SEH pseudo instruction as meta instructions (again) (#112962)
When adding new SEH pseudo instructions in #110024 I noticed that some of the tests were changing their output since these new instructions were counting towards thresholds for branching versus folding decisions. These instructions do not result in real machine instructions being emitted, so they should be marked as meta instructions. This is a re-do of #110889 as we hit an issue where some of the SEH pseudo instructions in the prolog were being duplicated, which resulted errors being raised as the CodeView generator was seeing prolog directives after an end-prolog directive: <#110889 (comment)>. The fix for this is to mark the prolog related SEH pseudo instructions as being non-duplicatable.
1 parent 3903cb4 commit 6e1a7ac

File tree

3 files changed

+142
-13
lines changed

3 files changed

+142
-13
lines changed

llvm/lib/Target/X86/X86InstrCompiler.td

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,13 @@ let isBranch = 1, isTerminator = 1, isCodeGenOnly = 1 in {
235235
//===----------------------------------------------------------------------===//
236236
// Pseudo instructions used by unwind info.
237237
//
238-
let isPseudo = 1, SchedRW = [WriteSystem] in {
238+
239+
// Prolog instructions should not be duplicated, since this can cause issues
240+
// because 1) if only some of the instructions are duplicated, then we will
241+
// observe prolog instructions after the end-prolog instruction and 2) Windows
242+
// expects there to only be a single prolog (e.g., when checking if unwinding
243+
// is happening in the middle of a prolog).
244+
let isPseudo = 1, isMeta = 1, isNotDuplicable = 1, SchedRW = [WriteSystem] in {
239245
def SEH_PushReg : I<0, Pseudo, (outs), (ins i32imm:$reg),
240246
"#SEH_PushReg $reg", []>;
241247
def SEH_SaveReg : I<0, Pseudo, (outs), (ins i32imm:$reg, i32imm:$dst),
@@ -252,6 +258,10 @@ let isPseudo = 1, SchedRW = [WriteSystem] in {
252258
"#SEH_PushFrame $mode", []>;
253259
def SEH_EndPrologue : I<0, Pseudo, (outs), (ins),
254260
"#SEH_EndPrologue", []>;
261+
}
262+
263+
// Epilog instructions:
264+
let isPseudo = 1, isMeta = 1, SchedRW = [WriteSystem] in {
255265
def SEH_Epilogue : I<0, Pseudo, (outs), (ins),
256266
"#SEH_Epilogue", []>;
257267
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
; RUN: llc -O3 < %s | FileCheck %s
2+
3+
; Regression test for https://github.com/llvm/llvm-project/pull/110889#issuecomment-2393405613
4+
; Marking x64 SEH instructions as meta led to cv directives being duplicated, which caused
5+
; `cv_fpo_stackalloc` to be observed after seeing a `cv_fpo_endprologue`, which is an error.
6+
7+
; Generated from the following code:
8+
; int q;
9+
; class b {
10+
; public:
11+
; b();
12+
; };
13+
; struct G {
14+
; char n[sizeof(void *)];
15+
; int *i;
16+
; int p() const { return n[0] ? *i : 1; }
17+
; int s() const;
18+
; };
19+
; int G::s() const {
20+
; q = p();
21+
; b();
22+
; }
23+
; To reproduce: clang -target i686-w64-mingw32 -w -c repro.cpp -O3 -g -gcodeview -emit-llvm
24+
25+
; CHECK-LABEL: __ZNK1G1sEv:
26+
; CHECK: .cv_fpo_proc __ZNK1G1sEv 0
27+
; CHECK: .cv_fpo_stackalloc 4
28+
; CHECK: .cv_fpo_endprologue
29+
; CHECK-NOT: .cv_fpo_stackalloc
30+
; CHECK-NOT: .cv_fpo_endprologue
31+
32+
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"
33+
target triple = "i686-w64-windows-gnu"
34+
35+
%class.b = type { i8 }
36+
37+
@q = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0
38+
39+
; Function Attrs: mustprogress noreturn
40+
define dso_local x86_thiscallcc noundef i32 @_ZNK1G1sEv(ptr nocapture noundef nonnull readonly align 4 dereferenceable(8) %this) local_unnamed_addr #0 align 2 !dbg !13 {
41+
entry:
42+
%agg.tmp.ensured = alloca %class.b, align 1
43+
#dbg_value(ptr %this, !30, !DIExpression(), !32)
44+
#dbg_value(ptr %this, !33, !DIExpression(), !36)
45+
%0 = load i8, ptr %this, align 4, !dbg !38, !tbaa !39
46+
%tobool.not.i = icmp eq i8 %0, 0, !dbg !38
47+
br i1 %tobool.not.i, label %_ZNK1G1pEv.exit, label %cond.true.i, !dbg !38
48+
49+
cond.true.i: ; preds = %entry
50+
%i.i = getelementptr inbounds nuw i8, ptr %this, i32 4, !dbg !38
51+
%1 = load ptr, ptr %i.i, align 4, !dbg !38, !tbaa !42
52+
%2 = load i32, ptr %1, align 4, !dbg !38, !tbaa !45
53+
br label %_ZNK1G1pEv.exit, !dbg !38
54+
55+
_ZNK1G1pEv.exit: ; preds = %entry, %cond.true.i
56+
%cond.i = phi i32 [ %2, %cond.true.i ], [ 1, %entry ], !dbg !38
57+
store i32 %cond.i, ptr @q, align 4, !dbg !47, !tbaa !45
58+
call x86_thiscallcc void @_ZN1bC1Ev(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp.ensured), !dbg !48
59+
unreachable, !dbg !48
60+
}
61+
62+
declare dso_local x86_thiscallcc void @_ZN1bC1Ev(ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #1
63+
64+
attributes #0 = { mustprogress noreturn "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
65+
attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
66+
67+
!llvm.dbg.cu = !{!2}
68+
!llvm.module.flags = !{!6, !7, !8, !9, !10, !11}
69+
!llvm.ident = !{!12}
70+
71+
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
72+
!1 = distinct !DIGlobalVariable(name: "q", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
73+
!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 20.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
74+
!3 = !DIFile(filename: "repro.cpp", directory: "C:\\llvm", checksumkind: CSK_MD5, checksum: "54362b0cc0bf4b9927aafc8b00498049")
75+
!4 = !{!0}
76+
!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
77+
!6 = !{i32 1, !"NumRegisterParameters", i32 0}
78+
!7 = !{i32 2, !"CodeView", i32 1}
79+
!8 = !{i32 2, !"Debug Info Version", i32 3}
80+
!9 = !{i32 1, !"wchar_size", i32 2}
81+
!10 = !{i32 1, !"MaxTLSAlign", i32 65536}
82+
!11 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
83+
!12 = !{!"clang version 20.0.0"}
84+
!13 = distinct !DISubprogram(name: "s", linkageName: "_ZNK1G1sEv", scope: !14, file: !3, line: 12, type: !24, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !28, retainedNodes: !29)
85+
!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "G", file: !3, line: 6, size: 64, flags: DIFlagTypePassByValue, elements: !15, identifier: "_ZTS1G")
86+
!15 = !{!16, !21, !23, !28}
87+
!16 = !DIDerivedType(tag: DW_TAG_member, name: "n", scope: !14, file: !3, line: 7, baseType: !17, size: 32)
88+
!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 32, elements: !19)
89+
!18 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
90+
!19 = !{!20}
91+
!20 = !DISubrange(count: 4)
92+
!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !14, file: !3, line: 8, baseType: !22, size: 32, offset: 32)
93+
!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 32)
94+
!23 = !DISubprogram(name: "p", linkageName: "_ZNK1G1pEv", scope: !14, file: !3, line: 9, type: !24, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
95+
!24 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !25)
96+
!25 = !{!5, !26}
97+
!26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !27, size: 32, flags: DIFlagArtificial | DIFlagObjectPointer)
98+
!27 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !14)
99+
!28 = !DISubprogram(name: "s", linkageName: "_ZNK1G1sEv", scope: !14, file: !3, line: 10, type: !24, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
100+
!29 = !{!30}
101+
!30 = !DILocalVariable(name: "this", arg: 1, scope: !13, type: !31, flags: DIFlagArtificial | DIFlagObjectPointer)
102+
!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !27, size: 32)
103+
!32 = !DILocation(line: 0, scope: !13)
104+
!33 = !DILocalVariable(name: "this", arg: 1, scope: !34, type: !31, flags: DIFlagArtificial | DIFlagObjectPointer)
105+
!34 = distinct !DISubprogram(name: "p", linkageName: "_ZNK1G1pEv", scope: !14, file: !3, line: 9, type: !24, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !23, retainedNodes: !35)
106+
!35 = !{!33}
107+
!36 = !DILocation(line: 0, scope: !34, inlinedAt: !37)
108+
!37 = distinct !DILocation(line: 13, scope: !13)
109+
!38 = !DILocation(line: 9, scope: !34, inlinedAt: !37)
110+
!39 = !{!40, !40, i64 0}
111+
!40 = !{!"omnipotent char", !41, i64 0}
112+
!41 = !{!"Simple C++ TBAA"}
113+
!42 = !{!43, !44, i64 4}
114+
!43 = !{!"_ZTS1G", !40, i64 0, !44, i64 4}
115+
!44 = !{!"any pointer", !40, i64 0}
116+
!45 = !{!46, !46, i64 0}
117+
!46 = !{!"int", !40, i64 0}
118+
!47 = !DILocation(line: 13, scope: !13)
119+
!48 = !DILocation(line: 14, scope: !13)

llvm/test/CodeGen/X86/x86-win64-shrink-wrapping.ll

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) #0 {
1717
; ENABLE-NEXT: .seh_pushreg %rbx
1818
; ENABLE-NEXT: .seh_endprologue
1919
; ENABLE-NEXT: testl %ecx, %ecx
20-
; ENABLE-NEXT: je .LBB0_4
20+
; ENABLE-NEXT: je .LBB0_5
2121
; ENABLE-NEXT: # %bb.1: # %for.preheader
2222
; ENABLE-NEXT: #APP
2323
; ENABLE-NEXT: nop
@@ -38,11 +38,11 @@ define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) #0 {
3838
; ENABLE-NEXT: nop
3939
; ENABLE-NEXT: #NO_APP
4040
; ENABLE-NEXT: shll $3, %eax
41-
; ENABLE-NEXT: jmp .LBB0_5
42-
; ENABLE-NEXT: .LBB0_4: # %if.else
41+
; ENABLE-NEXT: popq %rbx
42+
; ENABLE-NEXT: retq
43+
; ENABLE-NEXT: .LBB0_5: # %if.else
4344
; ENABLE-NEXT: movl %edx, %eax
4445
; ENABLE-NEXT: addl %edx, %eax
45-
; ENABLE-NEXT: .LBB0_5: # %if.end
4646
; ENABLE-NEXT: popq %rbx
4747
; ENABLE-NEXT: retq
4848
; ENABLE-NEXT: .seh_endproc
@@ -53,7 +53,7 @@ define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) #0 {
5353
; DISABLE-NEXT: .seh_pushreg %rbx
5454
; DISABLE-NEXT: .seh_endprologue
5555
; DISABLE-NEXT: testl %ecx, %ecx
56-
; DISABLE-NEXT: je .LBB0_4
56+
; DISABLE-NEXT: je .LBB0_5
5757
; DISABLE-NEXT: # %bb.1: # %for.preheader
5858
; DISABLE-NEXT: #APP
5959
; DISABLE-NEXT: nop
@@ -74,11 +74,11 @@ define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) #0 {
7474
; DISABLE-NEXT: nop
7575
; DISABLE-NEXT: #NO_APP
7676
; DISABLE-NEXT: shll $3, %eax
77-
; DISABLE-NEXT: jmp .LBB0_5
78-
; DISABLE-NEXT: .LBB0_4: # %if.else
77+
; DISABLE-NEXT: popq %rbx
78+
; DISABLE-NEXT: retq
79+
; DISABLE-NEXT: .LBB0_5: # %if.else
7980
; DISABLE-NEXT: movl %edx, %eax
8081
; DISABLE-NEXT: addl %edx, %eax
81-
; DISABLE-NEXT: .LBB0_5: # %if.end
8282
; DISABLE-NEXT: popq %rbx
8383
; DISABLE-NEXT: retq
8484
; DISABLE-NEXT: .seh_endproc
@@ -157,7 +157,7 @@ define i32 @loopInfoSaveOutsideLoop2(i32 %cond, i32 %N) #0 {
157157
; DISABLE-NEXT: .seh_pushreg %rbx
158158
; DISABLE-NEXT: .seh_endprologue
159159
; DISABLE-NEXT: testl %ecx, %ecx
160-
; DISABLE-NEXT: je .LBB1_4
160+
; DISABLE-NEXT: je .LBB1_5
161161
; DISABLE-NEXT: # %bb.1: # %for.preheader
162162
; DISABLE-NEXT: #APP
163163
; DISABLE-NEXT: nop
@@ -178,11 +178,11 @@ define i32 @loopInfoSaveOutsideLoop2(i32 %cond, i32 %N) #0 {
178178
; DISABLE-NEXT: nop
179179
; DISABLE-NEXT: #NO_APP
180180
; DISABLE-NEXT: shll $3, %eax
181-
; DISABLE-NEXT: jmp .LBB1_5
182-
; DISABLE-NEXT: .LBB1_4: # %if.else
181+
; DISABLE-NEXT: popq %rbx
182+
; DISABLE-NEXT: retq
183+
; DISABLE-NEXT: .LBB1_5: # %if.else
183184
; DISABLE-NEXT: addl %edx, %edx
184185
; DISABLE-NEXT: movl %edx, %eax
185-
; DISABLE-NEXT: .LBB1_5: # %if.end
186186
; DISABLE-NEXT: popq %rbx
187187
; DISABLE-NEXT: retq
188188
; DISABLE-NEXT: .seh_endproc

0 commit comments

Comments
 (0)