See https://discourse.llvm.org/t/psa-opty-create-now-with-100-more-tab-complete/87339. I plan to mark these as deprecated in https://github.com/llvm/llvm-project/pull/164649.
159 lines
6.5 KiB
C++
159 lines
6.5 KiB
C++
//===-- lib/Utisl/OpenMP.cpp ------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "flang/Utils/OpenMP.h"
|
|
|
|
#include "flang/Lower/ConvertExprToHLFIR.h"
|
|
#include "flang/Optimizer/Builder/DirectivesCommon.h"
|
|
#include "flang/Optimizer/Builder/FIRBuilder.h"
|
|
#include "flang/Optimizer/Dialect/FIROps.h"
|
|
#include "flang/Optimizer/Dialect/FIRType.h"
|
|
|
|
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
|
|
#include "mlir/Transforms/RegionUtils.h"
|
|
|
|
namespace Fortran::utils::openmp {
|
|
mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
|
|
mlir::Location loc, mlir::Value baseAddr, mlir::Value varPtrPtr,
|
|
llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,
|
|
llvm::ArrayRef<mlir::Value> members, mlir::ArrayAttr membersIndex,
|
|
mlir::omp::ClauseMapFlags mapType,
|
|
mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,
|
|
bool partialMap, mlir::FlatSymbolRefAttr mapperId) {
|
|
|
|
if (auto boxTy = llvm::dyn_cast<fir::BaseBoxType>(baseAddr.getType())) {
|
|
baseAddr = fir::BoxAddrOp::create(builder, loc, baseAddr);
|
|
retTy = baseAddr.getType();
|
|
}
|
|
|
|
mlir::TypeAttr varType = mlir::TypeAttr::get(
|
|
llvm::cast<mlir::omp::PointerLikeType>(retTy).getElementType());
|
|
|
|
// For types with unknown extents such as <2x?xi32> we discard the incomplete
|
|
// type info and only retain the base type. The correct dimensions are later
|
|
// recovered through the bounds info.
|
|
if (auto seqType = llvm::dyn_cast<fir::SequenceType>(varType.getValue()))
|
|
if (seqType.hasDynamicExtents())
|
|
varType = mlir::TypeAttr::get(seqType.getEleTy());
|
|
|
|
mlir::omp::MapInfoOp op =
|
|
mlir::omp::MapInfoOp::create(builder, loc, retTy, baseAddr, varType,
|
|
builder.getAttr<mlir::omp::ClauseMapFlagsAttr>(mapType),
|
|
builder.getAttr<mlir::omp::VariableCaptureKindAttr>(mapCaptureType),
|
|
varPtrPtr, members, membersIndex, bounds, mapperId,
|
|
builder.getStringAttr(name), builder.getBoolAttr(partialMap));
|
|
return op;
|
|
}
|
|
|
|
mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
|
|
mlir::omp::TargetOp targetOp, mlir::Value val, llvm::StringRef name) {
|
|
mlir::OpBuilder::InsertionGuard guard(firOpBuilder);
|
|
mlir::Operation *valOp = val.getDefiningOp();
|
|
|
|
if (valOp)
|
|
firOpBuilder.setInsertionPointAfter(valOp);
|
|
else
|
|
// This means val is a block argument
|
|
firOpBuilder.setInsertionPoint(targetOp);
|
|
|
|
auto copyVal = firOpBuilder.createTemporary(val.getLoc(), val.getType());
|
|
firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);
|
|
|
|
fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr(
|
|
firOpBuilder, val, /*isOptional=*/false, val.getLoc());
|
|
llvm::SmallVector<mlir::Value> bounds =
|
|
fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
|
|
mlir::omp::MapBoundsType>(firOpBuilder, info,
|
|
hlfir::translateToExtendedValue(
|
|
val.getLoc(), firOpBuilder, hlfir::Entity{val})
|
|
.first,
|
|
/*dataExvIsAssumedSize=*/false, val.getLoc());
|
|
|
|
firOpBuilder.setInsertionPoint(targetOp);
|
|
|
|
mlir::omp::ClauseMapFlags mapFlag = mlir::omp::ClauseMapFlags::implicit;
|
|
mlir::omp::VariableCaptureKind captureKind =
|
|
mlir::omp::VariableCaptureKind::ByRef;
|
|
|
|
mlir::Type eleType = copyVal.getType();
|
|
if (auto refType = mlir::dyn_cast<fir::ReferenceType>(copyVal.getType())) {
|
|
eleType = refType.getElementType();
|
|
}
|
|
|
|
if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
|
|
captureKind = mlir::omp::VariableCaptureKind::ByCopy;
|
|
} else if (!fir::isa_builtin_cptr_type(eleType)) {
|
|
mapFlag |= mlir::omp::ClauseMapFlags::to;
|
|
}
|
|
|
|
mlir::Value mapOp = createMapInfoOp(firOpBuilder, copyVal.getLoc(), copyVal,
|
|
/*varPtrPtr=*/mlir::Value{}, name.str(), bounds,
|
|
/*members=*/llvm::SmallVector<mlir::Value>{},
|
|
/*membersIndex=*/mlir::ArrayAttr{}, mapFlag, captureKind,
|
|
copyVal.getType());
|
|
|
|
auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
|
|
mlir::Region ®ion = targetOp.getRegion();
|
|
|
|
// Get the index of the first non-map argument before modifying mapVars,
|
|
// then append an element to mapVars and an associated entry block
|
|
// argument at that index.
|
|
unsigned insertIndex =
|
|
argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs();
|
|
targetOp.getMapVarsMutable().append(mapOp);
|
|
mlir::Value clonedValArg =
|
|
region.insertArgument(insertIndex, copyVal.getType(), copyVal.getLoc());
|
|
|
|
mlir::Block *entryBlock = ®ion.getBlocks().front();
|
|
firOpBuilder.setInsertionPointToStart(entryBlock);
|
|
auto loadOp =
|
|
fir::LoadOp::create(firOpBuilder, clonedValArg.getLoc(), clonedValArg);
|
|
return loadOp.getResult();
|
|
}
|
|
|
|
void cloneOrMapRegionOutsiders(
|
|
fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp) {
|
|
mlir::Region ®ion = targetOp.getRegion();
|
|
mlir::Block *entryBlock = ®ion.getBlocks().front();
|
|
|
|
llvm::SetVector<mlir::Value> valuesDefinedAbove;
|
|
mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
|
|
while (!valuesDefinedAbove.empty()) {
|
|
for (mlir::Value val : valuesDefinedAbove) {
|
|
mlir::Operation *valOp = val.getDefiningOp();
|
|
|
|
// NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the
|
|
// indices separately, as the alternative is to eventually map the Box,
|
|
// which comes with a fairly large overhead comparatively. We could be
|
|
// more robust about this and check using a BackwardsSlice to see if we
|
|
// run the risk of mapping a box.
|
|
if (valOp && mlir::isMemoryEffectFree(valOp) &&
|
|
!mlir::isa<fir::BoxDimsOp>(valOp)) {
|
|
mlir::Operation *clonedOp = valOp->clone();
|
|
entryBlock->push_front(clonedOp);
|
|
|
|
auto replace = [entryBlock](mlir::OpOperand &use) {
|
|
return use.getOwner()->getBlock() == entryBlock;
|
|
};
|
|
|
|
valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), replace);
|
|
valOp->replaceUsesWithIf(clonedOp, replace);
|
|
} else {
|
|
mlir::Value mappedTemp = mapTemporaryValue(firOpBuilder, targetOp, val,
|
|
/*name=*/{});
|
|
val.replaceUsesWithIf(mappedTemp, [entryBlock](mlir::OpOperand &use) {
|
|
return use.getOwner()->getBlock() == entryBlock;
|
|
});
|
|
}
|
|
}
|
|
valuesDefinedAbove.clear();
|
|
mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
|
|
}
|
|
}
|
|
} // namespace Fortran::utils::openmp
|