blob: 84fa6703263f25b4649998fa6245102e6638e14e [file] [edit]
//===- StackToShared.cpp -------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file implements various OpenMP dialect utilities.
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/OpenMP/Utils/Utils.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
using namespace mlir;
static bool allocaUseRequiresSharedMem(const OpOperand &use) {
Operation *owner = use.getOwner();
if (auto parallelOp = dyn_cast<omp::ParallelOp>(owner)) {
if (llvm::is_contained(parallelOp.getReductionVars(), use.get()))
return true;
} else if (auto callOp = dyn_cast<CallOpInterface>(owner)) {
if (llvm::is_contained(callOp.getArgOperands(), use.get()))
return true;
}
// If it is used directly inside of a parallel region, it has to be replaced
// unless the use is a private clause.
if (owner->getParentOfType<omp::ParallelOp>()) {
if (auto argIface = dyn_cast<omp::BlockArgOpenMPOpInterface>(owner)) {
OperandRange privateVars = argIface.getPrivateVars();
auto it = llvm::find(privateVars, use.get());
if (it != privateVars.end()) {
auto privateSyms = owner->getAttrOfType<ArrayAttr>("private_syms");
size_t idx = std::distance(privateVars.begin(), it);
auto privateOp =
SymbolTable::lookupNearestSymbolFrom<omp::PrivateClauseOp>(
owner, cast<SymbolRefAttr>(privateSyms[idx]));
return privateOp.getDataSharingType() !=
omp::DataSharingClauseType::Private;
}
}
return true;
}
return false;
}
bool mlir::omp::allocaUsesRequireSharedMem(Value alloc) {
for (const OpOperand &use : alloc.getUses()) {
Operation *owner = use.getOwner();
if (isa<LLVM::AddrSpaceCastOp, LLVM::GEPOp>(owner)) {
if (llvm::any_of(owner->getResults(), [&](Value result) {
return allocaUsesRequireSharedMem(result);
}))
return true;
} else if (allocaUseRequiresSharedMem(use)) {
return true;
}
}
return false;
}
bool mlir::omp::opInSharedDeviceContext(Operation &op) {
if (isa<omp::ParallelOp>(op))
return false;
auto offloadIface = op.getParentOfType<omp::OffloadModuleInterface>();
if (!offloadIface || !offloadIface.getIsTargetDevice())
return false;
auto targetOp = op.getParentOfType<omp::TargetOp>();
// It must be inside of a generic omp.target or in a target device function,
// and not inside of omp.parallel.
if (auto parallelOp = op.getParentOfType<omp::ParallelOp>()) {
if (!targetOp || targetOp->isProperAncestor(parallelOp))
return false;
}
// The omp.target operation itself is considered in a shared device context in
// order to properly process its own allocation-defining entry block
// arguments.
if (!targetOp)
targetOp = dyn_cast<omp::TargetOp>(op);
if (targetOp) {
if (targetOp.getKernelType() != omp::TargetExecMode::generic)
return false;
} else {
auto declTargetIface = op.getParentOfType<omp::DeclareTargetInterface>();
if (!declTargetIface || !declTargetIface.isDeclareTarget() ||
declTargetIface.getDeclareTargetDeviceType() ==
omp::DeclareTargetDeviceType::host)
return false;
}
return true;
}