From: Nico Weber Date: Wed, 29 Apr 2015 03:08:32 +0000 (+0000) Subject: Revert r236052, it caused linker errors when building 32-bit applications. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=50d6060ac86d3e405bdd31132da5a79deb50cfcf;p=clang Revert r236052, it caused linker errors when building 32-bit applications. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@236082 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1ed97acd0b..a7327243ae 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5546,8 +5546,6 @@ def err_seh_try_outside_functions : Error< "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< "cannot use C++ 'try' in the same function as SEH '__try'">; -def err_seh_try_unsupported : Error< - "SEH '__try' is not supported on this target">; def note_conflicting_try_here : Note< "conflicting %0 here">; def warn_jump_out_of_seh_finally : Warning< diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index a8913ddd09..cb7570ad4a 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -807,11 +807,6 @@ public: return TLSSupported; } - /// \brief Whether the target supports SEH __try. - bool isSEHTrySupported() const { - return getTriple().isOSWindows(); - } - /// \brief Return true if {|} are normal characters in the asm string. /// /// If this returns false (the default), then {abc|xyz} is syntax diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index ae47efe1ad..337aaf23fd 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -20,7 +20,6 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Basic/TargetBuiltins.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" @@ -1272,6 +1271,14 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { } void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { + // FIXME: Implement SEH on other architectures. + const llvm::Triple &T = CGM.getTarget().getTriple(); + if (T.getArch() != llvm::Triple::x86_64 || + !T.isKnownWindowsMSVCEnvironment()) { + ErrorUnsupported(&S, "__try statement"); + return; + } + EnterSEHTryStmt(S); { JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); @@ -1296,39 +1303,25 @@ struct PerformSEHFinally : EHScopeStack::Cleanup { void Emit(CodeGenFunction &CGF, Flags F) override { ASTContext &Context = CGF.getContext(); - CodeGenModule &CGM = CGF.CGM; + QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; + FunctionProtoType::ExtProtoInfo EPI; + const auto *FTP = cast( + Context.getFunctionType(Context.VoidTy, ArgTys, EPI)); - // In 64-bit, we call the child function with arguments. In 32-bit, we store - // zero in the parent frame and use framerecover to check the value. - const CGFunctionInfo *FnInfo; CallArgList Args; - if (CGF.getTarget().getTriple().getArch() == llvm::Triple::x86_64) { - // Compute the two argument values. - QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; - llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress); - llvm::Value *FP = - CGF.Builder.CreateCall(FrameAddr, CGF.Builder.getInt32(0)); - llvm::Value *IsForEH = - llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); - Args.add(RValue::get(IsForEH), ArgTys[0]); - Args.add(RValue::get(FP), ArgTys[1]); - - // Arrange a two-arg function info and type. - FunctionProtoType::ExtProtoInfo EPI; - const auto *FPT = cast( - Context.getFunctionType(Context.VoidTy, ArgTys, EPI)); - FnInfo = &CGM.getTypes().arrangeFreeFunctionCall(Args, FPT, - /*chainCall=*/false); - } else { - // Emit the zero store if this is normal control flow. There are no - // explicit arguments. - if (F.isForNormalCleanup() && CGF.ChildAbnormalTerminationSlot) - CGF.Builder.CreateStore(CGF.Builder.getInt32(0), - CGF.ChildAbnormalTerminationSlot); - FnInfo = &CGM.getTypes().arrangeNullaryFunction(); - } + llvm::Value *IsForEH = + llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); + Args.add(RValue::get(IsForEH), ArgTys[0]); - CGF.EmitCall(*FnInfo, OutlinedFinally, ReturnValueSlot(), Args); + CodeGenModule &CGM = CGF.CGM; + llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0); + llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress); + llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero); + Args.add(RValue::get(FP), ArgTys[1]); + + const CGFunctionInfo &FnInfo = + CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false); + CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args); } }; } @@ -1339,7 +1332,6 @@ struct CaptureFinder : ConstStmtVisitor { CodeGenFunction &ParentCGF; const VarDecl *ParentThis; SmallVector Captures; - llvm::Value *AbnormalTermination = nullptr; CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis) : ParentCGF(ParentCGF), ParentThis(ParentThis) {} @@ -1366,93 +1358,25 @@ struct CaptureFinder : ConstStmtVisitor { void VisitCXXThisExpr(const CXXThisExpr *E) { Captures.push_back(ParentThis); } - - void VisitCallExpr(const CallExpr *E) { - // We only need to add parent frame allocations for these builtins in x86. - if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86) - return; - - unsigned ID = E->getBuiltinCallee(); - switch (ID) { - case Builtin::BI__abnormal_termination: - case Builtin::BI_abnormal_termination: - // This is the simple case where we are the outermost finally. All we - // have to do here is make sure we escape this and recover it in the - // outlined handler. - if (!AbnormalTermination) - AbnormalTermination = ParentCGF.CreateMemTemp( - ParentCGF.getContext().IntTy, "abnormal_termination"); - break; - } - } }; } -llvm::Value *CodeGenFunction::recoverAddrOfEscapedLocal( - CodeGenFunction &ParentCGF, llvm::Value *ParentVar, llvm::Value *ParentFP) { - llvm::CallInst *RecoverCall = nullptr; - CGBuilderTy Builder(AllocaInsertPt); - if (auto *ParentAlloca = dyn_cast(ParentVar)) { - // Mark the variable escaped if nobody else referenced it and compute the - // frameescape index. - auto InsertPair = ParentCGF.EscapedLocals.insert( - std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); - int FrameEscapeIdx = InsertPair.first->second; - // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N) - llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( - &CGM.getModule(), llvm::Intrinsic::framerecover); - llvm::Constant *ParentI8Fn = - llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); - RecoverCall = - Builder.CreateCall3(FrameRecoverFn, ParentI8Fn, ParentFP, - llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)); - - } else { - // If the parent didn't have an alloca, we're doing some nested outlining. - // Just clone the existing framerecover call, but tweak the FP argument to - // use our FP value. All other arguments are constants. - auto *ParentRecover = - cast(ParentVar->stripPointerCasts()); - assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover && - "expected alloca or framerecover in parent LocalDeclMap"); - RecoverCall = cast(ParentRecover->clone()); - RecoverCall->setArgOperand(1, ParentFP); - RecoverCall->insertBefore(AllocaInsertPt); - } - - // Bitcast the variable, rename it, and insert it in the local decl map. - llvm::Value *ChildVar = - Builder.CreateBitCast(RecoverCall, ParentVar->getType()); - ChildVar->setName(ParentVar->getName()); - return ChildVar; -} - void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, - const Stmt *OutlinedStmt) { + const Stmt *OutlinedStmt, + llvm::Value *ParentFP) { // Find all captures in the Stmt. CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl); Finder.Visit(OutlinedStmt); // Typically there are no captures and we can exit early. - if (Finder.Captures.empty() && !Finder.AbnormalTermination) + if (Finder.Captures.empty()) return; - // The parent FP is passed in as EBP on x86 and the second argument on x64. - llvm::Value *ParentFP; - if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) { - auto AI = CurFn->arg_begin(); - ++AI; - ParentFP = AI; - } else { - CGBuilderTy Builder(AllocaInsertPt); - ParentFP = Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::frameaddress), Builder.getInt32(1)); - - // Inlining will break llvm.frameaddress(1), so disable it. - // FIXME: We could teach the inliner about the special meaning of - // frameaddress, framerecover, and frameescape to remove this limitation. - CurFn->addFnAttr(llvm::Attribute::NoInline); - } + // Prepare the first two arguments to llvm.framerecover. + llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::framerecover); + llvm::Constant *ParentI8Fn = + llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); // Create llvm.framerecover calls for all captures. for (const VarDecl *VD : Finder.Captures) { @@ -1475,16 +1399,39 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, continue; llvm::Value *ParentVar = I->second; - LocalDeclMap[VD] = - recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP); - } + llvm::CallInst *RecoverCall = nullptr; + CGBuilderTy Builder(AllocaInsertPt); + if (auto *ParentAlloca = dyn_cast(ParentVar)) { + // Mark the variable escaped if nobody else referenced it and compute the + // frameescape index. + auto InsertPair = + ParentCGF.EscapedLocals.insert(std::make_pair(ParentAlloca, -1)); + if (InsertPair.second) + InsertPair.first->second = ParentCGF.EscapedLocals.size() - 1; + int FrameEscapeIdx = InsertPair.first->second; + // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N) + RecoverCall = + Builder.CreateCall3(FrameRecoverFn, ParentI8Fn, ParentFP, + llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)); + + } else { + // If the parent didn't have an alloca, we're doing some nested outlining. + // Just clone the existing framerecover call, but tweak the FP argument to + // use our FP value. All other arguments are constants. + auto *ParentRecover = + cast(ParentVar->stripPointerCasts()); + assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover && + "expected alloca or framerecover in parent LocalDeclMap"); + RecoverCall = cast(ParentRecover->clone()); + RecoverCall->setArgOperand(1, ParentFP); + RecoverCall->insertBefore(AllocaInsertPt); + } - // AbnormalTermination is just another capture, but it has no Decl. - if (Finder.AbnormalTermination) { - AbnormalTerminationSlot = recoverAddrOfEscapedLocal( - ParentCGF, Finder.AbnormalTermination, ParentFP); - // Save the slot on the parent so it can store 1 and 0 to it. - ParentCGF.ChildAbnormalTerminationSlot = Finder.AbnormalTermination; + // Bitcast the variable, rename it, and insert it in the local decl map. + llvm::Value *ChildVar = + Builder.CreateBitCast(RecoverCall, ParentVar->getType()); + ChildVar->setName(ParentVar->getName()); + LocalDeclMap[VD] = ChildVar; } } @@ -1519,7 +1466,10 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart()); CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn); - EmitCapturedLocals(ParentCGF, OutlinedStmt); + + auto AI = Fn->arg_begin(); + ++AI; + EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI); } /// Create a stub filter function that will ultimately hold the code of the @@ -1531,16 +1481,14 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, const Expr *FilterExpr = Except.getFilterExpr(); SourceLocation StartLoc = FilterExpr->getLocStart(); + SEHPointersDecl = ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy); FunctionArgList Args; - if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) { - SEHPointersDecl = ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy); - Args.push_back(SEHPointersDecl); - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); - } + Args.push_back(SEHPointersDecl); + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); // Get the mangled function name. SmallString<128> Name; @@ -1581,15 +1529,13 @@ CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, SourceLocation StartLoc = FinallyBlock->getLocStart(); FunctionArgList Args; - if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) { - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("abnormal_termination"), - getContext().UnsignedCharTy)); - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); - } + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("abnormal_termination"), + getContext().UnsignedCharTy)); + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); // Get the mangled function name. SmallString<128> Name; @@ -1621,7 +1567,7 @@ void CodeGenFunction::EmitSEHExceptionCodeSave() { // }; // void *exn.slot = // (void *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode; - llvm::Value *Ptrs = EmitSEHExceptionInfo(); + llvm::Value *Ptrs = Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl)); llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo(); llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr); Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo()); @@ -1636,9 +1582,6 @@ void CodeGenFunction::EmitSEHExceptionCodeSave() { } llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() { - if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86_64) - return Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::eh_exceptioninfo)); // Sema should diagnose calling this builtin outside of a filter context, but // don't crash if we screw up. if (!SEHPointersDecl) @@ -1656,8 +1599,6 @@ llvm::Value *CodeGenFunction::EmitSEHExceptionCode() { } llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { - if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86_64) - return Builder.CreateLoad(AbnormalTerminationSlot); // Abnormal termination is just the first parameter to the outlined finally // helper. auto AI = CurFn->arg_begin(); @@ -1667,15 +1608,9 @@ llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { - // Outline the finally block. + // Push a cleanup for __finally blocks. llvm::Function *FinallyFunc = HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); - - // Store 1 to indicate abnormal termination if an exception is thrown. - if (ChildAbnormalTerminationSlot) - Builder.CreateStore(Builder.getInt32(1), ChildAbnormalTerminationSlot); - - // Push a cleanup for __finally blocks. EHStack.pushCleanup(NormalAndEHCleanup, FinallyFunc); return; } @@ -1707,7 +1642,6 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { // Just pop the cleanup if it's a __finally block. if (S.getFinallyHandler()) { PopCleanupBlock(); - ChildAbnormalTerminationSlot = nullptr; return; } diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index f07548e00f..ff3efa1c02 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -45,13 +45,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr), EHSelectorSlot(nullptr), - ChildAbnormalTerminationSlot(nullptr), AbnormalTerminationSlot(nullptr), - SEHPointersDecl(nullptr), DebugInfo(CGM.getModuleDebugInfo()), - DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr), - PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr), - CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0), - NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr), - CXXABIThisValue(nullptr), CXXThisValue(nullptr), + AbnormalTerminationSlot(nullptr), SEHPointersDecl(nullptr), + DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false), + DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm), + SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr), + UnreachableBlock(nullptr), NumReturnExprs(0), NumSimpleReturnExprs(0), + CXXABIThisDecl(nullptr), CXXABIThisValue(nullptr), CXXThisValue(nullptr), CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr), CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr), CurLexicalScope(nullptr), TerminateLandingPad(nullptr), diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 8a007d5983..7eca347246 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -310,13 +310,7 @@ public: /// write the current selector value into this alloca. llvm::AllocaInst *EHSelectorSlot; - /// Entering and leaving an SEH __try / __finally scope causes stores to this - /// slot. - llvm::Value *ChildAbnormalTerminationSlot; - - /// The SEH __abnormal_termination() intrinsic lowers down to loads from this - /// slot from a parent function. - llvm::Value *AbnormalTerminationSlot; + llvm::AllocaInst *AbnormalTerminationSlot; /// The implicit parameter to SEH filter functions of type /// 'EXCEPTION_POINTERS*'. @@ -2039,16 +2033,8 @@ public: /// Scan the outlined statement for captures from the parent function. For /// each capture, mark the capture as escaped and emit a call to /// llvm.framerecover. Insert the framerecover result into the LocalDeclMap. - void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt); - - /// Recovers the address of a local in a parent function. ParentVar is the - /// address of the variable used in the immediate parent function. It can - /// either be an alloca or a call to llvm.framerecover if there are nested - /// outlined functions. ParentFP is the frame pointer of the outermost parent - /// frame. - llvm::Value *recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, - llvm::Value *ParentVar, - llvm::Value *ParentFP); + void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt, + llvm::Value *ParentFP); void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef Attrs = None); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 33c71318b6..ed5da43f8a 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -25,7 +25,6 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" -#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -3638,10 +3637,6 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, else Diag(TryLoc, diag::err_seh_try_outside_functions); - // Reject __try on unsupported targets. - if (!Context.getTargetInfo().isSEHTrySupported()) - Diag(TryLoc, diag::err_seh_try_unsupported); - return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler); } diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c index 6366c35039..345d514611 100644 --- a/test/CodeGen/exceptions-seh-finally.c +++ b/test/CodeGen/exceptions-seh-finally.c @@ -1,7 +1,4 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -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: | FileCheck %s --check-prefix=CHECK --check-prefix=X86 +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s void abort(void) __attribute__((noreturn)); void might_crash(void); @@ -20,20 +17,18 @@ void basic_finally(void) { // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) -// X86: call void @"\01?fin$0@0@basic_finally@@"() +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: ret void // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) -// X86: call void @"\01?fin$0@0@basic_finally@@"() +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) // CHECK: resume { i8*, i32 } -// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}}) +// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: call void @cleanup() // Mostly check that we don't double emit 'r' which would crash. @@ -62,12 +57,11 @@ l: // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// X64: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]]) -// X86: call void @"\01?fin$0@0@label_in_finally@@"() +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]]) // CHECK: ret void -// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"({{.*}}) +// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: br label %[[l:[^ ]*]] // // CHECK: [[l]] @@ -86,33 +80,23 @@ void use_abnormal_termination(void) { } // CHECK-LABEL: define void @use_abnormal_termination() -// X86: call void (...) @llvm.frameescape(i32* %[[abnormal_termination:[^ ),]*]]) -// X86: store i32 1, i32* %[[abnormal_termination]] // CHECK: invoke void @might_crash() // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 0, i8* %[[fp]]) -// X86: store i32 0, i32* %[[abnormal_termination]] -// X86: call void @"\01?fin$0@0@use_abnormal_termination@@"() +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 0, i8* %[[fp]]) // CHECK: ret void // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]]) -// X86: call void @"\01?fin$0@0@use_abnormal_termination@@"() +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]]) // CHECK: resume { i8*, i32 } -// X64: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %[[abnormal:abnormal_termination]], i8* %frame_pointer) -// X64: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32 -// X86: define internal void @"\01?fin$0@0@use_abnormal_termination@@"() -// X86: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1) -// X86: %[[abnormal_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @use_abnormal_termination to i8*), i8* %[[fp]], i32 0) -// X86: %[[abnormal:[^ ]*]] = bitcast i8* %[[abnormal_i8]] to i32* -// X86: %[[abnormal_zext:[^ ]*]] = load i32, i32* %[[abnormal]] +// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %abnormal_termination to i32 // CHECK: store i32 %[[abnormal_zext]], i32* @crashed // CHECK-NEXT: ret void @@ -125,10 +109,11 @@ void noreturn_noop_finally() { } // CHECK-LABEL: define void @noreturn_noop_finally() -// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i8 0, i8* %[[fp]]) // CHECK: ret void -// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"({{.*}}) +// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: call void @abort() // CHECK: unreachable @@ -145,16 +130,18 @@ void noreturn_finally() { // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i8 0, i8* %[[fp]]) // CHECK: ret void // // CHECK: [[lpad]] // CHECK: landingpad // CHECK-NEXT: cleanup -// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i8 1, i8* %[[fp]]) // CHECK: resume { i8*, i32 } -// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) +// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: call void @abort() // CHECK: unreachable @@ -165,10 +152,11 @@ int finally_with_return() { } } // CHECK-LABEL: define i32 @finally_with_return() -// CHECK: call void @"\01?fin$0@0@finally_with_return@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: ret i32 42 -// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"({{.*}}) +// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK-NOT: br i1 // CHECK-NOT: br label // CHECK: ret void @@ -186,22 +174,25 @@ int nested___finally___finally() { } // CHECK-LABEL: define i32 @nested___finally___finally -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[outercont]] -// CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: ret i32 0 // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) +// 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@@"({{.*}}) +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: unreachable int nested___finally___finally_with_eh_edge() { @@ -221,27 +212,31 @@ int nested___finally___finally_with_eh_edge() { // CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]] // // [[invokecont]] -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 0, i8* %[[fp]]) // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]] // // CHECK: [[outercont]] -// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: ret i32 912 // // CHECK: [[lpad1]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 1, i8* %[[fp]]) // CHECK: to label %[[outercont:[^ ]*]] 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: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 1, i8* %[[fp]]) // CHECK: resume -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: ret void -// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: unreachable diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c index 40796bc075..d8135e805c 100644 --- a/test/CodeGen/exceptions-seh.c +++ b/test/CodeGen/exceptions-seh.c @@ -1,7 +1,4 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -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: | FileCheck %s --check-prefix=CHECK --check-prefix=X86 +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s void try_body(int numerator, int denominator, int *myres) { *myres = numerator / denominator; @@ -27,8 +24,7 @@ int safe_div(int numerator, int denominator, int *res) { // CHECK: to label %{{.*}} unwind label %[[lpad:[^ ]*]] // // CHECK: [[lpad]] -// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X86: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK-NEXT: catch i8* null // CHECK-NOT: br i1 // CHECK: br label %[[except:[^ ]*]] @@ -56,19 +52,14 @@ int filter_expr_capture(void) { // CHECK: invoke void @j() #[[NOINLINE]] // // CHECK: landingpad -// CHECK-NEXT: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@filter_expr_capture@@" to i8*) +// CHECK-NEXT: catch i8* bitcast (i32 (i8*, i8*)* @"\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.framerecover(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: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1) -// X86: call i8* @llvm.framerecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[fp]], i32 0) -// +// CHECK-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer) +// CHECK: call i8* @llvm.framerecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer, i32 0) // CHECK: store i32 -1, i32* %{{.*}} // CHECK: ret i32 -1 @@ -96,20 +87,19 @@ int nested_try(void) { // CHECK: br label %[[inner_try_cont:[^ ]*]] // // CHECK: [[lpad]] -// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X86: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -// 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: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*) +// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*) // CHECK: store i8* %{{.*}}, i8** %[[ehptr_slot:[^ ]*]] // CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]] // // 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: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*)) // CHECK: icmp eq i32 // CHECK: br i1 // // 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: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*)) // CHECK: icmp eq i32 // CHECK: br i1 // @@ -125,20 +115,6 @@ int nested_try(void) { // // 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.eh.exceptioninfo() -// CHECK: load i32*, i32** -// CHECK: load i32, i32* -// CHECK: ptrtoint -// CHECK: icmp eq i32 %{{.*}}, 456 -// -// CHECK-LABEL: define internal i32 @"\01?filt$1@0@nested_try@@"({{.*}}) -// X86: call i8* @llvm.eh.exceptioninfo() -// CHECK: load i32*, i32** -// CHECK: load i32, i32* -// CHECK: ptrtoint -// CHECK: icmp eq i32 %{{.*}}, 123 static unsigned g = 0; void basic_finally(void) { @@ -158,21 +134,18 @@ void basic_finally(void) { // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) -// X86: call void @"\01?fin$0@0@basic_finally@@"() +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) // CHECK: ret void // // CHECK: [[lpad]] -// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// X86: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK-NEXT: cleanup -// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) -// X86: call void @"\01?fin$0@0@basic_finally@@"() +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) // CHECK: resume -// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}}) +// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) // CHECK: load i32, i32* @g, align 4 // CHECK: add i32 %{{.*}}, -1 // CHECK: store i32 %{{.*}}, i32* @g, align 4