"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<
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
#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"
}
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");
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<FunctionType>(
+ 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<FunctionProtoType>(
- 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);
}
};
}
CodeGenFunction &ParentCGF;
const VarDecl *ParentThis;
SmallVector<const VarDecl *, 4> Captures;
- llvm::Value *AbnormalTermination = nullptr;
CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
: ParentCGF(ParentCGF), ParentThis(ParentThis) {}
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<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.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<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,
- 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) {
continue;
llvm::Value *ParentVar = I->second;
- LocalDeclMap[VD] =
- recoverAddrOfEscapedLocal(ParentCGF, ParentVar, 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, -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<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.
- 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;
}
}
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
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;
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;
// };
// 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());
}
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)
}
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();
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<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
return;
}
// Just pop the cleanup if it's a __finally block.
if (S.getFinallyHandler()) {
PopCleanupBlock();
- ChildAbnormalTerminationSlot = nullptr;
return;
}
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),
/// 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*'.
/// 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<const Attr *> Attrs = None);
#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"
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);
}
-// 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);
// 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.
// 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]]
}
// 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
}
// 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
// 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
}
}
// 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
}
// 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() {
// 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
-// 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;
// 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:[^ ]*]]
// 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
// 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
//
//
// 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) {
// 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
// RUN: %clang_cc1 -triple i686-unknown-win32 -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=I686-WIN32 %s
-// I686-WIN32: target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+// I686-WIN32: target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32"
// RUN: %clang_cc1 -triple i686-unknown-cygwin -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=I686-CYGWIN %s
-// I686-CYGWIN: target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+// I686-CYGWIN: target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32"
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=X86_64 %s