Revert "Re-land r236052, "[SEH] Add 32-bit lowering code for __try""

This reverts commit r239415. This was committed accidentally, LLVM isn't
ready for this.

llvm-svn: 239417
This commit is contained in:
Reid Kleckner 2015-06-09 17:49:42 +00:00
parent f8439940ef
commit 0b9bbbfc13
8 changed files with 152 additions and 277 deletions

View File

@ -5559,8 +5559,6 @@ def err_seh_try_outside_functions : Error<
"cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">;
def err_mixing_cxx_try_seh_try : Error< def err_mixing_cxx_try_seh_try : Error<
"cannot use C++ 'try' in the same function as SEH '__try'">; "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< def note_conflicting_try_here : Note<
"conflicting %0 here">; "conflicting %0 here">;
def warn_jump_out_of_seh_finally : Warning< def warn_jump_out_of_seh_finally : Warning<

View File

@ -797,11 +797,6 @@ public:
return TLSSupported; 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. /// \brief Return true if {|} are normal characters in the asm string.
/// ///
/// If this returns false (the default), then {abc|xyz} is syntax /// If this returns false (the default), then {abc|xyz} is syntax

View File

@ -20,7 +20,6 @@
#include "clang/AST/StmtCXX.h" #include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtVisitor.h" #include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/IR/CallSite.h" #include "llvm/IR/CallSite.h"
#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/IntrinsicInst.h"
@ -1275,6 +1274,14 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
} }
void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { 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); EnterSEHTryStmt(S);
{ {
JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
@ -1299,39 +1306,25 @@ struct PerformSEHFinally : EHScopeStack::Cleanup {
void Emit(CodeGenFunction &CGF, Flags F) override { void Emit(CodeGenFunction &CGF, Flags F) override {
ASTContext &Context = CGF.getContext(); ASTContext &Context = CGF.getContext();
CodeGenModule &CGM = CGF.CGM;
// 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}; QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress); FunctionProtoType::ExtProtoInfo EPI;
llvm::Value *FP = const auto *FTP = cast<FunctionType>(
CGF.Builder.CreateCall(FrameAddr, {CGF.Builder.getInt32(0)}); Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
CallArgList Args;
llvm::Value *IsForEH = llvm::Value *IsForEH =
llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
Args.add(RValue::get(IsForEH), ArgTys[0]); Args.add(RValue::get(IsForEH), ArgTys[0]);
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]); Args.add(RValue::get(FP), ArgTys[1]);
// Arrange a two-arg function info and type. const CGFunctionInfo &FnInfo =
FunctionProtoType::ExtProtoInfo EPI; CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
const auto *FPT = cast<FunctionProtoType>( CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
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();
}
CGF.EmitCall(*FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
} }
}; };
} }
@ -1342,7 +1335,6 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
CodeGenFunction &ParentCGF; CodeGenFunction &ParentCGF;
const VarDecl *ParentThis; const VarDecl *ParentThis;
SmallVector<const VarDecl *, 4> Captures; SmallVector<const VarDecl *, 4> Captures;
llvm::Value *AbnormalTermination = nullptr;
CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis) CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
: ParentCGF(ParentCGF), ParentThis(ParentThis) {} : ParentCGF(ParentCGF), ParentThis(ParentThis) {}
@ -1369,93 +1361,25 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
void VisitCXXThisExpr(const CXXThisExpr *E) { void VisitCXXThisExpr(const CXXThisExpr *E) {
Captures.push_back(ParentThis); 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<llvm::AllocaInst>(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.CreateCall(
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<llvm::IntrinsicInst>(ParentVar->stripPointerCasts());
assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover &&
"expected alloca or framerecover in parent LocalDeclMap");
RecoverCall = cast<llvm::CallInst>(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, void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
const Stmt *OutlinedStmt) { const Stmt *OutlinedStmt,
llvm::Value *ParentFP) {
// Find all captures in the Stmt. // Find all captures in the Stmt.
CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl); CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl);
Finder.Visit(OutlinedStmt); Finder.Visit(OutlinedStmt);
// Typically there are no captures and we can exit early. // Typically there are no captures and we can exit early.
if (Finder.Captures.empty() && !Finder.AbnormalTermination) if (Finder.Captures.empty())
return; return;
// The parent FP is passed in as EBP on x86 and the second argument on x64. // Prepare the first two arguments to llvm.framerecover.
llvm::Value *ParentFP; llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) { &CGM.getModule(), llvm::Intrinsic::framerecover);
auto AI = CurFn->arg_begin(); llvm::Constant *ParentI8Fn =
++AI; llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
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);
}
// Create llvm.framerecover calls for all captures. // Create llvm.framerecover calls for all captures.
for (const VarDecl *VD : Finder.Captures) { for (const VarDecl *VD : Finder.Captures) {
@ -1478,16 +1402,39 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
continue; continue;
llvm::Value *ParentVar = I->second; llvm::Value *ParentVar = I->second;
LocalDeclMap[VD] = llvm::CallInst *RecoverCall = nullptr;
recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP); CGBuilderTy Builder(AllocaInsertPt);
if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(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.CreateCall(
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<llvm::IntrinsicInst>(ParentVar->stripPointerCasts());
assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover &&
"expected alloca or framerecover in parent LocalDeclMap");
RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
RecoverCall->setArgOperand(1, ParentFP);
RecoverCall->insertBefore(AllocaInsertPt);
} }
// AbnormalTermination is just another capture, but it has no Decl. // Bitcast the variable, rename it, and insert it in the local decl map.
if (Finder.AbnormalTermination) { llvm::Value *ChildVar =
AbnormalTerminationSlot = recoverAddrOfEscapedLocal( Builder.CreateBitCast(RecoverCall, ParentVar->getType());
ParentCGF, Finder.AbnormalTermination, ParentFP); ChildVar->setName(ParentVar->getName());
// Save the slot on the parent so it can store 1 and 0 to it. LocalDeclMap[VD] = ChildVar;
ParentCGF.ChildAbnormalTerminationSlot = Finder.AbnormalTermination;
} }
} }
@ -1522,7 +1469,10 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart()); OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn); 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 /// Create a stub filter function that will ultimately hold the code of the
@ -1534,16 +1484,14 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
const Expr *FilterExpr = Except.getFilterExpr(); const Expr *FilterExpr = Except.getFilterExpr();
SourceLocation StartLoc = FilterExpr->getLocStart(); SourceLocation StartLoc = FilterExpr->getLocStart();
FunctionArgList Args;
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
SEHPointersDecl = ImplicitParamDecl::Create( SEHPointersDecl = ImplicitParamDecl::Create(
getContext(), nullptr, StartLoc, getContext(), nullptr, StartLoc,
&getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy); &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
FunctionArgList Args;
Args.push_back(SEHPointersDecl); Args.push_back(SEHPointersDecl);
Args.push_back(ImplicitParamDecl::Create( Args.push_back(ImplicitParamDecl::Create(
getContext(), nullptr, StartLoc, getContext(), nullptr, StartLoc,
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
}
// Get the mangled function name. // Get the mangled function name.
SmallString<128> Name; SmallString<128> Name;
@ -1584,7 +1532,6 @@ CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
SourceLocation StartLoc = FinallyBlock->getLocStart(); SourceLocation StartLoc = FinallyBlock->getLocStart();
FunctionArgList Args; FunctionArgList Args;
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
Args.push_back(ImplicitParamDecl::Create( Args.push_back(ImplicitParamDecl::Create(
getContext(), nullptr, StartLoc, getContext(), nullptr, StartLoc,
&getContext().Idents.get("abnormal_termination"), &getContext().Idents.get("abnormal_termination"),
@ -1592,7 +1539,6 @@ CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
Args.push_back(ImplicitParamDecl::Create( Args.push_back(ImplicitParamDecl::Create(
getContext(), nullptr, StartLoc, getContext(), nullptr, StartLoc,
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
}
// Get the mangled function name. // Get the mangled function name.
SmallString<128> Name; SmallString<128> Name;
@ -1624,7 +1570,7 @@ void CodeGenFunction::EmitSEHExceptionCodeSave() {
// }; // };
// void *exn.slot = // void *exn.slot =
// (void *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode; // (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 *RecordTy = CGM.Int32Ty->getPointerTo();
llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr); llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo()); Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo());
@ -1639,9 +1585,6 @@ void CodeGenFunction::EmitSEHExceptionCodeSave() {
} }
llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() { 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 // Sema should diagnose calling this builtin outside of a filter context, but
// don't crash if we screw up. // don't crash if we screw up.
if (!SEHPointersDecl) if (!SEHPointersDecl)
@ -1659,8 +1602,6 @@ llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
} }
llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { 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 // Abnormal termination is just the first parameter to the outlined finally
// helper. // helper.
auto AI = CurFn->arg_begin(); auto AI = CurFn->arg_begin();
@ -1670,15 +1611,9 @@ llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
// Outline the finally block. // Push a cleanup for __finally blocks.
llvm::Function *FinallyFunc = llvm::Function *FinallyFunc =
HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); 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<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc); EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
return; return;
} }
@ -1710,7 +1645,6 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
// Just pop the cleanup if it's a __finally block. // Just pop the cleanup if it's a __finally block.
if (S.getFinallyHandler()) { if (S.getFinallyHandler()) {
PopCleanupBlock(); PopCleanupBlock();
ChildAbnormalTerminationSlot = nullptr;
return; return;
} }

View File

@ -45,13 +45,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr), NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
ExceptionSlot(nullptr), EHSelectorSlot(nullptr), ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
ChildAbnormalTerminationSlot(nullptr), AbnormalTerminationSlot(nullptr), AbnormalTerminationSlot(nullptr), SEHPointersDecl(nullptr),
SEHPointersDecl(nullptr), DebugInfo(CGM.getModuleDebugInfo()), DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false),
DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr), DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm),
PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr), SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr),
CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0), UnreachableBlock(nullptr), NumReturnExprs(0), NumSimpleReturnExprs(0),
NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr), CXXABIThisDecl(nullptr), CXXABIThisValue(nullptr), CXXThisValue(nullptr),
CXXABIThisValue(nullptr), CXXThisValue(nullptr),
CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr), CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr),
CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr), CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr),
CurLexicalScope(nullptr), TerminateLandingPad(nullptr), CurLexicalScope(nullptr), TerminateLandingPad(nullptr),

