From ca1f034abb55888ebcc3c6c92a89766096acd98d Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Tue, 7 Apr 2015 10:07:47 +0000 Subject: [PATCH] Revert "[SEH] Implement filter capturing in CodeGen" Test fails: http://lab.llvm.org:8080/green/job/clang-stage2-configure-Rlto_check/3182/ git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@234306 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGException.cpp | 129 +++--------------- lib/CodeGen/CodeGenFunction.cpp | 14 -- lib/CodeGen/CodeGenFunction.h | 10 -- .../exceptions-seh-filter-captures.cpp | 81 ----------- 4 files changed, 20 insertions(+), 214 deletions(-) delete mode 100644 test/CodeGenCXX/exceptions-seh-filter-captures.cpp diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index cc16053ac7..f96c0a3d21 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -19,10 +19,8 @@ #include "clang/AST/Mangle.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" -#include "clang/AST/StmtVisitor.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Intrinsics.h" -#include "llvm/IR/IntrinsicInst.h" using namespace clang; using namespace CodeGen; @@ -1341,110 +1339,6 @@ struct PerformSEHFinally : EHScopeStack::Cleanup { }; } -namespace { -/// Find all local variable captures in the statement. -struct CaptureFinder : ConstStmtVisitor { - CodeGenFunction &ParentCGF; - const VarDecl *ParentThis; - SmallVector Captures; - CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis) - : ParentCGF(ParentCGF), ParentThis(ParentThis) {} - - void Visit(const Stmt *S) { - // See if this is a capture, then recurse. - ConstStmtVisitor::Visit(S); - for (const Stmt *Child : S->children()) - Visit(Child); - } - - void VisitDeclRefExpr(const DeclRefExpr *E) { - // If this is already a capture, just make sure we capture 'this'. - if (E->refersToEnclosingVariableOrCapture()) { - Captures.push_back(ParentThis); - return; - } - - const auto *D = dyn_cast(E->getDecl()); - if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage()) - Captures.push_back(D); - } - - void VisitCXXThisExpr(const CXXThisExpr *E) { - Captures.push_back(ParentThis); - } -}; -} - -void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, - 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()) - return; - - // 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) { - if (isa(VD)) { - CGM.ErrorUnsupported(VD, "'this' captured by SEH"); - CXXThisValue = llvm::UndefValue::get(ConvertTypeForMem(VD->getType())); - continue; - } - if (VD->getType()->isVariablyModifiedType()) { - CGM.ErrorUnsupported(VD, "VLA captured by SEH"); - continue; - } - - assert((isa(VD) || VD->isLocalVarDeclOrParm()) && - "captured non-local variable"); - - llvm::Value *ParentVar = ParentCGF.LocalDeclMap[VD]; - assert(ParentVar && "capture was not a local decl"); - llvm::CallInst *RecoverCall = nullptr; - CGBuilderTy Builder(AllocaInsertPt); - if (auto *ParentAlloca = dyn_cast(ParentVar)) { - // Mark the variable escaped if nobody else referenced it and compute the - // frameescape index. - auto InsertPair = - ParentCGF.EscapedLocals.insert(std::make_pair(ParentAlloca, -1)); - if (InsertPair.second) - InsertPair.first->second = ParentCGF.EscapedLocals.size() - 1; - int FrameEscapeIdx = InsertPair.first->second; - // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N) - RecoverCall = - Builder.CreateCall3(FrameRecoverFn, ParentI8Fn, ParentFP, - llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)); - - } else { - // If the parent didn't have an alloca, we're doing some nested outlining. - // Just clone the existing framerecover call, but tweak the FP argument to - // use our FP value. All other arguments are constants. - auto *ParentRecover = - cast(ParentVar->stripPointerCasts()); - assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover && - "expected alloca or framerecover in parent LocalDeclMap"); - RecoverCall = cast(ParentRecover->clone()); - RecoverCall->setArgOperand(1, ParentFP); - RecoverCall->insertBefore(AllocaInsertPt); - } - - // 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; - } -} - /// Create a stub filter function that will ultimately hold the code of the /// filter expression. The EH preparation passes in LLVM will outline the code /// from the main function body into this stub. @@ -1498,9 +1392,15 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, EmitSEHExceptionCodeSave(); - auto AI = Fn->arg_begin(); - ++AI; - EmitCapturedLocals(ParentCGF, FilterExpr, &*AI); + // Insert dummy allocas for every local variable in scope. We'll initialize + // them and prune the unused ones after we find out which ones were + // referenced. + for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) { + const Decl *VD = DeclPtrs.first; + llvm::Value *Ptr = DeclPtrs.second; + auto *ValTy = cast(Ptr->getType())->getElementType(); + LocalDeclMap[VD] = CreateTempAlloca(ValTy, Ptr->getName() + ".filt"); + } // Emit the original filter expression, convert to i32, and return. llvm::Value *R = EmitScalarExpr(FilterExpr); @@ -1510,6 +1410,17 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, FinishFunction(FilterExpr->getLocEnd()); + for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) { + const Decl *VD = DeclPtrs.first; + auto *Alloca = cast(LocalDeclMap[VD]); + if (Alloca->hasNUses(0)) { + Alloca->eraseFromParent(); + continue; + } + ErrorUnsupported(FilterExpr, + "SEH filter expression local variable capture"); + } + return Fn; } diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index e59a50ee76..7de61e354a 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -279,20 +279,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { Builder.ClearInsertionPoint(); } - // If some of our locals escaped, insert a call to llvm.frameescape in the - // entry block. - if (!EscapedLocals.empty()) { - // Invert the map from local to index into a simple vector. There should be - // no holes. - SmallVector EscapeArgs; - EscapeArgs.resize(EscapedLocals.size()); - for (auto &Pair : EscapedLocals) - EscapeArgs[Pair.second] = Pair.first; - llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration( - &CGM.getModule(), llvm::Intrinsic::frameescape); - CGBuilderTy(AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs); - } - // Remove the AllocaInsertPt instruction, which is just a convenience for us. llvm::Instruction *Ptr = AllocaInsertPt; AllocaInsertPt = nullptr; diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 6183b49fe1..8d3408a4d5 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -877,10 +877,6 @@ private: typedef llvm::DenseMap DeclMapTy; DeclMapTy LocalDeclMap; - /// Track escaped local variables with auto storage. Used during SEH - /// outlining to produce a call to llvm.frameescape. - llvm::DenseMap EscapedLocals; - /// LabelMap - This keeps track of the LLVM basic block for each C label. llvm::DenseMap LabelMap; @@ -2011,12 +2007,6 @@ public: llvm::Value *EmitSEHExceptionInfo(); llvm::Value *EmitSEHAbnormalTermination(); - /// 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, - llvm::Value *ParentFP); - void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef Attrs = None); diff --git a/test/CodeGenCXX/exceptions-seh-filter-captures.cpp b/test/CodeGenCXX/exceptions-seh-filter-captures.cpp deleted file mode 100644 index 2175de52c8..0000000000 --- a/test/CodeGenCXX/exceptions-seh-filter-captures.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s -triple=x86_64-windows-msvc -emit-llvm \ -// RUN: -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CXXEH - -extern "C" int basic_filter(int v, ...); -extern "C" void might_crash(); - -extern "C" void test_freefunc(int p1) { - int l1 = 13; - static int s1 = 42; - __try { - might_crash(); - } __except(basic_filter(p1, l1, s1)) { - } -} - -// CHECK-LABEL: define void @test_freefunc(i32 %p1) -// CHECK: @llvm.frameescape(i32* %[[p1_ptr:[^, ]*]], i32* %[[l1_ptr:[^, ]*]]) -// CHECK: store i32 %p1, i32* %[[p1_ptr]], align 4 -// CHECK: store i32 13, i32* %[[l1_ptr]], align 4 -// CHECK: invoke void @might_crash() - -// CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_freefunc@@"(i8* %exception_pointers, i8* %frame_pointer) -// CHECK: %[[p1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 0) -// CHECK: %[[p1_ptr:[^ ]*]] = bitcast i8* %[[p1_i8]] to i32* -// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 1) -// CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32* -// CHECK: %[[s1:[^ ]*]] = load i32, i32* @"\01?s1@?1??test_freefunc@@9@4HA", align 4 -// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]] -// CHECK: %[[p1:[^ ]*]] = load i32, i32* %[[p1_ptr]] -// CHECK: call i32 (i32, ...)* @basic_filter(i32 %[[p1]], i32 %[[l1]], i32 %[[s1]]) - -struct S { - int m1; - void test_method(void); -}; - -void S::test_method() { - int l1 = 13; - __try { - might_crash(); - } __except(basic_filter(l1)) { - // FIXME: Test capturing 'this' and 'm1'. - } -} - -// CHECK-LABEL: define void @"\01?test_method@S@@QEAAXXZ"(%struct.S* %this) -// CHECK: @llvm.frameescape(i32* %[[l1_addr:[^, ]*]]) -// CHECK: store i32 13, i32* %[[l1_addr]], align 4 -// CHECK: invoke void @might_crash() - -// CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_method@S@@"(i8* %exception_pointers, i8* %frame_pointer) -// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (%struct.S*)* @"\01?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer, i32 0) -// CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32* -// CHECK: %[[l1:[^ ]]] = load i32, i32* %[[l1_ptr]] -// CHECK: call i32 (i32, ...)* @basic_filter(i32 %[[l1]]) - -void test_lambda() { - int l1 = 13; - auto lambda = [&]() { - int l2 = 42; - __try { - might_crash(); - } __except(basic_filter(l2)) { - // FIXME: Test 'l1' when we can capture the lambda's 'this' decl. - } - }; - lambda(); -} - -// CHECK-LABEL: define internal void @"\01??R@?test_lambda@@YAXXZ@QEBAXXZ"(%class.anon* %this) -// CHECK: @llvm.frameescape(i32* %[[l2_addr:[^, ]*]]) -// CHECK: store i32 42, i32* %[[l2_addr]], align 4 -// CHECK: invoke void @might_crash() - -// CHECK-LABEL: define internal i32 @"\01?filt$0@0@?R@?test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer) -// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (%class.anon*)* @"\01??R@?test_lambda@@YAXXZ@QEBAXXZ" to i8*), i8* %frame_pointer, i32 0) -// CHECK: %[[l2_ptr:[^ ]*]] = bitcast i8* %[[l2_i8]] to i32* -// CHECK: %[[l2:[^ ]]] = load i32, i32* %[[l2_ptr]] -// CHECK: call i32 (i32, ...)* @basic_filter(i32 %[[l2]]) - -- 2.50.1