r212010 - Using of variable length arrays in captured statements and OpenMP constructs.
Alexey Bataev
a.bataev at hotmail.com
Sun Jun 29 19:55:54 PDT 2014
Author: abataev
Date: Sun Jun 29 21:55:54 2014
New Revision: 212010
URL: http://llvm.org/viewvc/llvm-project?rev=212010&view=rev
Log:
Using of variable length arrays in captured statements and OpenMP constructs.
Differential Revision: http://reviews.llvm.org/D4067
Modified:
cfe/trunk/lib/CodeGen/CGStmt.cpp
cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/CodeGen/captured-statements-nested.c
cfe/trunk/test/CodeGen/captured-statements.c
Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=212010&r1=212009&r2=212010&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Sun Jun 29 21:55:54 2014
@@ -2054,20 +2054,29 @@ static LValue InitCapturedStruct(CodeGen
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::GenerateCapturedStmtArg
/// 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::GenerateCapturedStmtFun
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();
Modified: cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp?rev=212010&r1=212009&r2=212010&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp Sun Jun 29 21:55:54 2014
@@ -32,8 +32,7 @@ void CodeGenFunction::EmitOMPParallelDir
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*/)
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=212010&r1=212009&r2=212010&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sun Jun 29 21:55:54 2014
@@ -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);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=212010&r1=212009&r2=212010&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Jun 29 21:55:54 2014
@@ -11668,7 +11668,7 @@ static bool isVariableCapturable(Capturi
}
// 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 *V
// 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.
Modified: cfe/trunk/test/CodeGen/captured-statements-nested.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/captured-statements-nested.c?rev=212010&r1=212009&r2=212010&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/captured-statements-nested.c (original)
+++ cfe/trunk/test/CodeGen/captured-statements-nested.c Sun Jun 29 21:55:54 2014
@@ -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]]
}
}
}
Modified: cfe/trunk/test/CodeGen/captured-statements.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/captured-statements.c?rev=212010&r1=212009&r2=212010&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/captured-statements.c (original)
+++ cfe/trunk/test/CodeGen/captured-statements.c Sun Jun 29 21:55:54 2014
@@ -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]
More information about the cfe-commits
mailing list