View File

@ -310,13 +310,7 @@ public:
/// write the current selector value into this alloca. /// write the current selector value into this alloca.
llvm::AllocaInst *EHSelectorSlot; llvm::AllocaInst *EHSelectorSlot;
/// Entering and leaving an SEH __try / __finally scope causes stores to this llvm::AllocaInst *AbnormalTerminationSlot;
/// slot.
llvm::Value *ChildAbnormalTerminationSlot;
/// The SEH __abnormal_termination() intrinsic lowers down to loads from this
/// slot from a parent function.
llvm::Value *AbnormalTerminationSlot;
/// The implicit parameter to SEH filter functions of type /// The implicit parameter to SEH filter functions of type
/// 'EXCEPTION_POINTERS*'. /// 'EXCEPTION_POINTERS*'.
@ -2045,15 +2039,7 @@ public:
/// Scan the outlined statement for captures from the parent function. For /// Scan the outlined statement for captures from the parent function. For
/// each capture, mark the capture as escaped and emit a call to /// each capture, mark the capture as escaped and emit a call to
/// llvm.framerecover. Insert the framerecover result into the LocalDeclMap. /// llvm.framerecover. Insert the framerecover result into the LocalDeclMap.
void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt); 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); llvm::Value *ParentFP);
void EmitCXXForRangeStmt(const CXXForRangeStmt &S, void EmitCXXForRangeStmt(const CXXForRangeStmt &S,

View File

@ -25,7 +25,6 @@
#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtObjC.h"
#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h" #include "clang/AST/TypeOrdering.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h" #include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h" #include "clang/Sema/Lookup.h"
@ -3649,10 +3648,6 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
else else
Diag(TryLoc, diag::err_seh_try_outside_functions); 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); return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
} }

