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