[flang][openacc] support array section privatization in lowering (#175184)

Add support array section in private, firstprivate, and reduction.

Key changes:
- Change the related data operation result type to return the same type
as the array base (same type as the acc variable input in the
operation), while it was the type of the section before. This allows
remapping the base the to result value (to use the data operation result
as the base when generating addressing inside the compute region).
- The generatePrivateInit implementation of FIROpenACCTypeInterfaces is
modified to allocate storage only for the section, and to return the
mock base address (that is the address of the allocation minus the
offset/lower bound of the privatized section).
- The code generating the copy and combiner region is moved from
OpenACC.cpp to FIROpenACCTypeInterfaces.cpp via the addition of new
generateCopy and generateCombiner interface in the
MappableTypeInterface. This allows sharing all the addressing helper
with generatePrivateInit, and will allow late generation of all recipes
with Fortran.
- Update generatePrivateDestroy to deallocate the beginning of the
section if any.
 
In the process, the generatePrivateInit implementation is
modified so that it is more uniform to make it easier to deal with the
section. This also allowed removing runtime calls when initializing the
private for array reduction.
This commit is contained in:
jeanPerier 2026-01-15 09:32:13 +01:00 committed by GitHub
parent 2789ad2b79
commit b0b1ab8a40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 1560 additions and 1245 deletions

View File

@ -88,23 +88,23 @@ void genOpenACCRoutineConstruct(
/// Get a acc.private.recipe op for the given type or create it if it does not
/// exist yet.
mlir::acc::PrivateRecipeOp createOrGetPrivateRecipe(fir::FirOpBuilder &,
llvm::StringRef,
mlir::Location, mlir::Type);
mlir::acc::PrivateRecipeOp
createOrGetPrivateRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location,
mlir::Type,
llvm::SmallVector<mlir::Value> &dataOperationBounds);
/// Get a acc.reduction.recipe op for the given type or create it if it does not
/// exist yet.
mlir::acc::ReductionRecipeOp
createOrGetReductionRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location,
mlir::Type, mlir::acc::ReductionOperator,
llvm::SmallVector<mlir::Value> &);
llvm::SmallVector<mlir::Value> &dataOperationBounds);
/// Get a acc.firstprivate.recipe op for the given type or create it if it does
/// not exist yet.
mlir::acc::FirstprivateRecipeOp
createOrGetFirstprivateRecipe(fir::FirOpBuilder &, llvm::StringRef,
mlir::Location, mlir::Type,
llvm::SmallVector<mlir::Value> &);
mlir::acc::FirstprivateRecipeOp createOrGetFirstprivateRecipe(
fir::FirOpBuilder &, llvm::StringRef, mlir::Location, mlir::Type,
llvm::SmallVector<mlir::Value> &dataOperationBounds);
void attachDeclarePostAllocAction(AbstractConverter &, fir::FirOpBuilder &,
const Fortran::semantics::Symbol &);

View File

@ -576,7 +576,7 @@ public:
/// Fortran 2018 9.5.3.3.2 section for more details.
mlir::Value genExtentFromTriplet(mlir::Location loc, mlir::Value lb,
mlir::Value ub, mlir::Value step,
mlir::Type type);
mlir::Type type, bool fold = false);
/// Create an AbsentOp of \p argTy type and handle special cases, such as
/// Character Procedure Tuple arguments.

View File

@ -86,7 +86,22 @@ struct OpenACCMappableModel
bool &needsDestroy) const;
bool generatePrivateDestroy(mlir::Type type, mlir::OpBuilder &builder,
mlir::Location loc, mlir::Value privatized) const;
mlir::Location loc, mlir::Value privatized,
mlir::ValueRange bounds) const;
bool generateCopy(mlir::Type type, mlir::OpBuilder &mlirBuilder,
mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> source,
mlir::TypedValue<mlir::acc::MappableType> dest,
mlir::ValueRange bounds) const;
bool generateCombiner(mlir::Type type, mlir::OpBuilder &mlirBuilder,
mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> dest,
mlir::TypedValue<mlir::acc::MappableType> source,
mlir::ValueRange bounds,
mlir::acc::ReductionOperator op,
mlir::Attribute fastmathFlags) const;
};
} // namespace fir::acc

View File