View File

@ -1,7 +1,4 @@
// 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 -emit-llvm -o - | FileCheck %s
// 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
void abort(void) __attribute__((noreturn)); void abort(void) __attribute__((noreturn));
void might_crash(void); void might_crash(void);
@ -20,20 +17,18 @@ void basic_finally(void) {
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
// //
// CHECK: [[invoke_cont]] // CHECK: [[invoke_cont]]
// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) // CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]])
// X86: call void @"\01?fin$0@0@basic_finally@@"()
// CHECK-NEXT: ret void // CHECK-NEXT: ret void
// //
// CHECK: [[lpad]] // CHECK: [[lpad]]
// CHECK-NEXT: landingpad // CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup // CHECK-NEXT: cleanup
// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) // CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]])
// X86: call void @"\01?fin$0@0@basic_finally@@"()
// CHECK: resume { i8*, i32 } // 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() // CHECK: call void @cleanup()
// Mostly check that we don't double emit 'r' which would crash. // 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: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
// //
// CHECK: [[invoke_cont]] // CHECK: [[invoke_cont]]
// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
// X64: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]]) // CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]])
// X86: call void @"\01?fin$0@0@label_in_finally@@"()
// CHECK: ret void // 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: br label %[[l:[^ ]*]]
// //
// CHECK: [[l]] // CHECK: [[l]]
@ -86,33 +80,23 @@ void use_abnormal_termination(void) {
} }
// CHECK-LABEL: define void @use_abnormal_termination() // 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: invoke void @might_crash()
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
// //
// CHECK: [[invoke_cont]] // CHECK: [[invoke_cont]]
// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 0, i8* %[[fp]]) // CHECK: 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: ret void // CHECK: ret void
// //
// CHECK: [[lpad]] // CHECK: [[lpad]]
// CHECK-NEXT: landingpad // CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup // CHECK-NEXT: cleanup
// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]]) // CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]])
// X86: call void @"\01?fin$0@0@use_abnormal_termination@@"()
// CHECK: resume { i8*, i32 } // CHECK: resume { i8*, i32 }
// X64: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %[[abnormal:abnormal_termination]], i8* %frame_pointer) // CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %abnormal_termination, i8* %frame_pointer)
// X64: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32 // CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %abnormal_termination 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: store i32 %[[abnormal_zext]], i32* @crashed // CHECK: store i32 %[[abnormal_zext]], i32* @crashed
// CHECK-NEXT: ret void // CHECK-NEXT: ret void
@ -125,10 +109,11 @@ void noreturn_noop_finally() {
} }
// CHECK-LABEL: define 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: 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: call void @abort()
// CHECK: unreachable // CHECK: unreachable
@ -145,16 +130,18 @@ void noreturn_finally() {
// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
// //
// CHECK: [[cont]] // 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: ret void
// //
// CHECK: [[lpad]] // CHECK: [[lpad]]
// CHECK: landingpad // CHECK: landingpad
// CHECK-NEXT: cleanup // 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: 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: call void @abort()
// CHECK: unreachable // CHECK: unreachable
@ -165,10 +152,11 @@ int finally_with_return() {
} }
} }
// CHECK-LABEL: define i32 @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-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 i1
// CHECK-NOT: br label // CHECK-NOT: br label
// CHECK: ret void // CHECK: ret void
@ -186,22 +174,25 @@ int nested___finally___finally() {
} }
// CHECK-LABEL: define i32 @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: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
// //
// CHECK: [[outercont]] // 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-NEXT: ret i32 0
// //
// CHECK: [[lpad]] // CHECK: [[lpad]]
// CHECK-NEXT: landingpad // CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup // 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: 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 // CHECK: unreachable
int nested___finally___finally_with_eh_edge() { 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:[^ ]*]] // CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]
// //
// [[invokecont]] // [[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: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
// //
// CHECK: [[outercont]] // 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-NEXT: ret i32 912
// //
// CHECK: [[lpad1]] // CHECK: [[lpad1]]
// CHECK-NEXT: landingpad // CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup // 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: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]
// //
// CHECK: [[lpad2]] // CHECK: [[lpad2]]
// CHECK-NEXT: landingpad // CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup // 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: 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: 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 // CHECK: unreachable

