MLIR 24.0.0git
LoopAnnotationImporter.cpp
Go to the documentation of this file.
1//===- LoopAnnotationImporter.cpp - Loop annotation import ----------------===//
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
10#include "llvm/IR/Constants.h"
11
12using namespace mlir;
13using namespace mlir::LLVM;
14using namespace mlir::LLVM::detail;
15
16namespace {
17/// Helper class that keeps the state of one metadata to attribute conversion.
18struct LoopMetadataConversion {
19 LoopMetadataConversion(const llvm::MDNode *node, Location loc,
20 LoopAnnotationImporter &loopAnnotationImporter)
21 : node(node), loc(loc), loopAnnotationImporter(loopAnnotationImporter),
22 ctx(loc->getContext()){};
23 /// Converts this structs loop metadata node into a LoopAnnotationAttr.
24 LoopAnnotationAttr convert();
25
26 /// Initializes the shared state for the conversion member functions.
27 LogicalResult initConversionState();
28
29 /// Helper function to get and erase a property.
30 const llvm::MDNode *lookupAndEraseProperty(StringRef name);
31
32 /// Helper functions to lookup and convert MDNodes into a specifc attribute
33 /// kind. These functions return null-attributes if there is no node with the
34 /// specified name, or failure, if the node is ill-formatted.
35 FailureOr<BoolAttr> lookupUnitNode(StringRef name);
36 FailureOr<BoolAttr> lookupBoolNode(StringRef name, bool negated = false);
37 FailureOr<BoolAttr> lookupIntNodeAsBoolAttr(StringRef name);
38 FailureOr<IntegerAttr> lookupIntNode(StringRef name);
39 FailureOr<llvm::MDNode *> lookupMDNode(StringRef name);
40 FailureOr<SmallVector<llvm::MDNode *>> lookupMDNodes(StringRef name);
41 FailureOr<LoopAnnotationAttr> lookupFollowupNode(StringRef name);
42 FailureOr<BoolAttr> lookupBooleanUnitNode(StringRef enableName,
43 StringRef disableName,
44 bool negated = false);
45
46 /// Conversion functions for sub-attributes.
47 FailureOr<LoopVectorizeAttr> convertVectorizeAttr();
48 FailureOr<LoopInterleaveAttr> convertInterleaveAttr();
49 FailureOr<LoopUnrollAttr> convertUnrollAttr();
50 FailureOr<LoopUnrollAndJamAttr> convertUnrollAndJamAttr();
51 FailureOr<LoopLICMAttr> convertLICMAttr();
52 FailureOr<LoopDistributeAttr> convertDistributeAttr();
53 FailureOr<LoopPipelineAttr> convertPipelineAttr();
54 FailureOr<LoopPeeledAttr> convertPeeledAttr();
55 FailureOr<LoopUnswitchAttr> convertUnswitchAttr();
56 FailureOr<SmallVector<AccessGroupAttr>> convertParallelAccesses();
57 FusedLoc convertStartLoc();
58 FailureOr<FusedLoc> convertEndLoc();
59
60 llvm::SmallVector<llvm::DILocation *, 2> locations;
61 llvm::StringMap<const llvm::MDNode *> propertyMap;
62 const llvm::MDNode *node;
63 Location loc;
64 LoopAnnotationImporter &loopAnnotationImporter;
65 MLIRContext *ctx;
66};
67} // namespace
68
69LogicalResult LoopMetadataConversion::initConversionState() {
70 // Check if it's a valid node.
71 if (node->getNumOperands() == 0 ||
72 dyn_cast<llvm::MDNode>(node->getOperand(0)) != node)
73 return emitWarning(loc) << "invalid loop node";
74
75 for (const llvm::MDOperand &operand : llvm::drop_begin(node->operands())) {
76 if (auto *diLoc = dyn_cast<llvm::DILocation>(operand)) {
77 locations.push_back(diLoc);
78 continue;
79 }
80
81 auto *property = dyn_cast<llvm::MDNode>(operand);
82 if (!property)
83 return emitWarning(loc) << "expected all loop properties to be either "
84 "debug locations or metadata nodes";
85
86 if (property->getNumOperands() == 0)
87 return emitWarning(loc) << "cannot import empty loop property";
88
89 auto *nameNode = dyn_cast<llvm::MDString>(property->getOperand(0));
90 if (!nameNode)
91 return emitWarning(loc) << "cannot import loop property without a name";
92 StringRef name = nameNode->getString();
93
94 bool succ = propertyMap.try_emplace(name, property).second;
95 if (!succ)
96 return emitWarning(loc)
97 << "cannot import loop properties with duplicated names " << name;
98 }
99
100 return success();
101}
102
103const llvm::MDNode *
104LoopMetadataConversion::lookupAndEraseProperty(StringRef name) {
105 auto it = propertyMap.find(name);
106 if (it == propertyMap.end())
107 return nullptr;
108 const llvm::MDNode *property = it->getValue();
109 propertyMap.erase(it);
110 return property;
111}
112
113FailureOr<BoolAttr> LoopMetadataConversion::lookupUnitNode(StringRef name) {
114 const llvm::MDNode *property = lookupAndEraseProperty(name);
115 if (!property)
116 return BoolAttr(nullptr);
117
118 if (property->getNumOperands() != 1)
119 return emitWarning(loc)
120 << "expected metadata node " << name << " to hold no value";
121
122 return BoolAttr::get(ctx, true);
123}
124
125FailureOr<BoolAttr> LoopMetadataConversion::lookupBooleanUnitNode(
126 StringRef enableName, StringRef disableName, bool negated) {
127 auto enable = lookupUnitNode(enableName);
128 auto disable = lookupUnitNode(disableName);
129 if (failed(enable) || failed(disable))
130 return failure();
131
132 if (*enable && *disable)
133 return emitWarning(loc)
134 << "expected metadata nodes " << enableName << " and " << disableName
135 << " to be mutually exclusive.";
136
137 if (*enable)
138 return BoolAttr::get(ctx, !negated);
139
140 if (*disable)
141 return BoolAttr::get(ctx, negated);
142 return BoolAttr(nullptr);
143}
144
145FailureOr<BoolAttr> LoopMetadataConversion::lookupBoolNode(StringRef name,
146 bool negated) {
147 const llvm::MDNode *property = lookupAndEraseProperty(name);
148 if (!property)
149 return BoolAttr(nullptr);
150
151 auto emitNodeWarning = [&]() {
152 return emitWarning(loc)
153 << "expected metadata node " << name << " to hold a boolean value";
154 };
155
156 if (property->getNumOperands() != 2)
157 return emitNodeWarning();
158 llvm::ConstantInt *val =
159 llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
160 if (!val || val->getBitWidth() != 1)
161 return emitNodeWarning();
162
163 return BoolAttr::get(ctx, val->getValue().getLimitedValue(1) ^ negated);
164}
165
166FailureOr<BoolAttr>
167LoopMetadataConversion::lookupIntNodeAsBoolAttr(StringRef name) {
168 const llvm::MDNode *property = lookupAndEraseProperty(name);
169 if (!property)
170 return BoolAttr(nullptr);
171
172 auto emitNodeWarning = [&]() {
173 return emitWarning(loc)
174 << "expected metadata node " << name << " to hold an integer value";
175 };
176
177 if (property->getNumOperands() != 2)
178 return emitNodeWarning();
179 llvm::ConstantInt *val =
180 llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
181 if (!val || val->getBitWidth() != 32)
182 return emitNodeWarning();
183
184 return BoolAttr::get(ctx, val->getValue().getLimitedValue(1));
185}
186
187FailureOr<IntegerAttr> LoopMetadataConversion::lookupIntNode(StringRef name) {
188 const llvm::MDNode *property = lookupAndEraseProperty(name);
189 if (!property)
190 return IntegerAttr(nullptr);
191
192 auto emitNodeWarning = [&]() {
193 return emitWarning(loc)
194 << "expected metadata node " << name << " to hold an i32 value";
195 };
196
197 if (property->getNumOperands() != 2)
198 return emitNodeWarning();
199
200 llvm::ConstantInt *val =
201 llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
202 if (!val || val->getBitWidth() != 32)
203 return emitNodeWarning();
204
205 return IntegerAttr::get(IntegerType::get(ctx, 32),
206 val->getValue().getLimitedValue());
207}
208
209FailureOr<llvm::MDNode *> LoopMetadataConversion::lookupMDNode(StringRef name) {
210 const llvm::MDNode *property = lookupAndEraseProperty(name);
211 if (!property)
212 return nullptr;
213
214 auto emitNodeWarning = [&]() {
215 return emitWarning(loc)
216 << "expected metadata node " << name << " to hold an MDNode";
217 };
218
219 if (property->getNumOperands() != 2)
220 return emitNodeWarning();
221
222 auto *node = dyn_cast<llvm::MDNode>(property->getOperand(1));
223 if (!node)
224 return emitNodeWarning();
225
226 return node;
227}
228
229FailureOr<SmallVector<llvm::MDNode *>>
230LoopMetadataConversion::lookupMDNodes(StringRef name) {
231 const llvm::MDNode *property = lookupAndEraseProperty(name);
232 SmallVector<llvm::MDNode *> res;
233 if (!property)
234 return res;
235
236 auto emitNodeWarning = [&]() {
237 return emitWarning(loc) << "expected metadata node " << name
238 << " to hold one or multiple MDNodes";
239 };
240
241 if (property->getNumOperands() < 2)
242 return emitNodeWarning();
243
244 for (unsigned i = 1, e = property->getNumOperands(); i < e; ++i) {
245 auto *node = dyn_cast<llvm::MDNode>(property->getOperand(i));
246 if (!node)
247 return emitNodeWarning();
248 res.push_back(node);
249 }
250
251 return res;
252}
253
254FailureOr<LoopAnnotationAttr>
255LoopMetadataConversion::lookupFollowupNode(StringRef name) {
256 auto node = lookupMDNode(name);
257 if (failed(node))
258 return failure();
259 if (*node == nullptr)
260 return LoopAnnotationAttr(nullptr);
261
262 return loopAnnotationImporter.translateLoopAnnotation(*node, loc);
263}
264
265static bool isEmptyOrNull(const Attribute attr) { return !attr; }
266
267template <typename T>
268static bool isEmptyOrNull(const SmallVectorImpl<T> &vec) {
269 return vec.empty();
270}
271
272/// Helper function that only creates and attribute of type T if all argument
273/// conversion were successfull and at least one of them holds a non-null value.
274template <typename T, typename... P>
275static T createIfNonNull(MLIRContext *ctx, const P &...args) {
276 bool anyFailed = (failed(args) || ...);
277 if (anyFailed)
278 return {};
279
280 bool allEmpty = (isEmptyOrNull(*args) && ...);
281 if (allEmpty)
282 return {};
283
284 return T::get(ctx, *args...);
285}
286
287FailureOr<LoopVectorizeAttr> LoopMetadataConversion::convertVectorizeAttr() {
288 FailureOr<BoolAttr> enable = lookupBooleanUnitNode(
289 "llvm.loop.vectorize.enable", "llvm.loop.vectorize.disable",
290 /*negated=*/true);
291 FailureOr<BoolAttr> predicateEnable =
292 lookupBoolNode("llvm.loop.vectorize.predicate.enable");
293 FailureOr<BoolAttr> scalableEnable =
294 lookupBoolNode("llvm.loop.vectorize.scalable.enable");
295 FailureOr<IntegerAttr> width = lookupIntNode("llvm.loop.vectorize.width");
296 FailureOr<LoopAnnotationAttr> followupVec =
297 lookupFollowupNode("llvm.loop.vectorize.followup_vectorized");
298 FailureOr<LoopAnnotationAttr> followupEpi =
299 lookupFollowupNode("llvm.loop.vectorize.followup_epilogue");
300 FailureOr<LoopAnnotationAttr> followupAll =
301 lookupFollowupNode("llvm.loop.vectorize.followup_all");
302
303 return createIfNonNull<LoopVectorizeAttr>(ctx, enable, predicateEnable,
304 scalableEnable, width, followupVec,
305 followupEpi, followupAll);
306}
307
308FailureOr<LoopInterleaveAttr> LoopMetadataConversion::convertInterleaveAttr() {
309 FailureOr<IntegerAttr> count = lookupIntNode("llvm.loop.interleave.count");
310 return createIfNonNull<LoopInterleaveAttr>(ctx, count);
311}
312
313FailureOr<LoopUnrollAttr> LoopMetadataConversion::convertUnrollAttr() {
314 FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
315 "llvm.loop.unroll.enable", "llvm.loop.unroll.disable", /*negated=*/true);
316 FailureOr<IntegerAttr> count = lookupIntNode("llvm.loop.unroll.count");
317 FailureOr<BoolAttr> runtimeDisable =
318 lookupUnitNode("llvm.loop.unroll.runtime.disable");
319 FailureOr<BoolAttr> full = lookupUnitNode("llvm.loop.unroll.full");
320 FailureOr<LoopAnnotationAttr> followupUnrolled =
321 lookupFollowupNode("llvm.loop.unroll.followup_unrolled");
322 FailureOr<LoopAnnotationAttr> followupRemainder =
323 lookupFollowupNode("llvm.loop.unroll.followup_remainder");
324 FailureOr<LoopAnnotationAttr> followupAll =
325 lookupFollowupNode("llvm.loop.unroll.followup_all");
326
327 return createIfNonNull<LoopUnrollAttr>(ctx, disable, count, runtimeDisable,
328 full, followupUnrolled,
329 followupRemainder, followupAll);
330}
331
332FailureOr<LoopUnrollAndJamAttr>
333LoopMetadataConversion::convertUnrollAndJamAttr() {
334 FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
335 "llvm.loop.unroll_and_jam.enable", "llvm.loop.unroll_and_jam.disable",
336 /*negated=*/true);
337 FailureOr<IntegerAttr> count =
338 lookupIntNode("llvm.loop.unroll_and_jam.count");
339 FailureOr<LoopAnnotationAttr> followupOuter =
340 lookupFollowupNode("llvm.loop.unroll_and_jam.followup_outer");
341 FailureOr<LoopAnnotationAttr> followupInner =
342 lookupFollowupNode("llvm.loop.unroll_and_jam.followup_inner");
343 FailureOr<LoopAnnotationAttr> followupRemainderOuter =
344 lookupFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_outer");
345 FailureOr<LoopAnnotationAttr> followupRemainderInner =
346 lookupFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_inner");
347 FailureOr<LoopAnnotationAttr> followupAll =
348 lookupFollowupNode("llvm.loop.unroll_and_jam.followup_all");
350 ctx, disable, count, followupOuter, followupInner, followupRemainderOuter,
351 followupRemainderInner, followupAll);
352}
353
354FailureOr<LoopLICMAttr> LoopMetadataConversion::convertLICMAttr() {
355 FailureOr<BoolAttr> disable = lookupUnitNode("llvm.licm.disable");
356 FailureOr<BoolAttr> versioningDisable =
357 lookupUnitNode("llvm.loop.licm_versioning.disable");
358 return createIfNonNull<LoopLICMAttr>(ctx, disable, versioningDisable);
359}
360
361FailureOr<LoopDistributeAttr> LoopMetadataConversion::convertDistributeAttr() {
362 FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
363 "llvm.loop.distribute.enable", "llvm.loop.distribute.disable",
364 /*negated=*/true);
365 FailureOr<LoopAnnotationAttr> followupCoincident =
366 lookupFollowupNode("llvm.loop.distribute.followup_coincident");
367 FailureOr<LoopAnnotationAttr> followupSequential =
368 lookupFollowupNode("llvm.loop.distribute.followup_sequential");
369 FailureOr<LoopAnnotationAttr> followupFallback =
370 lookupFollowupNode("llvm.loop.distribute.followup_fallback");
371 FailureOr<LoopAnnotationAttr> followupAll =
372 lookupFollowupNode("llvm.loop.distribute.followup_all");
373 return createIfNonNull<LoopDistributeAttr>(ctx, disable, followupCoincident,
374 followupSequential,
375 followupFallback, followupAll);
376}
377
378FailureOr<LoopPipelineAttr> LoopMetadataConversion::convertPipelineAttr() {
379 FailureOr<BoolAttr> disable = lookupBoolNode("llvm.loop.pipeline.disable");
380 FailureOr<IntegerAttr> initiationinterval =
381 lookupIntNode("llvm.loop.pipeline.initiationinterval");
382 return createIfNonNull<LoopPipelineAttr>(ctx, disable, initiationinterval);
383}
384
385FailureOr<LoopPeeledAttr> LoopMetadataConversion::convertPeeledAttr() {
386 FailureOr<IntegerAttr> count = lookupIntNode("llvm.loop.peeled.count");
387 return createIfNonNull<LoopPeeledAttr>(ctx, count);
388}
389
390FailureOr<LoopUnswitchAttr> LoopMetadataConversion::convertUnswitchAttr() {
391 FailureOr<BoolAttr> partialDisable =
392 lookupUnitNode("llvm.loop.unswitch.partial.disable");
393 return createIfNonNull<LoopUnswitchAttr>(ctx, partialDisable);
394}
395
396FailureOr<SmallVector<AccessGroupAttr>>
397LoopMetadataConversion::convertParallelAccesses() {
398 FailureOr<SmallVector<llvm::MDNode *>> nodes =
399 lookupMDNodes("llvm.loop.parallel_accesses");
400 if (failed(nodes))
401 return failure();
402 SmallVector<AccessGroupAttr> refs;
403 for (llvm::MDNode *node : *nodes) {
404 FailureOr<SmallVector<AccessGroupAttr>> accessGroups =
405 loopAnnotationImporter.lookupAccessGroupAttrs(node);
406 if (failed(accessGroups)) {
407 emitWarning(loc) << "could not lookup access group";
408 continue;
409 }
410 llvm::append_range(refs, *accessGroups);
411 }
412 return refs;
413}
414
415FusedLoc LoopMetadataConversion::convertStartLoc() {
416 if (locations.empty())
417 return {};
418 return dyn_cast<FusedLoc>(
419 loopAnnotationImporter.moduleImport.translateLoc(locations[0]));
420}
421
422FailureOr<FusedLoc> LoopMetadataConversion::convertEndLoc() {
423 if (locations.size() < 2)
424 return FusedLoc();
425 if (locations.size() > 2)
426 return emitError(loc)
427 << "expected loop metadata to have at most two DILocations";
428 return dyn_cast<FusedLoc>(
429 loopAnnotationImporter.moduleImport.translateLoc(locations[1]));
430}
431
432LoopAnnotationAttr LoopMetadataConversion::convert() {
433 if (failed(initConversionState()))
434 return {};
435
436 FailureOr<BoolAttr> disableNonForced =
437 lookupUnitNode("llvm.loop.disable_nonforced");
438 FailureOr<LoopVectorizeAttr> vecAttr = convertVectorizeAttr();
439 FailureOr<LoopInterleaveAttr> interleaveAttr = convertInterleaveAttr();
440 FailureOr<LoopUnrollAttr> unrollAttr = convertUnrollAttr();
441 FailureOr<LoopUnrollAndJamAttr> unrollAndJamAttr = convertUnrollAndJamAttr();
442 FailureOr<LoopLICMAttr> licmAttr = convertLICMAttr();
443 FailureOr<LoopDistributeAttr> distributeAttr = convertDistributeAttr();
444 FailureOr<LoopPipelineAttr> pipelineAttr = convertPipelineAttr();
445 FailureOr<LoopPeeledAttr> peeledAttr = convertPeeledAttr();
446 FailureOr<LoopUnswitchAttr> unswitchAttr = convertUnswitchAttr();
447 FailureOr<BoolAttr> mustProgress = lookupUnitNode("llvm.loop.mustprogress");
448 FailureOr<BoolAttr> isVectorized =
449 lookupIntNodeAsBoolAttr("llvm.loop.isvectorized");
450 FailureOr<SmallVector<AccessGroupAttr>> parallelAccesses =
451 convertParallelAccesses();
452
453 // Drop the metadata if there are parts that cannot be imported.
454 if (!propertyMap.empty()) {
455 for (auto name : propertyMap.keys())
456 emitWarning(loc) << "unknown loop annotation " << name;
457 return {};
458 }
459
460 FailureOr<FusedLoc> startLoc = convertStartLoc();
461 FailureOr<FusedLoc> endLoc = convertEndLoc();
462
464 ctx, disableNonForced, vecAttr, interleaveAttr, unrollAttr,
465 unrollAndJamAttr, licmAttr, distributeAttr, pipelineAttr, peeledAttr,
466 unswitchAttr, mustProgress, isVectorized, startLoc, endLoc,
467 parallelAccesses);
468}
469
470LoopAnnotationAttr
472 Location loc) {
473 if (!node)
474 return {};
475
476 // Note: This check is necessary to distinguish between failed translations
477 // and not yet attempted translations.
478 auto it = loopMetadataMapping.find(node);
479 if (it != loopMetadataMapping.end())
480 return it->getSecond();
481
482 LoopAnnotationAttr attr = LoopMetadataConversion(node, loc, *this).convert();
483
484 mapLoopMetadata(node, attr);
485 return attr;
486}
487
488LogicalResult
490 Location loc) {
492 if (!node->getNumOperands())
493 accessGroups.push_back(node);
494 for (const llvm::MDOperand &operand : node->operands()) {
495 auto *childNode = dyn_cast<llvm::MDNode>(operand);
496 if (!childNode)
497 return failure();
498 accessGroups.push_back(cast<llvm::MDNode>(operand.get()));
499 }
500
501 // Convert all entries of the access group list to access group operations.
502 for (const llvm::MDNode *accessGroup : accessGroups) {
503 if (accessGroupMapping.count(accessGroup))
504 continue;
505 // Verify the access group node is distinct and empty.
506 if (accessGroup->getNumOperands() != 0 || !accessGroup->isDistinct())
507 return emitWarning(loc)
508 << "expected an access group node to be empty and distinct";
509
510 // Add a mapping from the access group node to the newly created attribute.
511 accessGroupMapping[accessGroup] = builder.getAttr<AccessGroupAttr>();
512 }
513 return success();
514}
515
516FailureOr<SmallVector<AccessGroupAttr>>
517LoopAnnotationImporter::lookupAccessGroupAttrs(const llvm::MDNode *node) const {
518 // An access group node is either a single access group or an access group
519 // list.
520 SmallVector<AccessGroupAttr> accessGroups;
521 if (!node->getNumOperands())
522 accessGroups.push_back(accessGroupMapping.lookup(node));
523 for (const llvm::MDOperand &operand : node->operands()) {
524 auto *node = cast<llvm::MDNode>(operand.get());
525 accessGroups.push_back(accessGroupMapping.lookup(node));
526 }
527 // Exit if one of the access group node lookups failed.
528 if (llvm::is_contained(accessGroups, nullptr))
529 return failure();
530 return accessGroups;
531}
return success()
static T createIfNonNull(MLIRContext *ctx, const P &...args)
Helper function that only creates and attribute of type T if all argument conversion were successfull...
static bool isEmptyOrNull(const Attribute attr)
b getContext())
Attributes are known-constant values of operations.
Definition Attributes.h:25
static BoolAttr get(MLIRContext *context, bool value)
Location translateLoc(llvm::DILocation *loc)
Translates the debug location.
LoopAnnotationAttr translateLoopAnnotation(const llvm::MDNode *node, Location loc)
LogicalResult translateAccessGroup(const llvm::MDNode *node, Location loc)
Converts all LLVM access groups starting from node to MLIR access group attributes.
ModuleImport & moduleImport
The ModuleImport owning this instance.
FailureOr< SmallVector< AccessGroupAttr > > lookupAccessGroupAttrs(const llvm::MDNode *node) const
Returns the access group attribute that map to the access group nodes starting from the access group ...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:717
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.