@ -27,14 +27,17 @@
#include "flang/Optimizer/Builder/HLFIRTools.h"
#include "flang/Optimizer/Builder/IntrinsicCall.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
#include "flang/Optimizer/Support/Utils.h"
#include "flang/Parser/parse-tree-visitor.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Parser/tools.h"
#include "flang/Semantics/expression.h"
#include "flang/Semantics/scope.h"
#include "flang/Semantics/tools.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/OpenACC/OpenACCUtils.h"
#include "mlir/IR/IRMapping.h"
@ -646,54 +649,19 @@ void genAtomicCapture(Fortran::lower::AbstractConverter &converter,
firOpBuilder.setInsertionPointAfter(atomicCaptureOp);
}
/// Rebuild the array type from the acc.bounds operation with constant
/// lowerbound/upperbound or extent.
static mlir::Type getTypeFromBounds(llvm::SmallVector<mlir::Value> &bounds,
mlir::Type ty) {
auto seqTy =
mlir::dyn_cast_or_null<fir::SequenceType>(fir::unwrapRefType(ty));
if (!bounds.empty() && seqTy) {
llvm::SmallVector<int64_t> shape;
for (auto b : bounds) {
auto boundsOp =
mlir::dyn_cast<mlir::acc::DataBoundsOp>(b.getDefiningOp());
if (boundsOp.getLowerbound() &&
fir::getIntIfConstant(boundsOp.getLowerbound()) &&
boundsOp.getUpperbound() &&
fir::getIntIfConstant(boundsOp.getUpperbound())) {
int64_t ext = *fir::getIntIfConstant(boundsOp.getUpperbound()) -
*fir::getIntIfConstant(boundsOp.getLowerbound()) + 1;
shape.push_back(ext);
} else if (boundsOp.getExtent() &&
fir::getIntIfConstant(boundsOp.getExtent())) {
shape.push_back(*fir::getIntIfConstant(boundsOp.getExtent()));
} else {
return ty; // TODO: handle dynamic shaped array slice.
}
}
if (shape.empty() || shape.size() != bounds.size())
return ty;
auto newSeqTy = fir::SequenceType::get(shape, seqTy.getEleTy());
if (mlir::isa<fir::ReferenceType, fir::PointerType>(ty))
return fir::ReferenceType::get(newSeqTy);
return newSeqTy;
}
return ty;
}
static mlir::SymbolRefAttr
createOrGetRecipe(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::acc::RecipeKind kind, mlir::Value addr,
llvm::SmallVector<mlir::Value> &bounds) {
mlir::Type ty = getTypeFromBounds(bounds, addr.getType());
mlir::Type ty = addr.getType();
// Compute the canonical recipe name for the given kind, type, address and
// bounds so that recipes are shared wherever possible.
std::string recipeName = fir::acc::getRecipeName(kind, ty, addr, bounds);
switch (kind) {
case mlir::acc::RecipeKind::private_recipe: {
auto recipe =
Fortran::lower::createOrGetPrivateRecipe(builder, recipeName, loc, ty);
auto recipe = Fortran::lower::createOrGetPrivateRecipe(builder, recipeName,
loc, ty, bounds);
return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
}
case mlir::acc::RecipeKind::firstprivate_recipe: {
@ -791,6 +759,9 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
dataRef->u);
}
bool isPrivate = std::is_same_v<Op, mlir::acc::PrivateOp> ||
std::is_same_v<Op, mlir::acc::FirstprivateOp>;
fir::factory::AddrAndBoundsInfo info =
Fortran::lower::gatherDataOperandAddrAndBounds<
mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>(
@ -807,8 +778,6 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
// For privatization, absent OPTIONAL are illegal as per OpenACC 3.3
// section 2.17.1 and the descriptor must be used to drive the creation of
// the temporary and the copy.
bool isPrivate = std::is_same_v<Op, mlir::acc::PrivateOp> ||
std::is_same_v<Op, mlir::acc::FirstprivateOp>;
mlir::Value baseAddr = (!isPrivate &&
(fir::unwrapRefType(info.addr.getType()) !=
fir::unwrapRefType(info.rawInput.getType())) &&
@ -816,17 +785,9 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
? info.rawInput
: info.addr;
// TODO: update privatization of array section to return the base
// address and update the recipe generation to "offset back" the returned
// address. Then it will be possible to remap them like in other cases.
bool isPrivateArraySection = isPrivate && !bounds.empty();
mlir::Type resTy = isPrivateArraySection
? getTypeFromBounds(bounds, baseAddr.getType())
: baseAddr.getType();
Op op = createDataEntryOp<Op>(
builder, operandLocation, baseAddr, asFortran, bounds, structured,
implicit, dataClause, resTy, async, asyncDeviceTypes,
implicit, dataClause, baseAddr.getType(), async, asyncDeviceTypes,
asyncOnlyDeviceTypes, unwrapBoxAddr, info.isPresent);
dataOperands.push_back(op.getAccVar());
@ -844,7 +805,7 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
// Track the symbol and its corresponding mlir::Value if requested so that
// accesses inside regions can be remapped.
if (dataMap && !isPrivateArraySection && !isNoCreateWithBounds) {
if (dataMap && !isNoCreateWithBounds) {
if (componentRef)
dataMap->emplaceComponent(op.getAccVar(), std::move(*componentRef),
baseAddr);
@ -1084,16 +1045,6 @@ genDataExitOperations(fir::FirOpBuilder &builder,
}
}
fir::ShapeOp genShapeOp(mlir::OpBuilder &builder, fir::SequenceType seqTy,
mlir::Location loc) {
llvm::SmallVector<mlir::Value> extents;
mlir::Type idxTy = builder.getIndexType();
for (auto extent : seqTy.getShape())
extents.push_back(mlir::arith::ConstantOp::create(
builder, loc, idxTy, builder.getIntegerAttr(idxTy, extent)));
return fir::ShapeOp::create(builder, loc, extents);
}
/// Get the initial value for reduction operator.
template <typename R>
static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) {
@ -1207,10 +1158,71 @@ static mlir::Value getReductionInitValue(fir::FirOpBuilder &builder,
llvm::report_fatal_error("Unsupported OpenACC reduction type");
}
static llvm::SmallVector<mlir::Value>
getRecipeBounds(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::ValueRange dataBoundOps,
mlir::ValueRange blockBoundArgs) {
if (dataBoundOps.empty())
return {};
mlir::Type idxTy = builder.getIndexType();
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
llvm::SmallVector<mlir::Value> bounds;
if (!blockBoundArgs.empty()) {
for (unsigned i = 0; i + 2 < blockBoundArgs.size(); i += 3) {
bounds.push_back(blockBoundArgs[i]);
bounds.push_back(blockBoundArgs[i + 1]);
// acc data bound strides is the inner size in bytes or elements, but
// sections are always 1-based, so there is no need to try to compute
// that back from the acc bounds.
bounds.push_back(one);
}
return bounds;
}
for (auto bound : dataBoundOps) {
auto dataBound = llvm::dyn_cast_if_present<mlir::acc::DataBoundsOp>(
bound.getDefiningOp());
assert(dataBound && "expect acc bounds to be produced by DataBoundsOp");
assert(
dataBound.getLowerbound() && dataBound.getUpperbound() &&
"expect acc bounds for Fortran to always have lower and upper bounds");
std::optional<std::int64_t> lb =
fir::getIntIfConstant(dataBound.getLowerbound());
std::optional<std::int64_t> ub =
fir::getIntIfConstant(dataBound.getUpperbound());
assert(lb.has_value() && ub.has_value() &&
"must get constant bounds when there are no bound block arguments");
bounds.push_back(builder.createIntegerConstant(loc, idxTy, *lb));
bounds.push_back(builder.createIntegerConstant(loc, idxTy, *ub));
bounds.push_back(one);
}
return bounds;
}
static void addRecipeBoundsArgs(llvm::SmallVector<mlir::Value> &bounds,
bool allConstantBound,
llvm::SmallVector<mlir::Type> &argsTy,
llvm::SmallVector<mlir::Location> &argsLoc) {
if (!allConstantBound) {
for (mlir::Value bound : llvm::reverse(bounds)) {
auto dataBound =
mlir::dyn_cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
argsTy.push_back(dataBound.getLowerbound().getType());
argsLoc.push_back(dataBound.getLowerbound().getLoc());
argsTy.push_back(dataBound.getUpperbound().getType());
argsLoc.push_back(dataBound.getUpperbound().getLoc());
argsTy.push_back(dataBound.getStartIdx().getType());
argsLoc.push_back(dataBound.getStartIdx().getLoc());
}
}
}
using MappableValue = mlir::TypedValue<mlir::acc::MappableType>;
template <typename RecipeOp>
static RecipeOp genRecipeOp(
fir::FirOpBuilder &builder, mlir::ModuleOp mod, llvm::StringRef recipeName,
mlir::Location loc, mlir::Type ty,
llvm::SmallVector<mlir::Value> &dataOperationBounds, bool allConstantBound,
mlir::acc::ReductionOperator op = mlir::acc::ReductionOperator::AccNone) {
mlir::OpBuilder modBuilder(mod.getBodyRegion());
RecipeOp recipe;
@ -1221,20 +1233,13 @@ static RecipeOp genRecipeOp(
recipe = RecipeOp::create(modBuilder, loc, recipeName, ty);
}
assert(hlfir::isFortranVariableType(ty) && "expect Fortran variable type");
llvm::SmallVector<mlir::Type> argsTy{ty};
llvm::SmallVector<mlir::Location> argsLoc{loc};
if (auto refTy = mlir::dyn_cast_or_null<fir::ReferenceType>(ty)) {
if (auto seqTy =
mlir::dyn_cast_or_null<fir::SequenceType>(refTy.getEleTy())) {
if (seqTy.hasDynamicExtents()) {
mlir::Type idxTy = builder.getIndexType();
for (unsigned i = 0; i < seqTy.getDimension(); ++i) {
argsTy.push_back(idxTy);
argsLoc.push_back(loc);
}
}
}
}
if (!dataOperationBounds.empty())
addRecipeBoundsArgs(dataOperationBounds, allConstantBound, argsTy, argsLoc);
auto initBlock = builder.createBlock(
&recipe.getInitRegion(), recipe.getInitRegion().end(), argsTy, argsLoc);
builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
@ -1256,15 +1261,13 @@ static RecipeOp genRecipeOp(
assert(mappableTy &&
"Expected that all variable types are considered mappable");
bool needsDestroy = false;
auto retVal = mappableTy.generatePrivateInit(
builder, loc,
mlir::cast<mlir::TypedValue<mlir::acc::MappableType>>(
initBlock->getArgument(0)),
initName,
initBlock->getArguments().take_back(initBlock->getArguments().size() - 1),
initValue, needsDestroy);
mlir::acc::YieldOp::create(builder, loc,
retVal ? retVal : initBlock->getArgument(0));
llvm::SmallVector<mlir::Value> initBounds =
getRecipeBounds(builder, loc, dataOperationBounds,
initBlock->getArguments().drop_front(1));
mlir::Value retVal = mappableTy.generatePrivateInit(
builder, loc, mlir::cast<MappableValue>(initBlock->getArgument(0)),
initName, initBounds, initValue, needsDestroy);
mlir::acc::YieldOp::create(builder, loc, retVal);
// Create destroy region and generate destruction if requested.
if (needsDestroy) {
llvm::SmallVector<mlir::Type> destroyArgsTy;
@ -1280,189 +1283,59 @@ static RecipeOp genRecipeOp(
destroyArgsLoc.insert(destroyArgsLoc.end(), argsTy.size() - 1, loc);
}
builder.createBlock(&recipe.getDestroyRegion(),
recipe.getDestroyRegion().end(), destroyArgsTy,
destroyArgsLoc);
builder.setInsertionPointToEnd(&recipe.getDestroyRegion().back());
// Call interface on the privatized/reduction value (2nd argument).
(void)mappableTy.generatePrivateDestroy(
builder, loc, recipe.getDestroyRegion().front().getArgument(1));
mlir::Block *destroyBlock = builder.createBlock(
&recipe.getDestroyRegion(), recipe.getDestroyRegion().end(),
destroyArgsTy, destroyArgsLoc);
builder.setInsertionPointToEnd(destroyBlock);
llvm::SmallVector<mlir::Value> destroyBounds =
getRecipeBounds(builder, loc, dataOperationBounds,
destroyBlock->getArguments().drop_front(2));
[[maybe_unused]] bool success = mappableTy.generatePrivateDestroy(
builder, loc, destroyBlock->getArgument(1), destroyBounds);
assert(success && "failed to generate destroy region");
mlir::acc::TerminatorOp::create(builder, loc);
}
return recipe;
}
mlir::acc::PrivateRecipeOp
Fortran::lower::createOrGetPrivateRecipe(fir::FirOpBuilder &builder,
llvm::StringRef recipeName,
mlir::Location loc, mlir::Type ty) {
mlir::acc::PrivateRecipeOp Fortran::lower::createOrGetPrivateRecipe(
fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc,
mlir::Type ty, llvm::SmallVector<mlir::Value> &bounds) {
mlir::ModuleOp mod =
builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
if (auto recipe = mod.lookupSymbol<mlir::acc::PrivateRecipeOp>(recipeName))
return recipe;
auto ip = builder.saveInsertionPoint();
auto recipe = genRecipeOp<mlir::acc::PrivateRecipeOp>(builder, mod,
recipeName, loc, ty);
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
auto recipe = genRecipeOp<mlir::acc::PrivateRecipeOp>(
builder, mod, recipeName, loc, ty, bounds, allConstantBound);
builder.restoreInsertionPoint(ip);
return recipe;
}
/// Check if the DataBoundsOp is a constant bound (lb and ub are constants or
/// extent is a constant).
bool isConstantBound(mlir::acc::DataBoundsOp &op) {
if (op.getLowerbound() && fir::getIntIfConstant(op.getLowerbound()) &&
op.getUpperbound() && fir::getIntIfConstant(op.getUpperbound()))
return true;
if (op.getExtent() && fir::getIntIfConstant(op.getExtent()))
return true;
return false;
}
static llvm::SmallVector<mlir::Value>
genConstantBounds(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::acc::DataBoundsOp &dataBound) {
mlir::Type idxTy = builder.getIndexType();
mlir::Value lb, ub, step;
if (dataBound.getLowerbound() &&
fir::getIntIfConstant(dataBound.getLowerbound()) &&
dataBound.getUpperbound() &&
fir::getIntIfConstant(dataBound.getUpperbound())) {
lb = builder.createIntegerConstant(
loc, idxTy, *fir::getIntIfConstant(dataBound.getLowerbound()));
ub = builder.createIntegerConstant(
loc, idxTy, *fir::getIntIfConstant(dataBound.getUpperbound()));
step = builder.createIntegerConstant(loc, idxTy, 1);
} else if (dataBound.getExtent()) {
lb = builder.createIntegerConstant(loc, idxTy, 0);
ub = builder.createIntegerConstant(
loc, idxTy, *fir::getIntIfConstant(dataBound.getExtent()) - 1);
step = builder.createIntegerConstant(loc, idxTy, 1);
} else {
llvm::report_fatal_error("Expect constant lb/ub or extent");
}
return {lb, ub, step};
}
static hlfir::Entity genDesignateWithTriplets(
fir::FirOpBuilder &builder, mlir::Location loc, hlfir::Entity &entity,
hlfir::DesignateOp::Subscripts &triplets, mlir::Value shape) {
llvm::SmallVector<mlir::Value> lenParams;
hlfir::genLengthParameters(loc, builder, entity, lenParams);
auto designate = hlfir::DesignateOp::create(
builder, loc, entity.getBase().getType(), entity, /*component=*/"",
/*componentShape=*/mlir::Value{}, triplets,
/*substring=*/mlir::ValueRange{}, /*complexPartAttr=*/std::nullopt, shape,
lenParams);
return hlfir::Entity{designate.getResult()};
}
// Designate uses triplets based on object lower bounds while acc.bounds are
// zero based. This helper shift the bounds to create the designate triplets.
static hlfir::DesignateOp::Subscripts
genTripletsFromAccBounds(fir::FirOpBuilder &builder, mlir::Location loc,
const llvm::SmallVector<mlir::Value> &accBounds,
hlfir::Entity entity) {
assert(entity.getRank() * 3 == static_cast<int>(accBounds.size()) &&
"must get lb,ub,step for each dimension");
hlfir::DesignateOp::Subscripts triplets;
for (unsigned i = 0; i < accBounds.size(); i += 3) {
mlir::Value lb = hlfir::genLBound(loc, builder, entity, i / 3);
lb = builder.createConvert(loc, accBounds[i].getType(), lb);
assert(accBounds[i].getType() == accBounds[i + 1].getType() &&
"mix of integer types in triplets");
mlir::Value sliceLB =
builder.createOrFold<mlir::arith::AddIOp>(loc, accBounds[i], lb);
mlir::Value sliceUB =
builder.createOrFold<mlir::arith::AddIOp>(loc, accBounds[i + 1], lb);
triplets.emplace_back(
hlfir::DesignateOp::Triplet{sliceLB, sliceUB, accBounds[i + 2]});
}
return triplets;
}
static std::pair<hlfir::Entity, hlfir::Entity>
genArraySectionsInRecipe(fir::FirOpBuilder &builder, mlir::Location loc,
llvm::SmallVector<mlir::Value> &dataOperationBounds,
mlir::ValueRange recipeArguments,
bool allConstantBound, hlfir::Entity lhs,
hlfir::Entity rhs) {
lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs);
// Get the list of lb,ub,step values for the sections that can be used inside
// the recipe region.
llvm::SmallVector<mlir::Value> bounds;
if (allConstantBound) {
// For constant bounds, the bounds are not region arguments. Materialize
// constants looking at the IR for the bounds on the data operation.
for (auto bound : dataOperationBounds) {
auto dataBound =
mlir::cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
bounds.append(genConstantBounds(builder, loc, dataBound));
}
} else {
// If one bound is not constant, all of the bounds are region arguments.
for (auto arg : recipeArguments.drop_front(2))
bounds.push_back(arg);
}
// Compute the fir.shape of the array section and the triplets to create
// hlfir.designate.
assert(lhs.getRank() * 3 == static_cast<int>(bounds.size()) &&
"must get lb,ub,step for each dimension");
llvm::SmallVector<mlir::Value> extents;
mlir::Type idxTy = builder.getIndexType();
for (unsigned i = 0; i < bounds.size(); i += 3)
extents.push_back(builder.genExtentFromTriplet(
loc, bounds[i], bounds[i + 1], bounds[i + 2], idxTy));
mlir::Value shape = fir::ShapeOp::create(builder, loc, extents);
hlfir::DesignateOp::Subscripts rhsTriplets =
genTripletsFromAccBounds(builder, loc, bounds, rhs);
hlfir::DesignateOp::Subscripts lhsTriplets;
// Share the bounds when both rhs/lhs are known to be 1-based to avoid noise
// in the IR for the most common cases.
if (!lhs.mayHaveNonDefaultLowerBounds() &&
!rhs.mayHaveNonDefaultLowerBounds())
lhsTriplets = rhsTriplets;
else
lhsTriplets = genTripletsFromAccBounds(builder, loc, bounds, lhs);
hlfir::Entity leftSection =
genDesignateWithTriplets(builder, loc, lhs, lhsTriplets, shape);
hlfir::Entity rightSection =
genDesignateWithTriplets(builder, loc, rhs, rhsTriplets, shape);
return {leftSection, rightSection};
}
// Generate the combiner or copy region block and block arguments and return the
// source and destination entities.
static std::pair<hlfir::Entity, hlfir::Entity>
static std::pair<MappableValue, MappableValue>
genRecipeCombinerOrCopyRegion(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Type ty, mlir::Region &region,
llvm::SmallVector<mlir::Value> &bounds,
bool allConstantBound) {
llvm::SmallVector<mlir::Type> argsTy{ty, ty};
llvm::SmallVector<mlir::Location> argsLoc{loc, loc};
if (!allConstantBound) {
for (mlir::Value bound : llvm::reverse(bounds)) {
auto dataBound =
mlir::dyn_cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
argsTy.push_back(dataBound.getLowerbound().getType());
argsLoc.push_back(dataBound.getLowerbound().getLoc());
argsTy.push_back(dataBound.getUpperbound().getType());
argsLoc.push_back(dataBound.getUpperbound().getLoc());
argsTy.push_back(dataBound.getStartIdx().getType());
argsLoc.push_back(dataBound.getStartIdx().getLoc());
}
}
addRecipeBoundsArgs(bounds, allConstantBound, argsTy, argsLoc);
mlir::Block *block =
builder.createBlock(&region, region.end(), argsTy, argsLoc);
builder.setInsertionPointToEnd(&region.back());
return {hlfir::Entity{block->getArgument(0)},
hlfir::Entity{block->getArgument(1)}};
auto firstArg = mlir::cast<MappableValue>(block->getArgument(0));
auto secondArg = mlir::cast<MappableValue>(block->getArgument(1));
return {firstArg, secondArg};
}
mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc,
mlir::Type ty, llvm::SmallVector<mlir::Value> &bounds) {
mlir::Type ty, llvm::SmallVector<mlir::Value> &dataBoundOps) {
mlir::ModuleOp mod =
builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
if (auto recipe =
@ -1470,38 +1343,21 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
return recipe;
mlir::OpBuilder::InsertionGuard guard(builder);
bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps);
auto recipe = genRecipeOp<mlir::acc::FirstprivateRecipeOp>(
builder, mod, recipeName, loc, ty);
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound);
auto [source, destination] = genRecipeCombinerOrCopyRegion(
builder, loc, ty, recipe.getCopyRegion(), bounds, allConstantBound);
builder, loc, ty, recipe.getCopyRegion(), dataBoundOps, allConstantBound);
llvm::SmallVector<mlir::Value> copyBounds =
getRecipeBounds(builder, loc, dataBoundOps,
recipe.getCopyRegion().getArguments().drop_front(2));
fir::FirOpBuilder firBuilder{builder, recipe.getOperation()};
source = hlfir::derefPointersAndAllocatables(loc, builder, source);
destination = hlfir::derefPointersAndAllocatables(loc, builder, destination);
if (!bounds.empty())
std::tie(source, destination) = genArraySectionsInRecipe(
firBuilder, loc, bounds, recipe.getCopyRegion().getArguments(),
allConstantBound, source, destination);
// The source and the destination of the firstprivate copy cannot alias,
// the destination is already properly allocated, so a simple assignment
// can be generated right away to avoid ending-up with runtime calls
// for arrays of numerical, logical and, character types.
//
// The temporary_lhs flag allows indicating that user defined assignments
// should not be called while copying components, and that the LHS and RHS
// are known to not alias since the LHS is a created object.
//
// TODO: detect cases where user defined assignment is needed and add a TODO.
// using temporary_lhs allows more aggressive optimizations of simple derived
// types. Existing compilers supporting OpenACC do not call user defined
// assignments, some use case is needed to decide what to do.
source = hlfir::loadTrivialScalar(loc, builder, source);
hlfir::AssignOp::create(builder, loc, source, destination, /*realloc=*/false,
/*keep_lhs_length_if_realloc=*/false,
/*temporary_lhs=*/true);
auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
assert(mappableTy &&
"Expected that all variable types are considered mappable");
[[maybe_unused]] bool success =
mappableTy.generateCopy(builder, loc, source, destination, copyBounds);
assert(success && "failed to generate copy");
mlir::acc::TerminatorOp::create(builder, loc);
return recipe;
}
@ -1537,124 +1393,37 @@ getReductionOperator(const Fortran::parser::ReductionOperator &op) {
llvm_unreachable("unexpected reduction operator");
}
template <typename Op>
static mlir::Value genLogicalCombiner(fir::FirOpBuilder &builder,
mlir::Location loc, mlir::Value value1,
mlir::Value value2) {
mlir::Type i1 = builder.getI1Type();
mlir::Value v1 = fir::ConvertOp::create(builder, loc, i1, value1);
mlir::Value v2 = fir::ConvertOp::create(builder, loc, i1, value2);
mlir::Value combined = Op::create(builder, loc, v1, v2);
return fir::ConvertOp::create(builder, loc, value1.getType(), combined);
}
static mlir::Value genComparisonCombiner(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::arith::CmpIPredicate pred,
mlir::Value value1,
mlir::Value value2) {
mlir::Type i1 = builder.getI1Type();
mlir::Value v1 = fir::ConvertOp::create(builder, loc, i1, value1);
mlir::Value v2 = fir::ConvertOp::create(builder, loc, i1, value2);
mlir::Value add = mlir::arith::CmpIOp::create(builder, loc, pred, v1, v2);
return fir::ConvertOp::create(builder, loc, value1.getType(), add);
}
static mlir::Value genScalarCombiner(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::acc::ReductionOperator op,
mlir::Type ty, mlir::Value value1,
mlir::Value value2) {
value1 = builder.loadIfRef(loc, value1);
value2 = builder.loadIfRef(loc, value2);
if (op == mlir::acc::ReductionOperator::AccAdd) {
if (ty.isIntOrIndex())
return mlir::arith::AddIOp::create(builder, loc, value1, value2);
if (mlir::isa<mlir::FloatType>(ty))
return mlir::arith::AddFOp::create(builder, loc, value1, value2);
if (auto cmplxTy = mlir::dyn_cast_or_null<mlir::ComplexType>(ty))
return fir::AddcOp::create(builder, loc, value1, value2);
TODO(loc, "reduction add type");
}
if (op == mlir::acc::ReductionOperator::AccMul) {
if (ty.isIntOrIndex())
return mlir::arith::MulIOp::create(builder, loc, value1, value2);
if (mlir::isa<mlir::FloatType>(ty))
return mlir::arith::MulFOp::create(builder, loc, value1, value2);
if (mlir::isa<mlir::ComplexType>(ty))
return fir::MulcOp::create(builder, loc, value1, value2);
TODO(loc, "reduction mul type");
}
if (op == mlir::acc::ReductionOperator::AccMin)
return fir::genMin(builder, loc, {value1, value2});
if (op == mlir::acc::ReductionOperator::AccMax)
return fir::genMax(builder, loc, {value1, value2});
if (op == mlir::acc::ReductionOperator::AccIand)
return mlir::arith::AndIOp::create(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccIor)
return mlir::arith::OrIOp::create(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccXor)
return mlir::arith::XOrIOp::create(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccLand)
return genLogicalCombiner<mlir::arith::AndIOp>(builder, loc, value1,
value2);
if (op == mlir::acc::ReductionOperator::AccLor)
return genLogicalCombiner<mlir::arith::OrIOp>(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccEqv)
return genComparisonCombiner(builder, loc, mlir::arith::CmpIPredicate::eq,
value1, value2);
if (op == mlir::acc::ReductionOperator::AccNeqv)
return genComparisonCombiner(builder, loc, mlir::arith::CmpIPredicate::ne,
value1, value2);
TODO(loc, "reduction operator");
}
mlir::acc::ReductionRecipeOp Fortran::lower::createOrGetReductionRecipe(
fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc,
mlir::Type ty, mlir::acc::ReductionOperator op,
llvm::SmallVector<mlir::Value> &bounds) {
llvm::SmallVector<mlir::Value> &dataBoundOps) {
mlir::ModuleOp mod =
builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
if (auto recipe = mod.lookupSymbol<mlir::acc::ReductionRecipeOp>(recipeName))
return recipe;
mlir::OpBuilder::InsertionGuard guard(builder);
bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps);
auto recipe = genRecipeOp<mlir::acc::ReductionRecipeOp>(
builder, mod, recipeName, loc, ty, op);
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound, op);
auto [dest, src] = genRecipeCombinerOrCopyRegion(
builder, loc, ty, recipe.getCombinerRegion(), bounds, allConstantBound);
// Generate loops that combine and assign the inputs into dest (or array
// section of the inputs when there are bounds).
hlfir::Entity srcSection = src;
hlfir::Entity destSection = dest;
if (!bounds.empty())
std::tie(srcSection, destSection) = genArraySectionsInRecipe(
builder, loc, bounds, recipe.getCombinerRegion().getArguments(),
allConstantBound, srcSection, destSection);
auto [dest, source] = genRecipeCombinerOrCopyRegion(
builder, loc, ty, recipe.getCombinerRegion(), dataBoundOps,
allConstantBound);
llvm::SmallVector<mlir::Value> combinerBounds =
getRecipeBounds(builder, loc, dataBoundOps,
recipe.getCombinerRegion().getArguments().drop_front(2));
mlir::Type elementType = fir::getFortranElementType(ty);
auto genKernel = [&](mlir::Location l, fir::FirOpBuilder &b,
hlfir::Entity srcElementValue,
hlfir::Entity destElementValue) -> hlfir::Entity {
return hlfir::Entity{genScalarCombiner(builder, loc, op, elementType,
srcElementValue, destElementValue)};
};
hlfir::genNoAliasAssignment(loc, builder, srcSection, destSection,
/*emitWorkshareLoop=*/false,
/*temporaryLHS=*/false, genKernel);
auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
assert(mappableTy &&
"Expected that all variable types are considered mappable");
mlir::Attribute fastMathAttr;
if (builder.getFastMathFlags() != mlir::arith::FastMathFlags::none)
fastMathAttr = mlir::arith::FastMathFlagsAttr::get(
builder.getContext(), builder.getFastMathFlags());
[[maybe_unused]] bool success = mappableTy.generateCombiner(
builder, loc, dest, source, combinerBounds, op, fastMathAttr);
assert(success && "failed to generate combiner");
mlir::acc::YieldOp::create(builder, loc, dest);
return recipe;
}
@ -1729,10 +1498,6 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
mlir::acc::DataClause::acc_reduction, info.addr.getType(), async,
asyncDeviceTypes, asyncOnlyDeviceTypes, /*unwrapBoxAddr=*/true);
mlir::Type ty = op.getAccVar().getType();
if (!fir::acc::areAllBoundsConstant(bounds) ||
fir::isAssumedShape(info.addr.getType()) ||
fir::isAllocatableOrPointerArray(info.addr.getType()))
ty = info.addr.getType();
std::string recipeName = fir::acc::getRecipeName(
mlir::acc::RecipeKind::reduction_recipe, ty, info.addr, bounds, mlirOp);

