summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp3
-rw-r--r--clang/lib/CodeGen/CGException.cpp82
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp3
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h22
4 files changed, 95 insertions, 15 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f192788c787..aa6d8d6587d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1663,6 +1663,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__exception_info:
case Builtin::BI_exception_info:
return RValue::get(EmitSEHExceptionInfo());
+ case Builtin::BI__abnormal_termination:
+ case Builtin::BI_abnormal_termination:
+ return RValue::get(EmitSEHAbnormalTermination());
case Builtin::BI_setjmpex: {
if (getTarget().getTriple().isOSMSVCRT()) {
llvm::Type *ArgTypes[] = {Int8PtrTy, Int8PtrTy};
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index f94a380c210..e90f56810dd 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -451,6 +451,12 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() {
return Builder.CreateLoad(getEHSelectorSlot(), "sel");
}
+llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() {
+ if (!AbnormalTerminationSlot)
+ AbnormalTerminationSlot = CreateTempAlloca(Int8Ty, "abnormal.termination.slot");
+ return AbnormalTerminationSlot;
+}
+
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
bool KeepInsertionPoint) {
if (!E->getSubExpr()) {
@@ -1686,18 +1692,45 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
return;
}
- EnterSEHTryStmt(S);
+ SEHFinallyInfo FI;
+ EnterSEHTryStmt(S, FI);
EmitStmt(S.getTryBlock());
- ExitSEHTryStmt(S);
+ ExitSEHTryStmt(S, FI);
}
namespace {
struct PerformSEHFinally : EHScopeStack::Cleanup {
- Stmt *Block;
- PerformSEHFinally(Stmt *Block) : Block(Block) {}
+ CodeGenFunction::SEHFinallyInfo *FI;
+ PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {}
+
void Emit(CodeGenFunction &CGF, Flags F) override {
- // FIXME: Don't double-emit LabelDecls.
- CGF.EmitStmt(Block);
+ // Cleanups are emitted at most twice: once for normal control flow and once
+ // for exception control flow. Branch into the finally block, and remember
+ // the continuation block so we can branch out later.
+ if (!FI->FinallyBB) {
+ FI->FinallyBB = CGF.createBasicBlock("__finally");
+ FI->FinallyBB->insertInto(CGF.CurFn);
+ FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock());
+ }
+
+ // Set the termination status and branch in.
+ CGF.Builder.CreateStore(
+ llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()),
+ CGF.getAbnormalTerminationSlot());
+ CGF.Builder.CreateBr(FI->FinallyBB);
+
+ // Create a continuation block for normal or exceptional control.
+ if (F.isForEHCleanup()) {
+ assert(!FI->ResumeBB && "double emission for EH");
+ FI->ResumeBB = CGF.createBasicBlock("__finally.resume");
+ CGF.EmitBlock(FI->ResumeBB);
+ } else {
+ assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission");
+ FI->ContBB = CGF.createBasicBlock("__finally.cont");
+ CGF.EmitBlock(FI->ContBB);
+ // Try to keep source order.
+ FI->ContBB->moveAfter(FI->FinallyBB);
+ }
}
};
}
@@ -1827,11 +1860,17 @@ llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
return Builder.CreateTrunc(Code, CGM.Int32Ty);
}
-void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
+ // Load from the abnormal termination slot. It will be uninitialized outside
+ // of __finally blocks, which we should warn or error on.
+ llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot());
+ return Builder.CreateZExt(IsEH, Int32Ty);
+}
+
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
if (SEHFinallyStmt *Finally = S.getFinallyHandler()) {
// Push a cleanup for __finally blocks.
- EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup,
- Finally->getBlock());
+ EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, &FI);
return;
}
@@ -1859,15 +1898,34 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
}
-void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
// Just pop the cleanup if it's a __finally block.
- if (S.getFinallyHandler()) {
+ if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
PopCleanupBlock();
+
+ // Emit the code into FinallyBB.
+ Builder.SetInsertPoint(FI.FinallyBB);
+ EmitStmt(Finally->getBlock());
+
+ assert(FI.ContBB);
+ if (FI.ResumeBB) {
+ llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
+ "abnormal.termination");
+ IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
+ Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
+ } else {
+ // There was nothing exceptional in the try body, so we only have normal
+ // control flow.
+ Builder.CreateBr(FI.ContBB);
+ }
+
+ Builder.SetInsertPoint(FI.ContBB);
+
return;
}
// Otherwise, we must have an __except block.
- SEHExceptStmt *Except = S.getExceptHandler();
+ const SEHExceptStmt *Except = S.getExceptHandler();
assert(Except && "__try must have __finally xor __except");
EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 43c9dfe87a0..79425d4c21e 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -43,7 +43,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
BlockInfo(nullptr), BlockPointer(nullptr),
LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
- ExceptionSlot(nullptr), EHSelectorSlot(nullptr), SEHPointersDecl(nullptr),
+ ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
+ AbnormalTerminationSlot(nullptr), SEHPointersDecl(nullptr),
DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false),
DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm),
SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr),
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 60e81db3753..f6e2bae3195 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -306,6 +306,8 @@ public:
/// write the current selector value into this alloca.
llvm::AllocaInst *EHSelectorSlot;
+ llvm::AllocaInst *AbnormalTerminationSlot;
+
/// The implicit parameter to SEH filter functions of type
/// 'EXCEPTION_POINTERS*'.
ImplicitParamDecl *SEHPointersDecl;
@@ -348,6 +350,17 @@ public:
void exit(CodeGenFunction &CGF);
};
+ /// Cleanups can be emitted for two reasons: normal control leaving a region
+ /// exceptional control flow leaving a region.
+ struct SEHFinallyInfo {
+ SEHFinallyInfo()
+ : FinallyBB(nullptr), ContBB(nullptr), ResumeBB(nullptr) {}
+
+ llvm::BasicBlock *FinallyBB;
+ llvm::BasicBlock *ContBB;
+ llvm::BasicBlock *ResumeBB;
+ };
+
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
/// current full-expression. Safe against the possibility that
/// we're currently inside a conditionally-evaluated expression.
@@ -1085,6 +1098,10 @@ public:
llvm::Value *getExceptionSlot();
llvm::Value *getEHSelectorSlot();
+ /// Stack slot that contains whether a __finally block is being executed as an
+ /// EH cleanup or as a normal cleanup.
+ llvm::Value *getAbnormalTerminationSlot();
+
/// Returns the contents of the function's exception object and selector
/// slots.
llvm::Value *getExceptionFromSlot();
@@ -2007,8 +2024,8 @@ public:
void EmitCXXTryStmt(const CXXTryStmt &S);
void EmitSEHTryStmt(const SEHTryStmt &S);
void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
- void EnterSEHTryStmt(const SEHTryStmt &S);
- void ExitSEHTryStmt(const SEHTryStmt &S);
+ void EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
+ void ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
const SEHExceptStmt &Except);
@@ -2016,6 +2033,7 @@ public:
void EmitSEHExceptionCodeSave();
llvm::Value *EmitSEHExceptionCode();
llvm::Value *EmitSEHExceptionInfo();
+ llvm::Value *EmitSEHAbnormalTermination();
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
ArrayRef<const Attr *> Attrs = None);
OpenPOWER on IntegriCloud