diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2014-06-30 02:55:54 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2014-06-30 02:55:54 +0000 |
commit | aca7fcf2766272483484b17b113aa0cc485311b0 (patch) | |
tree | aa12fd7adfc4fa0b3e65a2f1375f8b8e869dc1b1 | |
parent | e5c4e9f3704f2f0198f4b880215fe03c321ec2ec (diff) | |
download | bcm5719-llvm-aca7fcf2766272483484b17b113aa0cc485311b0.tar.gz bcm5719-llvm-aca7fcf2766272483484b17b113aa0cc485311b0.zip |
Using of variable length arrays in captured statements and OpenMP constructs.
Differential Revision: http://reviews.llvm.org/D4067
llvm-svn: 212010
-rw-r--r-- | clang/lib/CodeGen/CGStmt.cpp | 31 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGStmtOpenMP.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 105 | ||||
-rw-r--r-- | clang/test/CodeGen/captured-statements-nested.c | 34 | ||||
-rw-r--r-- | clang/test/CodeGen/captured-statements.c | 5 |
6 files changed, 159 insertions, 23 deletions
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 8edee89e74d..529cca117b4 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2054,20 +2054,29 @@ static LValue InitCapturedStruct(CodeGenFunction &CGF, const CapturedStmt &S) { return SlotLV; } +static void InitVLACaptures(CodeGenFunction &CGF, const CapturedStmt &S) { + for (CapturedStmt::const_capture_iterator I = S.capture_begin(), + E = S.capture_end(); + I != E; ++I) { + if (I->capturesVariable()) { + QualType QTy = I->getCapturedVar()->getType(); + if (QTy->isVariablyModifiedType()) { + CGF.EmitVariablyModifiedType(QTy); + } + } + } +} + /// Generate an outlined function for the body of a CapturedStmt, store any /// captured variables into the captured struct, and call the outlined function. llvm::Function * CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) { - const CapturedDecl *CD = S.getCapturedDecl(); - const RecordDecl *RD = S.getCapturedRecordDecl(); - assert(CD->hasBody() && "missing CapturedDecl body"); - LValue CapStruct = InitCapturedStruct(*this, S); // Emit the CapturedDecl CodeGenFunction CGF(CGM, true); CGF.CapturedStmtInfo = new CGCapturedStmtInfo(S, K); - llvm::Function *F = CGF.GenerateCapturedStmtFunction(CD, RD, S.getLocStart()); + llvm::Function *F = CGF.GenerateCapturedStmtFunction(S); delete CGF.CapturedStmtInfo; // Emit call to the helper function. @@ -2084,11 +2093,13 @@ CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) { /// Creates the outlined function for a CapturedStmt. llvm::Function * -CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD, - const RecordDecl *RD, - SourceLocation Loc) { +CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) { assert(CapturedStmtInfo && "CapturedStmtInfo should be set when generating the captured function"); + const CapturedDecl *CD = S.getCapturedDecl(); + const RecordDecl *RD = S.getCapturedRecordDecl(); + SourceLocation Loc = S.getLocStart(); + assert(CD->hasBody() && "missing CapturedDecl body"); // Build the argument list. ASTContext &Ctx = CGM.getContext(); @@ -2111,12 +2122,14 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD, StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(), CD->getBody()->getLocStart()); - // Set the context parameter in CapturedStmtInfo. llvm::Value *DeclPtr = LocalDeclMap[CD->getContextParam()]; assert(DeclPtr && "missing context parameter for CapturedStmt"); CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr)); + // Initialize variable-length arrays. + InitVLACaptures(*this, S); + // If 'this' is captured, load it into CXXThisValue. if (CapturedStmtInfo->isCXXThisExprCaptured()) { FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl(); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 805eeaf40d7..02c73c9da0f 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -32,8 +32,7 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { CodeGenFunction CGF(CGM, true); CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind()); CGF.CapturedStmtInfo = &CGInfo; - OutlinedFn = CGF.GenerateCapturedStmtFunction( - CS->getCapturedDecl(), CS->getCapturedRecordDecl(), CS->getLocStart()); + OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS); } // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 4786b08f03f..baad667c716 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1895,9 +1895,7 @@ public: const ArrayRef<const Attr *> &Attrs = None); llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K); - llvm::Function *GenerateCapturedStmtFunction(const CapturedDecl *CD, - const RecordDecl *RD, - SourceLocation Loc); + llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S); llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S); void EmitOMPParallelDirective(const OMPParallelDirective &S); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2f1d1a61729..864c2826f69 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11668,7 +11668,7 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, } // Prohibit variably-modified types; they're difficult to deal with. - if (Var->getType()->isVariablyModifiedType()) { + if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) { if (Diagnose) { if (IsBlock) S.Diag(Loc, diag::err_ref_vm_type); @@ -12155,8 +12155,107 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, // certain types of variables (unnamed, variably modified types etc.) // so check for eligibility. if (!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this)) - return true; - + return true; + + // Try to capture variable-length arrays types. + if (Var->getType()->isVariablyModifiedType()) { + // We're going to walk down into the type and look for VLA + // expressions. + QualType QTy = Var->getType(); + if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var)) + QTy = PVD->getOriginalType(); + do { + const Type *Ty = QTy.getTypePtr(); + switch (Ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + QTy = QualType(); + break; + // These types are never variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::Record: + case Type::Enum: + case Type::Elaborated: + case Type::TemplateSpecialization: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + llvm_unreachable("type class is never variably-modified!"); + case Type::Adjusted: + QTy = cast<AdjustedType>(Ty)->getOriginalType(); + break; + case Type::Decayed: + QTy = cast<DecayedType>(Ty)->getPointeeType(); + break; + case Type::Pointer: + QTy = cast<PointerType>(Ty)->getPointeeType(); + break; + case Type::BlockPointer: + QTy = cast<BlockPointerType>(Ty)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + QTy = cast<ReferenceType>(Ty)->getPointeeType(); + break; + case Type::MemberPointer: + QTy = cast<MemberPointerType>(Ty)->getPointeeType(); + break; + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + QTy = cast<ArrayType>(Ty)->getElementType(); + break; + case Type::VariableArray: { + // Losing element qualification here is fine. + const VariableArrayType *Vat = cast<VariableArrayType>(Ty); + + // Unknown size indication requires no size computation. + // Otherwise, evaluate and record it. + if (Expr *Size = Vat->getSizeExpr()) { + MarkDeclarationsReferencedInExpr(Size); + } + QTy = Vat->getElementType(); + break; + } + case Type::FunctionProto: + case Type::FunctionNoProto: + QTy = cast<FunctionType>(Ty)->getReturnType(); + break; + case Type::Paren: + case Type::TypeOf: + case Type::UnaryTransform: + case Type::Attributed: + case Type::SubstTemplateTypeParm: + case Type::PackExpansion: + // Keep walking after single level desugaring. + QTy = QTy.getSingleStepDesugaredType(getASTContext()); + break; + case Type::Typedef: + QTy = cast<TypedefType>(Ty)->desugar(); + break; + case Type::Decltype: + QTy = cast<DecltypeType>(Ty)->desugar(); + break; + case Type::Auto: + QTy = cast<AutoType>(Ty)->getDeducedType(); + break; + case Type::TypeOfExpr: + QTy = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType(); + break; + case Type::Atomic: + QTy = cast<AtomicType>(Ty)->getValueType(); + break; + } + } while (!QTy.isNull() && QTy->isVariablyModifiedType()); + } + if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) { // No capture-default, and this is not an explicit capture // so cannot capture this variable. diff --git a/clang/test/CodeGen/captured-statements-nested.c b/clang/test/CodeGen/captured-statements-nested.c index d8ec74692ad..a567e753453 100644 --- a/clang/test/CodeGen/captured-statements-nested.c +++ b/clang/test/CodeGen/captured-statements-nested.c @@ -8,11 +8,12 @@ struct A { char c; }; -void test_nest_captured_stmt(int param) { +void test_nest_captured_stmt(int param, int size, int param_arr[size]) { int w; - // CHECK1: %struct.anon{{.*}} = type { i32*, i32* } - // CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i32**, i32* } - // CHECK1: [[T:%struct.anon.*]] = type { i32*, i32*, %struct.A*, i32**, i32* } + int arr[param][size]; + // CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i32*, i32**, i32* } + // CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i32**, i32*, i32*, i32**, i32* } + // CHECK1: [[T:%struct.anon.*]] = type { i32*, i32*, %struct.A*, i32**, i32*, i32*, i32**, i32* } #pragma clang __debug captured { int x; @@ -26,6 +27,8 @@ void test_nest_captured_stmt(int param) { *y = param; z.b = 0.1f; z.c = 'c'; + param_arr[size - 1] = 2; + arr[10][z.a] = 12; // CHECK1: define internal void @__captured_stmt{{.*}}([[T]] // @@ -59,6 +62,29 @@ void test_nest_captured_stmt(int param) { // CHECK1-NEXT: load %struct.A** // CHECK1-NEXT: getelementptr inbounds %struct.A* // CHECK1-NEXT: store i8 99 + // + // CHECK1: [[SIZE_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 5 + // CHECK1-NEXT: [[SIZE_ADDR:%.*]] = load i32** [[SIZE_ADDR_REF]] + // CHECK1-NEXT: [[SIZE:%.*]] = load i32* [[SIZE_ADDR]] + // CHECK1-NEXT: [[SIZE_MINUS_1:%.*]] = sub nsw i32 [[SIZE]], 1 + // CHECK1-NEXT: [[PARAM_ARR_IDX:%.*]] = {{.*}} [[SIZE_MINUS_1]] + // CHECK1-NEXT: [[PARAM_ARR_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 6 + // CHECK1-NEXT: [[PARAM_ARR_ADDR:%.*]] = load i32*** [[PARAM_ARR_ADDR_REF]] + // CHECK1-NEXT: [[PARAM_ARR:%.*]] = load i32** [[PARAM_ARR_ADDR]] + // CHECK1-NEXT: [[PARAM_ARR_SIZE_MINUS_1_ADDR:%.*]] = getelementptr inbounds i32* [[PARAM_ARR]], i{{.*}} [[PARAM_ARR_IDX]] + // CHECK1-NEXT: store i32 2, i32* [[PARAM_ARR_SIZE_MINUS_1_ADDR]] + // + // CHECK1: [[Z_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2 + // CHECK1-NEXT: [[Z_ADDR:%.*]] = load %struct.A** [[Z_ADDR_REF]] + // CHECK1-NEXT: [[Z_A_ADDR:%.*]] = getelementptr inbounds %struct.A* [[Z_ADDR]], i32 0, i32 0 + // CHECK1-NEXT: [[Z_A:%.*]] = load i32* [[Z_A_ADDR]] + // CHECK1-NEXT: [[ARR_IDX_2:%.*]] = {{.*}} [[Z_A]] + // CHECK1-NEXT: [[ARR_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 7 + // CHECK1-NEXT: [[ARR_ADDR:%.*]] = load i32** [[ARR_ADDR_REF]] + // CHECK1-NEXT: [[ARR_IDX_1:%.*]] = mul {{.*}} 10 + // CHECK1-NEXT: [[ARR_10_ADDR:%.*]] = getelementptr inbounds i32* [[ARR_ADDR]], i{{.*}} [[ARR_IDX_1]] + // CHECK1-NEXT: [[ARR_10_Z_A_ADDR:%.*]] = getelementptr inbounds i32* [[ARR_10_ADDR]], i{{.*}} [[ARR_IDX_2]] + // CHECK1-NEXT: store i32 12, i32* [[ARR_10_Z_A_ADDR]] } } } diff --git a/clang/test/CodeGen/captured-statements.c b/clang/test/CodeGen/captured-statements.c index b52d115ef04..4ff87910c22 100644 --- a/clang/test/CodeGen/captured-statements.c +++ b/clang/test/CodeGen/captured-statements.c @@ -48,11 +48,12 @@ void test2(int x) { // CHECK-2: %i = alloca i32 // Capture array -void test3() { +void test3(int size) { int arr[] = {1, 2, 3, 4, 5}; + int vla_arr[size]; #pragma clang __debug captured { - arr[2] = arr[1]; + arr[2] = vla_arr[size - 1]; } // CHECK-3: test3 // CHECK-3: alloca [5 x i32] |