View File

@ -859,21 +859,32 @@ mlir::Value fir::FirOpBuilder::genIsNullAddr(mlir::Location loc,
mlir::arith::CmpIPredicate::eq);
}
mlir::Value fir::FirOpBuilder::genExtentFromTriplet(mlir::Location loc,
mlir::Value lb,
mlir::Value ub,
mlir::Value step,
mlir::Type type) {
template <typename OpTy, typename... Args>
static mlir::Value createAndMaybeFold(bool fold, fir::FirOpBuilder &builder,
mlir::Location loc, Args &&...args) {
if (fold)
return builder.createOrFold<OpTy>(loc, std::forward<Args>(args)...);
return OpTy::create(builder, loc, std::forward<Args>(args)...);
}
mlir::Value
fir::FirOpBuilder::genExtentFromTriplet(mlir::Location loc, mlir::Value lb,
mlir::Value ub, mlir::Value step,
mlir::Type type, bool fold) {
auto zero = createIntegerConstant(loc, type, 0);
lb = createConvert(loc, type, lb);
ub = createConvert(loc, type, ub);
step = createConvert(loc, type, step);
auto diff = mlir::arith::SubIOp::create(*this, loc, ub, lb);
auto add = mlir::arith::AddIOp::create(*this, loc, diff, step);
auto div = mlir::arith::DivSIOp::create(*this, loc, add, step);
auto cmp = mlir::arith::CmpIOp::create(
*this, loc, mlir::arith::CmpIPredicate::sgt, div, zero);
return mlir::arith::SelectOp::create(*this, loc, cmp, div, zero);
auto diff = createAndMaybeFold<mlir::arith::SubIOp>(fold, *this, loc, ub, lb);
auto add =
createAndMaybeFold<mlir::arith::AddIOp>(fold, *this, loc, diff, step);
auto div =
createAndMaybeFold<mlir::arith::DivSIOp>(fold, *this, loc, add, step);
auto cmp = createAndMaybeFold<mlir::arith::CmpIOp>(
fold, *this, loc, mlir::arith::CmpIPredicate::sgt, div, zero);
return createAndMaybeFold<mlir::arith::SelectOp>(fold, *this, loc, cmp, div,
zero);
}
mlir::Value fir::FirOpBuilder::genAbsentOp(mlir::Location loc,

View File

@ -1417,13 +1417,14 @@ void hlfir::genNoAliasArrayAssignment(
rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs);
lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
mlir::Value lhsShape = hlfir::genShape(loc, builder, lhs);
llvm::SmallVector<mlir::Value> lhsExtents =
hlfir::getIndexExtents(loc, builder, lhsShape);
mlir::Value rhsShape = hlfir::genShape(loc, builder, rhs);
llvm::SmallVector<mlir::Value> rhsExtents =
hlfir::getIndexExtents(loc, builder, rhsShape);
llvm::SmallVector<mlir::Value> extents =
fir::factory::deduceOptimalExtents(lhsExtents, rhsExtents);
hlfir::getIndexExtents(loc, builder, lhsShape);
if (rhs.isArray()) {
mlir::Value rhsShape = hlfir::genShape(loc, builder, rhs);
llvm::SmallVector<mlir::Value> rhsExtents =
hlfir::getIndexExtents(loc, builder, rhsShape);
extents = fir::factory::deduceOptimalExtents(extents, rhsExtents);
}
hlfir::LoopNest loopNest =
hlfir::genLoopNest(loc, builder, extents,
/*isUnordered=*/true, emitWorkshareLoop);

View File

@ -15,6 +15,7 @@
#include "flang/Optimizer/Builder/DirectivesCommon.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/HLFIRTools.h"
#include "flang/Optimizer/Builder/IntrinsicCall.h"
#include "flang/Optimizer/Dialect/FIRCG/CGOps.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
@ -565,30 +566,141 @@ OpenACCPointerLikeModel<fir::LLVMPointerType>::getPointeeTypeCategory(
return categorizePointee(pointer, varPtr, varType);
}
static fir::ShapeOp genShapeOp(mlir::OpBuilder &builder,
fir::SequenceType seqTy, mlir::Location loc) {
static hlfir::Entity
genDesignateWithTriplets(fir::FirOpBuilder &builder, mlir::Location loc,
hlfir::Entity &entity,
hlfir::DesignateOp::Subscripts &triplets,
mlir::Value shape, mlir::ValueRange extents) {
llvm::SmallVector<mlir::Value> lenParams;
hlfir::genLengthParameters(loc, builder, entity, lenParams);
// Compute result type of array section.
fir::SequenceType::Shape resultTypeShape;
bool shapeIsConstant = true;
for (mlir::Value extent : extents) {
if (std::optional<std::int64_t> cst_extent =
fir::getIntIfConstant(extent)) {
resultTypeShape.push_back(*cst_extent);
} else {
resultTypeShape.push_back(fir::SequenceType::getUnknownExtent());
shapeIsConstant = false;
}
}
assert(!resultTypeShape.empty() &&
"expect private sections to always represented as arrays");
mlir::Type eleTy = entity.getFortranElementType();
auto seqTy = fir::SequenceType::get(resultTypeShape, eleTy);
bool isVolatile = fir::isa_volatile_type(entity.getType());
bool resultNeedsBox =
llvm::isa<fir::BaseBoxType>(entity.getType()) || !shapeIsConstant;
bool isPolymorphic = fir::isPolymorphicType(entity.getType());
mlir::Type resultType;
if (isPolymorphic) {
resultType = fir::ClassType::get(seqTy, isVolatile);
} else if (resultNeedsBox) {
resultType = fir::BoxType::get(seqTy, isVolatile);
} else {
resultType = fir::ReferenceType::get(seqTy, isVolatile);
}
// Generate section with hlfir.designate.
auto designate = hlfir::DesignateOp::create(
builder, loc, resultType, entity, /*component=*/"",
/*componentShape=*/mlir::Value{}, triplets,
/*substring=*/mlir::ValueRange{}, /*complexPartAttr=*/std::nullopt, shape,
lenParams);
return hlfir::Entity{designate.getResult()};
}
// Designate uses triplets based on object lower bounds while acc.bounds are
// zero based. This helper shift the bounds to create the designate triplets.
static hlfir::DesignateOp::Subscripts
genTripletsFromAccBounds(fir::FirOpBuilder &builder, mlir::Location loc,
const llvm::SmallVector<mlir::Value> &accBounds,
hlfir::Entity entity) {
assert(entity.getRank() * 3 == static_cast<int>(accBounds.size()) &&
"must get lb,ub,step for each dimension");
hlfir::DesignateOp::Subscripts triplets;
for (unsigned i = 0; i < accBounds.size(); i += 3) {
mlir::Value lb = hlfir::genLBound(loc, builder, entity, i / 3);
lb = builder.createConvert(loc, accBounds[i].getType(), lb);
assert(accBounds[i].getType() == accBounds[i + 1].getType() &&
"mix of integer types in triplets");
mlir::Value sliceLB =
builder.createOrFold<mlir::arith::AddIOp>(loc, accBounds[i], lb);
mlir::Value sliceUB =
builder.createOrFold<mlir::arith::AddIOp>(loc, accBounds[i + 1], lb);
triplets.emplace_back(
hlfir::DesignateOp::Triplet{sliceLB, sliceUB, accBounds[i + 2]});
}
return triplets;
}
static std::pair<mlir::Value, llvm::SmallVector<mlir::Value>>
computeSectionShapeAndExtents(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::ValueRange bounds) {
llvm::SmallVector<mlir::Value> extents;
// Compute the fir.shape of the array section and the triplets to create
// hlfir.designate.
mlir::Type idxTy = builder.getIndexType();
for (auto extent : seqTy.getShape())
extents.push_back(mlir::arith::ConstantOp::create(
builder, loc, idxTy, builder.getIntegerAttr(idxTy, extent)));
return fir::ShapeOp::create(builder, loc, extents);
for (unsigned i = 0; i + 2 < bounds.size(); i += 3)
extents.push_back(builder.genExtentFromTriplet(
loc, bounds[i], bounds[i + 1], bounds[i + 2], idxTy, /*fold=*/true));
mlir::Value shape = fir::ShapeOp::create(builder, loc, extents);
return {shape, extents};
}
static std::pair<hlfir::Entity, hlfir::Entity>
genArraySectionsInRecipe(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::ValueRange bounds, hlfir::Entity lhs,
hlfir::Entity rhs) {
assert(lhs.getRank() * 3 == static_cast<int>(bounds.size()) &&
"must get lb,ub,step for each dimension");
lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs);
// Get the list of lb,ub,step values for the sections that can be used inside
// the recipe region.
auto [shape, extents] = computeSectionShapeAndExtents(builder, loc, bounds);
hlfir::DesignateOp::Subscripts rhsTriplets =
genTripletsFromAccBounds(builder, loc, bounds, rhs);
hlfir::DesignateOp::Subscripts lhsTriplets;
// Share the bounds when both rhs/lhs are known to be 1-based to avoid noise
// in the IR for the most common cases.
if (!lhs.mayHaveNonDefaultLowerBounds() &&
!rhs.mayHaveNonDefaultLowerBounds())
lhsTriplets = rhsTriplets;
else
lhsTriplets = genTripletsFromAccBounds(builder, loc, bounds, lhs);
hlfir::Entity leftSection =
genDesignateWithTriplets(builder, loc, lhs, lhsTriplets, shape, extents);
hlfir::Entity rightSection =
genDesignateWithTriplets(builder, loc, rhs, rhsTriplets, shape, extents);
return {leftSection, rightSection};
}
static bool boundsAreAllConstants(mlir::ValueRange bounds) {
for (mlir::Value bound : bounds)
if (!fir::getIntIfConstant(bound).has_value())
return false;
return true;
}
template <typename Ty>
mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const {
needsDestroy = false;
mlir::Value retVal;
mlir::Type unwrappedTy = fir::unwrapRefType(type);
mlir::ModuleOp mod = builder.getInsertionBlock()
mlir::ValueRange bounds, mlir::Value initVal, bool &needsDestroy) const {
mlir::ModuleOp mod = mlirBuilder.getInsertionBlock()
->getParent()
->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve ModuleOp");
fir::FirOpBuilder builder(mlirBuilder, mod);
if (auto recType = llvm::dyn_cast<fir::RecordType>(
fir::getFortranElementType(unwrappedTy))) {
hlfir::Entity inputVar = hlfir::Entity{var};
if (inputVar.isPolymorphic())
TODO(loc, "OpenACC: polymorphic variable privatization");
if (auto recType =
llvm::dyn_cast<fir::RecordType>(inputVar.getFortranElementType())) {
// Need to make deep copies of allocatable components.
if (fir::isRecordWithAllocatableMember(recType))
TODO(loc,
@ -597,117 +709,161 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
if (fir::isRecordWithFinalRoutine(recType, mod).value_or(false))
TODO(loc, "OpenACC: privatizing derived type with user assignment or "
"final routine ");
// Pointer components needs to be initialized to NULL() for private-like
// recipes.
if (fir::isRecordWithDescriptorMember(recType))
TODO(loc, "OpenACC: privatizing derived type with pointer components");
}
bool isPointerOrAllocatable = inputVar.isMutableBox();
hlfir::Entity dereferencedVar =
hlfir::derefPointersAndAllocatables(loc, builder, inputVar);
// Step 1: Gather the address, shape, extents, and lengths parameters of the
// entity being privatized. Designate the array section if only a section is
// privatized, otherwise just use the original variable.
hlfir::Entity privatizedVar = dereferencedVar;
mlir::Value tempShape;
llvm::SmallVector<mlir::Value> tempExtents;
// TODO: while it seems best to allocate as little memory as possible and
// allocate only the storage for the section, this may actually have drawbacks
// when the array has static size and can be privatized with an alloca while
// the section size is dynamic and requires an dynamic allocmem. Hence, we
// currently allocate the full array storage in such cases. This could be
// improved via some kind of threshold if the base array size is large enough
// to justify doing a dynamic allocation with the hope that it is much
// smaller.
bool allocateSection = false;
bool isDynamicSectionOfStaticSizeArray =
!bounds.empty() &&
!fir::hasDynamicSize(dereferencedVar.getElementOrSequenceType()) &&
!boundsAreAllConstants(bounds);
if (!bounds.empty() && !isDynamicSectionOfStaticSizeArray) {
allocateSection = true;
hlfir::DesignateOp::Subscripts triplets;
std::tie(tempShape, tempExtents) =
computeSectionShapeAndExtents(builder, loc, bounds);
triplets = genTripletsFromAccBounds(builder, loc, bounds, dereferencedVar);
privatizedVar = genDesignateWithTriplets(builder, loc, dereferencedVar,
triplets, tempShape, tempExtents);
} else if (privatizedVar.getRank() > 0) {
mlir::Value shape = hlfir::genShape(loc, builder, privatizedVar);
tempExtents = hlfir::getExplicitExtentsFromShape(shape, builder);
tempShape = fir::ShapeOp::create(builder, loc, tempExtents);
}
llvm::SmallVector<mlir::Value> typeParams;
hlfir::genLengthParameters(loc, builder, privatizedVar, typeParams);
mlir::Type baseType = privatizedVar.getElementOrSequenceType();
// Step2: Create a temporary allocation for the privatized part.
mlir::Value alloc;
if (fir::hasDynamicSize(baseType) ||
(isPointerOrAllocatable && bounds.empty())) {
// Note: heap allocation is forced for whole pointers/allocatable so that
// the private POINTER/ALLOCATABLE can be deallocated/reallocated on the
// device inside the compute region. It may not be a requirement, and this
// could be revisited. In practice, this only matters for scalars since
// array POINTER and ALLOCATABLE always have dynamic size. Constant sections
// of POINTER/ALLOCATABLE can use alloca since only part of the data is
// privatized (it makes no sense to deallocate them).
alloc = builder.createHeapTemporary(loc, baseType, varName, tempExtents,
typeParams);
needsDestroy = true;
} else {
alloc = builder.createTemporary(loc, baseType, varName, tempExtents,
typeParams);
}
// Step3: Assign the initial value to the privatized part if any.
if (initVal) {
mlir::Value tempEntity = alloc;
if (fir::hasDynamicSize(baseType))
tempEntity =
fir::EmboxOp::create(builder, loc, fir::BoxType::get(baseType), alloc,
tempShape, /*slice=*/mlir::Value{}, typeParams);
hlfir::genNoAliasAssignment(
loc, builder, hlfir::Entity{initVal}, hlfir::Entity{tempEntity},
/*emitWorkshareLoop=*/false, /*temporaryLHS=*/true);
}
fir::FirOpBuilder firBuilder(builder, mod);
auto getDeclareOpForType = [&](mlir::Type ty) -> hlfir::DeclareOp {
auto alloca = fir::AllocaOp::create(firBuilder, loc, ty);
return hlfir::DeclareOp::create(firBuilder, loc, alloca, varName);
};
// Making a dynamic allocation of the size of the whole base instead of the
// section in case of section would lead to improper deallocation because
// generatePrivateDestroy always deallocates the start of the section when
// there is a section.
assert(!(needsDestroy && !bounds.empty() && !allocateSection) &&
"dynamic allocation of the whole base in case of section is not "
"expected");
if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(unwrappedTy)) {
if (fir::isa_trivial(seqTy.getEleTy())) {
mlir::Value shape;
if (seqTy.hasDynamicExtents()) {
shape = fir::ShapeOp::create(firBuilder, loc, llvm::to_vector(extents));
} else {
shape = genShapeOp(firBuilder, seqTy, loc);
}
auto alloca = fir::AllocaOp::create(
firBuilder, loc, seqTy, /*typeparams=*/mlir::ValueRange{}, extents);
auto declareOp =
hlfir::DeclareOp::create(firBuilder, loc, alloca, varName, shape);
if (inputVar.getType() == alloc.getType() && !allocateSection)
return alloc;
if (initVal) {
mlir::Type idxTy = firBuilder.getIndexType();
mlir::Type refTy = fir::ReferenceType::get(seqTy.getEleTy());
llvm::SmallVector<fir::DoLoopOp> loops;
llvm::SmallVector<mlir::Value> ivs;
if (seqTy.hasDynamicExtents()) {
hlfir::AssignOp::create(firBuilder, loc, initVal,
declareOp.getBase());
} else {
// Generate loop nest from slowest to fastest running dimension
for (auto ext : llvm::reverse(seqTy.getShape())) {
auto lb = firBuilder.createIntegerConstant(loc, idxTy, 0);
auto ub = firBuilder.createIntegerConstant(loc, idxTy, ext - 1);
auto step = firBuilder.createIntegerConstant(loc, idxTy, 1);
auto loop = fir::DoLoopOp::create(firBuilder, loc, lb, ub, step,
/*unordered=*/false);
firBuilder.setInsertionPointToStart(loop.getBody());
loops.push_back(loop);
ivs.push_back(loop.getInductionVar());
}
// Reverse IVs to match CoordinateOp's canonical index order.
std::reverse(ivs.begin(), ivs.end());
auto coord = fir::CoordinateOp::create(firBuilder, loc, refTy,
declareOp.getBase(), ivs);
fir::StoreOp::create(firBuilder, loc, initVal, coord);
firBuilder.setInsertionPointAfter(loops[0]);
}
}
retVal = declareOp.getBase();
// Step4: reconstruct the input variable from the privatized part:
// - get a mock base address if the privatized part is a section (so that any
// addressing of the input variable can be replaced by the same addressing of
// the privatized part even though the allocated part for the private does not
// cover all the input variable storage. This is relying on OpenACC
// constraint that any addressing of such privatized variable inside the
// construct region can only address the variable inside the privatized
// section).
// - reconstruct a descriptor with the same bounds and type parameters as the
// input if needed.
// - store this new descriptor in a temporary allocation if the input variable
// is a POINTER/ALLOCATABLE.
llvm::SmallVector<mlir::Value> inputVarLowerBounds, inputVarExtents;
if (dereferencedVar.isArray()) {
for (int dim = 0; dim < dereferencedVar.getRank(); ++dim) {
inputVarLowerBounds.push_back(
hlfir::genLBound(loc, builder, dereferencedVar, dim));
inputVarExtents.push_back(
hlfir::genExtent(loc, builder, dereferencedVar, dim));
}
} else if (auto boxTy =
mlir::dyn_cast_or_null<fir::BaseBoxType>(unwrappedTy)) {
mlir::Type innerTy = fir::unwrapRefType(boxTy.getEleTy());
if (fir::isa_trivial(innerTy)) {
retVal = getDeclareOpForType(unwrappedTy).getBase();
mlir::Value allocatedScalar =
fir::AllocMemOp::create(builder, loc, innerTy);
mlir::Value firClass =
fir::EmboxOp::create(builder, loc, boxTy, allocatedScalar);
fir::StoreOp::create(builder, loc, firClass, retVal);
needsDestroy = true;
} else if (mlir::isa<fir::SequenceType>(innerTy)) {
hlfir::Entity source = hlfir::Entity{var};
auto [temp, cleanupFlag] =
hlfir::createTempFromMold(loc, firBuilder, source);
if (fir::isa_ref_type(type)) {
// When the temp is created - it is not a reference - thus we can
// end up with a type inconsistency. Therefore ensure storage is created
// for it.
retVal = getDeclareOpForType(unwrappedTy).getBase();
mlir::Value storeDst = retVal;
if (fir::unwrapRefType(retVal.getType()) != temp.getType()) {
// `createTempFromMold` makes the unfortunate choice to lose the
// `fir.heap` and `fir.ptr` types when wrapping with a box. Namely,
// when wrapping a `fir.heap<fir.array>`, it will create instead a
// `fir.box<fir.array>`. Cast here to deal with this inconsistency.
storeDst = firBuilder.createConvert(
loc, firBuilder.getRefType(temp.getType()), retVal);
}
fir::StoreOp::create(builder, loc, temp, storeDst);
} else {
retVal = temp;
}
// If heap was allocated, a destroy is required later.
if (cleanupFlag)
needsDestroy = true;
}
mlir::Value privateVarBaseAddr = alloc;
if (allocateSection) {
// To compute the mock base address without doing pointer arithmetic,
// compute: TYPE, TEMP(ZERO_BASED_SECTION_LB:) MOCK_BASE = TEMP(0)
// This addresses the section "backwards" (0 <= ZERO_BASED_SECTION_LB). This
// is currently OK, but care should be taken to avoid tripping bound checks
// if added in the future.
mlir::Type inputBaseAddrType =
dereferencedVar.getBoxType().getBaseAddressType();
mlir::Value tempBaseAddr =
builder.createConvert(loc, inputBaseAddrType, alloc);
mlir::Value zero =
builder.createIntegerConstant(loc, builder.getIndexType(), 0);
llvm::SmallVector<mlir::Value> lowerBounds;
llvm::SmallVector<mlir::Value> zeros;
for (unsigned i = 0; i < bounds.size(); i += 3) {
lowerBounds.push_back(bounds[i]);
zeros.push_back(zero);
}
mlir::Value offsetShapeShift =
builder.genShape(loc, lowerBounds, inputVarExtents);
mlir::Type eleRefType =
builder.getRefType(privatizedVar.getFortranElementType());
mlir::Value mockBase = fir::ArrayCoorOp::create(
builder, loc, eleRefType, tempBaseAddr, offsetShapeShift,
/*slice=*/mlir::Value{}, /*indices=*/zeros,
/*typeParams=*/mlir::ValueRange{});
privateVarBaseAddr =
builder.createConvert(loc, inputBaseAddrType, mockBase);
}
mlir::Value retVal = privateVarBaseAddr;
if (inputVar.isBoxAddressOrValue()) {
// Recreate descriptor with same bounds as the input variable.
mlir::Value shape;
if (!inputVarExtents.empty())
shape = builder.genShape(loc, inputVarLowerBounds, inputVarExtents);
mlir::Value box = fir::EmboxOp::create(builder, loc, inputVar.getBoxType(),
privateVarBaseAddr, shape,
/*slice=*/mlir::Value{}, typeParams);
if (inputVar.isMutableBox()) {
mlir::Value boxAlloc =
fir::AllocaOp::create(builder, loc, inputVar.getBoxType());
fir::StoreOp::create(builder, loc, box, boxAlloc);
retVal = boxAlloc;
} else {
TODO(loc, "Unsupported boxed type for OpenACC private-like recipe");
retVal = box;
}
if (initVal) {
hlfir::AssignOp::create(builder, loc, initVal, retVal);
}
} else if (llvm::isa<fir::BoxCharType, fir::CharacterType>(unwrappedTy)) {
TODO(loc, "Character type for OpenACC private-like recipe");
} else {
assert((fir::isa_trivial(unwrappedTy) ||
llvm::isa<fir::RecordType>(unwrappedTy)) &&
"expected numerical, logical, and derived type without length "
"parameters");
auto declareOp = getDeclareOpForType(unwrappedTy);
if (initVal && fir::isa_trivial(unwrappedTy)) {
auto convert = firBuilder.createConvert(loc, unwrappedTy, initVal);
fir::StoreOp::create(firBuilder, loc, convert, declareOp.getBase());
} else if (initVal) {
// hlfir.assign with temporary LHS flag should just do it. Not implemented
// because not clear it is needed, so cannot be tested.
TODO(loc, "initial value for derived type in private-like recipe");
}
retVal = declareOp.getBase();
}
return retVal;
}
@ -735,43 +891,250 @@ OpenACCMappableModel<fir::PointerType>::generatePrivateInit(
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const;
template <typename Ty>
bool OpenACCMappableModel<Ty>::generateCopy(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> src,
mlir::TypedValue<mlir::acc::MappableType> dest,
mlir::ValueRange bounds) const {
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve parent module");
fir::FirOpBuilder builder(mlirBuilder, mod);
hlfir::Entity source{src};
hlfir::Entity destination{dest};
source = hlfir::derefPointersAndAllocatables(loc, builder, source);
destination = hlfir::derefPointersAndAllocatables(loc, builder, destination);
if (!bounds.empty())
std::tie(source, destination) =
genArraySectionsInRecipe(builder, loc, bounds, source, destination);
// The source and the destination of the firstprivate copy cannot alias,
// the destination is already properly allocated, so a simple assignment
// can be generated right away to avoid ending-up with runtime calls
// for arrays of numerical, logical and, character types.
//
// The temporary_lhs flag allows indicating that user defined assignments
// should not be called while copying components, and that the LHS and RHS
// are known to not alias since the LHS is a created object.
//
// TODO: detect cases where user defined assignment is needed and add a TODO.
// using temporary_lhs allows more aggressive optimizations of simple derived
// types. Existing compilers supporting OpenACC do not call user defined
// assignments, some use case is needed to decide what to do.
source = hlfir::loadTrivialScalar(loc, builder, source);
hlfir::AssignOp::create(builder, loc, source, destination, /*realloc=*/false,
/*keep_lhs_length_if_realloc=*/false,
/*temporary_lhs=*/true);
return true;
}
template bool OpenACCMappableModel<fir::BaseBoxType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
template bool OpenACCMappableModel<fir::PointerType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
template bool OpenACCMappableModel<fir::HeapType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
template <typename Op>
static mlir::Value genLogicalCombiner(fir::FirOpBuilder &builder,
mlir::Location loc, mlir::Value value1,
mlir::Value value2) {
mlir::Type i1 = builder.getI1Type();
mlir::Value v1 = fir::ConvertOp::create(builder, loc, i1, value1);
mlir::Value v2 = fir::ConvertOp::create(builder, loc, i1, value2);
mlir::Value combined = Op::create(builder, loc, v1, v2);
return fir::ConvertOp::create(builder, loc, value1.getType(), combined);
}
static mlir::Value genComparisonCombiner(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::arith::CmpIPredicate pred,
mlir::Value value1,
mlir::Value value2) {
mlir::Type i1 = builder.getI1Type();
mlir::Value v1 = fir::ConvertOp::create(builder, loc, i1, value1);
mlir::Value v2 = fir::ConvertOp::create(builder, loc, i1, value2);
mlir::Value add = mlir::arith::CmpIOp::create(builder, loc, pred, v1, v2);
return fir::ConvertOp::create(builder, loc, value1.getType(), add);
}
static mlir::Value genScalarCombiner(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::acc::ReductionOperator op,
mlir::Type ty, mlir::Value value1,
mlir::Value value2) {
value1 = builder.loadIfRef(loc, value1);
value2 = builder.loadIfRef(loc, value2);
if (op == mlir::acc::ReductionOperator::AccAdd) {
if (ty.isIntOrIndex())
return mlir::arith::AddIOp::create(builder, loc, value1, value2);
if (mlir::isa<mlir::FloatType>(ty))
return mlir::arith::AddFOp::create(builder, loc, value1, value2);
if (auto cmplxTy = mlir::dyn_cast_or_null<mlir::ComplexType>(ty))
return fir::AddcOp::create(builder, loc, value1, value2);
TODO(loc, "reduction add type");
}
if (op == mlir::acc::ReductionOperator::AccMul) {
if (ty.isIntOrIndex())
return mlir::arith::MulIOp::create(builder, loc, value1, value2);
if (mlir::isa<mlir::FloatType>(ty))
return mlir::arith::MulFOp::create(builder, loc, value1, value2);
if (mlir::isa<mlir::ComplexType>(ty))
return fir::MulcOp::create(builder, loc, value1, value2);
TODO(loc, "reduction mul type");
}
if (op == mlir::acc::ReductionOperator::AccMin)
return fir::genMin(builder, loc, {value1, value2});
if (op == mlir::acc::ReductionOperator::AccMax)
return fir::genMax(builder, loc, {value1, value2});
if (op == mlir::acc::ReductionOperator::AccIand)
return mlir::arith::AndIOp::create(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccIor)
return mlir::arith::OrIOp::create(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccXor)
return mlir::arith::XOrIOp::create(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccLand)
return genLogicalCombiner<mlir::arith::AndIOp>(builder, loc, value1,
value2);
if (op == mlir::acc::ReductionOperator::AccLor)
return genLogicalCombiner<mlir::arith::OrIOp>(builder, loc, value1, value2);
if (op == mlir::acc::ReductionOperator::AccEqv)
return genComparisonCombiner(builder, loc, mlir::arith::CmpIPredicate::eq,
value1, value2);
if (op == mlir::acc::ReductionOperator::AccNeqv)
return genComparisonCombiner(builder, loc, mlir::arith::CmpIPredicate::ne,
value1, value2);
TODO(loc, "reduction operator");
}
template <typename Ty>
bool OpenACCMappableModel<Ty>::generateCombiner(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> dest,
mlir::TypedValue<mlir::acc::MappableType> source, mlir::ValueRange bounds,
mlir::acc::ReductionOperator op, mlir::Attribute fastmathFlags) const {
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve parent module");
fir::FirOpBuilder builder(mlirBuilder, mod);
if (fastmathFlags)
if (auto fastMathAttr =
mlir::dyn_cast<mlir::arith::FastMathFlagsAttr>(fastmathFlags))
builder.setFastMathFlags(fastMathAttr.getValue());
// Generate loops that combine and assign the inputs into dest (or array
// section of the inputs when there are bounds).
hlfir::Entity srcSection{source};
hlfir::Entity destSection{dest};
if (!bounds.empty()) {
std::tie(srcSection, destSection) =
genArraySectionsInRecipe(builder, loc, bounds, srcSection, destSection);
}
mlir::Type elementType = fir::getFortranElementType(dest.getType());
auto genKernel = [&](mlir::Location l, fir::FirOpBuilder &b,
hlfir::Entity srcElementValue,
hlfir::Entity destElementValue) -> hlfir::Entity {
return hlfir::Entity{genScalarCombiner(builder, loc, op, elementType,
srcElementValue, destElementValue)};
};
hlfir::genNoAliasAssignment(loc, builder, srcSection, destSection,
/*emitWorkshareLoop=*/false,
/*temporaryLHS=*/false, genKernel);
return true;
}
template bool OpenACCMappableModel<fir::BaseBoxType>::generateCombiner(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
mlir::acc::ReductionOperator op, mlir::Attribute) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generateCombiner(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
mlir::acc::ReductionOperator op, mlir::Attribute) const;
template bool OpenACCMappableModel<fir::PointerType>::generateCombiner(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
mlir::acc::ReductionOperator op, mlir::Attribute) const;
template bool OpenACCMappableModel<fir::HeapType>::generateCombiner(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
mlir::acc::ReductionOperator op, mlir::Attribute) const;
template <typename Ty>
bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized) const {
mlir::Type unwrappedTy = fir::unwrapRefType(type);
// For boxed scalars allocated with AllocMem during init, free the heap.
if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(unwrappedTy)) {
mlir::Value boxVal = privatized;
if (fir::isa_ref_type(boxVal.getType()))
boxVal = fir::LoadOp::create(builder, loc, boxVal);
mlir::Value addr = fir::BoxAddrOp::create(builder, loc, boxVal);
// FreeMem only accepts fir.heap and this may not be represented in the box
// type if the privatized entity is not an allocatable.
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::Value privatized, mlir::ValueRange bounds) const {
hlfir::Entity inputVar = hlfir::Entity{privatized};
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve parent module");
fir::FirOpBuilder builder(mlirBuilder, mod);
auto genFreeRawAddress = [&](hlfir::Entity entity) {
mlir::Value addr = hlfir::genVariableRawAddress(loc, builder, entity);
mlir::Type heapType =
fir::HeapType::get(fir::unwrapRefType(addr.getType()));
if (heapType != addr.getType())
addr = fir::ConvertOp::create(builder, loc, heapType, addr);
fir::FreeMemOp::create(builder, loc, addr);
};
if (bounds.empty()) {
genFreeRawAddress(inputVar);
return true;
}
// Nothing to do for other categories by default, they are stack allocated.
// The input variable is an array section, the base address is not the real
// allocation. Compute the section base address and deallocate that.
hlfir::Entity dereferencedVar =
hlfir::derefPointersAndAllocatables(loc, builder, inputVar);
hlfir::DesignateOp::Subscripts triplets;
auto [tempShape, tempExtents] =
computeSectionShapeAndExtents(builder, loc, bounds);
(void)tempExtents;
triplets = genTripletsFromAccBounds(builder, loc, bounds, dereferencedVar);
hlfir::Entity arraySection = genDesignateWithTriplets(
builder, loc, dereferencedVar, triplets, tempShape, tempExtents);
genFreeRawAddress(arraySection);
return true;
}
template bool OpenACCMappableModel<fir::BaseBoxType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized) const;
mlir::Value privatized, mlir::ValueRange bounds) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized) const;
mlir::Value privatized, mlir::ValueRange bounds) const;
template bool OpenACCMappableModel<fir::HeapType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized) const;
mlir::Value privatized, mlir::ValueRange bounds) const;
template bool OpenACCMappableModel<fir::PointerType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized) const;
mlir::Value privatized, mlir::ValueRange bounds) const;
template <typename Ty>
mlir::Value OpenACCPointerLikeModel<Ty>::genAllocate(

View File

@ -237,15 +237,9 @@ std::string getRecipeName(mlir::acc::RecipeKind kind, Type type, Value var,
switch (kind) {
case mlir::acc::RecipeKind::private_recipe:
prefixOS << "privatization";
// Private recipes do not currently include bounds in the name
// TODO: They should include them - but lowering tests would need to
// be updated.
break;
case mlir::acc::RecipeKind::firstprivate_recipe:
prefixOS << "firstprivatization";
// Add bounds to the prefix if applicable (only for firstprivate)
if (!bounds.empty() && areAllBoundsConstant(bounds))
prefixOS << getBoundsString(bounds);
break;
case mlir::acc::RecipeKind::reduction_recipe:
prefixOS << "reduction";
@ -253,12 +247,12 @@ std::string getRecipeName(mlir::acc::RecipeKind kind, Type type, Value var,
if (reductionOp != mlir::acc::ReductionOperator::AccNone)
prefixOS << "_"
<< mlir::acc::stringifyReductionOperator(reductionOp).str();
// Add bounds to the prefix if applicable (only for reduction)
if (!bounds.empty() && areAllBoundsConstant(bounds))
prefixOS << getBoundsString(bounds);
break;
}
if (!bounds.empty())
prefixOS << getBoundsString(bounds);
auto kindMap = var && var.getDefiningOp()
? fir::getKindMapping(var.getDefiningOp())
: fir::KindMapping(type.getContext());

View File

@ -8,8 +8,7 @@
// CHECK: acc.firstprivate.recipe @firstprivate_scalar : !fir.ref<f32> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<f32>):
// CHECK: %[[ALLOC:.*]] = fir.alloca f32
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "scalar"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<f32>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<f32>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<f32>, %[[DST:.*]]: !fir.ref<f32>):
// CHECK: %[[LOAD:.*]] = fir.load %[[SRC]] : !fir.ref<f32>
@ -31,8 +30,7 @@ func.func @test_scalar() {
// CHECK: acc.firstprivate.recipe @firstprivate_int : !fir.ref<i32> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<i32>):
// CHECK: %[[ALLOC:.*]] = fir.alloca i32
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "int"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<i32>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<i32>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<i32>, %[[DST:.*]]: !fir.ref<i32>):
// CHECK: %[[LOAD:.*]] = fir.load %[[SRC]] : !fir.ref<i32>
@ -54,8 +52,7 @@ func.func @test_int() {
// CHECK: acc.firstprivate.recipe @firstprivate_logical : !fir.ref<!fir.logical<4>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.logical<4>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.logical<4>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "logical"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.logical<4>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.logical<4>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.logical<4>>, %[[DST:.*]]: !fir.ref<!fir.logical<4>>):
// CHECK: %[[LOAD:.*]] = fir.load %[[SRC]] : !fir.ref<!fir.logical<4>>
@ -77,8 +74,7 @@ func.func @test_logical() {
// CHECK: acc.firstprivate.recipe @firstprivate_complex : !fir.ref<complex<f32>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<complex<f32>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca complex<f32>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "complex"} : (!fir.ref<complex<f32>>) -> (!fir.ref<complex<f32>>, !fir.ref<complex<f32>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<complex<f32>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<complex<f32>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<complex<f32>>, %[[DST:.*]]: !fir.ref<complex<f32>>):
// CHECK: %[[LOAD:.*]] = fir.load %[[SRC]] : !fir.ref<complex<f32>>
@ -99,11 +95,8 @@ func.func @test_complex() {
// Test 1D static array
// CHECK: acc.firstprivate.recipe @firstprivate_array_1d : !fir.ref<!fir.array<100xf32>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<100xf32>>):
// CHECK: %[[C100:.*]] = arith.constant 100 : index
// CHECK: %[[SHAPE:.*]] = fir.shape %[[C100]] : (index) -> !fir.shape<1>
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.array<100xf32>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]](%[[SHAPE]]) {uniq_name = "array_1d"} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.array<100xf32>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.array<100xf32>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<100xf32>>, %[[DST:.*]]: !fir.ref<!fir.array<100xf32>>):
// CHECK: hlfir.assign %[[SRC]] to %[[DST]] : !fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>
@ -123,12 +116,8 @@ func.func @test_array_1d() {
// Test 2D static array
// CHECK: acc.firstprivate.recipe @firstprivate_array_2d : !fir.ref<!fir.array<10x20xi32>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10x20xi32>>):
// CHECK: %[[C10:.*]] = arith.constant 10 : index
// CHECK: %[[C20:.*]] = arith.constant 20 : index
// CHECK: %[[SHAPE:.*]] = fir.shape %[[C10]], %[[C20]] : (index, index) -> !fir.shape<2>
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.array<10x20xi32>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]](%[[SHAPE]]) {uniq_name = "array_2d"} : (!fir.ref<!fir.array<10x20xi32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x20xi32>>, !fir.ref<!fir.array<10x20xi32>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.array<10x20xi32>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.array<10x20xi32>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<10x20xi32>>, %[[DST:.*]]: !fir.ref<!fir.array<10x20xi32>>):
// CHECK: hlfir.assign %[[SRC]] to %[[DST]] : !fir.ref<!fir.array<10x20xi32>>, !fir.ref<!fir.array<10x20xi32>>
@ -149,8 +138,7 @@ func.func @test_array_2d() {
// CHECK: acc.firstprivate.recipe @firstprivate_derived : !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.type<_QTpoint{x:f32,y:f32,z:f32}>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "derived"} : (!fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>) -> (!fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>, !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>, %[[DST:.*]]: !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>):
// CHECK: hlfir.assign %[[SRC]] to %[[DST]] : !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>, !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>

View File

@ -8,8 +8,7 @@
// CHECK: acc.private.recipe @private_scalar : !fir.ref<f32> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<f32>):
// CHECK: %[[ALLOC:.*]] = fir.alloca f32
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "scalar"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<f32>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<f32>
// CHECK: }
// CHECK-NOT: destroy
@ -26,8 +25,7 @@ func.func @test_scalar() {
// CHECK: acc.private.recipe @private_logical : !fir.ref<!fir.logical<4>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.logical<4>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.logical<4>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "logical"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.logical<4>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.logical<4>>
// CHECK: }
// CHECK-NOT: destroy
@ -44,8 +42,7 @@ func.func @test_logical() {
// CHECK: acc.private.recipe @private_complex : !fir.ref<complex<f32>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<complex<f32>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca complex<f32>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "complex"} : (!fir.ref<complex<f32>>) -> (!fir.ref<complex<f32>>, !fir.ref<complex<f32>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<complex<f32>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<complex<f32>>
// CHECK: }
// CHECK-NOT: destroy
@ -61,11 +58,8 @@ func.func @test_complex() {
// Test 1D static array
// CHECK: acc.private.recipe @private_array_1d : !fir.ref<!fir.array<100xf32>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<100xf32>>):
// CHECK: %[[C100:.*]] = arith.constant 100 : index
// CHECK: %[[SHAPE:.*]] = fir.shape %[[C100]] : (index) -> !fir.shape<1>
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.array<100xf32>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]](%[[SHAPE]]) {uniq_name = "array_1d"} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.array<100xf32>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.array<100xf32>>
// CHECK: }
// CHECK-NOT: destroy
@ -81,13 +75,8 @@ func.func @test_array_1d() {
// Test 3D static array
// CHECK: acc.private.recipe @private_array_3d : !fir.ref<!fir.array<5x10x15xi32>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<5x10x15xi32>>):
// CHECK: %[[C5:.*]] = arith.constant 5 : index
// CHECK: %[[C10:.*]] = arith.constant 10 : index
// CHECK: %[[C15:.*]] = arith.constant 15 : index
// CHECK: %[[SHAPE:.*]] = fir.shape %[[C5]], %[[C10]], %[[C15]] : (index, index, index) -> !fir.shape<3>
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.array<5x10x15xi32>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]](%[[SHAPE]]) {uniq_name = "array_3d"} : (!fir.ref<!fir.array<5x10x15xi32>>, !fir.shape<3>) -> (!fir.ref<!fir.array<5x10x15xi32>>, !fir.ref<!fir.array<5x10x15xi32>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.array<5x10x15xi32>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.array<5x10x15xi32>>
// CHECK: }
// CHECK-NOT: destroy
@ -104,8 +93,7 @@ func.func @test_array_3d() {
// CHECK: acc.private.recipe @private_derived : !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.type<_QTpoint{x:f32,y:f32,z:f32}>
// CHECK: %{{.*}}:2 = hlfir.declare %[[ALLOC]] {uniq_name = "derived"} : (!fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>) -> (!fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>, !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.type<_QTpoint{x:f32,y:f32,z:f32}>>
// CHECK: }
// CHECK-NOT: destroy
@ -121,12 +109,11 @@ func.func @test_derived() {
// Test box type with heap scalar (needs destroy)
// CHECK: acc.private.recipe @private_box_heap_scalar : !fir.ref<!fir.box<!fir.heap<f64>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>):
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.heap<f64>>
// CHECK: %{{.*}}:2 = hlfir.declare %[[BOXALLOC]] {uniq_name = "box_heap_scalar"} : (!fir.ref<!fir.box<!fir.heap<f64>>>) -> (!fir.ref<!fir.box<!fir.heap<f64>>>, !fir.ref<!fir.box<!fir.heap<f64>>>)
// CHECK: %[[SCALAR:.*]] = fir.allocmem f64
// CHECK: %[[EMBOX:.*]] = fir.embox %[[SCALAR]] : (!fir.heap<f64>) -> !fir.box<!fir.heap<f64>>
// CHECK: fir.store %[[EMBOX]] to %{{.*}}#0 : !fir.ref<!fir.box<!fir.heap<f64>>>
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.box<!fir.heap<f64>>>
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.heap<f64>>
// CHECK: fir.store %[[EMBOX]] to %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<f64>>>
// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<f64>>>
// CHECK: } destroy {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>):
// CHECK: acc.terminator
@ -144,12 +131,11 @@ func.func @test_box_heap_scalar() {
// Test box type with pointer scalar (needs destroy)
// CHECK: acc.private.recipe @private_box_ptr_scalar : !fir.ref<!fir.box<!fir.ptr<i32>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>):
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.ptr<i32>>
// CHECK: %{{.*}}:2 = hlfir.declare %[[BOXALLOC]] {uniq_name = "box_ptr_scalar"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
// CHECK: %[[SCALAR:.*]] = fir.allocmem i32
// CHECK: %[[EMBOX:.*]] = fir.embox %[[SCALAR]] : (!fir.heap<i32>) -> !fir.box<!fir.ptr<i32>>
// CHECK: fir.store %[[EMBOX]] to %{{.*}}#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.ptr<i32>>
// CHECK: fir.store %[[EMBOX]] to %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
// CHECK: } destroy {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>):
// CHECK: acc.terminator
@ -168,8 +154,7 @@ func.func @test_box_ptr_scalar() {
// CHECK: acc.private.recipe @private_box_heap_array_1d : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>):
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>>
// CHECK: %{{.*}}:2 = hlfir.declare %[[BOXALLOC]] {uniq_name = "box_heap_array_1d"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
// CHECK: } destroy {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>):
// CHECK: acc.terminator
@ -188,8 +173,7 @@ func.func @test_box_heap_array_1d() {
// CHECK: acc.private.recipe @private_box_heap_array_2d : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>):
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?x?xi64>>>
// CHECK: %{{.*}}:2 = hlfir.declare %[[BOXALLOC]] {uniq_name = "box_heap_array_2d"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>
// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>
// CHECK: } destroy {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>):
// CHECK: acc.terminator
@ -208,8 +192,7 @@ func.func @test_box_heap_array_2d() {
// CHECK: acc.private.recipe @private_box_ptr_array : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>>
// CHECK: %{{.*}}:2 = hlfir.declare %[[BOXALLOC]] {uniq_name = "box_ptr_array"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
// CHECK: acc.yield %{{.*}}#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
// CHECK: } destroy {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
// CHECK: acc.terminator

View File

@ -1,8 +1,11 @@
! Test lowering of firstprivate on derived type with pointer components.
! No deep copy must be done.
! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s --check-prefix=FIR-CHECK
! TODO: ensure pointer components are initialized to NULL for private.
! RUN: not bbc -fopenacc -emit-hlfir %s -o - 2>&1 | FileCheck %s
! CHECK: not yet implemented: OpenACC: privatizing derived type with pointer components
module m_firstprivate_derived_ptr_comp
type point
@ -17,66 +20,4 @@ module m_firstprivate_derived_ptr_comp
a%x(10) = 1
enddo
end
end module
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_rec__QMm_firstprivate_derived_ptr_compTpoint : !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>):
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) -> (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>)
! CHECK: acc.yield %[[VAL_2]]#0 : !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>
!
! CHECK: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, %[[VAL_1:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>):
! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_1]] temporary_lhs : !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>
! CHECK: acc.terminator
! CHECK: }
!
! CHECK-LABEL: func.func @_QMm_firstprivate_derived_ptr_compPtest(
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>> {fir.bindc_name = "a"}) {
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] arg {{[0-9]+}} {uniq_name = "_QMm_firstprivate_derived_ptr_compFtestEa"} : (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>)
! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QMm_firstprivate_derived_ptr_compFtestEi"}
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QMm_firstprivate_derived_ptr_compFtestEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_4:.*]] = fir.alloca i32 {bindc_name = "n", uniq_name = "_QMm_firstprivate_derived_ptr_compFtestEn"}
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QMm_firstprivate_derived_ptr_compFtestEn"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_6:.*]] = acc.firstprivate varPtr(%[[VAL_1]]#0 : !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) recipe(@firstprivatization_ref_rec__QMm_firstprivate_derived_ptr_compTpoint) -> !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>> {name = "a"}
! CHECK: acc.parallel combined(loop) firstprivate(%[[VAL_6]] : !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) {
! CHECK: %[[VAL_7:.*]] = fir.dummy_scope : !fir.dscope
! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]] dummy_scope %[[VAL_7]] {{.*}} {uniq_name = "_QMm_firstprivate_derived_ptr_compFtestEa"} : (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>)
! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32
! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32
! CHECK: %[[VAL_12:.*]] = acc.private varPtr(%[[VAL_3]]#0 : !fir.ref<i32>) recipe(@privatization_ref_i32) -> !fir.ref<i32> {implicit = true, name = "i"}
! CHECK: acc.loop combined(parallel) private(%[[VAL_12]] : !fir.ref<i32>) control(%[[VAL_14:.*]] : i32) = (%[[VAL_9]] : i32) to (%[[VAL_10]] : i32) step (%[[VAL_11]] : i32) {
! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QMm_firstprivate_derived_ptr_compFtestEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: fir.store %[[VAL_14]] to %[[VAL_13]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_15:.*]] = arith.constant 1.000000e+00 : f32
! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_8]]#0{"x"} {fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_16]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! CHECK: %[[VAL_18:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_17]] (%[[VAL_18]]) : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, index) -> !fir.ref<f32>
! CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_19]] : f32, !fir.ref<f32>
! CHECK: acc.yield
! CHECK: } attributes {inclusiveUpperbound = array<i1: true>, independent = [#acc.device_type<none>]}
! CHECK: acc.yield
! CHECK: }
! CHECK: return
! CHECK: }
! FIR-CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_rec__QMm_firstprivate_derived_ptr_compTpoint : !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>> init {
! FIR-CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>):
! FIR-CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>
! FIR-CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_1]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) -> !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>
! FIR-CHECK: acc.yield %[[VAL_2]] : !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>
!
! FIR-CHECK-LABEL: } copy {
! FIR-CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, %[[VAL_1:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>):
! FIR-CHECK: %[[VAL_2:.*]] = fir.field_index x, !fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>
! FIR-CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_0]], x : (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! FIR-CHECK: %[[VAL_4:.*]] = fir.field_index x, !fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>
! FIR-CHECK: %[[VAL_5:.*]] = fir.coordinate_of %[[VAL_1]], x : (!fir.ref<!fir.type<_QMm_firstprivate_derived_ptr_compTpoint{x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! FIR-CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_3]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! FIR-CHECK: fir.store %[[VAL_6]] to %[[VAL_5]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! FIR-CHECK: acc.terminator
! FIR-CHECK: }
end module

View File

@ -36,8 +36,7 @@ module m_firstprivate_derived_user_def
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_rec__QMm_firstprivate_derived_user_defTpoint : !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>):
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>) -> (!fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>, !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>)
! CHECK: acc.yield %[[VAL_2]]#0 : !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>
! CHECK: acc.yield %[[VAL_1]] : !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>
!
! CHECK: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>, %[[VAL_1:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>):
@ -77,8 +76,7 @@ module m_firstprivate_derived_user_def
! FIR-CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_rec__QMm_firstprivate_derived_user_defTpoint : !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>> init {
! FIR-CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>):
! FIR-CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>
! FIR-CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_1]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>) -> !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>
! FIR-CHECK: acc.yield %[[VAL_2]] : !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>
! FIR-CHECK: acc.yield %[[VAL_1]] : !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>
! FIR-CHECK: } copy {
! FIR-CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>, %[[VAL_1:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>>):
! FIR-CHECK: %[[VAL_2:.*]] = fir.field_index x, !fir.type<_QMm_firstprivate_derived_user_defTpoint{x:f32,y:f32,z:f32}>

View File

@ -22,8 +22,7 @@ module m_firstprivate_derived
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_rec__QMm_firstprivate_derivedTpoint : !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>):
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>) -> (!fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>, !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>)
! CHECK: acc.yield %[[VAL_2]]#0 : !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>
! CHECK: acc.yield %[[VAL_1]] : !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>
!
! CHECK: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>, %[[VAL_1:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>):
@ -63,8 +62,7 @@ module m_firstprivate_derived
! FIR-CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_rec__QMm_firstprivate_derivedTpoint : !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>> init {
! FIR-CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>):
! FIR-CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>
! FIR-CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_1]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>) -> !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>
! FIR-CHECK: acc.yield %[[VAL_2]] : !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>
! FIR-CHECK: acc.yield %[[VAL_1]] : !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>
! FIR-CHECK: } copy {
! FIR-CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>, %[[VAL_1:.*]]: !fir.ref<!fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>>):
! FIR-CHECK: %[[VAL_2:.*]] = fir.field_index x, !fir.type<_QMm_firstprivate_derivedTpoint{x:f32,y:f32,z:f32}>

View File

@ -4,10 +4,8 @@
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_10x10xf32 : !fir.ref<!fir.array<10x10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10x10xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}}, %{{.*}} : (index, index) -> !fir.shape<2>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10x10xf32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10x10xf32>>
! CHECK: acc.yield %[[ALLOCA]] : !fir.ref<!fir.array<10x10xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%arg0: !fir.ref<!fir.array<10x10xf32>>, %arg1: !fir.ref<!fir.array<10x10xf32>>):
! CHECK: acc.terminator
@ -15,9 +13,8 @@
! CHECK-LABEL: acc.private.recipe @privatization_ref_10x10xf32 : !fir.ref<!fir.array<10x10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10x10xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}}, %{{.*}} : (index, index) -> !fir.shape<2>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10x10xf32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10x10xf32>>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32>
! CHECK: acc.yield %[[ALLOCA]] : !fir.ref<!fir.array<10x10xf32>>
! CHECK: }
! CHECK-LABEL: func.func @_QPacc_parallel()

View File

@ -2,230 +2,371 @@
! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
! CHECK-LABEL: acc.private.recipe @privatization_ptr_10xf32 : !fir.ptr<!fir.array<10xf32>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.ptr<!fir.array<10xf32>>):
! CHECK: %[[C10:.*]] = arith.constant 10 : index
! CHECK: %[[SHAPE:.*]] = fir.shape %[[C10]] : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_box_UxUx2xi32 : !fir.box<!fir.array<?x?x2xi32>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[DIM0:.*]]:3 = fir.box_dims %arg0, %c0{{.*}} : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[DIM1:.*]]:3 = fir.box_dims %arg0, %c1{{.*}} : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE:.*]] = fir.shape %[[DIM0]]#1, %[[DIM1]]#1, %c2{{.*}} : (index, index, index) -> !fir.shape<3>
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?x?x2xi32>, %[[DIM0]]#1, %[[DIM1]]#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?x?x2xi32>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x2xi32>>, !fir.heap<!fir.array<?x?x2xi32>>)
! CHECK: acc.yield %[[DECL]]#0 : !fir.box<!fir.array<?x?x2xi32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: hlfir.assign %[[ARG0]] to %[[ARG1]] temporary_lhs : !fir.box<!fir.array<?x?x2xi32>>, !fir.box<!fir.array<?x?x2xi32>>
! CHECK: acc.terminator
! CHECK: } destroy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?x?x2xi32>>) -> !fir.ref<!fir.array<?x?x2xi32>>
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?x?x2xi32>>) -> !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ptr_10xf32 : !fir.ptr<!fir.array<10xf32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ptr<!fir.array<10xf32>>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.array<10xf32> {bindc_name = "acc.private.init"}
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 10 : index
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1>
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 10 : index
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.array<10xf32>>
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_lb4.ub9_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.box<!fir.array<?xi32>>):
! CHECK: } copy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: hlfir.assign {{.*}} to {{.*}} temporary_lhs : !fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: } destroy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_box_UxUx2xi32 : !fir.box<!fir.array<?x?x2xi32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_0]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 1 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_1]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 2 : index
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1, %[[BOX_DIMS_1]]#1, %[[CONSTANT_2]] : (index, index, index) -> !fir.shape<3>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1, %[[BOX_DIMS_1]]#1, %[[CONSTANT_2]] : (index, index, index) -> !fir.shape<3>
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?x?x2xi32>, %[[BOX_DIMS_0]]#1, %[[BOX_DIMS_1]]#1 {bindc_name = "acc.private.init", uniq_name = ""}
! CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_3]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_3:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_4]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 1 : index
! CHECK: %[[BOX_DIMS_4:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_5]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_6:.*]] = arith.constant 1 : index
! CHECK: %[[BOX_DIMS_5:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_6]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_7:.*]] = arith.constant 2 : index
! CHECK: %[[BOX_DIMS_6:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_7]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_8:.*]] = arith.constant 2 : index
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_2]]#0, %[[BOX_DIMS_3]]#1, %[[BOX_DIMS_4]]#0, %[[BOX_DIMS_5]]#1, %[[BOX_DIMS_6]]#0, %[[CONSTANT_8]] : (index, index, index, index, index, index) -> !fir.shapeshift<3>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?x?x2xi32>>, !fir.shapeshift<3>) -> !fir.box<!fir.array<?x?x2xi32>>
! CHECK: acc.yield %[[EMBOX_0]] : !fir.box<!fir.array<?x?x2xi32>>
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[C0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %c0 : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS]]#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
! CHECK: acc.yield %[[DECL]]#0 : !fir.box<!fir.array<?xi32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: hlfir.assign %[[ARG0]] to %[[ARG1]] temporary_lhs : !fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: } destroy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[VAL_1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_1]] temporary_lhs : !fir.box<!fir.array<?x?x2xi32>>, !fir.box<!fir.array<?x?x2xi32>>
! CHECK: acc.terminator
! CHECK-LABEL: acc.private.recipe @privatization_box_UxUx2xi32 : !fir.box<!fir.array<?x?x2xi32>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[DIM0:.*]]:3 = fir.box_dims %arg0, %c0{{.*}} : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[DIM1:.*]]:3 = fir.box_dims %arg0, %c1{{.*}} : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE:.*]] = fir.shape %[[DIM0]]#1, %[[DIM1]]#1, %c2{{.*}} : (index, index, index) -> !fir.shape<3>
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?x?x2xi32>, %[[DIM0]]#1, %[[DIM1]]#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?x?x2xi32>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x2xi32>>, !fir.heap<!fir.array<?x?x2xi32>>)
! CHECK: acc.yield %[[DECL]]#0 : !fir.box<!fir.array<?x?x2xi32>>
! CHECK: } destroy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?x?x2xi32>>) -> !fir.ref<!fir.array<?x?x2xi32>>
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?x?x2xi32>>) -> !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: } destroy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[VAL_1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?x?x2xi32>>) -> !fir.ref<!fir.array<?x?x2xi32>>
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ref<!fir.array<?x?x2xi32>>) -> !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: fir.freemem %[[CONVERT_0]] : !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_box_ptr_Uxi32 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>):
! CHECK: %[[LOADBOX:.*]] = fir.load %[[ARG0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
! CHECK: %[[C0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[LOADBOX]], %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS]]#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>>
! CHECK: %[[DECLAREBOX:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
! CHECK: %[[CONV:.*]] = fir.convert %[[DECLAREBOX]]#0 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: fir.store %[[DECLARE]]#0 to %[[CONV]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: acc.yield %[[DECLAREBOX]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
! CHECK: } destroy {
! CHECK: ^bb0(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, %arg1: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>):
! CHECK: %[[LOAD:.*]] = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> !fir.ptr<!fir.array<?xi32>>
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ptr<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_lb4.ub9_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.array<6xi32> {bindc_name = "acc.private.init"}
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 4 : index
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 9 : index
! CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 5 : index
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 6 : index
! CHECK: %[[CONSTANT_6:.*]] = arith.constant true
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_5]] : (index) -> !fir.shape<1>
! CHECK: %[[CONSTANT_7:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_7]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[ADDI_0:.*]] = arith.addi %[[BOX_DIMS_0]]#0, %[[CONSTANT_1]] : index
! CHECK: %[[ADDI_1:.*]] = arith.addi %[[BOX_DIMS_0]]#0, %[[CONSTANT_2]] : index
! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[VAL_0]] (%[[ADDI_0]]:%[[ADDI_1]]:%[[CONSTANT_0]]) shape %[[SHAPE_0]] : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<6xi32>>
! CHECK: %[[CONSTANT_8:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_8]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_9:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_9]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[ALLOCA_0]] : (!fir.ref<!fir.array<6xi32>>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[CONSTANT_10:.*]] = arith.constant 0 : index
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[CONSTANT_1]], %[[BOX_DIMS_2]]#1 : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[ARRAY_COOR_0:.*]] = fir.array_coor %[[CONVERT_0]](%[[SHAPE_SHIFT_0]]) %[[CONSTANT_10]] : (!fir.ref<!fir.array<?xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
! CHECK: %[[CONVERT_1:.*]] = fir.convert %[[ARRAY_COOR_0]] : (!fir.ref<i32>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[SHAPE_SHIFT_1:.*]] = fir.shape_shift %[[BOX_DIMS_1]]#0, %[[BOX_DIMS_2]]#1 : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[CONVERT_1]](%[[SHAPE_SHIFT_1]]) : (!fir.ref<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<?xi32>>
! CHECK: acc.yield %[[EMBOX_0]] : !fir.box<!fir.array<?xi32>>
! CHECK-LABEL: @privatization_ref_box_heap_i32 : !fir.ref<!fir.box<!fir.heap<i32>>> init {
! CHECK: ^bb0(%arg0: !fir.ref<!fir.box<!fir.heap<i32>>>):
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box<!fir.heap<i32>>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>)
! CHECK: %[[ALLOCMEM:.*]] = fir.allocmem i32
! CHECK: %[[BOX:.*]] = fir.embox %[[ALLOCMEM]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
! CHECK: fir.store %[[BOX]] to %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: } destroy {
! CHECK: ^bb0(%arg0: !fir.ref<!fir.box<!fir.heap<i32>>>, %arg1: !fir.ref<!fir.box<!fir.heap<i32>>>):
! CHECK: %[[LOAD:.*]] = fir.load %arg1 : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
! CHECK: fir.freemem %[[ADDR]] : !fir.heap<i32>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>, %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 4 : index
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 9 : index
! CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 5 : index
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 6 : index
! CHECK: %[[CONSTANT_6:.*]] = arith.constant true
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_5]] : (index) -> !fir.shape<1>
! CHECK: %[[CONSTANT_7:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[VAL_1]], %[[CONSTANT_7]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[ADDI_0:.*]] = arith.addi %[[BOX_DIMS_0]]#0, %[[CONSTANT_1]] : index
! CHECK: %[[ADDI_1:.*]] = arith.addi %[[BOX_DIMS_0]]#0, %[[CONSTANT_2]] : index
! CHECK: %[[CONSTANT_8:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_8]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[ADDI_2:.*]] = arith.addi %[[BOX_DIMS_1]]#0, %[[CONSTANT_1]] : index
! CHECK: %[[ADDI_3:.*]] = arith.addi %[[BOX_DIMS_1]]#0, %[[CONSTANT_2]] : index
! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[VAL_0]] (%[[ADDI_2]]:%[[ADDI_3]]:%[[CONSTANT_0]]) shape %[[SHAPE_0]] : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<6xi32>>
! CHECK: %[[DESIGNATE_1:.*]] = hlfir.designate %[[VAL_1]] (%[[ADDI_0]]:%[[ADDI_1]]:%[[CONSTANT_0]]) shape %[[SHAPE_0]] : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<6xi32>>
! CHECK: hlfir.assign %[[DESIGNATE_0]] to %[[DESIGNATE_1]] temporary_lhs : !fir.box<!fir.array<6xi32>>, !fir.box<!fir.array<6xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
! CHECK: %[[LOADBOX:.*]] = fir.load %[[ARG0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: %[[C0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[LOADBOX]], %[[C0]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS]]#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
! CHECK: %[[DECLAREBOX:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "acc.private.init"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
! CHECK: %[[CONV:.*]] = fir.convert %[[DECLAREBOX]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: fir.store %[[DECLARE]]#0 to %[[CONV]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: acc.yield %[[DECLAREBOX]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: } destroy {
! CHECK: ^bb0(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %arg1: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
! CHECK: %[[LOAD:.*]] = fir.load %arg1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[ADDR]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_0]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS_0]]#1 {bindc_name = "acc.private.init", uniq_name = ""}
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_1]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_2]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_1]]#0, %[[BOX_DIMS_2]]#1 : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<?xi32>>
! CHECK: acc.yield %[[EMBOX_0]] : !fir.box<!fir.array<?xi32>>
! CHECK-LABEL: acc.private.recipe @privatization_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[C0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[ARG0]], %[[C0]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?xi32>, %0#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
! CHECK: acc.yield %[[DECLARE:.*]]#0 : !fir.box<!fir.array<?xi32>>
! CHECK: } destroy {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>, %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_1]] temporary_lhs : !fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_lb50.ub99_ref_50xf32 : !fir.ref<!fir.array<50xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<50xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<50xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<50xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<50xf32>>, %[[DST:.*]]: !fir.ref<!fir.array<50xf32>>):
! CHECK: %[[C50:.*]] = arith.constant 50 : index
! CHECK: %[[C99:.*]] = arith.constant 99 : index
! CHECK: %[[C1:.*]] = arith.constant 1 : index
! CHECK: %[[C0:.*]] = arith.constant 0 : index
! CHECK: %[[D0:.*]] = arith.subi %[[C99]], %[[C50]] : index
! CHECK: %[[D1:.*]] = arith.addi %[[D0]], %[[C1]] : index
! CHECK: %[[D2:.*]] = arith.divsi %[[D1]], %[[C1]] : index
! CHECK: %[[CMP:.*]] = arith.cmpi sgt, %[[D2]], %[[C0]] : index
! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[D2]], %[[C0]] : index
! CHECK: %[[SH:.*]] = fir.shape %[[SEL]] : (index) -> !fir.shape<1>
! CHECK: %[[SEC_SRC:.*]] = hlfir.designate %[[SRC]] (%c51{{.*}}:%c100{{.*}}:%c1{{.*}}) shape %[[SH]] : (!fir.ref<!fir.array<50xf32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! CHECK: %[[SEC_DST:.*]] = hlfir.designate %[[DST]] (%c51{{.*}}:%c100{{.*}}:%c1{{.*}}) shape %[[SH]] : (!fir.ref<!fir.array<50xf32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! CHECK: hlfir.assign %[[SEC_SRC]] to %[[SEC_DST]] temporary_lhs : !fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: } destroy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>, %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[CONVERT_0]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<100xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<100xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<100xf32>>, %[[DST:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: hlfir.assign %[[SRC]] to %[[DST]] temporary_lhs : !fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_box_UxUx2xi32 : !fir.box<!fir.array<?x?x2xi32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_0]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 1 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_1]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 2 : index
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1, %[[BOX_DIMS_1]]#1, %[[CONSTANT_2]] : (index, index, index) -> !fir.shape<3>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1, %[[BOX_DIMS_1]]#1, %[[CONSTANT_2]] : (index, index, index) -> !fir.shape<3>
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?x?x2xi32>, %[[BOX_DIMS_0]]#1, %[[BOX_DIMS_1]]#1 {bindc_name = "acc.private.init", uniq_name = ""}
! CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_3]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_3:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_4]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 1 : index
! CHECK: %[[BOX_DIMS_4:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_5]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_6:.*]] = arith.constant 1 : index
! CHECK: %[[BOX_DIMS_5:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_6]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_7:.*]] = arith.constant 2 : index
! CHECK: %[[BOX_DIMS_6:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_7]] : (!fir.box<!fir.array<?x?x2xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_8:.*]] = arith.constant 2 : index
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_2]]#0, %[[BOX_DIMS_3]]#1, %[[BOX_DIMS_4]]#0, %[[BOX_DIMS_5]]#1, %[[BOX_DIMS_6]]#0, %[[CONSTANT_8]] : (index, index, index, index, index, index) -> !fir.shapeshift<3>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?x?x2xi32>>, !fir.shapeshift<3>) -> !fir.box<!fir.array<?x?x2xi32>>
! CHECK: acc.yield %[[EMBOX_0]] : !fir.box<!fir.array<?x?x2xi32>>
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_i32 : !fir.ref<i32> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<i32>):
! CHECK: %[[ALLOCA:.*]] = fir.alloca i32
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "acc.private.init"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<i32>
! CHECK: } copy {
! CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<i32>, %[[DST:.*]]: !fir.ref<i32>):
! CHECK: %[[VALUE:.*]] = fir.load %[[SRC]] : !fir.ref<i32>
! CHECK: fir.assign %[[VALUE]] to %[[DST]] temporary_lhs : i32, !fir.ref<i32>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: } destroy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[VAL_1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?x?x2xi32>>) -> !fir.ref<!fir.array<?x?x2xi32>>
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ref<!fir.array<?x?x2xi32>>) -> !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: fir.freemem %[[CONVERT_0]] : !fir.heap<!fir.array<?x?x2xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_50xf32 : !fir.ref<!fir.array<50xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<50xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<50xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<50xf32>>
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_box_ptr_Uxi32 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_0]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS_0]]#1 {bindc_name = "acc.private.init", uniq_name = ""}
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_1]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_2]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_1]]#0, %[[BOX_DIMS_2]]#1 : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
! CHECK-LABEL: acc.private.recipe @privatization_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<100xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<100xf32>>
! CHECK: }
! CHECK-LABEL: } destroy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> !fir.ptr<!fir.array<?xi32>>
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ptr<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[CONVERT_0]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_i32 : !fir.ref<i32> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<i32>):
! CHECK: %[[ALLOCA:.*]] = fir.alloca i32
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "acc.private.init"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<i32>
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_box_heap_i32 : !fir.ref<!fir.box<!fir.heap<i32>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem i32 {bindc_name = "acc.private.init", uniq_name = ""}
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.heap<i32>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK-LABEL: } destroy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<i32>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_0]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS_0]]#1 {bindc_name = "acc.private.init", uniq_name = ""}
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_1]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_2]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_1]]#0, %[[BOX_DIMS_2]]#1 : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK-LABEL: } destroy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_0]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS_0]]#1 {bindc_name = "acc.private.init", uniq_name = ""}
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_1]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[VAL_0]], %[[CONSTANT_2]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_1]]#0, %[[BOX_DIMS_2]]#1 : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<?xi32>>
! CHECK: acc.yield %[[EMBOX_0]] : !fir.box<!fir.array<?xi32>>
! CHECK-LABEL: } destroy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>, %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>):
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[CONVERT_0]] : !fir.heap<!fir.array<?xi32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_lb50.ub99_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.array<50xf32> {bindc_name = "acc.private.init"}
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 50 : index
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 99 : index
! CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 49 : index
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 50 : index
! CHECK: %[[CONSTANT_6:.*]] = arith.constant true
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_5]] : (index) -> !fir.shape<1>
! CHECK: %[[CONSTANT_7:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_8:.*]] = arith.constant 51 : index
! CHECK: %[[CONSTANT_9:.*]] = arith.constant 100 : index
! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[VAL_0]] (%[[CONSTANT_8]]:%[[CONSTANT_9]]:%[[CONSTANT_0]]) shape %[[SHAPE_0]] : (!fir.ref<!fir.array<100xf32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! CHECK: %[[CONSTANT_10:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_11:.*]] = arith.constant 100 : index
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[ALLOCA_0]] : (!fir.ref<!fir.array<50xf32>>) -> !fir.ref<!fir.array<100xf32>>
! CHECK: %[[CONSTANT_12:.*]] = arith.constant 0 : index
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[CONSTANT_1]], %[[CONSTANT_11]] : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[ARRAY_COOR_0:.*]] = fir.array_coor %[[CONVERT_0]](%[[SHAPE_SHIFT_0]]) %[[CONSTANT_12]] : (!fir.ref<!fir.array<100xf32>>, !fir.shapeshift<1>, index) -> !fir.ref<f32>
! CHECK: %[[CONVERT_1:.*]] = fir.convert %[[ARRAY_COOR_0]] : (!fir.ref<f32>) -> !fir.ref<!fir.array<100xf32>>
! CHECK: acc.yield %[[CONVERT_1]] : !fir.ref<!fir.array<100xf32>>
! CHECK-LABEL: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.array<100xf32>>, %[[VAL_1:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 50 : index
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 99 : index
! CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 49 : index
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 50 : index
! CHECK: %[[CONSTANT_6:.*]] = arith.constant true
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_5]] : (index) -> !fir.shape<1>
! CHECK: %[[CONSTANT_7:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_8:.*]] = arith.constant 51 : index
! CHECK: %[[CONSTANT_9:.*]] = arith.constant 100 : index
! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[VAL_0]] (%[[CONSTANT_8]]:%[[CONSTANT_9]]:%[[CONSTANT_0]]) shape %[[SHAPE_0]] : (!fir.ref<!fir.array<100xf32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! CHECK: %[[DESIGNATE_1:.*]] = hlfir.designate %[[VAL_1]] (%[[CONSTANT_8]]:%[[CONSTANT_9]]:%[[CONSTANT_0]]) shape %[[SHAPE_0]] : (!fir.ref<!fir.array<100xf32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! CHECK: hlfir.assign %[[DESIGNATE_0]] to %[[DESIGNATE_1]] temporary_lhs : !fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.array<100xf32> {bindc_name = "acc.private.init"}
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 100 : index
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.array<100xf32>>
! CHECK-LABEL: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.array<100xf32>>, %[[VAL_1:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_1]] temporary_lhs : !fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_i32 : !fir.ref<i32> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<i32>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca i32 {bindc_name = "acc.private.init"}
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<i32>
! CHECK-LABEL: } copy {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<i32>, %[[VAL_1:.*]]: !fir.ref<i32>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_0]] : !fir.ref<i32>
! CHECK: hlfir.assign %[[LOAD_0]] to %[[VAL_1]] temporary_lhs : i32, !fir.ref<i32>
! CHECK: acc.terminator
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_section_lb0.ub49_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.array<50xf32> {bindc_name = "acc.private.init"}
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 0 : index
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 49 : index
! CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 50 : index
! CHECK: %[[CONSTANT_5:.*]] = arith.constant true
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_4]] : (index) -> !fir.shape<1>
! CHECK: %[[CONSTANT_6:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_7:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_8:.*]] = arith.constant 50 : index
! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[VAL_0]] (%[[CONSTANT_7]]:%[[CONSTANT_8]]:%[[CONSTANT_0]]) shape %[[SHAPE_0]] : (!fir.ref<!fir.array<100xf32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! CHECK: %[[CONSTANT_9:.*]] = arith.constant 1 : index
! CHECK: %[[CONSTANT_10:.*]] = arith.constant 100 : index
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[ALLOCA_0]] : (!fir.ref<!fir.array<50xf32>>) -> !fir.ref<!fir.array<100xf32>>
! CHECK: %[[CONSTANT_11:.*]] = arith.constant 0 : index
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[CONSTANT_1]], %[[CONSTANT_10]] : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[ARRAY_COOR_0:.*]] = fir.array_coor %[[CONVERT_0]](%[[SHAPE_SHIFT_0]]) %[[CONSTANT_11]] : (!fir.ref<!fir.array<100xf32>>, !fir.shapeshift<1>, index) -> !fir.ref<f32>
! CHECK: %[[CONVERT_1:.*]] = fir.convert %[[ARRAY_COOR_0]] : (!fir.ref<f32>) -> !fir.ref<!fir.array<100xf32>>
! CHECK: acc.yield %[[CONVERT_1]] : !fir.ref<!fir.array<100xf32>>
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.array<100xf32> {bindc_name = "acc.private.init"}
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 100 : index
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.array<100xf32>>
! CHECK: }
! CHECK-LABEL: acc.private.recipe @privatization_ref_i32 : !fir.ref<i32> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<i32>):
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca i32 {bindc_name = "acc.private.init"}
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<i32>
! CHECK: }
program acc_private
integer :: i, c
@ -267,8 +408,8 @@ program acc_private
! CHECK: %[[LB:.*]] = arith.constant 0 : index
! CHECK: %[[UB:.*]] = arith.constant 49 : index
! CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%{{.*}} : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index)
! CHECK: %[[B_PRIVATE:.*]] = acc.private varPtr(%[[DECLB]]#0 : !fir.ref<!fir.array<100xf32>>) bounds(%[[BOUND]]) recipe(@privatization_ref_50xf32) -> !fir.ref<!fir.array<50xf32>> {name = "b(1:50)"}
! CHECK: acc.loop private(%[[B_PRIVATE]]{{.*}} : !fir.ref<!fir.array<50xf32>>{{.*}})
! CHECK: %[[B_PRIVATE:.*]] = acc.private varPtr(%[[DECLB]]#0 : !fir.ref<!fir.array<100xf32>>) bounds(%[[BOUND]]) recipe(@privatization_section_lb0.ub49_ref_100xf32) -> !fir.ref<!fir.array<100xf32>> {name = "b(1:50)"}
! CHECK: acc.loop private(%[[B_PRIVATE]]{{.*}} : !fir.ref<!fir.array<100xf32>>{{.*}})
!$acc parallel loop firstprivate(c)
DO i = 1, n
@ -300,8 +441,8 @@ program acc_private
! CHECK: %[[LB:.*]] = arith.constant 50 : index
! CHECK: %[[UB:.*]] = arith.constant 99 : index
! CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) extent(%{{.*}} : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index)
! CHECK: %[[FP_B:.*]] = acc.firstprivate varPtr(%[[DECLB]]#0 : !fir.ref<!fir.array<100xf32>>) bounds(%[[BOUND]]) recipe(@firstprivatization_section_lb50.ub99_ref_50xf32) -> !fir.ref<!fir.array<50xf32>> {name = "b(51:100)"}
! CHECK: acc.parallel {{.*}} firstprivate(%[[FP_B]] : !fir.ref<!fir.array<50xf32>>)
! CHECK: %[[FP_B:.*]] = acc.firstprivate varPtr(%[[DECLB]]#0 : !fir.ref<!fir.array<100xf32>>) bounds(%[[BOUND]]) recipe(@firstprivatization_section_lb50.ub99_ref_100xf32) -> !fir.ref<!fir.array<100xf32>> {name = "b(51:100)"}
! CHECK: acc.parallel {{.*}} firstprivate(%[[FP_B]] : !fir.ref<!fir.array<100xf32>>)
end program

File diff suppressed because it is too large Load Diff

View File

@ -4,18 +4,14 @@
! CHECK-LABEL: acc.private.recipe @privatization_ref_10xf32 : !fir.ref<!fir.array<10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK: acc.yield %[[ALLOCA]] : !fir.ref<!fir.array<10xf32>>
! CHECK: }
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_10xf32 : !fir.ref<!fir.array<10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK: acc.yield %[[ALLOCA]] : !fir.ref<!fir.array<10xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%arg0: !fir.ref<!fir.array<10xf32>>, %arg1: !fir.ref<!fir.array<10xf32>>):
! CHECK: acc.terminator

View File

@ -4,10 +4,8 @@
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_10x10xf32 : !fir.ref<!fir.array<10x10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10x10xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}}, %{{.*}} : (index, index) -> !fir.shape<2>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10x10xf32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10x10xf32>>
! CHECK: acc.yield %[[ALLOCA]] : !fir.ref<!fir.array<10x10xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%arg0: !fir.ref<!fir.array<10x10xf32>>, %arg1: !fir.ref<!fir.array<10x10xf32>>):
! CHECK: acc.terminator
@ -15,9 +13,8 @@
! CHECK-LABEL: acc.private.recipe @privatization_ref_10x10xf32 : !fir.ref<!fir.array<10x10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10x10xf32>>):
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}}, %{{.*}} : (index, index) -> !fir.shape<2>
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10x10xf32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>)
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10x10xf32>>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10x10xf32>
! CHECK: acc.yield %[[ALLOCA]] : !fir.ref<!fir.array<10x10xf32>>
! CHECK: }
! CHECK-LABEL: func.func @_QPacc_serial()

