forked from OSchip/llvm-project
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:
parent
f8439940ef
commit
0b9bbbfc13
|
@ -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<
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
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;
|
CallArgList Args;
|
||||||
if (CGF.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
|
llvm::Value *IsForEH =
|
||||||
// Compute the two argument values.
|
llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
|
||||||
QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
|
Args.add(RValue::get(IsForEH), ArgTys[0]);
|
||||||
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.
|
CodeGenModule &CGM = CGF.CGM;
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0);
|
||||||
const auto *FPT = cast<FunctionProtoType>(
|
llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
|
||||||
Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
|
llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero);
|
||||||
FnInfo = &CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
|
Args.add(RValue::get(FP), ArgTys[1]);
|
||||||
/*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);
|
const CGFunctionInfo &FnInfo =
|
||||||
|
CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
|
||||||
|
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)});
|
||||||
|
|
||||||
// AbnormalTermination is just another capture, but it has no Decl.
|
} else {
|
||||||
if (Finder.AbnormalTermination) {
|
// If the parent didn't have an alloca, we're doing some nested outlining.
|
||||||
AbnormalTerminationSlot = recoverAddrOfEscapedLocal(
|
// Just clone the existing framerecover call, but tweak the FP argument to
|
||||||
ParentCGF, Finder.AbnormalTermination, ParentFP);
|
// use our FP value. All other arguments are constants.
|
||||||
// Save the slot on the parent so it can store 1 and 0 to it.
|
auto *ParentRecover =
|
||||||
ParentCGF.ChildAbnormalTerminationSlot = Finder.AbnormalTermination;
|
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());
|
||||||
|
LocalDeclMap[VD] = ChildVar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
SEHPointersDecl = ImplicitParamDecl::Create(
|
||||||
|
getContext(), nullptr, StartLoc,
|
||||||
|
&getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
|
||||||
FunctionArgList Args;
|
FunctionArgList Args;
|
||||||
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
|
Args.push_back(SEHPointersDecl);
|
||||||
SEHPointersDecl = ImplicitParamDecl::Create(
|
Args.push_back(ImplicitParamDecl::Create(
|
||||||
getContext(), nullptr, StartLoc,
|
getContext(), nullptr, StartLoc,
|
||||||
&getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
|
&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.
|
// Get the mangled function name.
|
||||||
SmallString<128> Name;
|
SmallString<128> Name;
|
||||||
|
@ -1584,15 +1532,13 @@ 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"),
|
getContext().UnsignedCharTy));
|
||||||
getContext().UnsignedCharTy));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,16 +2039,8 @@ 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,
|
||||||
|
llvm::Value *ParentFP);
|
||||||
/// 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 EmitCXXForRangeStmt(const CXXForRangeStmt &S,
|
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
|
||||||
ArrayRef<const Attr *> Attrs = None);
|
ArrayRef<const Attr *> Attrs = None);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue