23#include "llvm/ADT/StringExtras.h"
24#include "llvm/Support/Debug.h"
28#define GEN_PASS_DEF_ACCEMITREMARKSLOOP
29#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
33#define DEBUG_TYPE "acc-emit-remarks-loop"
40computeRegionInSpecializedAccRoutine(acc::ComputeRegionOp computeRegion) {
41 if (
auto func = computeRegion->getParentOfType<FunctionOpInterface>())
46static bool shouldEmitLoopRemarks(acc::ComputeRegionOp computeRegion) {
47 StringRef origin = computeRegion.getOrigin();
48 if (origin == acc::KernelsOp::getOperationName() ||
49 origin == acc::ParallelOp::getOperationName() ||
50 origin == acc::SerialOp::getOperationName())
53 return computeRegionInSpecializedAccRoutine(computeRegion);
56static std::string getACCParLevelName(acc::GPUParallelDimAttr parDim,
58 acc::ComputeRegionOp computeRegion) {
60 if (policy.
isSeq(parDim))
61 accName =
"sequential";
66 else if (policy.
isGang(parDim))
71 if (!policy.
isSeq(parDim) &&
72 !computeRegionInSpecializedAccRoutine(computeRegion)) {
73 if (std::optional<uint64_t> constant =
74 computeRegion.getKnownConstantLaunchArg(parDim))
75 accName +=
"(" + std::to_string(*constant) +
")";
80static std::string getGPUParDimName(acc::GPUParallelDimAttr parDim,
81 llvm::StringRef separator) {
82 auto formatDim = [&](llvm::StringRef prefix,
char axis) {
83 return (prefix + separator).str() + axis;
86 if (parDim.isThreadX())
87 return formatDim(
"threadidx",
'x');
88 if (parDim.isThreadY())
89 return formatDim(
"threadidx",
'y');
90 if (parDim.isThreadZ())
91 return formatDim(
"threadidx",
'z');
92 if (parDim.isBlockX())
93 return formatDim(
"blockidx",
'x');
94 if (parDim.isBlockY())
95 return formatDim(
"blockidx",
'y');
96 if (parDim.isBlockZ())
97 return formatDim(
"blockidx",
'z');
101static void emitLoopMappingRemark(acc::ComputeRegionOp computeRegion,
102 LoopLikeOpInterface loopOp,
105 llvm::StringRef gpuDimSeparator) {
106 acc::GPUParallelDimsAttr parDimsAttr =
107 loopOp->getDiscardableAttrOfType<acc::GPUParallelDimsAttr>(
108 acc::GPUParallelDimsAttr::name);
113 parDims = parDimsAttr.getArray();
114 }
else if (isa<scf::ForOp>(loopOp.getOperation())) {
115 seqParDims.push_back(acc::GPUParallelDimAttr::seqDim(loopOp->getContext()));
116 parDims = seqParDims;
127 for (acc::GPUParallelDimAttr parDim : parDims) {
128 accMsgs.push_back(getACCParLevelName(parDim, policy, computeRegion));
129 if (std::string gpuName = getGPUParDimName(parDim, gpuDimSeparator);
131 gpuMsgs.push_back(std::move(gpuName));
134 std::string msg =
"!$acc loop " + llvm::join(accMsgs,
", ");
138 msg +=
" collapse(" + std::to_string(collapseCount) +
")";
140 if (!gpuMsgs.empty())
141 msg +=
" ! " + llvm::join(gpuMsgs,
" ");
148emitUnstructuredIndependentLoopRemark(
Operation *op,
151 "Loop is not parallelized: complex control "
152 "flow prevents parallelization",
156class ACCEmitRemarksLoop
159 using ACCEmitRemarksLoopBase<ACCEmitRemarksLoop>::ACCEmitRemarksLoopBase;
161 void runOnOperation()
override {
162 func::FuncOp
func = getOperation();
165 if (gpuDimSeparator.empty())
166 gpuDimSeparator =
".";
168 func.walk([&](acc::ComputeRegionOp computeRegion) {
169 if (!shouldEmitLoopRemarks(computeRegion))
172 computeRegion.getRegion().walk([&](
Operation *op) {
173 if (
auto loopOp = dyn_cast<LoopLikeOpInterface>(op))
174 emitLoopMappingRemark(computeRegion, loopOp, accSupport, policy,
177 emitUnstructuredIndependentLoopRemark(op, accSupport);
Operation is the basic unit of execution within MLIR.
bool hasAttr(StringAttr name)
Return true if the operation has an attribute with the provided name, false otherwise.
virtual bool isWorker(ParDimAttrT attr) const =0
Check if the attribute represents worker parallelism.
virtual bool isSeq(ParDimAttrT attr) const =0
Check if the attribute represents sequential execution.
virtual bool isVector(ParDimAttrT attr) const =0
Check if the attribute represents vector parallelism.
virtual bool isGang(ParDimAttrT attr) const =0
Check if the attribute represents gang parallelism (any gang dimension).
Default policy that provides the standard GPU mapping: gang(dim:1) -> BlockX (gridDim....
remark::detail::InFlightRemark emitRemark(Operation *op, std::function< std::string()> messageFn, llvm::StringRef category="openacc")
Emit an OpenACC remark with lazy message generation.
uint64_t getCollapseCount(Operation *op)
Number of original loops collapsed into op, or 1 when op carries no collapse_count attribute.
bool isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
static constexpr StringLiteral getUnstructuredIndependentLoopAttrName()
Name for a unit attribute attached to the region an unstructured independent loop was converted to,...
ACCParMappingPolicy< mlir::acc::GPUParallelDimAttr > ACCToGPUMappingPolicy
Type alias for the GPU-specific mapping policy.
Include the generated interface declarations.