From af74df2b286de555e2b26dbd3c8d888327a85ffb Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 8 Oct 2015 01:13:52 +0000 Subject: [PATCH] [WinEH] Remove NewMSEH and enable its behavior by default Testing has shown that it is at least as reliable as the old landingpad pattern matching code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@249647 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Frontend/CodeGenOptions.def | 1 - lib/CodeGen/CGCleanup.cpp | 3 +- lib/CodeGen/CGCleanup.h | 4 + lib/CodeGen/CGException.cpp | 64 ++-- lib/CodeGen/MicrosoftCXXABI.cpp | 49 +-- lib/Frontend/CompilerInvocation.cpp | 1 - test/CodeGen/exceptions-seh-finally.c | 71 ++-- test/CodeGen/exceptions-seh-leave-new.c | 347 ------------------ test/CodeGen/exceptions-seh-leave.c | 90 +++-- test/CodeGen/exceptions-seh-new.c | 289 --------------- test/CodeGen/exceptions-seh.c | 150 ++++---- test/CodeGenCXX/exceptions-seh.cpp | 33 +- test/CodeGenCXX/microsoft-abi-arg-order.cpp | 6 +- test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp | 5 +- .../CodeGenCXX/microsoft-abi-eh-terminate.cpp | 9 +- .../microsoft-abi-thread-safe-statics.cpp | 14 +- test/OpenMP/parallel_codegen.cpp | 2 +- 17 files changed, 253 insertions(+), 885 deletions(-) delete mode 100644 test/CodeGen/exceptions-seh-leave-new.c delete mode 100644 test/CodeGen/exceptions-seh-new.c diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index 7c00756090..b7050875cf 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -33,7 +33,6 @@ CODEGENOPT(CompressDebugSections, 1, 0) ///< -Wa,-compress-debug-sections CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm. CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe. -CODEGENOPT(NewMSEH , 1, 0) ///< Whether we should use the new IR representation for MS exceptions CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files. CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files. CODEGENOPT(CoverageExitBlockBeforeBody, 1, 0) ///< Whether to emit the exit block before the body blocks in GCNO files. diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index 31c870ff6f..5796320894 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -933,8 +933,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { EmitBlock(EHEntry); llvm::CleanupPadInst *CPI = nullptr; llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent); - if (CGM.getCodeGenOpts().NewMSEH && - EHPersonality::get(*this).isMSVCPersonality()) + if (EHPersonality::get(*this).usesFuncletPads()) CPI = Builder.CreateCleanupPad({}); // We only actually emit the cleanup code if the cleanup is either diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h index 51b33f43e9..5a0145eb0b 100644 --- a/lib/CodeGen/CGCleanup.h +++ b/lib/CodeGen/CGCleanup.h @@ -633,6 +633,10 @@ struct EHPersonality { static const EHPersonality MSVC_C_specific_handler; static const EHPersonality MSVC_CxxFrameHandler3; + /// Does this personality use landingpads or the family of pad instructions + /// designed to form funclets? + bool usesFuncletPads() const { return isMSVCPersonality(); } + bool isMSVCPersonality() const { return this == &MSVC_except_handler || this == &MSVC_C_specific_handler || this == &MSVC_CxxFrameHandler3; diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 2490098d67..16f6e83647 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -572,8 +572,7 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { llvm::BasicBlock * CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { - if (CGM.getCodeGenOpts().NewMSEH && - EHPersonality::get(*this).isMSVCPersonality()) + if (EHPersonality::get(*this).usesFuncletPads()) return getMSVCDispatchBlock(si); // The dispatch block for the end of the scope chain is a block that @@ -705,8 +704,8 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { if (!CurFn->hasPersonalityFn()) CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality)); - if (CGM.getCodeGenOpts().NewMSEH && Personality.isMSVCPersonality()) { - // We don't need separate landing pads in the MSVC model. + if (Personality.usesFuncletPads()) { + // We don't need separate landing pads in the funclet model. LP = getEHDispatchBlock(EHStack.getInnermostEHScope()); } else { // Build the landing pad for this scope. @@ -870,8 +869,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { return lpad; } -static llvm::BasicBlock *emitMSVCCatchDispatchBlock(CodeGenFunction &CGF, - EHCatchScope &CatchScope) { +static llvm::BasicBlock *emitCatchPadBlock(CodeGenFunction &CGF, + EHCatchScope &CatchScope) { llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock(); assert(DispatchBlock); @@ -922,9 +921,8 @@ static llvm::BasicBlock *emitMSVCCatchDispatchBlock(CodeGenFunction &CGF, /// block holding the final catchendblock instruction is returned. static llvm::BasicBlock *emitCatchDispatchBlock(CodeGenFunction &CGF, EHCatchScope &catchScope) { - if (CGF.CGM.getCodeGenOpts().NewMSEH && - EHPersonality::get(CGF).isMSVCPersonality()) - return emitMSVCCatchDispatchBlock(CGF, catchScope); + if (EHPersonality::get(CGF).usesFuncletPads()) + return emitCatchPadBlock(CGF, catchScope); llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock(); assert(dispatchBlock); @@ -1337,8 +1335,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { // end of the function by FinishFunction. TerminateHandler = createBasicBlock("terminate.handler"); Builder.SetInsertPoint(TerminateHandler); - if (CGM.getCodeGenOpts().NewMSEH && - EHPersonality::get(*this).isMSVCPersonality()) { + if (EHPersonality::get(*this).usesFuncletPads()) { Builder.CreateTerminatePad(/*UnwindBB=*/nullptr, CGM.getTerminateFn()); } else { llvm::Value *Exn = nullptr; @@ -1441,8 +1438,8 @@ struct PerformSEHFinally final : EHScopeStack::Cleanup { CGM.getTypes().arrangeFreeFunctionCall(Args, FPT, /*chainCall=*/false); - // If this is the normal cleanup or using the old EH IR, just emit the call. - if (!F.isForEHCleanup() || !CGM.getCodeGenOpts().NewMSEH) { + // If this is the normal cleanup, just emit the call. + if (!F.isForEHCleanup()) { CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args); return; } @@ -1888,31 +1885,22 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { EmitBlockAfterUses(ExceptBB); - if (CGM.getCodeGenOpts().NewMSEH) { - // __except blocks don't get outlined into funclets, so immediately do a - // catchret. - llvm::BasicBlock *CatchPadBB = ExceptBB->getSinglePredecessor(); - assert(CatchPadBB && "only ExceptBB pred should be catchpad"); - llvm::CatchPadInst *CPI = - cast(CatchPadBB->getFirstNonPHI()); - ExceptBB = createBasicBlock("__except"); - Builder.CreateCatchRet(CPI, ExceptBB); - EmitBlock(ExceptBB); - // On Win64, the exception code is returned in EAX. Copy it into the slot. - if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { - llvm::Function *SEHCodeIntrin = - CGM.getIntrinsic(llvm::Intrinsic::eh_exceptioncode); - llvm::Value *Code = Builder.CreateCall(SEHCodeIntrin, {CPI}); - Builder.CreateStore(Code, SEHCodeSlotStack.back()); - } - } else { - // On Win64, the exception pointer is the exception code. Copy it to the slot. - if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { - llvm::Value *Code = - Builder.CreatePtrToInt(getExceptionFromSlot(), IntPtrTy); - Code = Builder.CreateTrunc(Code, Int32Ty); - Builder.CreateStore(Code, SEHCodeSlotStack.back()); - } + // __except blocks don't get outlined into funclets, so immediately do a + // catchret. + llvm::BasicBlock *CatchPadBB = ExceptBB->getSinglePredecessor(); + assert(CatchPadBB && "only ExceptBB pred should be catchpad"); + llvm::CatchPadInst *CPI = + cast(CatchPadBB->getFirstNonPHI()); + ExceptBB = createBasicBlock("__except"); + Builder.CreateCatchRet(CPI, ExceptBB); + EmitBlock(ExceptBB); + + // On Win64, the exception code is returned in EAX. Copy it into the slot. + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { + llvm::Function *SEHCodeIntrin = + CGM.getIntrinsic(llvm::Intrinsic::eh_exceptioncode); + llvm::Value *Code = Builder.CreateCall(SEHCodeIntrin, {CPI}); + Builder.CreateStore(Code, SEHCodeSlotStack.back()); } // Emit the __except body. diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 504dc3fa09..369d21f398 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -879,20 +879,15 @@ void MicrosoftCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) { } namespace { -struct CallEndCatchMSVC final : EHScopeStack::Cleanup { +struct CatchRetScope final : EHScopeStack::Cleanup { llvm::CatchPadInst *CPI; - CallEndCatchMSVC(llvm::CatchPadInst *CPI) : CPI(CPI) {} + CatchRetScope(llvm::CatchPadInst *CPI) : CPI(CPI) {} void Emit(CodeGenFunction &CGF, Flags flags) override { - if (CGF.CGM.getCodeGenOpts().NewMSEH) { - llvm::BasicBlock *BB = CGF.createBasicBlock("catchret.dest"); - CGF.Builder.CreateCatchRet(CPI, BB); - CGF.EmitBlock(BB); - } else { - CGF.EmitNounwindRuntimeCall( - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch)); - } + llvm::BasicBlock *BB = CGF.createBasicBlock("catchret.dest"); + CGF.Builder.CreateCatchRet(CPI, BB); + CGF.EmitBlock(BB); } }; } @@ -902,39 +897,21 @@ void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF, // In the MS ABI, the runtime handles the copy, and the catch handler is // responsible for destruction. VarDecl *CatchParam = S->getExceptionDecl(); - llvm::Value *Exn = nullptr; - llvm::Function *BeginCatch = nullptr; - llvm::CatchPadInst *CPI = nullptr; - bool NewEH = CGF.CGM.getCodeGenOpts().NewMSEH; - if (!NewEH) { - Exn = CGF.getExceptionFromSlot(); - BeginCatch = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch); - } else { - llvm::BasicBlock *CatchPadBB = - CGF.Builder.GetInsertBlock()->getSinglePredecessor(); - CPI = cast(CatchPadBB->getFirstNonPHI()); - } + llvm::BasicBlock *CatchPadBB = + CGF.Builder.GetInsertBlock()->getSinglePredecessor(); + llvm::CatchPadInst *CPI = + cast(CatchPadBB->getFirstNonPHI()); + // If this is a catch-all or the catch parameter is unnamed, we don't need to // emit an alloca to the object. if (!CatchParam || !CatchParam->getDeclName()) { - if (!NewEH) { - llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)}; - CGF.EmitNounwindRuntimeCall(BeginCatch, Args); - } - CGF.EHStack.pushCleanup(NormalCleanup, CPI); + CGF.EHStack.pushCleanup(NormalCleanup, CPI); return; } CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam); - if (!NewEH) { - Address ParamAddr = - CGF.Builder.CreateElementBitCast(var.getObjectAddress(CGF), CGF.Int8Ty); - llvm::Value *Args[2] = {Exn, ParamAddr.getPointer()}; - CGF.EmitNounwindRuntimeCall(BeginCatch, Args); - } else { - CPI->setArgOperand(2, var.getObjectAddress(CGF).getPointer()); - } - CGF.EHStack.pushCleanup(NormalCleanup, CPI); + CPI->setArgOperand(2, var.getObjectAddress(CGF).getPointer()); + CGF.EHStack.pushCleanup(NormalCleanup, CPI); CGF.EmitAutoVarCleanups(var); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index a1afd80f69..8a7e879d07 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -462,7 +462,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); - Opts.NewMSEH = Args.hasArg(OPT_fnew_ms_eh); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = getCodeModel(Args, Diags); diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c index 772e28306b..03c04e6fe0 100644 --- a/test/CodeGen/exceptions-seh-finally.c +++ b/test/CodeGen/exceptions-seh-finally.c @@ -23,11 +23,14 @@ void basic_finally(void) { // CHECK-NEXT: ret void // // CHECK: [[lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup +// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) -// CHECK: resume { i8*, i32 } +// CHECK: invoke void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) +// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]] +// CHECK: cleanupret %[[pad]] unwind to caller +// +// CHECK: [[end]] +// CHECK: cleanupendpad %[[pad]] unwind to caller // CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}}) // CHECK: call void @cleanup() @@ -90,11 +93,14 @@ void use_abnormal_termination(void) { // CHECK: ret void // // CHECK: [[lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup +// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) -// CHECK: resume { i8*, i32 } +// CHECK: invoke void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) +// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]] +// CHECK: cleanupret %[[pad]] unwind to caller +// +// CHECK: [[end]] +// CHECK: cleanupendpad %[[pad]] unwind to caller // CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} %[[abnormal:abnormal_termination]], i8* %frame_pointer) // CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32 @@ -134,10 +140,13 @@ void noreturn_finally() { // CHECK: ret void // // CHECK: [[lpad]] -// CHECK: landingpad -// CHECK-NEXT: cleanup -// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) -// CHECK: resume { i8*, i32 } +// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad +// CHECK: invoke void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) +// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]] +// CHECK: cleanupret %[[pad]] unwind to caller +// +// CHECK: [[end]] +// CHECK: cleanupendpad %[[pad]] unwind to caller // CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) // CHECK: call void @abort() @@ -179,9 +188,13 @@ int nested___finally___finally() { // CHECK-NEXT: ret i32 0 // // CHECK: [[lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) +// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad +// CHECK: invoke void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) +// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]] +// CHECK: cleanupret %[[pad]] unwind to caller +// +// CHECK: [[end]] +// CHECK: cleanupendpad %[[pad]] unwind to caller // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) // CHECK: ret void @@ -189,6 +202,8 @@ int nested___finally___finally() { // CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"({{.*}}) // CHECK: unreachable +// FIXME: Our behavior seems suspiciously different. + int nested___finally___finally_with_eh_edge() { __try { __try { @@ -207,23 +222,33 @@ int nested___finally___finally_with_eh_edge() { // // [[invokecont]] // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) -// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]] +// CHECK-NEXT: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]] // // CHECK: [[outercont]] // CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK-NEXT: ret i32 912 // // CHECK: [[lpad1]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup +// CHECK-NEXT: %[[innerpad:[^ ]*]] = cleanuppad // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) -// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]] +// CHECK-NEXT: to label %[[innercleanupretbb:[^ ]*]] unwind label %[[innerend:[^ ]*]] +// +// CHECK: [[innercleanupretbb]] +// CHECK-NEXT: cleanupret %[[innerpad]] unwind label %[[lpad2]] +// +// CHECK: [[innerend]] +// CHECK-NEXT: cleanupendpad %[[innerpad]] unwind label %[[lpad2:[^ ]*]] // // CHECK: [[lpad2]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) -// CHECK: resume +// CHECK-NEXT: %[[outerpad:[^ ]*]] = cleanuppad +// CHECK: invoke void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) +// CHECK-NEXT: to label %[[outercleanupretbb:[^ ]*]] unwind label %[[outerend:[^ ]*]] +// +// CHECK: [[outercleanupretbb]] +// CHECK-NEXT: cleanupret %[[outerpad]] unwind to caller +// +// CHECK: [[outerend]] +// CHECK-NEXT: cleanupendpad %[[outerpad]] unwind to caller // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK: ret void diff --git a/test/CodeGen/exceptions-seh-leave-new.c b/test/CodeGen/exceptions-seh-leave-new.c deleted file mode 100644 index 2895edbdfe..0000000000 --- a/test/CodeGen/exceptions-seh-leave-new.c +++ /dev/null @@ -1,347 +0,0 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -fnew-ms-eh -emit-llvm -o - | opt -instnamer -S | FileCheck %s - -void g(void); - -////////////////////////////////////////////////////////////////////////////// -// __leave with __except - -// Nothing in the __try block can trap, so __try.cont isn't created. -int __leave_with___except_simple() { - int myres = 0; - __try { - myres = 15; - __leave; - myres = 23; - } __except (1) { - return 0; - } - return 1; -} -// CHECK-LABEL: define i32 @__leave_with___except_simple() -// CHECK: store i32 15, i32* %myres -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 -// CHECK: [[tryleave]] -// CHECK-NEXT: ret i32 1 - - -// The "normal" case. -int __leave_with___except() { - int myres = 0; - __try { - g(); - __leave; - myres = 23; - } __except (1) { - return 0; - } - return 1; -} -// CHECK-LABEL: define i32 @__leave_with___except() -// CHECK: invoke void @g() -// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} -// For __excepts, instead of an explicit __try.__leave label, we could use -// use invoke.cont as __leave jump target instead. However, not doing this -// keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will -// simplify this anyways. -// CHECK: [[cont]] -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 -// CHECK: [[tryleave]] -// CHECK-NEXT: br label % - - -////////////////////////////////////////////////////////////////////////////// -// __leave with __finally - -void abort(void) __attribute__((noreturn)); - -// Nothing in the __try block can trap, so __finally.cont and friends aren't -// created. -int __leave_with___finally_simple() { - int myres = 0; - __try { - myres = 15; - __leave; - myres = 23; - } __finally { - return 0; - } - return 1; -} -// CHECK-LABEL: define i32 @__leave_with___finally_simple() -// CHECK: store i32 15, i32* %myres -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 -// CHECK: [[tryleave]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i8 0, i8* %[[fp]]) - -// __finally block doesn't return, __finally.cont doesn't exist. -int __leave_with___finally_noreturn() { - int myres = 0; - __try { - myres = 15; - __leave; - myres = 23; - } __finally { - abort(); - } - return 1; -} -// CHECK-LABEL: define i32 @__leave_with___finally_noreturn() -// CHECK: store i32 15, i32* %myres -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 -// CHECK: [[tryleave]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i8 0, i8* %[[fp]]) - -// The "normal" case. -int __leave_with___finally() { - int myres = 0; - __try { - g(); - __leave; - myres = 23; - } __finally { - return 0; - } - return 1; -} -// CHECK-LABEL: define i32 @__leave_with___finally() -// CHECK: invoke void @g() -// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} -// For __finally, there needs to be an explicit __try.__leave, because -// abnormal.termination.slot needs to be set there. -// CHECK: [[cont]] -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 -// CHECK: [[tryleave]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i8 0, i8* %[[fp]]) - - -////////////////////////////////////////////////////////////////////////////// -// Mixed, nested cases. - -int nested___except___finally() { - int myres = 0; - __try { - __try { - g(); - } __finally { - g(); - __leave; // Refers to the outer __try, not the __finally! - myres = 23; - return 0; - } - - myres = 51; - } __except (1) { - } - return 1; -} -// CHECK-LABEL: define i32 @nested___except___finally() - -// CHECK-LABEL: invoke void @g() -// CHECK-NEXT: to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]] - -// CHECK: [[g1_cont1]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 0, i8* %[[fp]]) -// CHECK-NEXT: to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]] - -// CHECK: [[fin_cont]] -// CHECK: store i32 51, i32* % -// CHECK-NEXT: br label %[[trycont:[^ ]*]] - -// CHECK: [[g1_lpad]] -// CHECK-NEXT: cleanuppad -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 1, i8* %[[fp]]) -// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[cleanupend:[^ ]*]] -// CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]] - -// CHECK: [[g2_lpad]] -// CHECK: catchpad [i8* null] -// CHECK: catchret -// CHECK: br label %[[trycont]] - -// CHECK: [[trycont]] -// CHECK-NEXT: ret i32 1 - -// CHECK: [[cleanupend]] -// CHECK-NEXT: cleanupendpad {{.*}} unwind label %[[g2_lpad]] - -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) -// CHECK: call void @g() -// CHECK: unreachable - -int nested___except___except() { - int myres = 0; - __try { - __try { - g(); - myres = 16; - } __except (1) { - g(); - __leave; // Refers to the outer __try, not the __except we're in! - myres = 23; - return 0; - } - - myres = 51; - } __except (1) { - } - return 1; -} -// The order of basic blocks in the below doesn't matter. -// CHECK-LABEL: define i32 @nested___except___except() - -// CHECK-LABEL: invoke void @g() -// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] - -// CHECK: [[g1_lpad]] -// CHECK: catchpad [i8* null] -// CHECK: catchret {{.*}} to label %[[except:[^ ]*]] -// CHECK: [[except]] -// CHECK: invoke void @g() -// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] - -// CHECK: [[g2_lpad]] -// CHECK: catchpad [i8* null] -// CHECK: catchret -// CHECK: br label %[[trycont4:[^ ]*]] - -// CHECK: [[trycont4]] -// CHECK-NEXT: ret i32 1 - -// CHECK: [[g2_cont]] -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 - -// CHECK: [[g1_cont]] -// CHECK: store i32 16, i32* %myres -// CHECK-NEXT: br label %[[trycont:[^ ]*]] - -// CHECK: [[trycont]] -// CHECK-NEXT: store i32 51, i32* %myres -// CHECK-NEXT: br label %[[tryleave]] - -// CHECK: [[tryleave]] -// CHECK-NEXT: br label %[[trycont4]] - -int nested___finally___except() { - int myres = 0; - __try { - __try { - g(); - } __except (1) { - g(); - __leave; // Refers to the outer __try, not the __except! - myres = 23; - return 0; - } - - myres = 51; - } __finally { - } - return 1; -} -// The order of basic blocks in the below doesn't matter. -// CHECK-LABEL: define i32 @nested___finally___except() - -// CHECK-LABEL: invoke void @g() -// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] - -// CHECK: [[g1_lpad]] -// CHECK: catchpad -// CHECK: catchret -// CHECK: invoke void @g() -// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] - -// CHECK: [[g2_cont]] -// CHECK: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: 23 - -// CHECK: [[g1_cont]] -// CHECK-NEXT: br label %[[trycont:[^ ]*]] - -// CHECK: [[trycont]] -// CHECK: store i32 51, i32* % -// CHECK-NEXT: br label %[[tryleave]] - -// CHECK: [[tryleave]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 0, i8* %[[fp]]) -// CHECK-NEXT: ret i32 1 - -// CHECK: [[g2_lpad]] -// CHECK: cleanuppad -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]]) -// CHECK: cleanupret {{.*}} unwind to caller - -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i8 %abnormal_termination, i8* %frame_pointer) -// CHECK: ret void - -int nested___finally___finally() { - int myres = 0; - __try { - __try { - g(); - myres = 16; - } __finally { - g(); - __leave; // Refers to the outer __try, not the __finally we're in! - myres = 23; - return 0; - } - - myres = 51; - } __finally { - } - return 1; -} -// The order of basic blocks in the below doesn't matter. -// CHECK-LABEL: define i32 @nested___finally___finally() - -// CHECK: invoke void @g() -// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] - -// CHECK: [[g1_cont]] -// CHECK: store i32 16, i32* %[[myres:[^ ]*]], -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) -// CHECK-NEXT: to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]] - -// CHECK: [[finally_cont]] -// CHECK: store i32 51, i32* %[[myres]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) -// CHECK-NEXT: ret i32 1 - -// CHECK: [[g1_lpad]] -// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad [] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) -// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[endcleanup:[^ ]*]] -// CHECK: [[finally_cont2]] -// CHECK: cleanupret %[[padtoken]] unwind label %[[g2_lpad]] - -// CHECK: [[endcleanup]] -// CHECK-NEXT: cleanupendpad %[[padtoken]] unwind label %[[g2_lpad]] - -// CHECK: [[g2_lpad]] -// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad [] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) -// CHECK: cleanupret %[[padtoken]] unwind to caller - -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) -// CHECK: ret void - -// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) -// CHECK: call void @g() -// CHECK: unreachable diff --git a/test/CodeGen/exceptions-seh-leave.c b/test/CodeGen/exceptions-seh-leave.c index e56da17d0a..2895edbdfe 100644 --- a/test/CodeGen/exceptions-seh-leave.c +++ b/test/CodeGen/exceptions-seh-leave.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -fnew-ms-eh -emit-llvm -o - | opt -instnamer -S | FileCheck %s void g(void); @@ -157,18 +157,23 @@ int nested___except___finally() { // CHECK-NEXT: br label %[[trycont:[^ ]*]] // CHECK: [[g1_lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: catch i8* null -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: cleanuppad +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 1, i8* %[[fp]]) -// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]] +// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[cleanupend:[^ ]*]] +// CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]] // CHECK: [[g2_lpad]] +// CHECK: catchpad [i8* null] +// CHECK: catchret // CHECK: br label %[[trycont]] // CHECK: [[trycont]] // CHECK-NEXT: ret i32 1 +// CHECK: [[cleanupend]] +// CHECK-NEXT: cleanupendpad {{.*}} unwind label %[[g2_lpad]] + // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: call void @g() // CHECK: unreachable @@ -197,30 +202,29 @@ int nested___except___except() { // CHECK-LABEL: invoke void @g() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] -// CHECK: [[g1_cont]] -// CHECK: store i32 16, i32* %myres -// CHECK-NEXT: br label %[[trycont:[^ ]*]] - // CHECK: [[g1_lpad]] -// CHECK: br label %[[except:[^ ]*]] - +// CHECK: catchpad [i8* null] +// CHECK: catchret {{.*}} to label %[[except:[^ ]*]] // CHECK: [[except]] // CHECK: invoke void @g() // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] -// CHECK: [[g2_cont]] -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 - // CHECK: [[g2_lpad]] -// CHECK: br label %[[outerexcept:[^ ]*]] - -// CHECK: [[outerexcept]] +// CHECK: catchpad [i8* null] +// CHECK: catchret // CHECK: br label %[[trycont4:[^ ]*]] // CHECK: [[trycont4]] // CHECK-NEXT: ret i32 1 +// CHECK: [[g2_cont]] +// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: store i32 23 + +// CHECK: [[g1_cont]] +// CHECK: store i32 16, i32* %myres +// CHECK-NEXT: br label %[[trycont:[^ ]*]] + // CHECK: [[trycont]] // CHECK-NEXT: store i32 51, i32* %myres // CHECK-NEXT: br label %[[tryleave]] @@ -251,13 +255,9 @@ int nested___finally___except() { // CHECK-LABEL: invoke void @g() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] -// CHECK: [[g1_cont]] -// CHECK-NEXT: br label %[[trycont:[^ ]*]] - // CHECK: [[g1_lpad]] -// CHECK: br label %[[except:[^ ]*]] - -// CHECK: [[except]] +// CHECK: catchpad +// CHECK: catchret // CHECK: invoke void @g() // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] @@ -265,10 +265,8 @@ int nested___finally___except() { // CHECK: br label %[[tryleave:[^ ]*]] // CHECK-NOT: 23 -// CHECK: [[g2_lpad]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]]) -// CHECK-NEXT: br label %[[ehresume:[^ ]*]] +// CHECK: [[g1_cont]] +// CHECK-NEXT: br label %[[trycont:[^ ]*]] // CHECK: [[trycont]] // CHECK: store i32 51, i32* % @@ -279,8 +277,11 @@ int nested___finally___except() { // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: ret i32 1 -// CHECK: [[ehresume]] -// CHECK: resume +// CHECK: [[g2_lpad]] +// CHECK: cleanuppad +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]]) +// CHECK: cleanupret {{.*}} unwind to caller // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: ret void @@ -306,7 +307,7 @@ int nested___finally___finally() { // The order of basic blocks in the below doesn't matter. // CHECK-LABEL: define i32 @nested___finally___finally() -// CHECK-LABEL: invoke void @g() +// CHECK: invoke void @g() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont]] @@ -322,24 +323,21 @@ int nested___finally___finally() { // CHECK-NEXT: ret i32 1 // CHECK: [[g1_lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad [] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) -// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]] - -// CHECK: [[g2_lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: br label %[[ehcleanup:.*]] - +// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[endcleanup:[^ ]*]] // CHECK: [[finally_cont2]] -// CHECK: br label %[[ehcleanup]] +// CHECK: cleanupret %[[padtoken]] unwind label %[[g2_lpad]] -// CHECK: [[ehcleanup]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) -// CHECK: resume +// CHECK: [[endcleanup]] +// CHECK-NEXT: cleanupendpad %[[padtoken]] unwind label %[[g2_lpad]] + +// CHECK: [[g2_lpad]] +// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad [] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) +// CHECK: cleanupret %[[padtoken]] unwind to caller // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: ret void diff --git a/test/CodeGen/exceptions-seh-new.c b/test/CodeGen/exceptions-seh-new.c deleted file mode 100644 index 1a50ed0dea..0000000000 --- a/test/CodeGen/exceptions-seh-new.c +++ /dev/null @@ -1,289 +0,0 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -fnew-ms-eh -emit-llvm -o - \ -// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64 -// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -fnew-ms-eh -emit-llvm -o - \ -// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86 -// RUN: %clang_cc1 %s -triple i686-pc-windows-gnu -fms-extensions -fnew-ms-eh -emit-llvm -o - \ -// RUN: | FileCheck %s --check-prefix=X86-GNU -// RUN: %clang_cc1 %s -triple x86_64-pc-windows-gnu -fms-extensions -fnew-ms-eh -emit-llvm -o - \ -// RUN: | FileCheck %s --check-prefix=X64-GNU - -void try_body(int numerator, int denominator, int *myres) { - *myres = numerator / denominator; -} -// CHECK-LABEL: define void @try_body(i32 %numerator, i32 %denominator, i32* %myres) -// CHECK: sdiv i32 -// CHECK: store i32 %{{.*}}, i32* -// CHECK: ret void - -int safe_div(int numerator, int denominator, int *res) { - int myres = 0; - int success = 1; - __try { - try_body(numerator, denominator, &myres); - } __except (1) { - success = -42; - } - *res = myres; - return success; -} - -// CHECK-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) -// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -// CHECK: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]] -// CHECK: to label %{{.*}} unwind label %[[catchpad:[^ ]*]] -// -// CHECK: [[catchpad]] -// X64: %[[padtoken:[^ ]*]] = catchpad [i8* null] -// X86: %[[padtoken:[^ ]*]] = catchpad [i8* bitcast (i32 ()* @"\01?filt$0@0@safe_div@@" to i8*)] -// CHECK-NEXT: to label %[[exceptret:[^ ]*]] unwind label -// -// CHECK: [[exceptret]] -// CHECK: catchret %[[padtoken]] to label %[[except:[^ ]*]] -// -// CHECK: [[except]] -// CHECK: store i32 -42, i32* %[[success:[^ ]*]] -// -// CHECK: %[[res:[^ ]*]] = load i32, i32* %[[success]] -// CHECK: ret i32 %[[res]] - -// 32-bit SEH needs this filter to save the exception code. -// -// X86-LABEL: define internal i32 @"\01?filt$0@0@safe_div@@"() -// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1) -// X86: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 (i32, i32, i32*)* @safe_div to i8*), i8* %[[ebp]]) -// X86: call i8* @llvm.localrecover(i8* bitcast (i32 (i32, i32, i32*)* @safe_div to i8*), i8* %[[fp]], i32 0) -// X86: load i8*, i8** -// X86: load i32*, i32** -// X86: load i32, i32* -// X86: store i32 %{{.*}}, i32* -// X86: ret i32 1 - -// Mingw uses msvcrt, so it can also use _except_handler3. -// X86-GNU-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) -// X86-GNU-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -// X64-GNU-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) -// X64-GNU-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) - -void j(void); - -int filter_expr_capture(void) { - int r = 42; - __try { - j(); - } __except(r = -1) { - r = 13; - } - return r; -} - -// CHECK-LABEL: define i32 @filter_expr_capture() -// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -// X64: call void (...) @llvm.localescape(i32* %[[r:[^ ,]*]]) -// X86: call void (...) @llvm.localescape(i32* %[[r:[^ ,]*]], i32* %[[code:[^ ,]*]]) -// CHECK: store i32 42, i32* %[[r]] -// CHECK: invoke void @j() #[[NOINLINE]] -// -// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@filter_expr_capture@@" to i8*)] -// CHECK: store i32 13, i32* %[[r]] -// -// CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]] -// CHECK: ret i32 %[[rv]] - -// X64-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer) -// X64: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer, i32 0) -// -// X86-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"() -// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1) -// X86: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[ebp]]) -// X86: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[fp]], i32 0) -// -// CHECK: store i32 -1, i32* %{{.*}} -// CHECK: ret i32 -1 - -int nested_try(void) { - int r = 42; - __try { - __try { - j(); - r = 0; - } __except(_exception_code() == 123) { - r = 123; - } - } __except(_exception_code() == 456) { - r = 456; - } - return r; -} -// CHECK-LABEL: define i32 @nested_try() -// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -// CHECK: store i32 42, i32* %[[r:[^ ,]*]] -// CHECK: invoke void @j() #[[NOINLINE]] -// CHECK: to label %[[cont:[^ ]*]] unwind label %[[cpad_inner:[^ ]*]] -// -// CHECK: [[cpad_inner]] -// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*)] -// CHECK-NEXT: to label %[[exceptret_inner:[^ ]*]] unwind label %[[cpad_outer:[^ ]*]] -// -// CHECK: [[exceptret_inner]] -// CHECK: catchret {{.*}} to label %[[except_inner:[^ ]*]] -// -// CHECK: [[except_inner]] -// CHECK: store i32 123, i32* %[[r]] -// CHECK: br label %[[inner_try_cont:[^ ]*]] -// -// CHECK: [[inner_try_cont]] -// CHECK: br label %[[outer_try_cont:[^ ]*]] -// -// CHECK: [[cpad_outer]] -// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*)] -// CHECK-NEXT: to label %[[exceptret_outer:[^ ]*]] unwind label -// -// CHECK: [[exceptret_outer]] -// CHECK: catchret {{.*}} to label %[[except_outer:[^ ]*]] -// -// CHECK: [[except_outer]] -// CHECK: store i32 456, i32* %[[r]] -// CHECK: br label %[[outer_try_cont]] -// -// CHECK: [[outer_try_cont]] -// CHECK: %[[r_load:[^ ]*]] = load i32, i32* %[[r]] -// CHECK: ret i32 %[[r_load]] -// -// CHECK: [[cont]] -// CHECK: store i32 0, i32* %[[r]] -// CHECK: br label %[[inner_try_cont]] -// -// CHECK-LABEL: define internal i32 @"\01?filt$0@0@nested_try@@"({{.*}}) -// X86: call i8* @llvm.x86.seh.recoverfp({{.*}}) -// CHECK: load i32*, i32** -// CHECK: load i32, i32* -// CHECK: icmp eq i32 %{{.*}}, 456 -// -// CHECK-LABEL: define internal i32 @"\01?filt$1@0@nested_try@@"({{.*}}) -// X86: call i8* @llvm.x86.seh.recoverfp({{.*}}) -// CHECK: load i32*, i32** -// CHECK: load i32, i32* -// CHECK: icmp eq i32 %{{.*}}, 123 - -int basic_finally(int g) { - __try { - j(); - } __finally { - ++g; - } - return g; -} -// CHECK-LABEL: define i32 @basic_finally(i32 %g) -// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -// CHECK: %[[g_addr:[^ ]*]] = alloca i32, align 4 -// CHECK: call void (...) @llvm.localescape(i32* %[[g_addr]]) -// CHECK: store i32 %g, i32* %[[g_addr]] -// -// CHECK: invoke void @j() -// CHECK: to label %[[cont:[^ ]*]] unwind label %[[cleanuppad:[^ ]*]] -// -// CHECK: [[cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) -// CHECK: load i32, i32* %[[g_addr]], align 4 -// CHECK: ret i32 -// -// CHECK: [[cleanuppad]] -// CHECK: %[[padtoken:[^ ]*]] = cleanuppad [] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK: invoke void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) -// CHECK: to label %[[cleanupcont:[^ ]*]] unwind label %[[cleanupend:[^ ]*]] -// CHECK: [[cleanupcont]] -// CHECK: cleanupret %[[padtoken]] unwind to caller -// CHECK: [[cleanupend]] -// CHECK: cleanupendpad %[[padtoken]] unwind to caller - -// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} %abnormal_termination, i8* %frame_pointer) -// CHECK: call i8* @llvm.localrecover(i8* bitcast (i32 (i32)* @basic_finally to i8*), i8* %frame_pointer, i32 0) -// CHECK: load i32, i32* %{{.*}}, align 4 -// CHECK: add nsw i32 %{{.*}}, 1 -// CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 4 -// CHECK: ret void - -int returns_int(void); -int except_return(void) { - __try { - return returns_int(); - } __except(1) { - return 42; - } -} -// CHECK-LABEL: define i32 @except_return() -// CHECK: %[[tmp:[^ ]*]] = invoke i32 @returns_int() -// CHECK: to label %[[cont:[^ ]*]] unwind label %[[catchpad:[^ ]*]] -// -// CHECK: [[catchpad]] -// CHECK: catchpad -// CHECK: catchret -// CHECK: store i32 42, i32* %[[rv:[^ ]*]] -// CHECK: br label %[[retbb:[^ ]*]] -// -// CHECK: [[cont]] -// CHECK: store i32 %[[tmp]], i32* %[[rv]] -// CHECK: br label %[[retbb]] -// -// CHECK: [[retbb]] -// CHECK: %[[r:[^ ]*]] = load i32, i32* %[[rv]] -// CHECK: ret i32 %[[r]] - - -// PR 24751: don't assert if a variable is used twice in a __finally block. -// Also, make sure we don't do redundant work to capture/project it. -void finally_capture_twice(int x) { - __try { - } __finally { - int y = x; - int z = x; - } -} -// -// CHECK-LABEL: define void @finally_capture_twice( -// CHECK: [[X:%.*]] = alloca i32, align 4 -// CHECK: call void (...) @llvm.localescape(i32* [[X]]) -// CHECK-NEXT: store i32 {{.*}}, i32* [[X]], align 4 -// CHECK-NEXT: [[LOCAL:%.*]] = call i8* @llvm.localaddress() -// CHECK-NEXT: call void [[FINALLY:@.*]](i8{{ zeroext | }}0, i8* [[LOCAL]]) -// CHECK: define internal void [[FINALLY]]( -// CHECK: [[LOCAL:%.*]] = call i8* @llvm.localrecover( -// CHECK: [[X:%.*]] = bitcast i8* [[LOCAL]] to i32* -// CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[Z:%.*]] = alloca i32, align 4 -// CHECK-NEXT: store i8* -// CHECK-NEXT: store i8 -// CHECK-NEXT: [[T0:%.*]] = load i32, i32* [[X]], align 4 -// CHECK-NEXT: store i32 [[T0]], i32* [[Y]], align 4 -// CHECK-NEXT: [[T0:%.*]] = load i32, i32* [[X]], align 4 -// CHECK-NEXT: store i32 [[T0]], i32* [[Z]], align 4 -// CHECK-NEXT: ret void - -int exception_code_in_except(void) { - __try { - try_body(0, 0, 0); - } __except(1) { - return _exception_code(); - } -} - -// CHECK-LABEL: define i32 @exception_code_in_except() -// CHECK: %[[ret_slot:[^ ]*]] = alloca i32 -// CHECK: %[[code_slot:[^ ]*]] = alloca i32 -// CHECK: invoke void @try_body(i32 0, i32 0, i32* null) -// CHECK: %[[pad:[^ ]*]] = catchpad -// CHECK: catchret %[[pad]] -// X64: %[[code:[^ ]*]] = call i32 @llvm.eh.exceptioncode(token %[[pad]]) -// X64: store i32 %[[code]], i32* %[[code_slot]] -// CHECK: %[[ret1:[^ ]*]] = load i32, i32* %[[code_slot]] -// CHECK: store i32 %[[ret1]], i32* %[[ret_slot]] -// CHECK: %[[ret2:[^ ]*]] = load i32, i32* %[[ret_slot]] -// CHECK: ret i32 %[[ret2]] - -// CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} } diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c index b69616ba9b..1a50ed0dea 100644 --- a/test/CodeGen/exceptions-seh.c +++ b/test/CodeGen/exceptions-seh.c @@ -1,7 +1,11 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - \ +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -fnew-ms-eh -emit-llvm -o - \ // RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64 -// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - \ +// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -fnew-ms-eh -emit-llvm -o - \ // RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86 +// RUN: %clang_cc1 %s -triple i686-pc-windows-gnu -fms-extensions -fnew-ms-eh -emit-llvm -o - \ +// RUN: | FileCheck %s --check-prefix=X86-GNU +// RUN: %clang_cc1 %s -triple x86_64-pc-windows-gnu -fms-extensions -fnew-ms-eh -emit-llvm -o - \ +// RUN: | FileCheck %s --check-prefix=X64-GNU void try_body(int numerator, int denominator, int *myres) { *myres = numerator / denominator; @@ -23,36 +27,28 @@ int safe_div(int numerator, int denominator, int *res) { return success; } -// X64-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) {{.*}} personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X64: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]] -// X64: to label %{{.*}} unwind label %[[lpad:[^ ]*]] +// CHECK-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) +// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// CHECK: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]] +// CHECK: to label %{{.*}} unwind label %[[catchpad:[^ ]*]] // -// X64: [[lpad]] -// X64: landingpad { i8*, i32 } -// X64-NEXT: catch i8* null -// X64-NOT: br i1 -// X64: br label %[[except:[^ ]*]] -// X64: [[except]] -// X64: store i32 -42, i32* %[[success:[^ ]*]] +// CHECK: [[catchpad]] +// X64: %[[padtoken:[^ ]*]] = catchpad [i8* null] +// X86: %[[padtoken:[^ ]*]] = catchpad [i8* bitcast (i32 ()* @"\01?filt$0@0@safe_div@@" to i8*)] +// CHECK-NEXT: to label %[[exceptret:[^ ]*]] unwind label // -// X64: %[[res:[^ ]*]] = load i32, i32* %[[success]] -// X64: ret i32 %[[res]] - -// X86-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) {{.*}} personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -// X86: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]] -// X86: to label %{{.*}} unwind label %[[lpad:[^ ]*]] +// CHECK: [[exceptret]] +// CHECK: catchret %[[padtoken]] to label %[[except:[^ ]*]] // -// X86: [[lpad]] -// X86: landingpad { i8*, i32 } -// X86-NEXT: catch i8* bitcast (i32 ()* @"\01?filt$0@0@safe_div@@" to i8*) -// X86-NOT: br i1 -// X86: br label %[[except:[^ ]*]] -// X86: [[except]] -// X86: store i32 -42, i32* %[[success:[^ ]*]] +// CHECK: [[except]] +// CHECK: store i32 -42, i32* %[[success:[^ ]*]] // -// X86: %[[res:[^ ]*]] = load i32, i32* %[[success]] -// X86: ret i32 %[[res]] +// CHECK: %[[res:[^ ]*]] = load i32, i32* %[[success]] +// CHECK: ret i32 %[[res]] +// 32-bit SEH needs this filter to save the exception code. +// // X86-LABEL: define internal i32 @"\01?filt$0@0@safe_div@@"() // X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1) // X86: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 (i32, i32, i32*)* @safe_div to i8*), i8* %[[ebp]]) @@ -63,6 +59,12 @@ int safe_div(int numerator, int denominator, int *res) { // X86: store i32 %{{.*}}, i32* // X86: ret i32 1 +// Mingw uses msvcrt, so it can also use _except_handler3. +// X86-GNU-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) +// X86-GNU-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// X64-GNU-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) +// X64-GNU-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) + void j(void); int filter_expr_capture(void) { @@ -83,8 +85,7 @@ int filter_expr_capture(void) { // CHECK: store i32 42, i32* %[[r]] // CHECK: invoke void @j() #[[NOINLINE]] // -// CHECK: landingpad -// CHECK-NEXT: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@filter_expr_capture@@" to i8*) +// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@filter_expr_capture@@" to i8*)] // CHECK: store i32 13, i32* %[[r]] // // CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]] @@ -120,42 +121,41 @@ int nested_try(void) { // X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) // CHECK: store i32 42, i32* %[[r:[^ ,]*]] // CHECK: invoke void @j() #[[NOINLINE]] -// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] +// CHECK: to label %[[cont:[^ ]*]] unwind label %[[cpad_inner:[^ ]*]] // -// CHECK: [[cont]] -// CHECK: store i32 0, i32* %[[r]] +// CHECK: [[cpad_inner]] +// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*)] +// CHECK-NEXT: to label %[[exceptret_inner:[^ ]*]] unwind label %[[cpad_outer:[^ ]*]] +// +// CHECK: [[exceptret_inner]] +// CHECK: catchret {{.*}} to label %[[except_inner:[^ ]*]] +// +// CHECK: [[except_inner]] +// CHECK: store i32 123, i32* %[[r]] // CHECK: br label %[[inner_try_cont:[^ ]*]] // -// CHECK: [[lpad]] -// CHECK: landingpad { i8*, i32 } -// CHECK: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*) -// CHECK: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*) -// CHECK: store i8* %{{.*}}, i8** %[[ehptr_slot:[^ ]*]] -// CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]] +// CHECK: [[inner_try_cont]] +// CHECK: br label %[[outer_try_cont:[^ ]*]] // -// CHECK: load i32, i32* %[[sel_slot]] -// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*)) -// CHECK: icmp eq i32 -// CHECK: br i1 +// CHECK: [[cpad_outer]] +// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*)] +// CHECK-NEXT: to label %[[exceptret_outer:[^ ]*]] unwind label // -// CHECK: load i32, i32* %[[sel_slot]] -// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*)) -// CHECK: icmp eq i32 -// CHECK: br i1 +// CHECK: [[exceptret_outer]] +// CHECK: catchret {{.*}} to label %[[except_outer:[^ ]*]] // +// CHECK: [[except_outer]] // CHECK: store i32 456, i32* %[[r]] -// CHECK: br label %[[outer_try_cont:[^ ]*]] +// CHECK: br label %[[outer_try_cont]] // // CHECK: [[outer_try_cont]] // CHECK: %[[r_load:[^ ]*]] = load i32, i32* %[[r]] // CHECK: ret i32 %[[r_load]] // -// CHECK: store i32 123, i32* %[[r]] +// CHECK: [[cont]] +// CHECK: store i32 0, i32* %[[r]] // CHECK: br label %[[inner_try_cont]] // -// CHECK: [[inner_try_cont]] -// CHECK: br label %[[outer_try_cont]] -// // CHECK-LABEL: define internal i32 @"\01?filt$0@0@nested_try@@"({{.*}}) // X86: call i8* @llvm.x86.seh.recoverfp({{.*}}) // CHECK: load i32*, i32** @@ -184,7 +184,7 @@ int basic_finally(int g) { // CHECK: store i32 %g, i32* %[[g_addr]] // // CHECK: invoke void @j() -// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] +// CHECK: to label %[[cont:[^ ]*]] unwind label %[[cleanuppad:[^ ]*]] // // CHECK: [[cont]] // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() @@ -192,12 +192,15 @@ int basic_finally(int g) { // CHECK: load i32, i32* %[[g_addr]], align 4 // CHECK: ret i32 // -// CHECK: [[lpad]] -// CHECK: landingpad { i8*, i32 } -// CHECK-NEXT: cleanup +// CHECK: [[cleanuppad]] +// CHECK: %[[padtoken:[^ ]*]] = cleanuppad [] // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) -// CHECK: resume +// CHECK: invoke void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) +// CHECK: to label %[[cleanupcont:[^ ]*]] unwind label %[[cleanupend:[^ ]*]] +// CHECK: [[cleanupcont]] +// CHECK: cleanupret %[[padtoken]] unwind to caller +// CHECK: [[cleanupend]] +// CHECK: cleanupendpad %[[padtoken]] unwind to caller // CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} %abnormal_termination, i8* %frame_pointer) // CHECK: call i8* @llvm.localrecover(i8* bitcast (i32 (i32)* @basic_finally to i8*), i8* %frame_pointer, i32 0) @@ -216,14 +219,16 @@ int except_return(void) { } // CHECK-LABEL: define i32 @except_return() // CHECK: %[[tmp:[^ ]*]] = invoke i32 @returns_int() -// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] +// CHECK: to label %[[cont:[^ ]*]] unwind label %[[catchpad:[^ ]*]] // -// CHECK: [[cont]] -// CHECK: store i32 %[[tmp]], i32* %[[rv:[^ ]*]] +// CHECK: [[catchpad]] +// CHECK: catchpad +// CHECK: catchret +// CHECK: store i32 42, i32* %[[rv:[^ ]*]] // CHECK: br label %[[retbb:[^ ]*]] // -// CHECK: [[lpad]] -// CHECK: store i32 42, i32* %[[rv]] +// CHECK: [[cont]] +// CHECK: store i32 %[[tmp]], i32* %[[rv]] // CHECK: br label %[[retbb]] // // CHECK: [[retbb]] @@ -260,4 +265,25 @@ void finally_capture_twice(int x) { // CHECK-NEXT: store i32 [[T0]], i32* [[Z]], align 4 // CHECK-NEXT: ret void +int exception_code_in_except(void) { + __try { + try_body(0, 0, 0); + } __except(1) { + return _exception_code(); + } +} + +// CHECK-LABEL: define i32 @exception_code_in_except() +// CHECK: %[[ret_slot:[^ ]*]] = alloca i32 +// CHECK: %[[code_slot:[^ ]*]] = alloca i32 +// CHECK: invoke void @try_body(i32 0, i32 0, i32* null) +// CHECK: %[[pad:[^ ]*]] = catchpad +// CHECK: catchret %[[pad]] +// X64: %[[code:[^ ]*]] = call i32 @llvm.eh.exceptioncode(token %[[pad]]) +// X64: store i32 %[[code]], i32* %[[code_slot]] +// CHECK: %[[ret1:[^ ]*]] = load i32, i32* %[[code_slot]] +// CHECK: store i32 %[[ret1]], i32* %[[ret_slot]] +// CHECK: %[[ret2:[^ ]*]] = load i32, i32* %[[ret_slot]] +// CHECK: ret i32 %[[ret2]] + // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} } diff --git a/test/CodeGenCXX/exceptions-seh.cpp b/test/CodeGenCXX/exceptions-seh.cpp index 187ad4bc71..c6120b8172 100644 --- a/test/CodeGenCXX/exceptions-seh.cpp +++ b/test/CodeGenCXX/exceptions-seh.cpp @@ -32,13 +32,9 @@ extern "C" void use_cxx() { // CXXEH: ret void // // CXXEH: [[lpad]] -// CXXEH: landingpad { i8*, i32 } -// CXXEH-NEXT: cleanup +// CXXEH: cleanuppad // CXXEH: call void @"\01??1HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}}) -// CXXEH: br label %[[resume:[^ ]*]] -// -// CXXEH: [[resume]] -// CXXEH: resume +// CXXEH: cleanupret // NOCXX-LABEL: define void @use_cxx() // NOCXX-NOT: invoke @@ -64,17 +60,18 @@ extern "C" void use_seh() { // CHECK: invoke void @might_throw() #[[NOINLINE:[0-9]+]] // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // -// CHECK: [[cont]] -// CHECK: br label %[[ret:[^ ]*]] -// // CHECK: [[lpad]] -// CHECK: landingpad { i8*, i32 } -// CHECK-NEXT: catch i8* +// CHECK-NEXT: catchpad +// CHECK: catchret {{.*}} label %[[except:[^ ]*]] // -// CHECK: br label %[[ret]] +// CHECK: [[except]] +// CHECK: br label %[[ret:[^ ]*]] // // CHECK: [[ret]] // CHECK: ret void +// +// CHECK: [[cont]] +// CHECK: br label %[[ret]] void use_seh_in_lambda() { ([]() { @@ -89,7 +86,7 @@ void use_seh_in_lambda() { // CXXEH-LABEL: define void @"\01?use_seh_in_lambda@@YAXXZ"() // CXXEH-SAME: personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) -// CXXEH: landingpad { i8*, i32 } +// CXXEH: cleanuppad // NOCXX-LABEL: define void @"\01?use_seh_in_lambda@@YAXXZ"() // NOCXX-NOT: invoke @@ -98,7 +95,7 @@ void use_seh_in_lambda() { // CHECK-LABEL: define internal void @"\01??R@?use_seh_in_lambda@@YAXXZ@QEBAXXZ"(%class.anon* %this) // CXXEH-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK: invoke void @might_throw() #[[NOINLINE]] -// CHECK: landingpad { i8*, i32 } +// CHECK: catchpad static int my_unique_global; @@ -122,8 +119,7 @@ void use_inline() { // CHECK-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK: invoke void @might_throw() // -// CHECK: landingpad { i8*, i32 } -// CHECK-NEXT: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@use_seh_in_inline_func@@" to i8*) +// CHECK: catchpad [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@use_seh_in_inline_func@@" to i8*)] // // CHECK: invoke void @might_throw() // @@ -131,10 +127,9 @@ void use_inline() { // CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 0, i8* %[[fp]]) // CHECK: ret void // -// CHECK: landingpad { i8*, i32 } -// CHECK-NEXT: cleanup +// CHECK: cleanuppad // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() -// CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 1, i8* %[[fp]]) +// CHECK: invoke void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 1, i8* %[[fp]]) // CHECK-LABEL: define internal i32 @"\01?filt$0@0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func) // CHECK: icmp eq i32 %{{.*}}, 424242 diff --git a/test/CodeGenCXX/microsoft-abi-arg-order.cpp b/test/CodeGenCXX/microsoft-abi-arg-order.cpp index a4fdb8272a..e13ed5a8b6 100644 --- a/test/CodeGenCXX/microsoft-abi-arg-order.cpp +++ b/test/CodeGenCXX/microsoft-abi-arg-order.cpp @@ -52,8 +52,9 @@ void call_foo() { // X86: ret void // // lpad2: +// X86: cleanuppad [] // X86: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg2]]) -// X86: br label +// X86: cleanupret // // ehcleanup: // X86: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg3]]) @@ -67,8 +68,9 @@ void call_foo() { // X64: ret void // // lpad2: +// X64: cleanuppad [] // X64: call void @"\01??1A@@QEAA@XZ"(%struct.A* %[[arg2]]) -// X64: br label +// X64: cleanupret // // ehcleanup: // X64: call void @"\01??1A@@QEAA@XZ"(%struct.A* %[[arg3]]) diff --git a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp index c3f757a3bc..27e848b86b 100644 --- a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp +++ b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp @@ -148,7 +148,7 @@ C::C() { foo(); } // Verify that we don't bother with a vbtable lookup when adjusting the this // pointer to call a base destructor from a constructor while unwinding. // WIN32-LABEL: define {{.*}} @"\01??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} { -// WIN32: landingpad +// WIN32: cleanuppad // // We shouldn't do any vbptr loads, just constant GEPs. // WIN32-NOT: load @@ -185,7 +185,6 @@ void f() { // WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}}) // // WIN32: [[lpad]] -// WIN32-NEXT: landingpad -// WIN32-NEXT: cleanup +// WIN32-NEXT: cleanuppad // WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}}) } diff --git a/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp b/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp index cbc1686893..6d462bf7b0 100644 --- a/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp +++ b/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp @@ -6,10 +6,9 @@ void never_throws() noexcept(true) { may_throw(); } -// CHECK-LABEL: define void @"\01?never_throws@@YAXXZ" +// CHECK-LABEL: define void @"\01?never_throws@@YAXXZ"() +// CHECK-SAME: personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) // CHECK: invoke void @"\01?may_throw@@YAXXZ"() - -// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) -// MSVC2013: call void @"\01?terminate@@YAXXZ"() -// MSVC2015: call void @__std_terminate() +// MSVC2013: terminatepad [void ()* @"\01?terminate@@YAXXZ"] +// MSVC2015: terminatepad [void ()* @__std_terminate] // CHECK-NEXT: unreachable diff --git a/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp b/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp index 89a62c2cb3..dadc656a15 100644 --- a/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp +++ b/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp @@ -39,15 +39,11 @@ extern inline S &f() { // CHECK-NEXT: ret %struct.S* @"\01?s@?1??f@@YAAAUS@@XZ@4U2@A" // CHECK: [[lpad:.*]]: -// CHECK-NEXT: landingpad { i8*, i32 } -// CHECK-NEXT: cleanup +// CHECK-NEXT: cleanuppad [] // CHECK: %[[guard:.*]] = load i32, i32* @"\01??__J?1??f@@YAAAUS@@XZ@51" // CHECK-NEXT: %[[mask:.*]] = and i32 %[[guard]], -2 // CHECK-NEXT: store i32 %[[mask]], i32* @"\01??__J?1??f@@YAAAUS@@XZ@51" -// CHECK-NEXT: br label %[[eh_resume:.*]] -// -// CHECK: [[eh_resume]]: -// CHECK: resume { i8*, i32 } +// CHECK-NEXT: cleanupret {{.*}} unwind to caller return s; } @@ -79,11 +75,9 @@ extern inline S &g() { // CHECK-NEXT: ret %struct.S* @"\01?s@?1??g@@YAAAUS@@XZ@4U2@A" // // CHECK: [[lpad]]: +// CHECK-NEXT: cleanuppad [] // CHECK: call void @_Init_thread_abort(i32* @"\01?$TSS0@?1??g@@YAAAUS@@XZ") -// CHECK-NEXT: br label %[[eh_resume:.*]] -// -// CHECK: [[eh_resume]]: -// CHECK: resume { i8*, i32 } +// CHECK-NEXT: cleanupret {{.*}} unwind to caller return s; } diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp index 6a4de6d528..e43afdace9 100644 --- a/test/OpenMP/parallel_codegen.cpp +++ b/test/OpenMP/parallel_codegen.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -emit-llvm %s -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK-DEBUG %s // expected-no-diagnostics -- 2.40.0