-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[OpenACC][CIR] Generate private recipe pointer/array 'alloca's #160911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[OpenACC][CIR] Generate private recipe pointer/array 'alloca's #160911
Conversation
As a next step to generating pointer/array recipes, this patch generates just the 'alloca' lines that are necessary. Copying pointers over to restore the structure is held off to the next patch. In the case of a pointer, we need to allocate the level 'below' it (if we index into it), then copy the values into the pointers. In the case of an array, we skip the alloca (since the array's alloca contains the value). After this, we'll need a patch that copies the pointers into place, and finally one that does the initialization of these values.
@llvm/pr-subscribers-clang Author: Erich Keane (erichkeane) ChangesAs a next step to generating pointer/array recipes, this patch generates just the 'alloca' lines that are necessary. Copying pointers over to restore the structure is held off to the next patch. In the case of a pointer, we need to allocate the level 'below' it (if we index into it), then copy the values into the pointers. In the case of an array, we skip the alloca (since the array's alloca contains the value). After this, we'll need a patch that copies the pointers into place, and finally one that does the initialization of these values. Patch is 123.47 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/160911.diff 16 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index a3f167e3cde2c..3f83c302176c0 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -243,6 +243,13 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment);
}
+ mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
+ mlir::Type type, llvm::StringRef name,
+ clang::CharUnits alignment) {
+ mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
+ return createAlloca(loc, addrType, type, name, alignmentAttr);
+ }
+
/// Get constant address of a global variable as an MLIR attribute.
/// This wrapper infers the attribute type through the global op.
cir::GlobalViewAttr getGlobalViewAttr(cir::GlobalOp globalOp,
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
index a4c2641fe631c..e41c2d85fbd5d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
@@ -10,6 +10,8 @@
//
//===----------------------------------------------------------------------===//
+#include <numeric>
+
#include "CIRGenOpenACCRecipe.h"
namespace clang::CIRGen {
@@ -35,6 +37,110 @@ mlir::Block *OpenACCRecipeBuilderBase::createRecipeBlock(mlir::Region ®ion,
return builder.createBlock(®ion, region.end(), types, locs);
}
+mlir::Value OpenACCRecipeBuilderBase::makeBoundsAlloca(
+ mlir::Block *block, SourceRange exprRange, mlir::Location loc,
+ std::string_view allocaName, size_t numBounds,
+ llvm::ArrayRef<QualType> boundTypes) {
+ mlir::OpBuilder::InsertionGuard guardCase(builder);
+
+ // Get the range of bounds arguments, which are all but the 1st arg.
+ llvm::ArrayRef<mlir::BlockArgument> boundsRange =
+ block->getArguments().drop_front(1);
+
+ // boundTypes contains the before and after of each bounds, so it ends up
+ // having 1 extra. Assert this is the case to ensure we don't call this in the
+ // wrong 'block'.
+ assert(boundsRange.size() + 1 == boundTypes.size());
+
+ mlir::Type itrTy = cgf.cgm.convertType(cgf.getContext().UnsignedLongLongTy);
+ auto idxType = mlir::IndexType::get(&cgf.getMLIRContext());
+
+ auto getUpperBound = [&](mlir::Value bound) {
+ auto upperBoundVal =
+ mlir::acc::GetUpperboundOp::create(builder, loc, idxType, bound);
+ return mlir::UnrealizedConversionCastOp::create(builder, loc, itrTy,
+ upperBoundVal.getResult())
+ .getResult(0);
+ };
+
+ auto isArrayTy = [&](QualType ty) {
+ if (ty->isArrayType() && !ty->isConstantArrayType())
+ cgf.cgm.errorNYI(exprRange, "OpenACC recipe init for VLAs");
+ return ty->isConstantArrayType();
+ };
+
+ mlir::Type topLevelTy = cgf.convertType(boundTypes.back());
+ cir::PointerType topLevelTyPtr = builder.getPointerTo(topLevelTy);
+ // Do an alloca for the 'top' level type without bounds.
+ mlir::Value initialAlloca = builder.createAlloca(
+ loc, topLevelTyPtr, topLevelTy, allocaName,
+ cgf.getContext().getTypeAlignInChars(boundTypes.back()));
+
+ bool lastBoundWasArray = isArrayTy(boundTypes.back());
+
+ // Since we're iterating the types in reverse, this sets up for each index
+ // corresponding to the boundsRange to be the 'after application of the
+ // bounds.
+ llvm::ArrayRef<QualType> boundResults = boundTypes.drop_back(1);
+
+ // Collect the 'do we have any allocas needed after this type' list.
+ llvm::SmallVector<bool> allocasLeftArr;
+ llvm::ArrayRef<QualType> resultTypes = boundTypes.drop_front();
+ std::transform_inclusive_scan(
+ resultTypes.begin(), resultTypes.end(),
+ std::back_inserter(allocasLeftArr), std::plus<bool>{},
+ [](QualType ty) { return !ty->isConstantArrayType(); });
+
+ // Keep track of the number of 'elements' that we're allocating. Individual
+ // allocas should multiply this by the size of its current allocation.
+ mlir::Value cumulativeElts;
+ for (auto [bound, resultType, allocasLeft] : llvm::reverse(
+ llvm::zip_equal(boundsRange, boundResults, allocasLeftArr))) {
+
+ // if there is no further 'alloca' operation we need to do, we can skip
+ // creating the UB/multiplications/etc.
+ if (!allocasLeft)
+ break;
+
+ // First: figure out the number of elements in the current 'bound' list.
+ mlir::Value eltsPerSubArray = getUpperBound(bound);
+ mlir::Value eltsToAlloca;
+
+ // IF we are in a sub-bounds, the total number of elements to alloca is
+ // the product of that one and the current 'bounds' size. That is,
+ // arr[5][5], we would need 25 elements, not just 5. Else it is just the
+ // current number of elements.
+ if (cumulativeElts)
+ eltsToAlloca = builder.createMul(loc, eltsPerSubArray, cumulativeElts);
+ else
+ eltsToAlloca = eltsPerSubArray;
+
+ if (!lastBoundWasArray) {
+ // If we have to do an allocation, figure out the size of the
+ // allocation. alloca takes the number of bytes, not elements.
+ TypeInfoChars eltInfo = cgf.getContext().getTypeInfoInChars(resultType);
+ cir::ConstantOp eltSize = builder.getConstInt(
+ loc, itrTy, eltInfo.Width.alignTo(eltInfo.Align).getQuantity());
+ mlir::Value curSize = builder.createMul(loc, eltsToAlloca, eltSize);
+
+ mlir::Type eltTy = cgf.convertType(resultType);
+ cir::PointerType ptrTy = builder.getPointerTo(eltTy);
+ builder.createAlloca(loc, ptrTy, eltTy, "openacc.init.bounds",
+ cgf.getContext().getTypeAlignInChars(resultType),
+ curSize);
+
+ // TODO: OpenACC : At this point we should be copying the addresses of
+ // each element of this to the last allocation. At the moment, that is
+ // not yet implemented.
+ cgf.cgm.errorNYI(exprRange, "OpenACC recipe alloca copying");
+ }
+
+ cumulativeElts = eltsToAlloca;
+ lastBoundWasArray = isArrayTy(resultType);
+ }
+ return initialAlloca;
+}
+
mlir::Value
OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
mlir::Value bound,
@@ -258,7 +364,11 @@ void OpenACCRecipeBuilderBase::createPrivateInitRecipe(
cgf.emitAutoVarAlloca(*allocaDecl, builder.saveInsertionPoint());
cgf.emitAutoVarInit(tempDeclEmission);
} else {
- cgf.cgm.errorNYI(exprRange, "private-init with bounds");
+ makeBoundsAlloca(block, exprRange, loc, "openacc.private.init", numBounds,
+ boundTypes);
+
+ if (initExpr)
+ cgf.cgm.errorNYI(exprRange, "private-init with bounds initialization");
}
mlir::acc::YieldOp::create(builder, locEnd);
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
index 978c671f9a170..acd187bbaee0d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
@@ -24,6 +24,13 @@
namespace clang::CIRGen {
class OpenACCRecipeBuilderBase {
+ // This function generates the required alloca, similar to
+ // 'emitAutoVarAlloca', except for the OpenACC array/pointer types.
+ mlir::Value makeBoundsAlloca(mlir::Block *block, SourceRange exprRange,
+ mlir::Location loc, std::string_view allocaName,
+ size_t numBounds,
+ llvm::ArrayRef<QualType> boundTypes);
+
protected:
CIRGen::CIRGenFunction &cgf;
CIRGen::CIRGenBuilderTy &builder;
@@ -165,28 +172,9 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
// 'firstprivate' doesn't do its initialization in the 'init' section,
- // instead does it in the 'copy' section. SO only do init here.
- // 'reduction' appears to use it too (rather than a 'copy' section), so
- // we probably have to do it here too, but we can do that when we get to
- // reduction implementation.
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
- // We are OK with no init for builtins, arrays of builtins, or pointers,
- // else we should NYI so we know to go look for these.
- if (cgf.getContext().getLangOpts().CPlusPlus &&
- !varRecipe->getType()
- ->getPointeeOrArrayElementType()
- ->isBuiltinType() &&
- !varRecipe->getType()->isPointerType() && !varRecipe->getInit()) {
- // If we don't have any initialization recipe, we failed during Sema to
- // initialize this correctly. If we disable the
- // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
- // emit an error to tell us. However, emitting those errors during
- // production is a violation of the standard, so we cannot do them.
- cgf.cgm.errorNYI(exprRange, "private default-init recipe");
- }
- cgf.emitAutoVarInit(tempDeclEmission);
- } else if constexpr (std::is_same_v<RecipeTy,
- mlir::acc::ReductionRecipeOp>) {
+ // instead it does it in the 'copy' section. SO, only do 'init' here for
+ // reduction.
+ if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
// Unlike Private, the recipe here is always required as it has to do
// init, not just 'default' init.
if (!varRecipe->getInit())
diff --git a/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp
index f3ec9e1847b00..639320275ab0f 100644
--- a/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp
@@ -65,6 +65,7 @@ struct HasDtor {
// int[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -72,6 +73,7 @@ struct HasDtor {
// float[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -79,6 +81,7 @@ struct HasDtor {
// NoCopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -86,6 +89,7 @@ struct HasDtor {
// CopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_13CopyConstruct : !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_CopyConstruct x 5>, !cir.ptr<!cir.array<!rec_CopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -93,6 +97,7 @@ struct HasDtor {
// NonDefaultCtor[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_14NonDefaultCtor : !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NonDefaultCtor x 5>, !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -100,6 +105,7 @@ struct HasDtor {
// HasDtor[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_7HasDtor : !cir.ptr<!cir.array<!rec_HasDtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_HasDtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_HasDtor x 5>, !cir.ptr<!cir.array<!rec_HasDtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: } destroy {
diff --git a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c
index 5235aeec60713..097005e75dcbe 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c
+++ b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s
struct NoCopyConstruct {};
@@ -26,6 +26,7 @@ struct NoCopyConstruct {};
// int[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -33,6 +34,7 @@ struct NoCopyConstruct {};
// float[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -40,6 +42,7 @@ struct NoCopyConstruct {};
// NoCopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
diff --git a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp
index 12e14fa0f73b0..97399d9d4620e 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp
@@ -58,36 +58,42 @@ struct HasDtor {
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_13CopyConstruct : !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_CopyConstruct x 5>, !cir.ptr<!cir.array<!rec_CopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_14NonDefaultCtor : !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NonDefaultCtor x 5>, !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK: acc.private.recipe @privatization__Bcnt1__ZTSA5_7HasDtor : !cir.ptr<!cir.array<!rec_HasDtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_HasDtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_HasDtor x 5>, !cir.ptr<!cir.array<!rec_HasDtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: } destroy {
diff --git a/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp
index 0a0552e888721..d4fd4ccc68f7a 100644
--- a/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp
@@ -65,6 +65,7 @@ struct HasDtor {
// int[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -72,6 +73,7 @@ struct HasDtor {
// float[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -79,6 +81,7 @@ struct HasDtor {
// NoCopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -86,6 +89,7 @@ struct HasDtor {
// CopyConstruc...
[truncated]
|
@llvm/pr-subscribers-clangir Author: Erich Keane (erichkeane) ChangesAs a next step to generating pointer/array recipes, this patch generates just the 'alloca' lines that are necessary. Copying pointers over to restore the structure is held off to the next patch. In the case of a pointer, we need to allocate the level 'below' it (if we index into it), then copy the values into the pointers. In the case of an array, we skip the alloca (since the array's alloca contains the value). After this, we'll need a patch that copies the pointers into place, and finally one that does the initialization of these values. Patch is 123.47 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/160911.diff 16 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index a3f167e3cde2c..3f83c302176c0 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -243,6 +243,13 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment);
}
+ mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
+ mlir::Type type, llvm::StringRef name,
+ clang::CharUnits alignment) {
+ mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
+ return createAlloca(loc, addrType, type, name, alignmentAttr);
+ }
+
/// Get constant address of a global variable as an MLIR attribute.
/// This wrapper infers the attribute type through the global op.
cir::GlobalViewAttr getGlobalViewAttr(cir::GlobalOp globalOp,
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
index a4c2641fe631c..e41c2d85fbd5d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
@@ -10,6 +10,8 @@
//
//===----------------------------------------------------------------------===//
+#include <numeric>
+
#include "CIRGenOpenACCRecipe.h"
namespace clang::CIRGen {
@@ -35,6 +37,110 @@ mlir::Block *OpenACCRecipeBuilderBase::createRecipeBlock(mlir::Region ®ion,
return builder.createBlock(®ion, region.end(), types, locs);
}
+mlir::Value OpenACCRecipeBuilderBase::makeBoundsAlloca(
+ mlir::Block *block, SourceRange exprRange, mlir::Location loc,
+ std::string_view allocaName, size_t numBounds,
+ llvm::ArrayRef<QualType> boundTypes) {
+ mlir::OpBuilder::InsertionGuard guardCase(builder);
+
+ // Get the range of bounds arguments, which are all but the 1st arg.
+ llvm::ArrayRef<mlir::BlockArgument> boundsRange =
+ block->getArguments().drop_front(1);
+
+ // boundTypes contains the before and after of each bounds, so it ends up
+ // having 1 extra. Assert this is the case to ensure we don't call this in the
+ // wrong 'block'.
+ assert(boundsRange.size() + 1 == boundTypes.size());
+
+ mlir::Type itrTy = cgf.cgm.convertType(cgf.getContext().UnsignedLongLongTy);
+ auto idxType = mlir::IndexType::get(&cgf.getMLIRContext());
+
+ auto getUpperBound = [&](mlir::Value bound) {
+ auto upperBoundVal =
+ mlir::acc::GetUpperboundOp::create(builder, loc, idxType, bound);
+ return mlir::UnrealizedConversionCastOp::create(builder, loc, itrTy,
+ upperBoundVal.getResult())
+ .getResult(0);
+ };
+
+ auto isArrayTy = [&](QualType ty) {
+ if (ty->isArrayType() && !ty->isConstantArrayType())
+ cgf.cgm.errorNYI(exprRange, "OpenACC recipe init for VLAs");
+ return ty->isConstantArrayType();
+ };
+
+ mlir::Type topLevelTy = cgf.convertType(boundTypes.back());
+ cir::PointerType topLevelTyPtr = builder.getPointerTo(topLevelTy);
+ // Do an alloca for the 'top' level type without bounds.
+ mlir::Value initialAlloca = builder.createAlloca(
+ loc, topLevelTyPtr, topLevelTy, allocaName,
+ cgf.getContext().getTypeAlignInChars(boundTypes.back()));
+
+ bool lastBoundWasArray = isArrayTy(boundTypes.back());
+
+ // Since we're iterating the types in reverse, this sets up for each index
+ // corresponding to the boundsRange to be the 'after application of the
+ // bounds.
+ llvm::ArrayRef<QualType> boundResults = boundTypes.drop_back(1);
+
+ // Collect the 'do we have any allocas needed after this type' list.
+ llvm::SmallVector<bool> allocasLeftArr;
+ llvm::ArrayRef<QualType> resultTypes = boundTypes.drop_front();
+ std::transform_inclusive_scan(
+ resultTypes.begin(), resultTypes.end(),
+ std::back_inserter(allocasLeftArr), std::plus<bool>{},
+ [](QualType ty) { return !ty->isConstantArrayType(); });
+
+ // Keep track of the number of 'elements' that we're allocating. Individual
+ // allocas should multiply this by the size of its current allocation.
+ mlir::Value cumulativeElts;
+ for (auto [bound, resultType, allocasLeft] : llvm::reverse(
+ llvm::zip_equal(boundsRange, boundResults, allocasLeftArr))) {
+
+ // if there is no further 'alloca' operation we need to do, we can skip
+ // creating the UB/multiplications/etc.
+ if (!allocasLeft)
+ break;
+
+ // First: figure out the number of elements in the current 'bound' list.
+ mlir::Value eltsPerSubArray = getUpperBound(bound);
+ mlir::Value eltsToAlloca;
+
+ // IF we are in a sub-bounds, the total number of elements to alloca is
+ // the product of that one and the current 'bounds' size. That is,
+ // arr[5][5], we would need 25 elements, not just 5. Else it is just the
+ // current number of elements.
+ if (cumulativeElts)
+ eltsToAlloca = builder.createMul(loc, eltsPerSubArray, cumulativeElts);
+ else
+ eltsToAlloca = eltsPerSubArray;
+
+ if (!lastBoundWasArray) {
+ // If we have to do an allocation, figure out the size of the
+ // allocation. alloca takes the number of bytes, not elements.
+ TypeInfoChars eltInfo = cgf.getContext().getTypeInfoInChars(resultType);
+ cir::ConstantOp eltSize = builder.getConstInt(
+ loc, itrTy, eltInfo.Width.alignTo(eltInfo.Align).getQuantity());
+ mlir::Value curSize = builder.createMul(loc, eltsToAlloca, eltSize);
+
+ mlir::Type eltTy = cgf.convertType(resultType);
+ cir::PointerType ptrTy = builder.getPointerTo(eltTy);
+ builder.createAlloca(loc, ptrTy, eltTy, "openacc.init.bounds",
+ cgf.getContext().getTypeAlignInChars(resultType),
+ curSize);
+
+ // TODO: OpenACC : At this point we should be copying the addresses of
+ // each element of this to the last allocation. At the moment, that is
+ // not yet implemented.
+ cgf.cgm.errorNYI(exprRange, "OpenACC recipe alloca copying");
+ }
+
+ cumulativeElts = eltsToAlloca;
+ lastBoundWasArray = isArrayTy(resultType);
+ }
+ return initialAlloca;
+}
+
mlir::Value
OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
mlir::Value bound,
@@ -258,7 +364,11 @@ void OpenACCRecipeBuilderBase::createPrivateInitRecipe(
cgf.emitAutoVarAlloca(*allocaDecl, builder.saveInsertionPoint());
cgf.emitAutoVarInit(tempDeclEmission);
} else {
- cgf.cgm.errorNYI(exprRange, "private-init with bounds");
+ makeBoundsAlloca(block, exprRange, loc, "openacc.private.init", numBounds,
+ boundTypes);
+
+ if (initExpr)
+ cgf.cgm.errorNYI(exprRange, "private-init with bounds initialization");
}
mlir::acc::YieldOp::create(builder, locEnd);
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
index 978c671f9a170..acd187bbaee0d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
@@ -24,6 +24,13 @@
namespace clang::CIRGen {
class OpenACCRecipeBuilderBase {
+ // This function generates the required alloca, similar to
+ // 'emitAutoVarAlloca', except for the OpenACC array/pointer types.
+ mlir::Value makeBoundsAlloca(mlir::Block *block, SourceRange exprRange,
+ mlir::Location loc, std::string_view allocaName,
+ size_t numBounds,
+ llvm::ArrayRef<QualType> boundTypes);
+
protected:
CIRGen::CIRGenFunction &cgf;
CIRGen::CIRGenBuilderTy &builder;
@@ -165,28 +172,9 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
// 'firstprivate' doesn't do its initialization in the 'init' section,
- // instead does it in the 'copy' section. SO only do init here.
- // 'reduction' appears to use it too (rather than a 'copy' section), so
- // we probably have to do it here too, but we can do that when we get to
- // reduction implementation.
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
- // We are OK with no init for builtins, arrays of builtins, or pointers,
- // else we should NYI so we know to go look for these.
- if (cgf.getContext().getLangOpts().CPlusPlus &&
- !varRecipe->getType()
- ->getPointeeOrArrayElementType()
- ->isBuiltinType() &&
- !varRecipe->getType()->isPointerType() && !varRecipe->getInit()) {
- // If we don't have any initialization recipe, we failed during Sema to
- // initialize this correctly. If we disable the
- // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
- // emit an error to tell us. However, emitting those errors during
- // production is a violation of the standard, so we cannot do them.
- cgf.cgm.errorNYI(exprRange, "private default-init recipe");
- }
- cgf.emitAutoVarInit(tempDeclEmission);
- } else if constexpr (std::is_same_v<RecipeTy,
- mlir::acc::ReductionRecipeOp>) {
+ // instead it does it in the 'copy' section. SO, only do 'init' here for
+ // reduction.
+ if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
// Unlike Private, the recipe here is always required as it has to do
// init, not just 'default' init.
if (!varRecipe->getInit())
diff --git a/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp
index f3ec9e1847b00..639320275ab0f 100644
--- a/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp
@@ -65,6 +65,7 @@ struct HasDtor {
// int[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -72,6 +73,7 @@ struct HasDtor {
// float[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -79,6 +81,7 @@ struct HasDtor {
// NoCopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -86,6 +89,7 @@ struct HasDtor {
// CopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_13CopyConstruct : !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_CopyConstruct x 5>, !cir.ptr<!cir.array<!rec_CopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -93,6 +97,7 @@ struct HasDtor {
// NonDefaultCtor[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_14NonDefaultCtor : !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NonDefaultCtor x 5>, !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -100,6 +105,7 @@ struct HasDtor {
// HasDtor[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_7HasDtor : !cir.ptr<!cir.array<!rec_HasDtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_HasDtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_HasDtor x 5>, !cir.ptr<!cir.array<!rec_HasDtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: } destroy {
diff --git a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c
index 5235aeec60713..097005e75dcbe 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c
+++ b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.c
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s
struct NoCopyConstruct {};
@@ -26,6 +26,7 @@ struct NoCopyConstruct {};
// int[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -33,6 +34,7 @@ struct NoCopyConstruct {};
// float[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -40,6 +42,7 @@ struct NoCopyConstruct {};
// NoCopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
diff --git a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp
index 12e14fa0f73b0..97399d9d4620e 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp
@@ -58,36 +58,42 @@ struct HasDtor {
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_13CopyConstruct : !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_CopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_CopyConstruct x 5>, !cir.ptr<!cir.array<!rec_CopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_14NonDefaultCtor : !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NonDefaultCtor x 5>, !cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
//
// CHECK: acc.private.recipe @privatization__Bcnt1__ZTSA5_7HasDtor : !cir.ptr<!cir.array<!rec_HasDtor x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_HasDtor x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_HasDtor x 5>, !cir.ptr<!cir.array<!rec_HasDtor x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: } destroy {
diff --git a/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp
index 0a0552e888721..d4fd4ccc68f7a 100644
--- a/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp
@@ -65,6 +65,7 @@ struct HasDtor {
// int[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_i : !cir.ptr<!cir.array<!s32i x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!s32i x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!s32i x 5>, !cir.ptr<!cir.array<!s32i x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -72,6 +73,7 @@ struct HasDtor {
// float[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_f : !cir.ptr<!cir.array<!cir.float x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!cir.float x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!cir.float x 5>, !cir.ptr<!cir.array<!cir.float x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -79,6 +81,7 @@ struct HasDtor {
// NoCopyConstruct[5] with 1 'bound'
// CHECK-NEXT: acc.private.recipe @privatization__Bcnt1__ZTSA5_15NoCopyConstruct : !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> init {
// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> {{.*}}, %[[BOUND1:.*]]: !acc.data_bounds_ty {{.*}}):
+// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array<!rec_NoCopyConstruct x 5>, !cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>>, ["openacc.private.init"]
// TODO: Add Init here.
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
@@ -86,6 +89,7 @@ struct HasDtor {
// CopyConstruc...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
llvm::ArrayRef<mlir::BlockArgument> boundsRange = | ||
block->getArguments().drop_front(1); | ||
|
||
// boundTypes contains the before and after of each bounds, so it ends up |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still not completely clear on the why here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I basically need all of the types for one reason or another, both before and after each 'bounds' operation depending on what we need. SO I just store them all in boundTypes
. For example, the 'top level' allocation happens at the least-bounded type. See 84 and 89 for cases where we need the first-set or second set (befores vs afters).
Consider: A[N]:: 1 bound operation, 2 types (type of A, and type of an element of A). Or: A[N][M]: 2 bound operations, 3 types, etc.
The assert is a sanity check for me on that case.
Or is there something else I can clarify? I know I was a little verbose in my comments (I kept losing my way getting this right), so perhaps I wrote something confusing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
std::transform_inclusive_scan( | ||
resultTypes.begin(), resultTypes.end(), | ||
std::back_inserter(allocasLeftArr), std::plus<bool>{}, | ||
[](QualType ty) { return !ty->isConstantArrayType(); }); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I misunderstood something, but I think this part will not compile, from the header file, this part will report a type mismatch error ->
typename iterator_traits<_InputIterator>::value_type __init = __u(*__first); |
iterator_traits<_InputIterator>::value_type -> QualType
lambda(*resultTypes.begin()) -> bool
QualType __init = bool;
Error message
error: no viable conversion from 'bool' to 'typename iterator_traits<__wrap_iter<QualType *>>::value_type' (aka 'QualType')
I don't know why in transform_inclusive_scan
we expected that the init value type is the same value type as the Input iterator, not the Output iterator 🤔 😕
The code will compile if we use the other overloading version of transform_inclusive_scan
that takes init as parameter, and we can pass true or false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@erichkeane I just encountered the same compilation error. As @AmrDeveloper says the default parameter fixes this: #161428
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is strange, it compiles for me! I wonder if the lookup/etc rules have changed or are just different in our compilers. Thank you for the patch, I'll look at it ASAP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks you two! I looked at the review, that is fine.
It appears to be a mistake in the library, I suspect they're copying the restriction from transform_exclusive_scan
.
…160911) As a next step to generating pointer/array recipes, this patch generates just the 'alloca' lines that are necessary. Copying pointers over to restore the structure is held off to the next patch. In the case of a pointer, we need to allocate the level 'below' it (if we index into it), then copy the values into the pointers. In the case of an array, we skip the alloca (since the array's alloca contains the value). After this, we'll need a patch that copies the pointers into place, and finally one that does the initialization of these values.
As a next step to generating pointer/array recipes, this patch generates just the 'alloca' lines that are necessary. Copying pointers over to restore the structure is held off to the next patch.
In the case of a pointer, we need to allocate the level 'below' it (if we index into it), then copy the values into the pointers. In the case of an array, we skip the alloca (since the array's alloca contains the value).
After this, we'll need a patch that copies the pointers into place, and finally one that does the initialization of these values.