| //===- 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; |
| } |