View File

@ -1,7 +1,4 @@
// 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 -emit-llvm -o - | FileCheck %s
// 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
void try_body(int numerator, int denominator, int *myres) { void try_body(int numerator, int denominator, int *myres) {
*myres = numerator / denominator; *myres = numerator / denominator;
@ -27,8 +24,7 @@ int safe_div(int numerator, int denominator, int *res) {
// CHECK: to label %{{.*}} unwind label %[[lpad:[^ ]*]] // CHECK: to label %{{.*}} unwind label %[[lpad:[^ ]*]]
// //
// CHECK: [[lpad]] // CHECK: [[lpad]]
// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK: 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-NEXT: catch i8* null // CHECK-NEXT: catch i8* null
// CHECK-NOT: br i1 // CHECK-NOT: br i1
// CHECK: br label %[[except:[^ ]*]] // CHECK: br label %[[except:[^ ]*]]
@ -56,19 +52,14 @@ int filter_expr_capture(void) {
// CHECK: invoke void @j() #[[NOINLINE]] // CHECK: invoke void @j() #[[NOINLINE]]
// //
// CHECK: landingpad // 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: store i32 13, i32* %[[r]]
// //
// CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]] // CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]]
// CHECK: ret i32 %[[rv]] // CHECK: ret i32 %[[rv]]
// X64-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer) // CHECK-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) // CHECK: 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: store i32 -1, i32* %{{.*}} // CHECK: store i32 -1, i32* %{{.*}}
// CHECK: ret i32 -1 // CHECK: ret i32 -1
@ -96,20 +87,19 @@ int nested_try(void) {
// CHECK: br label %[[inner_try_cont:[^ ]*]] // CHECK: br label %[[inner_try_cont:[^ ]*]]
// //
// CHECK: [[lpad]] // CHECK: [[lpad]]
// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK: 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 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*)
// CHECK: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*) // CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@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 i8* %{{.*}}, i8** %[[ehptr_slot:[^ ]*]]
// CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]] // CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]]
// //
// CHECK: load 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: icmp eq i32
// CHECK: br i1 // CHECK: br i1
// //
// CHECK: load i32, i32* %[[sel_slot]] // 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: icmp eq i32
// CHECK: br i1 // CHECK: br i1
// //
@ -125,20 +115,6 @@ int nested_try(void) {
// //
// CHECK: [[inner_try_cont]] // CHECK: [[inner_try_cont]]
// CHECK: br label %[[outer_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; static unsigned g = 0;
void basic_finally(void) { void basic_finally(void) {
@ -158,21 +134,18 @@ void basic_finally(void) {
// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
// //
// CHECK: [[cont]] // CHECK: [[cont]]
// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) // CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]])
// X86: call void @"\01?fin$0@0@basic_finally@@"()
// CHECK: ret void // CHECK: ret void
// //
// CHECK: [[lpad]] // CHECK: [[lpad]]
// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK: 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-NEXT: cleanup // CHECK-NEXT: cleanup
// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) // CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]])
// X86: call void @"\01?fin$0@0@basic_finally@@"()
// CHECK: resume // 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: load i32, i32* @g, align 4
// CHECK: add i32 %{{.*}}, -1 // CHECK: add i32 %{{.*}}, -1
// CHECK: store i32 %{{.*}}, i32* @g, align 4 // CHECK: store i32 %{{.*}}, i32* @g, align 4