View File

@ -8,8 +8,7 @@
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_i32 : !fir.ref<i32> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<i32>):
// CHECK: %[[ALLOC:.*]] = fir.alloca i32
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<i32>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<i32>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<i32>, %[[DST:.*]]: !fir.ref<i32>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<i32>
@ -35,8 +34,7 @@ func.func @test_i32_scalar_in_parallel() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_i64 : !fir.ref<i64> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<i64>):
// CHECK: %[[ALLOC:.*]] = fir.alloca i64
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<i64>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<i64>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<i64>, %[[DST:.*]]: !fir.ref<i64>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<i64>
@ -62,8 +60,7 @@ func.func @test_i64_scalar_in_parallel() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_f32 : !fir.ref<f32> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<f32>):
// CHECK: %[[ALLOC:.*]] = fir.alloca f32
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<f32>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<f32>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<f32>, %[[DST:.*]]: !fir.ref<f32>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<f32>
@ -89,8 +86,7 @@ func.func @test_f32_scalar_in_parallel() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_f64 : !fir.ref<f64> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<f64>):
// CHECK: %[[ALLOC:.*]] = fir.alloca f64
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<f64>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<f64>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<f64>, %[[DST:.*]]: !fir.ref<f64>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<f64>
@ -116,8 +112,7 @@ func.func @test_f64_scalar_in_parallel() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_l32 : !fir.ref<!fir.logical<4>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.logical<4>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca !fir.logical<4>
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<!fir.logical<4>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<!fir.logical<4>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.logical<4>>, %[[DST:.*]]: !fir.ref<!fir.logical<4>>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<!fir.logical<4>>
@ -143,8 +138,7 @@ func.func @test_logical_scalar_in_parallel() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_z32 : !fir.ref<complex<f32>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<complex<f32>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca complex<f32>
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<complex<f32>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<complex<f32>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<complex<f32>>, %[[DST:.*]]: !fir.ref<complex<f32>>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<complex<f32>>
@ -170,8 +164,7 @@ func.func @test_complex_scalar_in_parallel() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_z64 : !fir.ref<complex<f64>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<complex<f64>>):
// CHECK: %[[ALLOC:.*]] = fir.alloca complex<f64>
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<complex<f64>>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<complex<f64>>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<complex<f64>>, %[[DST:.*]]: !fir.ref<complex<f64>>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<complex<f64>>
@ -233,8 +226,7 @@ func.func @test_f64_scalar_in_serial() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_i8 : !fir.ref<i8> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<i8>):
// CHECK: %[[ALLOC:.*]] = fir.alloca i8
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<i8>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<i8>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<i8>, %[[DST:.*]]: !fir.ref<i8>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<i8>
@ -260,8 +252,7 @@ func.func @test_i8_scalar_in_parallel() {
// CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_i16 : !fir.ref<i16> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<i16>):
// CHECK: %[[ALLOC:.*]] = fir.alloca i16
// CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]]
// CHECK: acc.yield %[[DECL]]#0 : !fir.ref<i16>
// CHECK: acc.yield %[[ALLOC]] : !fir.ref<i16>
// CHECK: } copy {
// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<i16>, %[[DST:.*]]: !fir.ref<i16>):
// CHECK: %[[LOADED:.*]] = fir.load %[[SRC]] : !fir.ref<i16>

View File

@ -342,7 +342,7 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
return ::mlir::acc::VariableTypeCategory::uncategorized;
}]
>,
InterfaceMethod<
InterfaceMethod<
/*description=*/[{
Generates the operations that would be normally placed in a recipe's
init region. It inserts at the builder's current location.
@ -381,6 +381,38 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
return {};
}]
>,
InterfaceMethod<
/*description=*/[{
}],
/*retTy=*/"bool",
/*methodName=*/"generateCopy",
/*args=*/(ins "::mlir::OpBuilder &":$builder,
"::mlir::Location":$loc,
"::mlir::TypedValue<::mlir::acc::MappableType>":$from,
"::mlir::TypedValue<::mlir::acc::MappableType>":$to,
"::mlir::ValueRange":$bounds),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return false;
}]
>,
InterfaceMethod<
/*description=*/[{
}],
/*retTy=*/"bool",
/*methodName=*/"generateCombiner",
/*args=*/(ins "::mlir::OpBuilder &":$builder,
"::mlir::Location":$loc,
"::mlir::TypedValue<::mlir::acc::MappableType>":$dest,
"::mlir::TypedValue<::mlir::acc::MappableType>":$source,
"::mlir::ValueRange":$bounds,
"::mlir::acc::ReductionOperator":$op,
"::mlir::Attribute":$fastmathFlags),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return false;
}]
>,
InterfaceMethod<
/*description=*/[{
Generates destruction operations for a privatized value previously
@ -393,6 +425,9 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
cleanup required for the given type. If no destruction is required,
this function should be a no-op and return `true`.
The `bounds` must be passed when only a section of the variable was
privatized.
Returns true if destruction was successfully generated or deemed not
necessary, false otherwise.
}],
@ -400,7 +435,8 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
/*methodName=*/"generatePrivateDestroy",
/*args=*/(ins "::mlir::OpBuilder &":$builder,
"::mlir::Location":$loc,
"::mlir::Value":$privatized),
"::mlir::Value":$privatized,
"::mlir::ValueRange":$extents),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return true;

View File

@ -1438,7 +1438,7 @@ static LogicalResult createDestroyRegion(OpBuilder &builder, Location loc,
cast<TypedValue<PointerLikeType>>(destroyBlock->getArgument(1));
if (isa<MappableType>(varType)) {
auto mappableTy = cast<MappableType>(varType);
if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree))
if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds))
return failure();
} else {
assert(isa<PointerLikeType>(varType) && "Expected PointerLikeType");