MLIR 24.0.0git
ACCEmitRemarksData.cpp
Go to the documentation of this file.
1//===- ACCEmitRemarksData.cpp - Emit OpenACC data-mapping remarks ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass emits optimization remarks describing OpenACC data-mapping clauses
10// associated with structured and unstructured data constructs.
11//
12//===----------------------------------------------------------------------===//
13
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/TypeSwitch.h"
20
21namespace mlir {
22namespace acc {
23#define GEN_PASS_DEF_ACCEMITREMARKSDATA
24#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
25} // namespace acc
26} // namespace mlir
27
28#define DEBUG_TYPE "acc-emit-remarks-data"
29
30using namespace mlir;
31
32namespace {
33
34static bool isStructuredDeclareEnter(acc::DeclareEnterOp op) {
35 return !op.getToken().getUsers().empty();
36}
37
38static StringRef getDataClauseRemarkPrefix(Operation *dataClauseOp) {
39 std::optional<acc::DataClause> clause = acc::getDataClause(dataClauseOp);
40 if (!clause)
41 return {};
42
43 switch (*clause) {
44 case acc::DataClause::acc_copyin:
45 return "copyin(";
46 case acc::DataClause::acc_copyin_readonly:
47 return "copyin(readonly:";
48 case acc::DataClause::acc_copy:
49 return "copy(";
50 case acc::DataClause::acc_copyout:
51 return "copyout(";
52 case acc::DataClause::acc_copyout_zero:
53 return "copyout(zero:";
54 case acc::DataClause::acc_present:
55 return "present(";
56 case acc::DataClause::acc_create:
57 return "create(";
58 case acc::DataClause::acc_create_zero:
59 return "create(zero:";
60 case acc::DataClause::acc_delete:
61 return "delete(";
62 case acc::DataClause::acc_attach:
63 return "attach(";
64 case acc::DataClause::acc_detach:
65 return "detach(";
66 case acc::DataClause::acc_no_create:
67 return "no_create(";
68 case acc::DataClause::acc_private:
69 return "private(";
70 case acc::DataClause::acc_firstprivate:
71 return "firstprivate(";
72 case acc::DataClause::acc_deviceptr:
73 return "deviceptr(";
74 case acc::DataClause::acc_update_host:
75 return "update_host(";
76 case acc::DataClause::acc_update_self:
77 return "update_self(";
78 case acc::DataClause::acc_update_device:
79 return "update_device(";
80 case acc::DataClause::acc_use_device:
81 return "use_device(";
82 case acc::DataClause::acc_reduction:
83 return isa<acc::CopyinOp>(dataClauseOp) ? "copy(" : "reduction(";
84 case acc::DataClause::acc_declare_device_resident:
85 return "device_resident(";
86 case acc::DataClause::acc_declare_link:
87 return "link(";
88 case acc::DataClause::acc_cache:
89 return "cache(";
90 case acc::DataClause::acc_cache_readonly:
91 return "cache(readonly:";
92 case acc::DataClause::acc_getdeviceptr:
93 return "";
94 }
95 llvm_unreachable("Unhandled data clause");
96}
97
98static bool shouldReport(Operation *op, acc::OpenACCSupport &accSupport,
99 std::string &varName) {
100 if (!isa_and_nonnull<ACC_DATA_CLAUSE_OPS>(op))
101 return false;
102 if (getDataClauseRemarkPrefix(op).empty())
103 return false;
104 if (op->getNumResults() == 0)
105 return false;
106 varName = accSupport.getVariableName(op->getResult(0));
107 // Not useful to report if the variable name is empty.
108 return !varName.empty();
109}
110
111static bool reportOnSameLine(Operation *lhs, Operation *rhs) {
114}
115
116static bool reportIfNotPresent(Operation *op) {
117 switch (acc::getDataClause(op).value()) {
118 case acc::DataClause::acc_copyin:
119 case acc::DataClause::acc_copyin_readonly:
120 case acc::DataClause::acc_copyout:
121 case acc::DataClause::acc_copyout_zero:
122 case acc::DataClause::acc_copy:
123 case acc::DataClause::acc_create:
124 case acc::DataClause::acc_create_zero:
125 case acc::DataClause::acc_no_create:
126 return true;
127 case acc::DataClause::acc_present:
128 case acc::DataClause::acc_delete:
129 case acc::DataClause::acc_attach:
130 case acc::DataClause::acc_detach:
131 case acc::DataClause::acc_private:
132 case acc::DataClause::acc_firstprivate:
133 case acc::DataClause::acc_deviceptr:
134 case acc::DataClause::acc_getdeviceptr:
135 case acc::DataClause::acc_update_host:
136 case acc::DataClause::acc_update_self:
137 case acc::DataClause::acc_update_device:
138 case acc::DataClause::acc_use_device:
139 case acc::DataClause::acc_declare_device_resident:
140 case acc::DataClause::acc_declare_link:
141 case acc::DataClause::acc_cache:
142 case acc::DataClause::acc_cache_readonly:
143 return false;
144 case acc::DataClause::acc_reduction:
145 return isa<acc::CopyinOp>(op);
146 }
147 llvm_unreachable("Unhandled data clause");
148}
149
150static void emitDataMappingRemarks(ValueRange mappingOperands,
151 StringRef directivePrefix,
152 acc::OpenACCSupport &accSupport) {
153 if (mappingOperands.empty())
154 return;
155
156 // Collect reportable ops with their variable names once so sorting and
157 // remark formatting do not recompute them.
158 struct MappingInfo {
159 Operation *op;
160 std::string varName;
161 };
163 mappingOps.reserve(mappingOperands.size());
164 for (Value operand : mappingOperands) {
165 Operation *defOp = operand.getDefiningOp();
166 std::string varName;
167 if (!shouldReport(defOp, accSupport, varName))
168 continue;
169 mappingOps.push_back({defOp, std::move(varName)});
170 }
171 if (mappingOps.empty())
172 return;
173
174 llvm::sort(mappingOps, [](const MappingInfo &lhs, const MappingInfo &rhs) {
175 acc::DataClause lhsClause = acc::getDataClause(lhs.op).value();
176 acc::DataClause rhsClause = acc::getDataClause(rhs.op).value();
177 if (lhsClause == rhsClause) {
178 bool lhsImplicit = acc::getImplicitFlag(lhs.op);
179 bool rhsImplicit = acc::getImplicitFlag(rhs.op);
180 if (lhsImplicit == rhsImplicit)
181 return lhs.varName < rhs.varName;
182 return lhsImplicit < rhsImplicit;
183 }
184 return lhsClause < rhsClause;
185 });
186
187 for (auto *it = mappingOps.begin(); it != mappingOps.end(); ++it) {
188 Operation *op = it->op;
189
190 SmallVector<MappingInfo *, 4> groupedOps = {it};
191 while (std::next(it) != mappingOps.end() &&
192 reportOnSameLine(op, std::next(it)->op)) {
193 ++it;
194 groupedOps.push_back(it);
195 }
196
197 // Anchor the remark on the data-clause op so its source location is used.
198 accSupport.emitRemark(
199 op,
200 [&]() {
201 std::string message = "Generating ";
202 message += directivePrefix.str();
204 message += "default ";
205 else if (acc::getImplicitFlag(op))
206 message += "implicit ";
207 message += getDataClauseRemarkPrefix(op).str();
208 message += groupedOps.front()->varName;
209 for (MappingInfo *grouped : llvm::drop_begin(groupedOps)) {
210 message += ", ";
211 message += grouped->varName;
212 }
213 message += ")";
214 if (reportIfNotPresent(op))
215 message += " [if not already present]";
216 return message;
217 },
218 DEBUG_TYPE);
219 }
220}
221
222class ACCEmitRemarksData
223 : public acc::impl::ACCEmitRemarksDataBase<ACCEmitRemarksData> {
224public:
225 using ACCEmitRemarksDataBase<ACCEmitRemarksData>::ACCEmitRemarksDataBase;
226
227 void runOnOperation() override {
228 func::FuncOp func = getOperation();
229
230 auto cachedAnalysis = getCachedParentAnalysis<acc::OpenACCSupport>();
231 acc::OpenACCSupport &accSupport = cachedAnalysis
232 ? cachedAnalysis->get()
233 : getAnalysis<acc::OpenACCSupport>();
234
235 // Remark emission policy:
236 // - update / enter (structured or unstructured): report
237 // - exit: only unstructured (structured exit was covered at enter)
238 // - declare: only structured declare enter; unstructured declare
239 // registration does not emit mapping remarks.
240 func.walk([&](Operation *op) {
242 .Case<acc::DataOp, acc::KernelEnvironmentOp>([&](auto dataOp) {
243 emitDataMappingRemarks(dataOp.getDataClauseOperands(), "",
244 accSupport);
245 })
246 .Case<acc::EnterDataOp>([&](acc::EnterDataOp enterOp) {
247 emitDataMappingRemarks(enterOp.getDataClauseOperands(),
248 "enter data ", accSupport);
249 })
250 .Case<acc::ExitDataOp>([&](acc::ExitDataOp exitOp) {
251 emitDataMappingRemarks(exitOp.getDataClauseOperands(), "exit data ",
252 accSupport);
253 })
254 .Case<acc::UpdateOp>([&](acc::UpdateOp updateOp) {
255 emitDataMappingRemarks(updateOp.getDataClauseOperands(), "",
256 accSupport);
257 })
258 .Case<acc::DeclareEnterOp>([&](acc::DeclareEnterOp declareEnterOp) {
259 if (isStructuredDeclareEnter(declareEnterOp))
260 emitDataMappingRemarks(declareEnterOp.getDataClauseOperands(), "",
261 accSupport);
262 });
263 });
264 }
265};
266
267} // namespace
lhs
#define DEBUG_TYPE
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
Definition Operation.h:559
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
remark::detail::InFlightRemark emitRemark(Operation *op, std::function< std::string()> messageFn, llvm::StringRef category="openacc")
Emit an OpenACC remark with lazy message generation.
std::string getVariableName(Value v)
Get the variable name for a given value.
static constexpr StringLiteral getFromDefaultClauseAttrName()
Definition OpenACC.h:205
std::optional< mlir::acc::DataClause > getDataClause(mlir::Operation *accDataEntryOp)
Used to obtain the dataClause from a data entry operation.
Definition OpenACC.cpp:5334
bool getImplicitFlag(mlir::Operation *accDataEntryOp)
Used to find out whether data operation is implicit.
Definition OpenACC.cpp:5344
Include the generated interface declarations.
llvm::TypeSwitch< T, ResultT > TypeSwitch
Definition LLVM.h:139