1# RUN: llc -start-before=x86-avoid-trailing-call %s -o - | FileCheck %s
2
3# If there is a trailing unreachable block, make sure it is non-empty.
4
5# Manually modified the IR of the following C++ to share one unreachable block,
6# as clang does for the real C++ throw:
7# void __declspec(noreturn) mythrow();
8# int multi_throw(bool c1, bool c2, bool c3) {
9#   try {
10#     if (c1)
11#       mythrow();
12#     if (c2)
13#       mythrow();
14#     if (c3)
15#       mythrow();
16#   } catch (...) {
17#     return 1;
18#   }
19#   return 0;
20# }
21
22# CHECK-LABEL: "?multi_throw@@YAH_N00@Z": # @"?multi_throw@@YAH_N00@Z"
23# CHECK: retq
24# CHECK: .LBB{{.*}} # %if.then
25# CHECK: callq mythrow
26# CHECK: .LBB{{.*}} # %if.then4
27# CHECK: callq mythrow
28# CHECK: .LBB{{.*}} # %if.then8
29# CHECK: callq mythrow
30# CHECK: .LBB{{.*}} # %unreachable
31# CHECK-NEXT: int3
32# CHECK: .seh_endproc
33# CHECK: # %catch
34
35--- |
36  ; ModuleID = '../llvm/test/CodeGen/X86/win64-eh-empty-block-2.ll'
37  source_filename = "t.cpp"
38  target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
39  target triple = "x86_64-unknown-windows-msvc19.11.0"
40
41  ; Function Attrs: uwtable
42  define dso_local i32 @"?multi_throw@@YAH_N00@Z"(i1 zeroext %c1, i1 zeroext %c2, i1 zeroext %c3) local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
43  entry:
44    br i1 %c1, label %if.then, label %if.end
45
46  if.then:                                          ; preds = %entry
47    invoke void @mythrow()
48            to label %unreachable unwind label %catch.dispatch
49
50  unreachable:                                      ; preds = %if.then8, %if.then4, %if.then
51    unreachable
52
53  if.end:                                           ; preds = %entry
54    br i1 %c2, label %if.then4, label %if.end6
55
56  if.then4:                                         ; preds = %if.end
57    invoke void @mythrow()
58            to label %unreachable unwind label %catch.dispatch
59
60  if.end6:                                          ; preds = %if.end
61    br i1 %c3, label %if.then8, label %return
62
63  if.then8:                                         ; preds = %if.end6
64    invoke void @mythrow()
65            to label %unreachable unwind label %catch.dispatch
66
67  catch.dispatch:                                   ; preds = %if.then8, %if.then4, %if.then
68    %0 = catchswitch within none [label %catch] unwind to caller
69
70  catch:                                            ; preds = %catch.dispatch
71    %1 = catchpad within %0 [i8* null, i32 64, i8* null]
72    catchret from %1 to label %return
73
74  return:                                           ; preds = %catch, %if.end6
75    %retval.0 = phi i32 [ 1, %catch ], [ 0, %if.end6 ]
76    ret i32 %retval.0
77  }
78
79  declare dso_local void @mythrow()
80
81  declare dso_local i32 @__CxxFrameHandler3(...)
82
83  attributes #0 = { uwtable }
84
85  !llvm.module.flags = !{!0, !1}
86
87  !0 = !{i32 1, !"wchar_size", i32 2}
88  !1 = !{i32 7, !"PIC Level", i32 2}
89
90...
91---
92name:            '?multi_throw@@YAH_N00@Z'
93alignment:       16
94exposesReturnsTwice: false
95legalized:       false
96regBankSelected: false
97selected:        false
98failedISel:      false
99tracksRegLiveness: true
100hasWinCFI:       true
101registers:       []
102liveins:
103  - { reg: '$cl', virtual-reg: '' }
104  - { reg: '$dl', virtual-reg: '' }
105  - { reg: '$r8b', virtual-reg: '' }
106frameInfo:
107  isFrameAddressTaken: false
108  isReturnAddressTaken: false
109  hasStackMap:     false
110  hasPatchPoint:   false
111  stackSize:       56
112  offsetAdjustment: -56
113  maxAlignment:    8
114  adjustsStack:    true
115  hasCalls:        true
116  stackProtector:  ''
117  maxCallFrameSize: 32
118  cvBytesOfCalleeSavedRegisters: 0
119  hasOpaqueSPAdjustment: true
120  hasVAStart:      false
121  hasMustTailInVarArgFunc: false
122  localFrameSize:  0
123  savePoint:       ''
124  restorePoint:    ''
125fixedStack:
126  - { id: 0, type: default, offset: -24, size: 8, alignment: 8, stack-id: default,
127      isImmutable: false, isAliased: false, callee-saved-register: '',
128      callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
129      debug-info-location: '' }
130  - { id: 1, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: default,
131      callee-saved-register: '', callee-saved-restored: true, debug-info-variable: '',
132      debug-info-expression: '', debug-info-location: '' }
133stack:
134  - { id: 0, name: '', type: spill-slot, offset: -28, size: 4, alignment: 4,
135      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
136      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
137callSites:       []
138constants:       []
139machineFunctionInfo: {}
140body:             |
141  bb.0.entry:
142    successors: %bb.1(0x00000001), %bb.3(0x7fffffff)
143    liveins: $cl, $dl, $r8b
144
145    frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp
146    frame-setup SEH_PushReg 50
147    $rsp = frame-setup SUB64ri8 $rsp, 48, implicit-def dead $eflags
148    frame-setup SEH_StackAlloc 48
149    $rbp = LEA64r $rsp, 1, $noreg, 48, $noreg
150    frame-setup SEH_SetFrame 50, 48
151    frame-setup SEH_EndPrologue
152    MOV64mi32 $rbp, 1, $noreg, -8, $noreg, -2 :: (store (s64) into %fixed-stack.0)
153    TEST8rr killed renamable $cl, renamable $cl, implicit-def $eflags
154    JCC_1 %bb.1, 5, implicit $eflags
155
156  bb.3.if.end:
157    successors: %bb.4(0x00000001), %bb.5(0x7fffffff)
158    liveins: $dl, $r8b
159
160    TEST8rr killed renamable $dl, renamable $dl, implicit-def $eflags
161    JCC_1 %bb.4, 5, implicit $eflags
162
163  bb.5.if.end6:
164    successors: %bb.6(0x00000001), %bb.8(0x7fffffff)
165    liveins: $r8b
166
167    MOV32mi $rbp, 1, $noreg, -12, $noreg, 0 :: (store (s32) into %stack.0)
168    TEST8rr killed renamable $r8b, renamable $r8b, implicit-def $eflags
169    JCC_1 %bb.6, 5, implicit $eflags
170
171  bb.8.return (address-taken):
172    $eax = MOV32rm $rbp, 1, $noreg, -12, $noreg :: (load (s32) from %stack.0)
173    SEH_Epilogue
174    $rsp = frame-destroy ADD64ri8 $rsp, 48, implicit-def dead $eflags
175    $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
176    RETQ $eax
177
178  bb.1.if.then:
179    successors: %bb.2(0x7ffff800), %bb.7(0x00000800)
180
181    EH_LABEL <mcsymbol .Leh1>
182    CALL64pcrel32 @mythrow, csr_win64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp
183    EH_LABEL <mcsymbol .Leh2>
184    JMP_1 %bb.2
185
186  bb.4.if.then4:
187    successors: %bb.2(0x7ffff800), %bb.7(0x00000800)
188
189    EH_LABEL <mcsymbol .Leh3>
190    CALL64pcrel32 @mythrow, csr_win64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp
191    EH_LABEL <mcsymbol .Leh4>
192    JMP_1 %bb.2
193
194  bb.6.if.then8:
195    successors: %bb.2(0x7ffff800), %bb.7(0x00000800)
196
197    EH_LABEL <mcsymbol .Leh5>
198    CALL64pcrel32 @mythrow, csr_win64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp
199    EH_LABEL <mcsymbol .Leh6>
200
201  bb.2.unreachable:
202    successors:
203
204
205  bb.7.catch (landing-pad, ehfunclet-entry):
206    successors: %bb.8(0x80000000)
207    liveins: $rdx
208
209    frame-setup MOV64mr killed $rsp, 1, $noreg, 16, $noreg, $rdx
210    frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp
211    frame-setup SEH_PushReg 50
212    $rsp = frame-setup SUB64ri8 $rsp, 32, implicit-def dead $eflags
213    frame-setup SEH_StackAlloc 32
214    $rbp = LEA64r $rdx, 1, $noreg, 48, $noreg
215    frame-setup SEH_EndPrologue
216    MOV32mi $rbp, 1, $noreg, -12, $noreg, 1 :: (store (s32) into %stack.0)
217    $rax = LEA64r $rip, 0, $noreg, %bb.8, $noreg
218    SEH_Epilogue
219    $rsp = frame-destroy ADD64ri8 $rsp, 32, implicit-def dead $eflags
220    $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
221    CATCHRET %bb.8, %bb.0
222
223...
224