• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# RUN: llc -mtriple="i386-pc-windows-msvc" -run-pass=stack-coloring %s -o - | FileCheck %s
2
3# There is a problem with the exception handler, we found in windows, when set
4# LifetimeStartOnFirstUse=true for stack-coloring in default. Take the following
5# case for example:
6#
7#// Compile with "clang-cl -m32 -O2 -EHs test.cpp"
8#__attribute__((noinline,nothrow,weak)) void escape(int *p) { }
9#struct object {
10#  int i;
11#  object() {
12#    i = 1;
13#  }
14#  ~object() {
15#    // if "object" and "exp" are assigned to the same slot,
16#    // this assign will corrupt "exp".
17#    i = 9999;
18#    escape(&i);
19#  }
20#};
21#inline void throwit() { throw 999; }
22#
23#volatile int v;
24#inline void func() {
25#  try {
26#    object o;
27#    throwit();
28#  }
29#  // "exp" is written by the OS when the "throw" occurs.
30#  // Then the destructor is called, and the store-assign
31#  // clobbers the value of "exp".
32#  // The dereference of "exp" (with value 9999) causes a crash.
33#  // All these done in libruntime, so it is hard to check in IR.
34#  catch (int &exp) {
35#    v = exp;
36#  }
37#}
38#
39#int main() {
40#  func();
41#  return 0;
42#}
43
44## Make sure that o.i not merge with exp.i
45# CHECK:      stack:
46# CHECK:  id: 2, name: o.i, type: default, offset: 0, size: 4, alignment: 4,
47# CHECK:  id: 3, name: exp.i, type: default, offset: 0, size: 4, alignment: 4,
48
49## Make sure that %stack.3.exp.i not replaced with %stack.2.o.i
50# CHECK:  bb.3.catch.i (landing-pad, ehfunclet-entry):
51# CHECK:    %7:gr32 = MOV32rm %stack.3.exp.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.exp.i)
52
53--- |
54  ; ModuleID = 'test-pre-stc.mir'
55  source_filename = "test.cpp"
56  target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:32-n8:16:32-a:0:32-S32"
57
58  %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
59  %eh.CatchableType = type { i32, i8*, i32, i32, i32, i32, i8* }
60  %eh.CatchableTypeArray.1 = type { i32, [1 x %eh.CatchableType*] }
61  %eh.ThrowInfo = type { i32, i8*, i8*, i8* }
62  %CXXExceptionRegistration = type { i8*, %EHRegistrationNode, i32 }
63  %EHRegistrationNode = type { %EHRegistrationNode*, i8* }
64  %struct.object = type { i32 }
65
66  $"_R0H@8" = comdat any
67
68  $"_CT_R0H@84" = comdat any
69
70  $_CTA1H = comdat any
71
72  $_TI1H = comdat any
73
74  @v__3HC = dso_local global i32 0, align 4
75  @"_7type_info__6B@" = external constant i8*
76  @"_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"_7type_info__6B@", i8* null, [3 x i8] c".H\00" }, comdat
77  @"_CT_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"_R0H@8" to i8*), i32 0, i32 -1, i32 0, i32 4, i8* null }, section ".xdata", comdat
78  @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT_R0H@84"] }, section ".xdata", comdat
79  @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1H to i8*) }, section ".xdata", comdat
80
81  ; Function Attrs: noinline nounwind sspstrong
82  define weak dso_local void @"escape__YAXPAH@Z"(i32* %p) local_unnamed_addr #0 {
83  entry:
84    ret void
85  }
86
87  ; Function Attrs: norecurse sspstrong
88  define dso_local i32 @main() local_unnamed_addr #1 personality i32 (...)* @__CxxFrameHandler3 {
89  entry:
90    %0 = alloca %CXXExceptionRegistration, align 4
91    %1 = bitcast %CXXExceptionRegistration* %0 to i8*
92    call void @llvm.x86.seh.ehregnode(i8* %1)
93    %2 = call i8* @llvm.stacksave()
94    %3 = getelementptr inbounds %CXXExceptionRegistration, %CXXExceptionRegistration* %0, i32 0, i32 0
95    store i8* %2, i8** %3, align 4
96    %4 = getelementptr inbounds %CXXExceptionRegistration, %CXXExceptionRegistration* %0, i32 0, i32 2
97    store i32 -1, i32* %4, align 4
98    %5 = getelementptr inbounds %CXXExceptionRegistration, %CXXExceptionRegistration* %0, i32 0, i32 1
99    %6 = getelementptr inbounds %EHRegistrationNode, %EHRegistrationNode* %5, i32 0, i32 1
100    store i8* bitcast (i32 (i8*, i8*, i8*, i8*)* @"__ehhandler$main" to i8*), i8** %6, align 4
101    %7 = load %EHRegistrationNode*, %EHRegistrationNode* addrspace(257)* null, align 4
102    %8 = getelementptr inbounds %EHRegistrationNode, %EHRegistrationNode* %5, i32 0, i32 0
103    store %EHRegistrationNode* %7, %EHRegistrationNode** %8, align 4
104    store %EHRegistrationNode* %5, %EHRegistrationNode* addrspace(257)* null, align 4
105    %tmp.i.i = alloca i32, align 4
106    %o.i = alloca %struct.object, align 4
107    %zx = alloca i32*, align 4
108    %exp.i = alloca i32*, align 4
109    %9 = bitcast i32** %exp.i to i8*
110    call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %9)
111    %10 = bitcast %struct.object* %o.i to i8*
112    call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %10) #7
113    %i.i.i1 = bitcast %struct.object* %o.i to i32*
114    store i32 1, i32* %i.i.i1, align 4
115    %11 = bitcast i32* %tmp.i.i to i8*
116    call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %11)
117    store i32 999, i32* %tmp.i.i, align 4
118    %12 = getelementptr inbounds %CXXExceptionRegistration, %CXXExceptionRegistration* %0, i32 0, i32 2
119    store i32 1, i32* %12, align 4
120    invoke void @_CxxThrowException(i8* nonnull %11, %eh.ThrowInfo* nonnull @_TI1H) #8
121            to label %.noexc.i unwind label %ehcleanup.i
122
123  .noexc.i:                                         ; preds = %entry
124    unreachable
125
126  ehcleanup.i:                                      ; preds = %entry
127    %13 = cleanuppad within none []
128    %14 = bitcast %struct.object* %o.i to i32*
129    %15 = bitcast %struct.object* %o.i to i8*
130    store i32 9999, i32* %14, align 4
131    call void @"escape__YAXPAH@Z"(i32* nonnull %14) #7 [ "funclet"(token %13) ]
132    call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %15) #7
133    cleanupret from %13 unwind label %catch.dispatch.i
134
135  catch.dispatch.i:                                 ; preds = %ehcleanup.i
136    %16 = catchswitch within none [label %catch.i] unwind to caller
137
138  catch.i:                                          ; preds = %catch.dispatch.i
139    %17 = catchpad within %16 [%rtti.TypeDescriptor2* @"_R0H@8", i32 8, i32** %exp.i]
140    %18 = load i32*, i32** %exp.i, align 4
141    %19 = load i32, i32* %18, align 4
142    store atomic volatile i32 %19, i32* @v__3HC release, align 4
143    catchret from %17 to label %func__YAXXZ.exit
144
145  func__YAXXZ.exit:                                 ; preds = %catch.i
146    %20 = bitcast i32** %exp.i to i8*
147    call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %20)
148    %21 = getelementptr inbounds %CXXExceptionRegistration, %CXXExceptionRegistration* %0, i32 0, i32 1
149    %22 = getelementptr inbounds %EHRegistrationNode, %EHRegistrationNode* %21, i32 0, i32 0
150    %23 = load %EHRegistrationNode*, %EHRegistrationNode** %22, align 4
151    store %EHRegistrationNode* %23, %EHRegistrationNode* addrspace(257)* null, align 4
152    ret i32 0
153  }
154
155  ; Function Attrs: argmemonly nofree nosync nounwind willreturn
156  declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #2
157
158  ; Function Attrs: nofree
159  declare dso_local i32 @__CxxFrameHandler3(...) #3
160
161  ; Function Attrs: argmemonly nofree nosync nounwind willreturn
162  declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2
163
164  ; Function Attrs: nofree
165  declare dso_local x86_stdcallcc void @_CxxThrowException(i8*, %eh.ThrowInfo*) local_unnamed_addr #3
166
167  declare i32 @_setjmp3(i8*, i32, ...)
168
169  ; Function Attrs: nofree nosync nounwind willreturn
170  declare i8* @llvm.stacksave() #4
171
172  define internal i32 @"__ehhandler$main"(i8* %0, i8* %1, i8* %2, i8* %3) #5 {
173  entry:
174    %4 = call i8* @llvm.x86.seh.lsda(i8* bitcast (i32 ()* @main to i8*))
175    %5 = tail call i32 bitcast (i32 (...)* @__CxxFrameHandler3 to i32 (i8*, i8*, i8*, i8*, i8*)*)(i8* inreg %4, i8* %0, i8* %1, i8* %2, i8* %3)
176    ret i32 %5
177  }
178
179  ; Function Attrs: nounwind readnone
180  declare i8* @llvm.x86.seh.lsda(i8*) #6
181
182  declare x86_stdcallcc void @__CxxLongjmpUnwind(i8*)
183
184  ; Function Attrs: nounwind
185  declare void @llvm.x86.seh.ehregnode(i8*) #7
186
187  attributes #0 = { noinline nounwind sspstrong "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
188  attributes #1 = { norecurse sspstrong "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
189  attributes #2 = { argmemonly nofree nosync nounwind willreturn }
190  attributes #3 = { nofree }
191  attributes #4 = { nofree nosync nounwind willreturn }
192  attributes #5 = { "safeseh" }
193  attributes #6 = { nounwind readnone }
194  attributes #7 = { nounwind }
195  attributes #8 = { noreturn }
196
197  !llvm.linker.options = !{!0, !1, !2}
198  !llvm.module.flags = !{!3, !4}
199  !llvm.ident = !{!5}
200
201  !0 = !{!"/DEFAULTLIB:libcmt.lib"}
202  !1 = !{!"/DEFAULTLIB:libmmt.lib"}
203  !2 = !{!"/DEFAULTLIB:oldnames.lib"}
204  !3 = !{i32 1, !"NumRegisterParameters", i32 0}
205  !4 = !{i32 1, !"wchar_size", i32 2}
206  !5 = !{!"Intel(R) oneAPI DPC++ Compiler Pro 2021.1 (YYYY.x.0.MMDD)"}
207
208...
209---
210name:            'escape__YAXPAH@Z'
211alignment:       16
212exposesReturnsTwice: false
213legalized:       false
214regBankSelected: false
215selected:        false
216failedISel:      false
217tracksRegLiveness: true
218hasWinCFI:       false
219registers:       []
220liveins:         []
221frameInfo:
222  isFrameAddressTaken: false
223  isReturnAddressTaken: false
224  hasStackMap:     false
225  hasPatchPoint:   false
226  stackSize:       0
227  offsetAdjustment: 0
228  maxAlignment:    4
229  adjustsStack:    false
230  hasCalls:        false
231  stackProtector:  ''
232  maxCallFrameSize: 4294967295
233  cvBytesOfCalleeSavedRegisters: 0
234  hasOpaqueSPAdjustment: false
235  hasVAStart:      false
236  hasMustTailInVarArgFunc: false
237  localFrameSize:  0
238  savePoint:       ''
239  restorePoint:    ''
240fixedStack:
241  - { id: 0, type: default, offset: 0, size: 4, alignment: 4, stack-id: default,
242      isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
243      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
244stack:           []
245callSites:       []
246debugValueSubstitutions: []
247constants:       []
248machineFunctionInfo: {}
249body:             |
250  bb.0.entry:
251    RET 0
252
253...
254---
255name:            main
256alignment:       16
257exposesReturnsTwice: false
258legalized:       false
259regBankSelected: false
260selected:        false
261failedISel:      false
262tracksRegLiveness: true
263hasWinCFI:       false
264registers:
265  - { id: 0, class: gr32, preferred-register: '' }
266  - { id: 1, class: gr32, preferred-register: '' }
267  - { id: 2, class: gr32, preferred-register: '' }
268  - { id: 3, class: gr32, preferred-register: '' }
269  - { id: 4, class: gr32, preferred-register: '' }
270  - { id: 5, class: gr32, preferred-register: '' }
271  - { id: 6, class: gr32, preferred-register: '' }
272  - { id: 7, class: gr32, preferred-register: '' }
273  - { id: 8, class: gr32, preferred-register: '' }
274  - { id: 9, class: gr32, preferred-register: '' }
275  - { id: 10, class: gr32, preferred-register: '' }
276liveins:         []
277frameInfo:
278  isFrameAddressTaken: false
279  isReturnAddressTaken: false
280  hasStackMap:     false
281  hasPatchPoint:   false
282  stackSize:       0
283  offsetAdjustment: 0
284  maxAlignment:    4
285  adjustsStack:    false
286  hasCalls:        true
287  stackProtector:  ''
288  maxCallFrameSize: 4294967295
289  cvBytesOfCalleeSavedRegisters: 0
290  hasOpaqueSPAdjustment: true
291  hasVAStart:      false
292  hasMustTailInVarArgFunc: false
293  localFrameSize:  0
294  savePoint:       ''
295  restorePoint:    ''
296fixedStack:      []
297stack:
298  - { id: 0, name: zx, type: default, offset: 0, size: 16, alignment: 4,
299      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
300      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
301  - { id: 1, name: tmp.i.i, type: default, offset: 0, size: 4, alignment: 4,
302      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
303      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
304  - { id: 2, name: o.i, type: default, offset: 0, size: 4, alignment: 4,
305      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
306      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
307  - { id: 3, name: exp.i, type: default, offset: 0, size: 4, alignment: 4,
308      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
309      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
310callSites:       []
311debugValueSubstitutions: []
312constants:       []
313machineFunctionInfo: {}
314body:             |
315  bb.0.entry:
316    successors: %bb.1(0x7ffff800), %bb.2(0x00000800)
317
318    %0:gr32 = COPY $esp
319    MOV32mr %stack.0.zx, 1, $noreg, 0, $noreg, %0 :: (store 4 into %ir.3)
320    MOV32mi %stack.0.zx, 1, $noreg, 12, $noreg, -1 :: (store 4 into %ir.4)
321    %1:gr32 = nuw LEA32r %stack.0.zx, 1, $noreg, 4, $noreg
322    MOV32mi %stack.0.zx, 1, $noreg, 8, $noreg, @"__ehhandler$main" :: (store 4 into %ir.6)
323    %2:gr32 = MOV32rm $noreg, 1, $noreg, 0, $fs :: (load 4 from `%EHRegistrationNode* addrspace(257)* null`, addrspace 257)
324    MOV32mr %stack.0.zx, 1, $noreg, 4, $noreg, killed %2 :: (store 4 into %ir.8)
325    MOV32mr $noreg, 1, $noreg, 0, $fs, killed %1 :: (store 4 into `%EHRegistrationNode* addrspace(257)* null`, addrspace 257)
326    MOV32mi %stack.2.o.i, 1, $noreg, 0, $noreg, 1 :: (store 4 into %ir.i.i.i1)
327    MOV32mi %stack.1.tmp.i.i, 1, $noreg, 0, $noreg, 999 :: (store 4 into %ir.tmp.i.i)
328    MOV32mi %stack.0.zx, 1, $noreg, 12, $noreg, 1 :: (store 4 into %ir.12)
329    ADJCALLSTACKDOWN32 8, 0, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
330    %3:gr32 = COPY $esp
331    %4:gr32 = LEA32r %stack.1.tmp.i.i, 1, $noreg, 0, $noreg
332    MOV32mr %3, 1, $noreg, 0, $noreg, killed %4 :: (store 4 into stack)
333    MOV32mi %3, 1, $noreg, 4, $noreg, @_TI1H :: (store 4 into stack + 4)
334    CALLpcrel32 @_CxxThrowException, csr_noregs, implicit $esp, implicit $ssp, implicit-def $esp, implicit-def $ssp
335    ADJCALLSTACKUP32 8, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
336    JMP_1 %bb.1
337
338  bb.1..noexc.i:
339    successors:
340
341
342  bb.2.ehcleanup.i (landing-pad, ehfunclet-entry):
343    successors: %bb.3(0x80000000)
344
345    MOV32mi %stack.2.o.i, 1, $noreg, 0, $noreg, 9999 :: (store 4 into %ir.14)
346    ADJCALLSTACKDOWN32 4, 0, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
347    %5:gr32 = COPY $esp
348    %6:gr32 = LEA32r %stack.2.o.i, 1, $noreg, 0, $noreg
349    MOV32mr %5, 1, $noreg, 0, $noreg, killed %6 :: (store 4 into stack)
350    CALLpcrel32 @"escape__YAXPAH@Z", csr_32, implicit $esp, implicit $ssp, implicit-def $esp, implicit-def $ssp
351    ADJCALLSTACKUP32 4, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
352    CLEANUPRET
353
354  bb.3.catch.i (landing-pad, ehfunclet-entry):
355    successors: %bb.4(0x80000000)
356
357    %7:gr32 = MOV32rm %stack.3.exp.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.exp.i)
358    %8:gr32 = MOV32rm killed %7, 1, $noreg, 0, $noreg :: (load 4 from %ir.18)
359    MOV32mr $noreg, 1, $noreg, @v__3HC, $noreg, killed %8 :: (volatile store release 4 into @v__3HC)
360    CATCHRET %bb.4, %bb.0
361
362  bb.4.catch.i (landing-pad):
363    successors: %bb.5(0x80000000)
364
365    JMP_4 %bb.5
366
367  bb.5.func__YAXXZ.exit:
368    %9:gr32 = MOV32rm %stack.0.zx, 1, $noreg, 4, $noreg :: (dereferenceable load 4 from %ir.22)
369    MOV32mr $noreg, 1, $noreg, 0, $fs, killed %9 :: (store 4 into `%EHRegistrationNode* addrspace(257)* null`, addrspace 257)
370    %10:gr32 = MOV32r0 implicit-def dead $eflags
371    $eax = COPY %10
372    RET 0, $eax
373
374...
375---
376name:            '__ehhandler$main'
377alignment:       16
378exposesReturnsTwice: false
379legalized:       false
380regBankSelected: false
381selected:        false
382failedISel:      false
383tracksRegLiveness: true
384hasWinCFI:       false
385registers:
386  - { id: 0, class: gr32, preferred-register: '' }
387liveins:         []
388frameInfo:
389  isFrameAddressTaken: false
390  isReturnAddressTaken: false
391  hasStackMap:     false
392  hasPatchPoint:   false
393  stackSize:       0
394  offsetAdjustment: 0
395  maxAlignment:    4
396  adjustsStack:    false
397  hasCalls:        false
398  stackProtector:  ''
399  maxCallFrameSize: 4294967295
400  cvBytesOfCalleeSavedRegisters: 0
401  hasOpaqueSPAdjustment: false
402  hasVAStart:      false
403  hasMustTailInVarArgFunc: false
404  localFrameSize:  0
405  savePoint:       ''
406  restorePoint:    ''
407fixedStack:
408  - { id: 0, type: default, offset: 0, size: 4, alignment: 4, stack-id: default,
409      isImmutable: false, isAliased: false, callee-saved-register: '',
410      callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
411      debug-info-location: '' }
412  - { id: 1, type: default, offset: 4, size: 4, alignment: 4, stack-id: default,
413      isImmutable: false, isAliased: false, callee-saved-register: '',
414      callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
415      debug-info-location: '' }
416  - { id: 2, type: default, offset: 8, size: 4, alignment: 4, stack-id: default,
417      isImmutable: false, isAliased: false, callee-saved-register: '',
418      callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
419      debug-info-location: '' }
420  - { id: 3, type: default, offset: 12, size: 4, alignment: 4, stack-id: default,
421      isImmutable: false, isAliased: false, callee-saved-register: '',
422      callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
423      debug-info-location: '' }
424stack:           []
425callSites:       []
426debugValueSubstitutions: []
427constants:       []
428machineFunctionInfo: {}
429body:             |
430  bb.0.entry:
431    %0:gr32 = MOV32ri <mcsymbol L__ehtable$main>
432    $eax = COPY %0
433    TCRETURNdi @__CxxFrameHandler3, 0, csr_32, implicit $esp, implicit $ssp, implicit $eax
434
435...
436